404 with Traefik Docker container as a proxy to Caddy, PHP, MySQL containers

Hello,

here is an image of what I want to do

I want to use Traefik to act as proxy for multiple docker containers running Caddy, PHP, MySQL. Each container serves a unique domain that I connected the virtual server’s IP address using DNS A records (DNS lookup works fine)

This is the current setup

  • /srvtraefik.toml
  • /srv/traefik_dynamic.toml
  • /srv/acme.json

– /srv/lcmp/docker-compose.yml

– /srv/lcmp/caddy_docker
—/srv/lcmp/caddy_docker/Caddyfile
—/srv/lcmp/caddy_docker/Dockerfile

– /srv/lcmp/php_docker
— /srv/lcmp/php_docker/Dockerfile

–/srv/lcmp/www

Content of traefik.toml

[entryPoints]
  [entryPoints.web]
    address = ":80"
    [entryPoints.web.http.redirections.entryPoint]
      to = "websecure"
      scheme = "https"

  [entryPoints.websecure]
    address = ":443"

[api]
  dashboard = true

[certificatesResolvers.lets-encrypt.acme]
  email = "mail@mydomain.tld"
  storage = "acme.json"
  [certificatesResolvers.lets-encrypt.acme.tlsChallenge]

[providers.docker]
  watch = true
  network = "web"

[providers.file]
  filename = "traefik_dynamic.toml"

Content of traefik_dynamic.toml

[http.middlewares.simpleAuth.basicAuth]
  users = [
    user:<pw>"
  ]


[http.routers.api]
  rule = "Host(`monitor.mydomain.tld`)"
  entrypoints = ["websecure"]
  middlewares = ["simpleAuth"]
  service = "api@internal"
  [http.routers.api.tls]
    certResolver = "lets-encrypt"

Content of acme.json is correct
Did a chmod 600 on acme.json

Content of /srv/lcmp/docker-compose.yml

version: "3.8"

networks:
  web:
    # Remove external option
    # driver: bridge
    external: true
  internal:
    external: false

services:
  # PHP Service
  php:
    build: './php_docker/'
    volumes:
      - ./www/:/var/www/html/
    networks:
      - internal

  # Caddy Service
  caddy:
    build: './caddy_docker/'
    depends_on:
      - php
    restart: unless-stopped
    volumes:
      - ./www/:/var/www/html/
      - ./caddy_docker/Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    labels:
      - traefik.enable=true
      - traefik.http.routers.caddy.rule=Host(`mydomain.tld`)
      - traefik.http.routers.caddy.entrypoint=http
      - traefik.http.routers.caddy.middlewares=auth
      - traefik.http.routers.caddy.middlewares=https-redirect
      - traefik.docker.network=web
      - traefik.constraint-label=web
      #- traefik.http.routers.caddy.entrypoints=websecure
      - traefik.port=80
    networks:
      - web
    healthcheck:
      test: curl --fail https://mydomain.tld || exit 1
      interval: 60s
      retries: 5
      start_period: 20s
      timeout: 10s

  # MySQL Service
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: <redacted>
    volumes:
      - mysqldata:/var/lib/mysql
    networks:
      - internal

  # phpMyAdmin Service
  phpmyadmin:
    image: phpmyadmin/phpmyadmin:latest
    ports:
      - 8080:80
    environment:
      PMA_HOST: mysql
    networks:
      - internal
    depends_on:
      - mysql

# Volumes
volumes:
  mysqldata:
  caddy_data:
  caddy_config:

Content of /srv/lcmp/caddy_docker/Caddyfile

(common) {
        header /* {
                -Server
        }
}

mydomain.tld {
        encode gzip zstd
        root * /var/www/html/public
        php_fastcgi php:9000
        file_server
        header {
                -server
                -Link
                -X-Powered-By

                # disable FLoC tracking
                #Permissions-Policy interest-cohort=()

                # enable HSTS
                Strict-Transport-Security max-age=31536000;

                # disable clients from sniffing the media type
                X-Content-Type-Options nosniff

                # clickjacking protection
                X-Frame-Options DENY

                # keep referrer data off of HTTP connections
                Referrer-Policy no-referrer-when-downgrade
        }
}

www.mydomain.tld {
        redir https://mydomain.tld{uri}
}

Content of /srv/lcmp/caddy_docker/Dockerfile

# Use the official Caddy Docker image
FROM caddy:latest

# Update package index and upgrade installed packages
RUN apk update && apk upgrade

# Copy Caddyfile to configure Caddy server
COPY Caddyfile /etc/caddy/Caddyfile

I’ve started the Traefik Docker container using this command

docker run -d \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v $PWD/traefik.toml:/traefik.toml \
  -v $PWD/traefik_dynamic.toml:/traefik_dynamic.toml \
  -v $PWD/acme.json:/acme.json \
  -p 80:80 \
  -p 443:443 \
  --network web \
  --name traefik \
  traefik:v2.11

The dashboard at monitor.mydomain.tld can be opened, I enter the user and password and I see Traefik’s dashboard and all the services, routers and middleware. I also see new routers and services when I run docker compose up -d in /srv/lcmp/

The webroot of the Caddyfile is set to /www/public because this is what shopware requires. Before using Traefik, the setup worked fine using this docker-compose.yml (no Traefik container running). Browsing to mydomain.tld showed the website located in /www/public

version: "3.8"
services:

  # PHP Service
  php:
    build: './php_docker/'
    volumes:
      - ./www/:/var/www/html/

  # Caddy Service
  caddy:
    build: './caddy_docker/'
    depends_on:
      - php
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./www/:/var/www/html/
      - ./caddy_docker/Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config

  # MySQL Service
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: <redacted>
    volumes:
      - mysqldata:/var/lib/mysql

  # phpMyAdmin Service
  phpmyadmin:
    image: phpmyadmin/phpmyadmin:latest
    ports:
      - 8080:80
    environment:
      PMA_HOST: mysql
    depends_on:
      - mysql


# Volumes
volumes:
  mysqldata:
  caddy_data:
  caddy_config:

I’m very confused concerning the docker labels for Traefik in the caddy service section of my docker-compose.yml and whether I need to have the ports in the specified in the caddy service section and I also do not know how to handle https since both Caddy and Docker provide automatic https support.

Here is the output of docker ps

CONTAINER ID   IMAGE                          COMMAND                  CREATED          STATUS                      PORTS                                                                      NAMES
9f9b1caac82d   lcmp-caddy                     "caddy run --config …"   39 minutes ago   Up 39 minutes (unhealthy)   80/tcp, 443/tcp, 2019/tcp, 443/udp                                         lcmp-caddy-1
645f0cf71aea   phpmyadmin/phpmyadmin:latest   "/docker-entrypoint.…"   39 minutes ago   Up 39 minutes               0.0.0.0:8080->80/tcp, :::8080->80/tcp                                      lcmp-phpmyadmin-1
66d5a3b00928   lcmp-php                       "docker-php-entrypoi…"   39 minutes ago   Up 39 minutes               9000/tcp                                                                   lcmp-php-1
5cec416971b9   mysql:8.0                      "docker-entrypoint.s…"   39 minutes ago   Up 39 minutes               3306/tcp, 33060/tcp                                                        lcmp-mysql-1
98c739d25175   traefik:v2.11                  "/entrypoint.sh trae…"   4 hours ago      Up 4 hours                  0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   traefik

Here is the output of docker network ls

NETWORK ID     NAME            DRIVER    SCOPE
f94a86c9651e   bridge          bridge    local
3c11f90c3c71   host            host      local
7461a2865805   internal        bridge    local
5cdec9ce389a   lcmp_internal   bridge    local
f41e6078c5f8   lcmp_web        bridge    local
b978f9127644   none            null      local
f83455745ea4   web             bridge    local

Here is the output of docker network inspect web

[
    {
        "Name": "web",
        "Id": "f83455745ea41d2ae698b45849102742056beb5c69b4d775940ca6afa30d3b10",
        "Created": "2024-03-20T10:26:15.115720734+01:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.31.0.0/16",
                    "Gateway": "172.31.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "98c739d25175715f6410100eb706bb0798eb355c348ac3797eff5382426fffe2": {
                "Name": "traefik",
                "EndpointID": "89b36aa2ec3d3da5800710dce4a8cc07d87ddfd71abf33c9b727b051c942a90a",
                "MacAddress": "02:42:ac:1f:00:02",
                "IPv4Address": "172.31.0.2/16",
                "IPv6Address": ""
            },
            "9f9b1caac82d87a87fc6304362eec5933b3b18677184ef3657d7c48ece6e84d0": {
                "Name": "lcmp-caddy-1",
                "EndpointID": "990411546cd871a36b9e6c5f5fd52aab4cfd9d8026b974329d4fe0407ccf0c40",
                "MacAddress": "02:42:ac:1f:00:03",
                "IPv4Address": "172.31.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

When I curl https://mydomain.tld i get 404 page not found
Sorry for the long post, any help is highly appreciated since I’m quite new to all this!