From e285b23534997e4b73dc8d3b7e311b96bba782ae Mon Sep 17 00:00:00 2001 From: Frank Schwenk Date: Mon, 6 Jul 2026 11:12:14 +0200 Subject: [PATCH] Add self-hosted ntfy deployment for ntfy.schwenk.online. Docker Compose with Traefik routing, auth-enabled server config, and local cache volume. Co-authored-by: Cursor --- .gitignore | 2 ++ compose.yml | 38 ++++++++++++++++++++++++++++++++++++++ config/server.yml | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 .gitignore create mode 100644 compose.yml create mode 100644 config/server.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa6c12e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Runtime data (auth DB, message cache, attachments) +cache/ diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..c5bd8fa --- /dev/null +++ b/compose.yml @@ -0,0 +1,38 @@ +services: + + ntfy: + image: binwiederhier/ntfy + container_name: ntfy.schwenk.online + command: + - serve + environment: + - TZ=Europe/Berlin + user: 1002:1002 + volumes: + - ./cache:/var/cache/ntfy + - ./config:/etc/ntfy + - /etc/localtime:/etc/localtime:ro + healthcheck: + test: ["CMD-SHELL", "wget -q --tries=1 http://localhost:80/v1/health -O - | grep -Eo '\"healthy\"\\s*:\\s*true' || exit 1"] + interval: 60s + timeout: 10s + retries: 3 + start_period: 40s + restart: unless-stopped + init: true + networks: + - traefik + labels: + - "traefik.enable=true" + - "traefik.http.routers.ntfyschwenkonline.rule=Host(`ntfy.schwenk.online`)" + - "traefik.http.routers.ntfyschwenkonline.entrypoints=websecure" + - "traefik.http.routers.ntfyschwenkonline.tls.certresolver=myresolver" + - "traefik.http.services.ntfyschwenkonline.loadbalancer.server.port=80" + # HSTS at TLS terminator (Traefik) + - "traefik.http.middlewares.ntfyschwenkonline-headers.headers.stsSeconds=31536000" + - "traefik.http.middlewares.ntfyschwenkonline-headers.headers.stsIncludeSubdomains=true" + - "traefik.http.routers.ntfyschwenkonline.middlewares=ntfyschwenkonline-headers" + +networks: + traefik: + external: true diff --git a/config/server.yml b/config/server.yml new file mode 100644 index 0000000..f84e738 --- /dev/null +++ b/config/server.yml @@ -0,0 +1,33 @@ +# ntfy.schwenk.online — personal push server (TLS terminated by Traefik) + +base-url: "https://ntfy.schwenk.online" +listen-http: ":80" +behind-proxy: true + +# Message cache (survives restarts, supports since= polling) +cache-file: "/var/cache/ntfy/cache.db" +cache-duration: "12h" +cache-startup-queries: | + pragma journal_mode = WAL; + pragma synchronous = normal; + pragma temp_store = memory; + pragma busy_timeout = 15000; + +# Access control — create your first admin user after start: +# docker exec -it ntfy.schwenk.online ntfy user add frank --role=admin +auth-file: "/var/cache/ntfy/auth.db" +auth-default-access: "deny-all" +enable-login: true +require-login: true +enable-signup: false + +# Attachments (e.g. Grafana alerts, backup reports) +attachment-cache-dir: "/var/cache/ntfy/attachments" +attachment-total-size-limit: "500M" +attachment-file-size-limit: "5M" +attachment-expiry-duration: "24h" + +# iOS app: uses ntfy.sh only for poll_request signaling; message content stays here +upstream-base-url: "https://ntfy.sh" + +keepalive-interval: "45s"