Skip to content

Docker Compose Deployment behind Traefik Reverse Proxy

Snawoot edited this page Jul 30, 2025 · 14 revisions

This example exposes dumbproxy via Traefik reverse proxy, routing connections by domain in SNI of TLS handshake. TLS connection is handled on Traefik side, dumbproxy gets plaintext HTTP connection. Original client address is preserved and passed to dumbproxy (-proxyproto option).

docker-compose.yaml:

version: "3.8"

networks:
  internal:
    external: false
  traefik_proxy:
    external: true

secrets:
  users:
    file: ./configs/users.conf
services:
  traefik:
    image: traefik:v3.5.0
    deploy:
      restart_policy:
        condition: any
    environment:
      TZ: Etc/UTC
    logging:
      driver: json-file
      options:
        max-file: "1"
        max-size: 90m
    networks:
      traefik_proxy:
    ports:
      - mode: host
        target: 80
        published: 80
        protocol: tcp
      - mode: host
        target: 443
        published: 443
        protocol: tcp
    volumes:
      - type: bind
        source: /var/run/docker.sock
        target: /var/run/docker.sock
        read_only: true
      - type: bind
        source: ./configs/traefik.yaml
        target: /etc/traefik/traefik.yaml
        read_only: true
      - type: bind
        source: ./configs/dynamic.yaml
        target: /etc/traefik/dynamic.yaml
        read_only: true
      - type: bind
        source: ./configs/acme.json
        target: /etc/traefik/acme.json
        read_only: false
  dumbproxy-http:
    image: ghcr.io/senseunit/dumbproxy:1.27.0
    command:
      - -bind-address=:8080
      - -auth=basicfile://?path=/run/secrets/users.conf&hidden_domain=opennet.ru&reload=10s
      - -proxyproto
      - -verbosity=20
    deploy:
      labels:
        traefik.enable: "true" 
        traefik.tcp.routers.dumbproxy.rule: HostSNI(`<your-domain.com>`)
        traefik.tcp.services.dumbproxy.loadBalancer.server.port: "8080"
        traefik.tcp.routers.dumbproxy.tls.passthrough: "false"
    dns:
      - 208.67.222.222
      - 208.67.220.220
    logging:
      driver: json-file
      options:
        max-file: "1"
        max-size: 100m
    networks:
      internal:
      traefik_proxy:
    secrets:
      - source: users
        target: /run/secrets/users.conf

configs/traefik.yaml:

global:
  checkNewVersion: false
  sendAnonymousUsage: false

log:
  level: INFO
  noColor: false
  filePath: /dev/stdout

accessLog:
  filePath: /dev/stdout

providers:
  swarm:
    exposedByDefault: false
    endpoint: unix:///var/run/docker.sock
    network: traefik_proxy
    watch: true
  file:
    filename: /etc/traefik/dynamic.yaml
    watch: true

api:
  dashboard: false

entryPoints:
  web:
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
          permanent: true

  websecure:
    address: :443
    forwardedHeaders:
      insecure: true
    http:
      tls:
        certResolver: letsencrypt
      middlewares:
        - default@file

certificatesResolvers:
  letsencrypt:
    acme:
      email: <your-email>
      storage: /etc/traefik/acme.json
      tlsChallenge: {}

configs/dynamic.yaml:

tls:
  options:
    default:
      minVersion: VersionTLS12
      maxVersion: VersionTLS13
      sniStrict: true
      curvePreferences:
        - CurveP521
        - CurveP384
      alpnProtocols:
        - http/1.1
        - h2
        - acme-tls/1

http:
  middlewares:
    default:
      headers:
        browserXssFilter: true
        referrerPolicy: strict-origin-when-cross-origin
        stsPreload: true
        sslRedirect: true
        sslTemporaryRedirect: true
        sslForceHost: true
        stsSeconds: "31536000"
        forceSTSHeader: true
        frameDeny: true
        contentSecurityPolicy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'
        contentSecurityPolicyReportOnly: default-src 'self'; script-src 'self' 'nonce-{random}'
        contentTypeNosniff: true
        customResponseHeaders:
          X-Forwarded-Server: traefik
          Permissions-Policy: camera=(), microphone=(), geolocation=()
          Cross-Origin-Embedder-Policy: require-corp
          Cross-Origin-Resource-Policy: same-origin
          Cross-Origin-Opener-Policy: same-origin

Clone this wiki locally