HTTPS passthrough from Traefik to Caddy

I have a host docker machine that runs several WordPress websites on FrankenPHP containers that run on top of the Caddy web server which handles its own SSL. To avoid port conflict, I've utilized Traefik as a reverse proxy. The problem is that my website keeps loading until it gives me PR_END_OF_FILE_ERROR.

services:
  proxy:
    image: "traefik:latest"
    container_name: proxy
    command:
      - "--api.insecure=false"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    ports:
      - "80:80"
      - "443:443"
    networks:
      - proxy
    restart: unless-stopped

networks:
  proxy:
    name: proxy
    driver: bridge

services:
...

  website:
    depends_on:
      - database
    build:
      context: .
      target: runner
      args:
        ...
    environment:
      SERVER_NAME: "${APP_DOMAIN:-localhost}"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.${APP_NAME}.rule=Host(`${APP_DOMAIN}`)"
      - "traefik.http.routers.${APP_NAME}.entrypoints=web"
      - "traefik.http.services.${APP_NAME}.loadbalancer.server.port=80"
      - "traefik.tcp.routers.${APP_NAME}-secure.rule=HostSNI(`${APP_DOMAIN}`)"
      - "traefik.tcp.routers.${APP_NAME}-secure.entrypoints=websecure"
      - "traefik.tcp.routers.${APP_NAME}-secure.tls.passthrough=true"
      - "traefik.tcp.services.${APP_NAME}-secure.loadbalancer.server.port=443"
    volumes:
      - "./data/caddy/data:/data"
      - "./data/caddy/config:/config"
    networks:
      - internal
      - proxy
    healthcheck:
      test: |
        curl --fail http://localhost || exit 1
      start_period: 60s
      interval: 60s
      timeout: 30s
      retries: 3
    restart: always

...

networks:
  internal:
    driver: bridge
  proxy:
    external: true

Here is the result of docker logs proxy:

...
ERR Error while dialing backend error="dial tcp 172.19.0.4:443: i/o timeout"

What am I doing wrong?

Make sure to set docker.network when having multiple networks on target service, which are not all used by Traefik. Traefik will forward requests to any IP it finds on the target service container, it doesn't check if it is connected to the required Docker network.

Are you creating separate TLS certs for Traefik and target service? For HostSNI() to work, Traefik needs access to the TLS cert files. Is that the case?

Set docker.network globally on provider or in target service labels (doc).

When Traefik has no TLS certs, you can not do any routing based on domain, you can only use HostSNI(`*`). For routing to different services you would need to use different ports.

For plain Traefik TCP pass-through, do not activate any TLS, simply use:

      - traefik.tcp.routers.${APP_NAME}-secure.entrypoints=websecure
      - traefik.tcp.routers.${APP_NAME}-secure.rule=HostSNI(`*`)
      - traefik.tcp.services.${APP_NAME}-secure.loadbalancer.server.port=443
      - traefik.docker.network=proxy