Reverse Proxy Traefik - sparkycz1/honeypot-shelf GitHub Wiki

🔒 Reverse proxy: Traefik

Already run Traefik? Point a router at it and move on.

Use this if you already run Traefik on the host where Honeypot Shelf's docker compose up -d --build (the base file, without docker-compose.caddy.yml) is running, exposing the app on 127.0.0.1:8080 (or whatever APP_PORT you set). Once working, consider also setting APP_BIND_ADDRESS=127.0.0.1 (no docker-compose.yml edit needed) so the app is only reachable through this proxy.

Two ways to wire Traefik up to a service: a static file provider entry pointing at an address, or Docker labels via Traefik's own Docker provider. The file provider is simpler when Honeypot Shelf and Traefik aren't in the same Compose project (the default here).

⚙️ Static config (traefik.yml)

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"
    http3: {}

certificatesResolvers:
  letsencrypt:
    acme:
      email: [email protected]
      storage: /letsencrypt/acme.json
      httpChallenge:
        entryPoint: web

providers:
  file:
    directory: /etc/traefik/dynamic
    watch: true

http3: {} enables HTTP/3 on the websecure entrypoint (Traefik still needs 443/udp published/open for QUIC to actually work).

🔐 TLS options: restrict to TLS 1.3 only (dynamic/tls.yml)

tls:
  options:
    tls13only:
      minVersion: VersionTLS13
      maxVersion: VersionTLS13

🔀 Route to Honeypot Shelf (dynamic/Honeypot Shelf.yml)

http:
  routers:
    Honeypot Shelf:
      rule: "Host(`your-domain.example.com`)"
      entryPoints:
        - websecure
      service: Honeypot Shelf
      tls:
        certResolver: letsencrypt
        options: tls13only@file
      middlewares:
        - Honeypot Shelf-headers

  middlewares:
    Honeypot Shelf-headers:
      headers:
        stsSeconds: 63072000
        stsIncludeSubdomains: true
        contentTypeNosniff: true
        referrerPolicy: "no-referrer"
        customResponseHeaders:
          Server: ""

  services:
    Honeypot Shelf:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1:8080"

If Traefik runs inside Docker, 127.0.0.1 from its point of view is the Traefik container, not the host — either run Traefik with network_mode: host, or use the host's Docker-bridge gateway address (commonly 172.17.0.1, check ip addr show docker0) in the service URL above.

🏷️ Alternative: Docker label-based discovery

If you'd rather use Traefik's Docker provider (labels on the web container) instead of the file provider above, web and Traefik need to share a Docker network — add an external network to both docker-compose.yml (on the web service) and Traefik's compose file, then label web:

labels:
  - traefik.enable=true
  - traefik.http.routers.Honeypot Shelf.rule=Host(`your-domain.example.com`)
  - traefik.http.routers.Honeypot Shelf.entrypoints=websecure
  - traefik.http.routers.Honeypot Shelf.tls.certresolver=letsencrypt
  - traefik.http.routers.Honeypot Shelf.tls.options=tls13only@file
  - traefik.http.services.Honeypot Shelf.loadbalancer.server.port=8080

This requires exposing the Docker socket to the Traefik container — a meaningfully larger trust boundary than the file-provider approach above — only do this if you already accept that trade-off for your other services.

🔎 Verifying

curl -sIv https://your-domain.example.com/healthz 2>&1 | grep -Ei 'HTTP/|strict-transport|server:'
curl --http3 -sI https://your-domain.example.com/healthz   # confirms HTTP/3
openssl s_client -connect your-domain.example.com:443 -tls1_2 </dev/null   # should fail