Skip to content

Instantly share code, notes, and snippets.

@axmad386
Last active September 3, 2025 09:57
Show Gist options
  • Select an option

  • Save axmad386/dca56db2a262c53482c3da3cf20599c0 to your computer and use it in GitHub Desktop.

Select an option

Save axmad386/dca56db2a262c53482c3da3cf20599c0 to your computer and use it in GitHub Desktop.
Dynamic Subpath to Subdomain Proxy Mapping using Traefik and Cloudflare DNS

Directory Structure

|-- traefik
|---|-- docker.compose.yml
|---|-- domains
|---|---| main.yml
|---|---| foo.myapp.com.yml --> all generated subdomain will be here
|---|-- traefik.yml

Suppose you have two service, app-be and app-fe. In app-be, you have dynamic route and want to map to subdomain /page/dynamic/foo --> foo.myapp.com /page/dynamic/bar --> bar.myapp.com

Just create foo.myapp.com.yml and bar.myapp.com via script, then traefik and cloudflare will handle the rest. No need to restart anything

services:
traefik:
image: traefik:latest
command: --providers.docker --providers.file.filename=/etc/traefik/traefik.yml
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8080:8080"
environment:
CF_DNS_API_TOKEN: "yourkey"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.yml:/etc/traefik/traefik.yml:ro # Mount your Traefik configuration file
- ./domains/:/etc/traefik/domains/:ro # Mount your Traefik configuration file
- letsencrypt:/letsencrypt # Optional: Persistent storage for Let's Encrypt certificates (recommended)
- ./acme.json:/letsencrypt/acme.json # Optional: Mount your ACME account credentials
networks:
- proxy
app-fe: # example fe service
build: /var/www/app-fe # Replace with path to your app directory
volumes:
- /var/www/app-fe/dist:/usr/share/nginx/html
depends_on:
- traefik
networks:
- proxy
networks:
proxy:
driver: bridge
volumes:
letsencrypt:
# domains/foo.myapp.com.yml
http:
routers:
foo.myapp.com:
rule: Host(`foo.myapp.com`)
service: app-be
middlewares:
- "replace-path"
entryPoints:
- secure
tls:
certResolver: letsencrypt
middlewares:
replace-path:
replacePathRegex:
regex: "^/(.*)"
replacement: "/page/dynamic/$1"
# domains/main.yml
http:
routers:
api:
rule: Host(`api.myapp.com`)
priority: 1
service: app-be
entryPoints:
- secure
tls:
certResolver: letsencrypt
dynamic:
rule: HostRegexp(`(?P<subdomain>[^.]+)\.myapp\.com`) && !Host(`api.myapp.com`)
priority: 2
service: app-be
middlewares:
- "replace-path"
entryPoints:
- secure
tls:
domains:
- sans: "*.myapp.com"
certResolver: letsencrypt
fe:
rule: "Host(`myapp.com`)"
service: app-fe
entryPoints:
- secure
tls:
certResolver: letsencrypt
services:
app-fe:
loadBalancer:
servers:
- url: "http://fe"
app-be:
loadBalancer:
servers:
- url: "http://172.17.0.1:8000"
middlewares:
replace-path:
replacePathRegex:
regex: "^/(.*)"
replacement: "/page/dynamic/$1"
api:
dashboard: true
insecure: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: secure
scheme: https
permanent: true
secure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
#caServer: https://acme-staging-v02.api.letsencrypt.org/directory --> staging
caServer: https://acme-v02.api.letsencrypt.org/directory # --> production
storage: /letsencrypt/acme.json
httpChallenge:
entryPoint: web
dnsChallenge:
provider: "cloudflare"
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
providers:
file:
directory: /etc/traefik/domains
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment