dockerdocker-composetraefik

how to route on private network ip


Using traefik 3 I want to route wg.my-domain.com to wg-easy UI which is listening on port 51821 of the wg-easy service. But I want to only allow so on the private network 10.0.0.0/24.

For now I point wg.my-domain.com to 10.0.0.4 in my /etc/hosts. I do control my-domain.com and the cert is created and valid. There is no A record for wg.my-domain.com.

When I map the port on the private ip using docker ports (see comment in the config), I can access the ui on http://10.0.0.4:51821 but I want to only allow access via the domain and use ssl (https://wg.my-domain.com).

My problem is, that when I go to https://wg.my-domain.com I only see 404 page not found. I expected it to work after I set traefik.http.routers.wg_easy.loadbalancer.server.port=51821 to tell the traefik router to route the domain to that specific port of the container.

Here is my docker-compose.yml:

services:
  traefik:
    image: traefik:3.0
    command:
      # - "--log.level=DEBUG"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
      - "--api.dashboard=false"
      - "--entryPoints.web.forwardedHeaders.trustedIPs=127.0.0.1/32"
      # use DNS challenge because we issue certs for services not having A records in public DNS
      - "--certificatesresolvers.leresolver.acme.dnschallenge=true"
      - "--certificatesresolvers.leresolver.acme.dnschallenge.provider=hetzner"
      - "--certificatesresolvers.leresolver.acme.storage=/letsencrypt/acme.json"
    environment:
      - "HETZNER_API_KEY=${HETZNER_DNS_API_KEY}"
    ports:
      - ${PRIVATE_IPV4}:80:80     # traefik
      - 443:443
    volumes:
      - ./traefik/certs:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
    restart: unless-stopped

  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:13
    environment:
      # ⚠️ Required:
      - WG_HOST=<my-public-ip>
      # Optional:
      # - WEBUI_HOST=10.0.0.4
      - PORT=51821 # web ui port
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
    volumes:
      - ./wg-easy:/etc/wireguard
    ports:
      - "51820:51820/udp"
        # I don't want to expose the UI port, but only allow accessing it via the domain via traefik on 10.0.0.0/24
        # When mapping the port on the private ip, I can access the ui on http://<ip>:51821 but I want to only allow access via the domain and use ssl.
        #      - "${PRIVATE_IPV4}:51821:51821/tcp"
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wg_easy.rule=Host(`wg.my-domain.com`)"
      - "traefik.http.routers.wg_easy.entrypoints=websecure"
      - "traefik.http.routers.wg_easy.loadbalancer.server.port=51821"
      - "traefik.http.routers.wg_easy.tls=true"
      - "traefik.http.routers.wg_easy.tls.certresolver=leresolver"

Solution

  • The loadbalancer is part of the service and not of routing, so the port must be set like this:

    -traefik.http.routers.wg_easy.loadbalancer.server.port=51821
    +traefik.http.services.wg_easy.loadbalancer.server.port=51821