I have a simple app that allows users to create websites, they can create as many as they want, and for each one select a subdomain. Those websites are being served on a different app, a web server written in Go. In front of it, I have a Traefik instance with a router for all subdomains of my domain my-domain.com
. So when Traefik receives a request from site.my-domain.com
it's sent to the web server, who does the lookup using the subdomain (site
) and the URL to serve the specific page of the website.
So far, it works like a charm, but I'd like to allow users to serve the websites from their custom domains. How can this be achieved using Traefik? I'm using Docker to run the web server, and it's discovered automatically by the labels.
I tried adding a match-all (.+
) router, but after that testing with a domain in Cloduflare that points with a CNAME to site.my-domain.com
I get “The page isn’t redirecting properly” in my browser, and this on the logs.
2024-11-25T01:13:16.101262289Z 172.70.255.53 - - [25/Nov/2024:01:13:16 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13589 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:16.197325817Z 172.70.255.53 - - [25/Nov/2024:01:13:16 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13590 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:16.289336604Z 172.70.255.53 - - [25/Nov/2024:01:13:16 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13591 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:16.368442572Z 172.70.255.53 - - [25/Nov/2024:01:13:16 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13592 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:16.486507994Z 172.70.255.53 - - [25/Nov/2024:01:13:16 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13593 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:16.568014849Z 172.70.255.53 - - [25/Nov/2024:01:13:16 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13594 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:16.689138507Z 172.70.255.53 - - [25/Nov/2024:01:13:16 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13595 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:16.795994457Z 172.70.255.53 - - [25/Nov/2024:01:13:16 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13596 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:16.908056576Z 172.70.255.53 - - [25/Nov/2024:01:13:16 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13597 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:17.016533546Z 172.70.255.53 - - [25/Nov/2024:01:13:17 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13598 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:17.188462313Z 172.70.255.53 - - [25/Nov/2024:01:13:17 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13599 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:17.290696033Z 172.70.255.53 - - [25/Nov/2024:01:13:17 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13600 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:17.415569504Z 172.70.255.53 - - [25/Nov/2024:01:13:17 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13601 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:17.509496704Z 172.70.255.53 - - [25/Nov/2024:01:13:17 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13602 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:17.609654892Z 172.70.255.53 - - [25/Nov/2024:01:13:17 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13603 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:17.710262455Z 172.70.255.53 - - [25/Nov/2024:01:13:17 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13604 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:17.810025004Z 172.70.255.53 - - [25/Nov/2024:01:13:17 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13605 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:17.909763448Z 172.70.255.53 - - [25/Nov/2024:01:13:17 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13606 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:18.009393068Z 172.70.255.53 - - [25/Nov/2024:01:13:18 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13607 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:18.141593073Z 172.70.255.53 - - [25/Nov/2024:01:13:18 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13608 "http-custom-web-server@docker" "-" 0ms
2024-11-25T01:13:18.229113881Z 172.70.255.53 - - [25/Nov/2024:01:13:18 +0000] "GET / HTTP/1.1" 302 5 "-" "-" 13609 "http-custom-web-server@docker" "-" 0ms
Other concern I have is with HTTPS, how to make it work for any domain? Ideally, I don't want to reset Traefik and have downtime each time a user add/changes a custom domain.
Traefik configuration:
networks:
coolify:
external: true
services:
traefik:
container_name: coolify-proxy
image: 'traefik:v3.1'
restart: unless-stopped
environment:
- CLOUDFLARE_DNS_API_TOKEN=****
- CF_ZONE_API_TOKEN=****
extra_hosts:
- 'host.docker.internal:host-gateway'
networks:
- coolify
ports:
- '80:80'
- '443:443'
- '443:443/udp'
- '8080:8080'
healthcheck:
test: 'wget -qO- http://localhost:80/ping || exit 1'
interval: 4s
timeout: 2s
retries: 5
volumes:
- '/var/run/docker.sock:/var/run/docker.sock:ro'
- '/data/coolify/proxy:/traefik'
command:
- '--ping=true'
- '--ping.entrypoint=http'
- '--api.dashboard=true'
- '--api.insecure=false'
- '--accesslog=true'
- '--entrypoints.http.address=:80'
- '--entrypoints.https.address=:443'
- '--entrypoints.http.http.encodequerysemicolons=true'
- '--entryPoints.http.http2.maxConcurrentStreams=50'
- '--entrypoints.https.http.encodequerysemicolons=true'
- '--entryPoints.https.http2.maxConcurrentStreams=50'
- '--entrypoints.https.http3'
- '--providers.docker.exposedbydefault=false'
- '--providers.file.directory=/traefik/dynamic/'
- '--providers.file.watch=true'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge=true'
- '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http'
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare'
- '--certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=0'
- '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json'
- '--providers.docker=true'
labels:
- traefik.enable=true
- traefik.http.routers.traefik.entrypoints=http
- traefik.http.routers.traefik.service=api@internal
- traefik.http.routers.traefik.tls.certresolver=letsencrypt
- traefik.http.routers.traefik.tls.domains[0].main=my-domain.com
- traefik.http.routers.traefik.tls.domains[0].sans=*.my-domain.com
- traefik.http.services.traefik.loadbalancer.server.port=8080
- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
- traefik.http.middlewares.gzip.compress=true
- coolify.managed=true
- coolify.proxy=true
Labels for web server running in Docker container:
traefik.enable=true
traefik.http.routers.https-web-server.rule=HostRegexp(`^.+\.my-domain\.com$`)
traefik.http.routers.https-web-server.entryPoints=https
traefik.http.routers.https-web-server.middlewares=gzip
traefik.http.routers.https-web-server.service=web-server-service
traefik.http.services.web-server-service.loadbalancer.server.port=3001
traefik.http.routers.https-web-server.tls=true
traefik.http.routers.https-web-server.tls.certresolver=letsencrypt
traefik.http.routers.http-web-server.rule=HostRegexp(`^.+\.my-domain\.com$`)
traefik.http.routers.http-web-server.entryPoints=http
traefik.http.routers.http-web-server.middlewares=redirect-to-https
# New configuration for any domain, this isn't working properly
# HTTPS router for any domain
traefik.http.routers.https-custom-web-server.rule=HostRegexp(`^.+$`)
traefik.http.routers.https-custom-web-server.entryPoints=https
traefik.http.routers.https-custom-web-server.middlewares=gzip
traefik.http.routers.https-custom-web-server.service=web-server-service
traefik.http.routers.https-custom-web-server.tls=true
traefik.http.routers.https-custom-web-server.tls.certresolver=letsencrypt
# HTTP router for any domain (redirect to HTTPS)
traefik.http.routers.http-custom-web-server.rule=HostRegexp(`^.+$`)
traefik.http.routers.http-custom-web-server.entryPoints=http
traefik.http.routers.http-custom-web-server.middlewares=redirect-to-https
Thanks in advance for any reply!