feat(ntfy): 푸시 알림 서버 Phase 1 인프라 구축
- docker-compose.yml에 ntfy 서비스 추가 (포트 30750) - ntfy/etc/server.yml 서버 설정 (인증 deny-all, 72h 캐시) - ntfy/README.md 운영 매뉴얼 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -481,6 +481,25 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- tk-network
|
- tk-network
|
||||||
|
|
||||||
|
# =================================================================
|
||||||
|
# ntfy — 푸시 알림 서버
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
ntfy:
|
||||||
|
image: binwiederhier/ntfy
|
||||||
|
container_name: tk-ntfy
|
||||||
|
restart: unless-stopped
|
||||||
|
command: serve
|
||||||
|
ports:
|
||||||
|
- "30750:80"
|
||||||
|
environment:
|
||||||
|
- TZ=Asia/Seoul
|
||||||
|
volumes:
|
||||||
|
- ./ntfy/etc:/etc/ntfy
|
||||||
|
- ntfy_cache:/var/cache/ntfy
|
||||||
|
networks:
|
||||||
|
- tk-network
|
||||||
|
|
||||||
# =================================================================
|
# =================================================================
|
||||||
# AI Service — 맥미니로 이전됨 (~/docker/tk-ai-service/)
|
# AI Service — 맥미니로 이전됨 (~/docker/tk-ai-service/)
|
||||||
# =================================================================
|
# =================================================================
|
||||||
@@ -544,6 +563,7 @@ services:
|
|||||||
- tksafety-web
|
- tksafety-web
|
||||||
- tksupport-web
|
- tksupport-web
|
||||||
- tkeg-web
|
- tkeg-web
|
||||||
|
- ntfy
|
||||||
networks:
|
networks:
|
||||||
- tk-network
|
- tk-network
|
||||||
|
|
||||||
@@ -563,6 +583,7 @@ volumes:
|
|||||||
name: tkqc-package_uploads
|
name: tkqc-package_uploads
|
||||||
tkeg_postgres_data:
|
tkeg_postgres_data:
|
||||||
tkeg_uploads:
|
tkeg_uploads:
|
||||||
|
ntfy_cache:
|
||||||
networks:
|
networks:
|
||||||
tk-network:
|
tk-network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|||||||
167
ntfy/README.md
Normal file
167
ntfy/README.md
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
# ntfy 푸시 알림 서버 — 운영 매뉴얼
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
ntfy는 Web Push(VAPID)의 iOS 제한, 전송 보장 부재 등을 보완하는 푸시 알림 채널이다.
|
||||||
|
모바일 ntfy 앱으로 알림을 수신하고, 탭하면 딥링크로 해당 페이지로 이동한다.
|
||||||
|
|
||||||
|
- **Docker 서비스명**: `ntfy`
|
||||||
|
- **내부 URL**: `http://ntfy:80` (Docker 네트워크)
|
||||||
|
- **외부 URL**: `https://ntfy.technicalkorea.net` (Cloudflare Tunnel)
|
||||||
|
- **호스트 포트**: `30750`
|
||||||
|
- **설정 파일**: `ntfy/etc/server.yml`
|
||||||
|
- **데이터**: `ntfy_cache` Docker 볼륨 (`/var/cache/ntfy`)
|
||||||
|
|
||||||
|
## 초기 설정 (최초 1회)
|
||||||
|
|
||||||
|
### 1. Cloudflare Tunnel 설정
|
||||||
|
|
||||||
|
Zero Trust 대시보드 → Tunnels → Public Hostname 추가:
|
||||||
|
|
||||||
|
| Subdomain | Domain | Service |
|
||||||
|
|-----------|--------|---------|
|
||||||
|
| ntfy | technicalkorea.net | http://ntfy:80 |
|
||||||
|
|
||||||
|
### 2. 컨테이너 기동
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d ntfy
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 관리자 계정 + 토큰 발급
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 관리자 계정 생성 (비밀번호 입력 프롬프트)
|
||||||
|
docker exec -it tk-ntfy ntfy user add --role=admin admin
|
||||||
|
|
||||||
|
# API 토큰 발급
|
||||||
|
docker exec -it tk-ntfy ntfy token add admin
|
||||||
|
# 출력 예: tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. .env에 토큰 설정
|
||||||
|
|
||||||
|
```env
|
||||||
|
NTFY_PUBLISH_TOKEN=<위에서 발급받은 토큰>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 메시지 발행 (서버 → 사용자)
|
||||||
|
|
||||||
|
### curl로 테스트
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 기본 메시지
|
||||||
|
curl -H "Authorization: Bearer $NTFY_PUBLISH_TOKEN" \
|
||||||
|
-d "테스트 메시지입니다." \
|
||||||
|
http://localhost:30750/tkfactory-test
|
||||||
|
|
||||||
|
# 제목 + 딥링크 포함
|
||||||
|
curl -H "Authorization: Bearer $NTFY_PUBLISH_TOKEN" \
|
||||||
|
-H "Title: 설비수리 요청" \
|
||||||
|
-H "Tags: wrench" \
|
||||||
|
-H "Click: https://tkfb.technicalkorea.net/pages/admin/repair-management.html" \
|
||||||
|
-d "A동 CNC 설비 수리 요청이 접수되었습니다." \
|
||||||
|
http://localhost:30750/tkfactory-user-1
|
||||||
|
|
||||||
|
# 우선순위 높은 알림 (5=max, 3=default, 1=min)
|
||||||
|
curl -H "Authorization: Bearer $NTFY_PUBLISH_TOKEN" \
|
||||||
|
-H "Title: 긴급 안전 알림" \
|
||||||
|
-H "Priority: 5" \
|
||||||
|
-H "Tags: warning" \
|
||||||
|
-d "즉시 확인이 필요합니다." \
|
||||||
|
http://localhost:30750/tkfactory-user-1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 토픽 네이밍 규칙
|
||||||
|
|
||||||
|
| 토픽 | 용도 |
|
||||||
|
|------|------|
|
||||||
|
| `tkfactory-user-{userId}` | 사용자별 개인 알림 (Phase 2에서 사용) |
|
||||||
|
| `tkfactory-test` | 테스트용 |
|
||||||
|
|
||||||
|
### 주요 헤더
|
||||||
|
|
||||||
|
| 헤더 | 설명 | 예시 |
|
||||||
|
|------|------|------|
|
||||||
|
| `Title` | 알림 제목 | `설비수리 요청` |
|
||||||
|
| `Click` | 탭 시 열릴 URL (딥링크) | `https://tkfb.technicalkorea.net/pages/work/tbm.html` |
|
||||||
|
| `Tags` | 이모지 태그 ([목록](https://docs.ntfy.sh/emojis/)) | `wrench`, `warning`, `white_check_mark` |
|
||||||
|
| `Priority` | 1(min) ~ 5(max) | `5` |
|
||||||
|
| `Authorization` | 인증 토큰 | `Bearer tk_...` |
|
||||||
|
|
||||||
|
## 사용자 관리
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 사용자 목록
|
||||||
|
docker exec tk-ntfy ntfy user list
|
||||||
|
|
||||||
|
# 일반 사용자 추가
|
||||||
|
docker exec -it tk-ntfy ntfy user add username
|
||||||
|
|
||||||
|
# 사용자 삭제
|
||||||
|
docker exec tk-ntfy ntfy user del username
|
||||||
|
|
||||||
|
# 특정 토픽 접근 권한 부여 (read-write / read-only / write-only)
|
||||||
|
docker exec tk-ntfy ntfy access username 'tkfactory-user-*' read-only
|
||||||
|
|
||||||
|
# 토큰 발급
|
||||||
|
docker exec tk-ntfy ntfy token add username
|
||||||
|
|
||||||
|
# 토큰 목록
|
||||||
|
docker exec tk-ntfy ntfy token list
|
||||||
|
|
||||||
|
# 토큰 삭제
|
||||||
|
docker exec tk-ntfy ntfy token remove username tk_...
|
||||||
|
```
|
||||||
|
|
||||||
|
## 모바일 앱 설정 (수신자용)
|
||||||
|
|
||||||
|
### Android
|
||||||
|
1. Play Store에서 **ntfy** 설치
|
||||||
|
2. 설정(⚙️) → **Default server** → `https://ntfy.technicalkorea.net` 입력
|
||||||
|
3. 우측 상단 사용자 아이콘 → 로그인 (발급받은 계정/비밀번호 또는 토큰)
|
||||||
|
4. **+** → 토픽 `tkfactory-user-{본인userId}` 구독
|
||||||
|
|
||||||
|
### iOS
|
||||||
|
1. App Store에서 **ntfy** 설치
|
||||||
|
2. Settings → **Default server** → `https://ntfy.technicalkorea.net` 입력
|
||||||
|
3. 로그인 후 토픽 구독 (Android와 동일)
|
||||||
|
|
||||||
|
## 서버 설정 (server.yml)
|
||||||
|
|
||||||
|
| 항목 | 현재 값 | 설명 |
|
||||||
|
|------|---------|------|
|
||||||
|
| `auth-default-access` | `deny-all` | 인증 없이 접근 불가 |
|
||||||
|
| `cache-duration` | `72h` | 메시지 보관 기간 (주말 포함 3일) |
|
||||||
|
| `visitor-request-limit-burst` | `60` | 버스트 요청 한도 |
|
||||||
|
| `visitor-request-limit-replenish` | `5s` | 요청 한도 보충 주기 |
|
||||||
|
|
||||||
|
설정 변경 후 컨테이너 재시작:
|
||||||
|
```bash
|
||||||
|
docker compose restart ntfy
|
||||||
|
```
|
||||||
|
|
||||||
|
## 트러블슈팅
|
||||||
|
|
||||||
|
### 401 Unauthorized
|
||||||
|
- 토큰이 맞는지 확인: `docker exec tk-ntfy ntfy token list`
|
||||||
|
- `auth-default-access: deny-all` 상태에서 토큰 없이 요청하면 발생
|
||||||
|
|
||||||
|
### 모바일 앱에서 알림이 안 옴
|
||||||
|
- Cloudflare Tunnel Public Hostname에 `ntfy.technicalkorea.net` 등록되었는지 확인
|
||||||
|
- 앱의 Default server URL이 `https://ntfy.technicalkorea.net`인지 확인
|
||||||
|
- 앱에서 로그인했는지, 토픽을 구독했는지 확인
|
||||||
|
- 폰 설정에서 ntfy 앱 알림 권한이 켜져 있는지 확인
|
||||||
|
|
||||||
|
### 컨테이너 로그 확인
|
||||||
|
```bash
|
||||||
|
docker logs tk-ntfy --tail 50
|
||||||
|
docker logs tk-ntfy -f # 실시간
|
||||||
|
```
|
||||||
|
|
||||||
|
## Phase 2 예정 사항 (참고)
|
||||||
|
|
||||||
|
- `system1-factory/api/models/notificationModel.js`의 `sendPushToUsers()`에서 ntfy 발송 연동
|
||||||
|
- `push_subscriptions` 테이블에 `channel` 컬럼 추가 (`web_push` | `ntfy`)
|
||||||
|
- ntfy 구독 사용자에게는 Web Push 미발송 (중복 방지)
|
||||||
|
- notification-bell.js에서 ntfy 구독 토글 UI 추가
|
||||||
23
ntfy/etc/server.yml
Normal file
23
ntfy/etc/server.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# ntfy server configuration
|
||||||
|
# Docs: https://docs.ntfy.sh/config/
|
||||||
|
|
||||||
|
# Base URL (Cloudflare Tunnel 경유)
|
||||||
|
base-url: "https://ntfy.technicalkorea.net"
|
||||||
|
|
||||||
|
# Listen on port 80 inside the container
|
||||||
|
listen-http: ":80"
|
||||||
|
|
||||||
|
# Cache — 72시간 (금요일 알림 → 월요일 확인 가능)
|
||||||
|
cache-duration: "72h"
|
||||||
|
cache-file: "/var/cache/ntfy/cache.db"
|
||||||
|
|
||||||
|
# Auth — 기본 접근 거부, 토큰 인증 필수
|
||||||
|
auth-default-access: "deny-all"
|
||||||
|
auth-file: "/var/cache/ntfy/user.db"
|
||||||
|
|
||||||
|
# Attachment (비활성화 — Phase 1에서는 텍스트 알림만)
|
||||||
|
# attachment-cache-dir: "/var/cache/ntfy/attachments"
|
||||||
|
|
||||||
|
# Rate limiting
|
||||||
|
visitor-request-limit-burst: 60
|
||||||
|
visitor-request-limit-replenish: "5s"
|
||||||
Reference in New Issue
Block a user