job "ntfy" { group "ntfy" { network { mode = "bridge" port "http" { to = 80 } } # Consul Connect sidecar with upstream to postgres service { connect { sidecar_service { proxy { upstreams { destination_name = "postgres" local_bind_port = 5432 } } } } } service { name = "ntfy" port = "http" tags = [ "traefik.enable=true", "traefik.http.routers.ntfy.middlewares=auth@file", # Token subdomain bypasses Authelia — ntfy's own token auth is sufficient for API access "traefik.http.routers.ntfy-token.rule=Host(`ntfy-2e30e5869ab6bfde4961012b48761a9b.othrayte.one`)", ] check { type = "http" path = "/healthz" interval = "10s" timeout = "2s" } } # Users and tokens are provisioned declaratively via auth-users / auth-tokens in server.yml. # ntfy reads and applies them on every startup — no poststart task, no race conditions. # # Bcrypt hashes are not secrets and are hardcoded below (same as /etc/shadow — safe to commit). # Generate with: docker run --rm -it binwiederhier/ntfy user hash # or: echo "mypassword" | docker run --rm -i binwiederhier/ntfy user hash # Required SOPS keys: # ntfy.database_pw — postgres password for the ntfy role task "ntfy" { driver = "docker" config { image = "binwiederhier/ntfy:latest" ports = ["http"] command = "serve" volumes = [ "local/server.yml:/etc/ntfy/server.yml", ] } env = { TZ = "Australia/Melbourne" } template { data = <