[DRAFT] 휴대폰으로 알람을 보내보자 - ntfy

[DRAFT] 휴대폰으로 알람을 보내보자 - ntfy

너무 오래 앉아있는 현대인을 일어나게 하라.

현대인 대부분은 사무실 의자에 앉아서 9시간 이상을 보낸다. 이 때 더욱 심각한 문제는 컴퓨터 모니터를 들여다보고 있다보면 한 시간이 훌쩍 지나도록 시간가는 줄 모른다는 것이다. 이런 생활 습관은 내 허리와 눈 건강에 지대한 악영향을 미칠 것이 자명하다. (실제 요즘 시력이 조금씩 떨어지고 있다…)

이 문제를 해결해 보고자 일명 구글 타이머도 구매하여 사용해보았지만, 여러 사람이 함께 쓰는 사무실에서 소리로 알람을 울리는 방식은 굉장한 민폐가 아닐 수 없다. 그렇다고 소리를 끄고 쓰면 잘 사용하지 않게 된다.

아… 어떡하나?
어떻게 해야 시간가는 줄 모르고 앉아있을 나의 옆구리를 쿡 찔러서, 잠시 몸을 풀 시간을 갖도록 만들 수 있을까?

고민을 하던 찰나, 우연히 ntfy라는 오픈소스 프로젝트를 알게 되었다. 그럼 같이 ntfy에 대해 알아보도록 하자.

ntfy는 무엇인가?

ntfy (pronounced notify) is a simple HTTP-based pub-sub notification service. It allows you to send notifications to your phone or desktop via scripts from any computer, and/or using a REST API. It’s infinitely flexible, and 100% free software.

ntfy 는 터미널 명령어를 통해 전송된(published) 메시지들을 수신하고, 그 메시지를 구독(subscribe)하고 있는 클라이언트들에게 알람으로써 전달해주는 서비스다.

  graph LR
    A(("Publisher"))
    B["ntfy<br>server"]
    C(("Client<br>아이폰"))
    D(("Client<br>데스크톱"))

    A e0@-->|메시지 생성 및 전달| B e1@-->|메시지| C 
    B e2@-->|메시지|D

    e0@{ animate: true }
    e1@{ animate: true }
    e2@{ animate: true }

슬쩍 보면 별 기능이 아닌 것처럼 보인다. 그러나, 쉘 스크립트와 crontab을 함께 잘 활용한다면, 메시지 보내는 원하는 대로 자동화할 수 있다. 또한, 메시지를 수신할 수 있는 클라이언트로 pc뿐만 아니라 안드로이드, 아이폰 모두를 사용할 수 있고, 클라이언트의 개수에도 제한이 없다.

자, 이제 ntfy가 뭔지 알았으니 실제 ntfy를 사용법을 알아보도록 하자.

구축하려는 환경

우리가 구축하려는 환경은 다음과 같다.

  graph LR
    A["Publisher"]
    B["ntfy<br>server"]
    C(("Client<br>아이폰"))
    D(("Client<br>데스크톱"))
    E(("Client<br>안드로이드"))
    
    subgraph Any desktop
    A
    end

    subgraph server
    B
    end

    A e0@-->|메시지 생성 및 전달| B e1@-->|메시지| C 
    B e2@-->|메시지|D
    B e3@-->|메시지|E


    e0@{ animate: true }
    e1@{ animate: true }
    e2@{ animate: true }
    e3@{ animate: true }

준비물

ntfy 환경 구축에 필요한 준비물은 1)서버와 2)개인 도메인이다. 개인 도메인은 메시지 수신을 위해 반드시 필요하다.

Tailscale을 사용한다면, 개인 도메인이 없더라도 tailscale funnel을 사용하여 공개하는 것도 가능하다! Tailscale 기본 사용법 포스트가 있으니 참고하시길.

ntfy 환경 구축하기

이번 포스팅에서는 proxmox 대신, 도커를 활용하기로 한다.

docker와 docker-compose 설치하기

본 포스팅에선 docker와 docker-compose가 설치되어 있고, 그 사용법에 익숙하다는 것을 전제로 한다. 이들의 절차는 arch wiki 를 참고하자.

ntfy를 위한 폴더 준비하기

ntfy 파일들이 저장될 경로를 하나 준비해주자. 필자는 ~/ntfy로 준비했다.

docker-compose.yml 파일 작성하기

docker compose로 환경 구축을 위해 docker-compose.yml을 다음처럼 작성해주자. 작성 내용은 필요에 따라 ntfy의 공식 가이드를 참고하여 커스텀해주자.

필자는 다음과 같은 옵션을 포함하였다.

  1. 개인 도메인으로 연결
  2. 계정 인증된 사용자만 subscribe 가능하도록 설정
  3. 아이폰에서 메시지 수신 가능하도록 설정
/home/will/ntfy/docker-compose.yml
services:
  ntfy:
    image: docker.io/binwiederhier/ntfy
    restart: unless-stopped
    environment:
      NTFY_BASE_URL: https://ntfy.mydomain.com # 이 부분을 개인 도메인으로 바꾸면 된다. subdomain은 ntfy가 아니어도 된다.
      NTFY_CACHE_FILE: /var/lib/ntfy/cache.db
      NTFY_AUTH_FILE: /var/lib/ntfy/auth.db
      NTFY_AUTH_DEFAULT_ACCESS: deny-all
      NTFY_BEHIND_PROXY: true
      NTFY_ATTACHMENT_CACHE_DIR: /var/lib/ntfy/attachments
      NTFY_ENABLE_LOGIN: true
      NTFY_UPSTREAM_BASE_URL: https://ntfy.sh # 아이폰으로 메시지 수신을 위해선 이 경로도 설정해줘야 한다. 필요없다면 이 줄은 제거하자.
    volumes:
      - ./:/var/lib/ntfy # docker-compose.yml이 있는 경로를 ntfy 시스템 파일들의 저장소로 연결
    ports:
      - 4080:80 # 좌측이 host의 포트, 우측이 도커 내부의 포트다. 필자는 호스트의 4080 포트를 ntfy의 80번 포트와 연결해주었다.
    command: serve

docker compose run 하기

도커파일 작성이 완료되었다면, docker-compose.yml 파일이 있는 경로에서 다음의 명령어를 입력하여 ntfy 서버를 작동해보자.

/home/will/ntfy에서 실행
docker compose up -d

에러가 뜬다면, docker-compose.yml 작성에 오류가 있는 것이니 잘 보고 오류를 해결해주자.

localhost:4080 접속 가능 여부 확인

정상적으로 docker compose가 이뤄졌다면, localhost:4080으로 접속이 잘 되는지 확인해보자. 필자는 다음처럼 ntfy 페이지가 잘 표시되었다.

localhost:4080으로 접속
localhost:4080으로 접속

authentication 작동 여부 확인

앞서 docker-compose.yml에서 아이디와 비밀번호를 통해 인증을 하도록 설정했었다. 실제 의도대로 동작하는지 다음의 그림처럼 subscribe를 시도하여 확인해보자.

subscribe to topic을 누른다.
subscribe to topic을 누른다.
아무 주제나 지정하여 구독해보자.
아무 주제나 지정하여 구독해보자.
id와 pw를 요구한다면 의도대로 동작하는 것이다.
id와 pw를 요구한다면 의도대로 동작하는 것이다.

계정 생성하기

내가 사용할 계정을 만들어보자. 이를 위해 먼저 우리가 만든 ntfy 컨테이너 내부로 sh 연결을 해줘야 한다.

docker exec -it ntfy sh # ntfy는 우리가 만든 컨테이너 이름이고, 연결할 쉘은 sh이다.

그러면 다음처럼 터미널의 prompt가 / #으로 바뀐 것을 알 수 있다. 우리는 지금 컨테이너 내부에 들어와있다.

[will@archbox ntfy]$ docker exec -it ntfy sh
/ #

본 포스팅에서는 관리자 계정 하나만 만든다. 이후 필요하다면 사용자 계정을 추가하면 된다.

다음 명령어로 관리자 계정을 만들어준다. 입력하면 password까지 설정할 수 있다.

ntfy 컨테이너 sh에서 실행
ntfy user add --role=admin will    # 관리자 will 추가, 원하는 이름으로 생성

계정 로그인 가능 여부 확인하기

계정을 추가했으니, localhost:4080에 다시 접속하여 로그인 가능 여부를 확인해주자.

우측 상단의 sign in을 눌러서 로그인을 시도한다.
우측 상단의 sign in을 눌러서 로그인을 시도한다.
sh에서 생성한 id와 pw를 입력한다.
sh에서 생성한 id와 pw를 입력한다.
정상적으로 로그인된 상태
정상적으로 로그인된 상태

로그인이 잘된다면 다음으로 넘어가자.

DNS record 및 reverse proxy 등록

자, 로컬에서 잘 동작하는 것을 확인하였으니 이어서 ntfy에 ntfy.mydomain.com으로 subdomain 주소를 부여해주자. 이 작업의 핵심은 localhost:4080ntfy.mydomain.com에 연결해주는 것이다.

이 부분도 굉장히 복잡하여 본 포스팅의 범위를 넘어선다. 자세한 내용은 구글링을 통해 수행하길 바란다.

연결된 ntfy 주소로 접속하고 로그인하기

DNS record 등록과 reverse proxy 등록이 잘 되었다면, ntfy 주소로 접속해보자. 다음처럼 접속이 잘되는 것을 확인하면 된다. 접속이 잘되면 로그인까지 진행해주자.

주소로 접속했을 때, 앞서 localhost로 접속한 것과 똑같은 화면이 뜨는지 확인해준다.
주소로 접속했을 때, 앞서 localhost로 접속한 것과 똑같은 화면이 뜨는지 확인해준다.

topic 구독하고 메시지 테스트하기

ntfy는 topic이라는 단위로 수집하는 메시지들을 구분짓고 있다. 나는 personal, server로 topic을 구분하여 수신하고 있다.

예시로써 다음처럼 personal이라는 topic을 구독(subscribe)해보자.

personal이라는 topic 구독
personal이라는 topic 구독

구독이 된 주제는 좌측 Subscribed topics에 뜨게된다.

구독이 되면, 좌측에 등록이 된 것을 볼 수 있다.
구독이 되면, 좌측에 등록이 된 것을 볼 수 있다.

이어서, 구독한 personal topic 페이지로 가서 테스트 메시지를 보내보자. 1-3번의 순서로 진행하면 된다.

주소로 접속했을 때, 앞서 localhost로 접속한 것과 똑같은 화면이 뜨는지 확인해준다.
주소로 접속했을 때, 앞서 localhost로 접속한 것과 똑같은 화면이 뜨는지 확인해준다.

테스트 메시지가 잘 수신되는 것을 알 수 있다.

주소로 접속했을 때, 앞서 localhost로 접속한 것과 똑같은 화면이 뜨는지 확인해준다.
주소로 접속했을 때, 앞서 localhost로 접속한 것과 똑같은 화면이 뜨는지 확인해준다.

이어서 terminal에서도 다음의 명령어를 통해 테스트 메시지를 테스트해보자. 터미널에서는 curl을 사용하여 다음처럼 메시지를 보낼 수 있다.

이때 유의할 점이 몇 가지 있다.

  • pw/id를 사용하도록 설정한 경우, 메시지를 보낼 때 그 인증정보를 붙여서 보내야 한다. (-u id:pw 옵션을 사용)
  • 특정 토픽으로 보내기 위해 ntfy의 주소 뒤에 /topic을 붙여준다. 여기선 /personal을 붙여주었다.
  • 메시지는 -d "메시지" 옵션으로 작성해준다.
bash
curl -u will:1234 -d "테스트 메시지 from terminal" https://ntfy.mydomain/personal

그러면 이런 출력이 나오면서 메시지가 웹 상에 나타난다.

[will@archbox ntfy]$ curl -u will:1234 -d "테스트 메시지 from terminal" https://ntfy.mydomain.com/personal
{"id":"5Z8FWYtKIYeQ","time":1772193126,"expires":1772236326,"event":"message","topic":"personal","message":"테스트 메시지 from terminal"}
발신한 메시지가 웹에서 수신된 것을 알 수 있다. 이 경우, 데스크톱의 웹이 클라이언트이다.
발신한 메시지가 웹에서 수신된 것을 알 수 있다. 이 경우, 데스크톱의 웹이 클라이언트이다.

iOS 클라이언트 설정하기

Last updated on