fix(phasefinal-web): healthcheck targeted ::1, so traefik skipped the container

The healthcheck used http://localhost/, which resolves to ::1 in nginx:alpine
while nginx listens on IPv4 only — so it never passed, the container stayed
unhealthy, and Traefik silently declined to create a router for it. That
presents as a broken docker provider: correct labels, right network, no route,
no error. Target 127.0.0.1 explicitly and add a start_period.

Adds the apex router (301 phasefinal.com -> www) and drops the file-provider
workaround, which was mitigating the wrong diagnosis.
This commit is contained in:
vh
2026-08-29 22:33:21 -07:00
parent 7ffbee6f09
commit 524aa4d860
3 changed files with 28 additions and 35 deletions
+13 -7
View File
@@ -21,14 +21,20 @@ requests rule. Both must be undone on import:
Without these the page silently falls back to system fonts and looks wrong Without these the page silently falls back to system fonts and looks wrong
rather than broken, which is the failure mode you won't notice. rather than broken, which is the failure mode you won't notice.
## Routing ## Routing — and the healthcheck trap that looks like a routing bug
`conf/traefik-dynamic-phasefinal-web.yml` deploys to Routers come from the compose labels: `phasefinal-web` serves
**`/opt/docker/conf/traefik-ana/config/phasefinal-web.yml`** — not into this `www.phasefinal.com`; `phasefinal-apex` 301s `phasefinal.com` to it.
stack's own conf dir. It exists because Traefik's docker provider on ana-docker
was not registering newly-created containers on 2026-08-29; the compose file ⚠ **Traefik silently skips containers Docker reports as unhealthy.** There is no
still carries the correct `traefik.*` labels, so once that is fixed the file error, no log line, and no router — it looks exactly like a broken provider. The
router can be deleted. See the header comment in that file. first deploy of this stack hit that: the healthcheck used
`http://localhost/`, which resolves to `::1` in `nginx:alpine`, and nginx listens
on IPv4 only, so the check got "Connection refused" forever and the container
never left `unhealthy`. **Use `127.0.0.1`, never `localhost`, in a healthcheck
for an IPv4-only listener** — and if a correctly-labelled container never appears
in `/api/http/routers`, check `docker inspect --format '{{.State.Health.Status}}'`
*before* suspecting Traefik.
## Deploy ## Deploy
+15 -1
View File
@@ -9,16 +9,30 @@ services:
networks: networks:
- tnet - tnet
healthcheck: healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost/"] # 127.0.0.1, NOT localhost: in this image `localhost` resolves to ::1 and
# nginx listens on IPv4 only, so `localhost` gives "Connection refused"
# forever. Traefik SKIPS unhealthy containers, so a wrong healthcheck here
# silently means "no route" rather than "unhealthy service".
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:80/"]
interval: 30s interval: 30s
timeout: 5s timeout: 5s
retries: 3 retries: 3
start_period: 10s
labels: labels:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.phasefinal-web.rule=Host(`www.phasefinal.com`) - traefik.http.routers.phasefinal-web.rule=Host(`www.phasefinal.com`)
- traefik.http.routers.phasefinal-web.tls=true - traefik.http.routers.phasefinal-web.tls=true
- traefik.http.routers.phasefinal-web.tls.certresolver=anaprod - traefik.http.routers.phasefinal-web.tls.certresolver=anaprod
- traefik.http.services.phasefinal-web.loadbalancer.server.port=80 - traefik.http.services.phasefinal-web.loadbalancer.server.port=80
# apex -> www, 301
- traefik.http.routers.phasefinal-apex.rule=Host(`phasefinal.com`)
- traefik.http.routers.phasefinal-apex.tls=true
- traefik.http.routers.phasefinal-apex.tls.certresolver=anaprod
- traefik.http.routers.phasefinal-apex.service=phasefinal-web
- traefik.http.routers.phasefinal-apex.middlewares=phasefinal-to-www
- traefik.http.middlewares.phasefinal-to-www.redirectregex.regex=^https?://phasefinal\.com/(.*)
- traefik.http.middlewares.phasefinal-to-www.redirectregex.replacement=https://www.phasefinal.com/$${1}
- traefik.http.middlewares.phasefinal-to-www.redirectregex.permanent=true
networks: networks:
tnet: tnet:
@@ -1,27 +0,0 @@
# Traefik file-provider router for phasefinal-web.
#
# DEPLOYS TO: ana-docker:/opt/docker/conf/traefik-ana/config/phasefinal-web.yml
# (NOT /opt/docker/conf/phasefinal-web/ — the file provider watches
# traefik-ana/config, so this file lives with Traefik, not the stack.)
#
# WHY A FILE ROUTER instead of container labels: as of 2026-08-29 the Traefik
# docker provider on ana-docker was not registering newly-created containers —
# phasefinal-web carried correct traefik.* labels, sat on traefik-net, and never
# appeared in /api/http/routers, with no provider activity in the logs. The file
# provider (watch: true) picks this up with no Traefik restart, so no other
# public service is interrupted. If the docker provider is fixed, this file can
# be deleted and the compose labels will take over.
http:
routers:
phasefinal-web:
rule: "Host(`www.phasefinal.com`)"
service: phasefinal-web
entryPoints:
- websecure
tls:
certResolver: anaprod
services:
phasefinal-web:
loadBalancer:
servers:
- url: "http://phasefinal-web:80"