fix(traefik): expose API on an internal-only entrypoint for container-to-container access

The public traefik.pivoine.art path round-trips through the host's
published port, and Docker's hairpin NAT there rewrites the source IP
before it reaches vpn-only's allowlist, so pulsenode's own request was
getting a 403 despite falcon_network being allowlisted. Port 8080 is
not published to the host, so it's reachable only from other
falcon_network containers - no TLS/vpn-only needed, and it's not
exposed externally.
This commit is contained in:
2026-08-17 19:29:43 +02:00
parent bed01b4fdf
commit 3761924242
2 changed files with 11 additions and 1 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ groups:
- type: traefik - type: traefik
name: Traefik name: Traefik
apiUrl: https://traefik.pivoine.art/api apiUrl: http://traefik:8080/api
interval: 15s interval: 15s
- type: docker - type: docker
+10
View File
@@ -21,6 +21,13 @@ services:
- "--entrypoints.web.http.redirections.entryPoint.scheme=https" - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.web.http.redirections.entryPoint.permanent=true" - "--entrypoints.web.http.redirections.entryPoint.permanent=true"
- "--entrypoints.web-secure.http.middlewares=security-headers@file,fail2ban@file" - "--entrypoints.web-secure.http.middlewares=security-headers@file,fail2ban@file"
# Not published to the host - reachable only container-to-container on
# falcon_network. Lets other stacks (e.g. pulsenode) read the API
# directly without going through the public hostname, where a hairpin
# NAT round-trip through the host's published port rewrites the source
# IP and defeats vpn-only's IP allowlist.
- "--entrypoints.internal.address=:8080"
- "--ping.entrypoint=web-secure"
- "--certificatesresolvers.resolver.acme.tlschallenge=true" - "--certificatesresolvers.resolver.acme.tlschallenge=true"
- "--certificatesresolvers.resolver.acme.email=${ACME_EMAIL}" - "--certificatesresolvers.resolver.acme.email=${ACME_EMAIL}"
- "--certificatesresolvers.resolver.acme.storage=/letsencrypt/acme.json" - "--certificatesresolvers.resolver.acme.storage=/letsencrypt/acme.json"
@@ -53,6 +60,9 @@ services:
- "traefik.http.routers.traefik-dashboard-web-secure.tls.certresolver=resolver" - "traefik.http.routers.traefik-dashboard-web-secure.tls.certresolver=resolver"
- "traefik.http.routers.traefik-dashboard-web-secure.middlewares=vpn-only@file,security-headers@file,no-index@file" - "traefik.http.routers.traefik-dashboard-web-secure.middlewares=vpn-only@file,security-headers@file,no-index@file"
- "traefik.http.routers.traefik-dashboard-web-secure.service=api@internal" - "traefik.http.routers.traefik-dashboard-web-secure.service=api@internal"
- "traefik.http.routers.traefik-internal.rule=PathPrefix(`/`)"
- "traefik.http.routers.traefik-internal.entrypoints=internal"
- "traefik.http.routers.traefik-internal.service=api@internal"
networks: networks:
- compose_network - compose_network
- coolify_network - coolify_network