services: headscale-client: image: tailscale/tailscale:latest hostname: headscale-client-{{ deployment_time }} environment: - DEPLOYMENT_TIME={{ deployment_time }} - TZ={{ timezone }} - TS_AUTHKEY={{ headscale_user_auth_key }} - TS_EXTRA_ARGS=--login-server=https://{{ headscale_host }} --accept-dns --stateful-filtering=false --advertise-routes={{ loadbalancer_ip }}/32 - TS_STATE_DIR=/var/lib/tailscale - TS_USERSPACE=false healthcheck: test: ["CMD-SHELL", "tailscale status"] interval: 1s timeout: 5s retries: 10 volumes: - {{ traefik_base }}/volumes/headscale:/var/lib/tailscale - /dev/net/tun:/dev/net/tun cap_add: - NET_ADMIN - SYS_ADMIN networks: - headnet deploy: mode: replicated replicas: 1 update_config: parallelism: 1 order: start-first failure_action: rollback monitor: 2s traefik: image: traefik:v3 depends_on: - headscale-client ports: - target: 80 published: 80 mode: host - target: 443 published: 443 mode: host # to get x-forwarded-for correctly, see https://github.com/moby/moby/issues/25526 healthcheck: test: traefik healthcheck --ping interval: 10s retries: 2 timeout: 3s environment: - DEPLOYMENT_TIME={{ deployment_time }} - TZ={{ timezone }} - CF_API_EMAIL={{ cloudflare_email }} - CF_DNS_API_TOKEN={{ cloudflare_dns_api_token }} volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - {{ traefik_base }}/stacks/traefik.yml:/traefik.yml - {{ traefik_base }}/volumes/certs:/certs networks: - proxy - headnet deploy: mode: global update_config: parallelism: 1 order: stop-first # only one service eating 80/443 per host, since failure_action: rollback monitor: 2s # go go go. labels: - traefik.enable=true - traefik.http.routers.dashboard.rule=Host(`{{ traefik_domain }}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`)) - traefik.http.routers.dashboard.service=api@internal - traefik.http.routers.dashboard.tls=true - traefik.http.routers.dashboard.tls.certresolver=letsencrypt - traefik.http.routers.ping.rule=Host(`{{ traefik_domain }}`) && PathPrefix(`/ping`) - traefik.http.routers.ping.service=ping@internal - traefik.http.routers.ping.tls=true - traefik.http.routers.ping.tls.certresolver=letsencrypt - traefik.http.services.dashboard.loadbalancer.server.port=8080 - traefik.http.services.ping.loadbalancer.server.port=8080 networks: proxy: name: proxy driver: overlay attachable: true headnet: