Logo
How to setup traefik with wildcard SSL certificates and routing

How to setup traefik with wildcard SSL certificates and routing

April 28, 2025
7 min read
index

How to Setup Traefik with Wildcard SSL Certificates and Dynamic Routing

Building a multi-tenant system with automatic subdomain provisioning made simple

When I started building a multi-tenant application that required dynamic subdomain allocation, I quickly realized that traditional reverse proxy setups weren’t going to cut it. I needed something that could automatically handle SSL certificates for an unlimited number of subdomains and route traffic intelligently based on the incoming domain.

Initially, I was using Cloudflare Tunnel—and I’ll admit, it’s an incredible tool that makes this kind of setup almost effortless. But as my project grew, I wanted more control and independence from external services. That’s when I discovered Traefik, and after wrestling with its configuration for longer than I’d like to admit, I finally cracked the code.

The Challenge: Multi-Tenant Subdomain Management

Picture this scenario: you’re building a SaaS application where each customer gets their own subdomain. When someone signs up for your service, you want to instantly give them access to customer1.yourdomain.com, startup-x.yourdomain.com, or whatever subdomain they choose.

The traditional approach would involve manually configuring nginx or Apache for each new subdomain, updating SSL certificates, and restarting services. Not exactly scalable when you’re hoping to onboard hundreds or thousands of tenants.

What we need is a system that can:

  • Automatically issue SSL certificates for any subdomain
  • Route traffic based on the incoming domain
  • Handle HTTPS redirection seamlessly
  • Scale without manual intervention

This is where Traefik shines.

Why Traefik for Dynamic Routing?

Traefik is a modern reverse proxy and load balancer that’s designed specifically for dynamic environments like Docker and Kubernetes. Unlike traditional proxies that require manual configuration updates, Traefik automatically discovers services and configures routing rules based on labels and annotations.

The magic happens through its integration with Let’s Encrypt and DNS providers. Instead of managing individual certificates for each subdomain, Traefik can request a single wildcard certificate that covers your entire domain and all its subdomains.

Setting Up the Foundation

Before diving into the configuration, you’ll need a few things in place. First, your domain needs to be managed by Cloudflare (we’ll use their DNS API for certificate validation). You’ll also need Docker and Docker Compose installed on your server.

The setup revolves around three main components: the Traefik container itself, its configuration file, and your application containers with proper labeling.

Getting Your Cloudflare Credentials

Head over to the Cloudflare dashboard and create an API token with DNS editing permissions. This token allows Traefik to create temporary DNS records that Let’s Encrypt uses to verify domain ownership. Store this token in an environment file:

.env
CF_DNS_API_TOKEN=your_cloudflare_api_token_here

The Traefik Container Configuration

The heart of our setup is the Traefik container. Here’s how I configure it:

docker-compose.yml
version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
# Security hardening
security_opt:
- no-new-privileges:true
networks:
- shared_net
ports:
- '80:80' # HTTP traffic
- '443:443' # HTTPS traffic
environment:
CF_API_TOKEN: ${CF_DNS_API_TOKEN}
env_file: .env
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme.json:/acme.json
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.traefik.entrypoints=http'
- 'traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https'
- 'traefik.http.routers.traefik.middlewares=traefik-https-redirect'
- 'traefik.http.routers.traefik-secure.entrypoints=https'
- 'traefik.http.routers.traefik-secure.tls=true'
- 'traefik.http.routers.traefik-secure.tls.certresolver=cloudflare'
- 'traefik.http.routers.traefik-secure.service=api@internal'
networks:
shared_net:
external: true

The key insight here is the volume mount for /var/run/docker.sock. This gives Traefik access to the Docker daemon, allowing it to automatically discover new containers and their configurations.

The Configuration Deep Dive

The real magic happens in the traefik.yml configuration file. This is where we define how Traefik should behave, how it should obtain certificates, and how it should route traffic.

data/traefik.yml
api:
dashboard: true
debug: true
entryPoints:
http:
address: ':80'
http:
redirections:
entryPoint:
to: https
scheme: https
https:
address: ':443'
serversTransport:
insecureSkipVerify: true
providers:
docker:
endpoint: 'unix:///var/run/docker.sock'
exposedByDefault: false
certificatesResolvers:
cloudflare:
acme:
storage: acme.json
caServer: https://acme-v02.api.letsencrypt.org/directory
dnsChallenge:
provider: cloudflare
disablePropagationCheck: true
delayBeforeCheck: 60s
resolvers:
- '1.1.1.1:53'
- '1.0.0.1:53'
log:
level: DEBUG

The certificatesResolvers section is where the wildcard SSL magic happens. By using the DNS challenge method with Cloudflare, Traefik can obtain certificates for domains that don’t even exist yet. This is perfect for our dynamic subdomain scenario.

Configuring Your Application

Now comes the interesting part—configuring your application to work with this setup. The beauty of Traefik is that all the routing logic is defined through Docker labels:

services:
myapp:
build:
context: .
dockerfile: Dockerfile
env_file:
- .env
labels:
- 'traefik.enable=true'
- "traefik.http.routers.myapp-web.rule=HostRegexp(`[a-z0-9-]+\\.yourdomain\\.com`) || Host(`yourdomain.com`)"
- 'traefik.http.routers.myapp-web.tls=true'
- 'traefik.http.routers.myapp-web.tls.certresolver=cloudflare'
- 'traefik.http.routers.myapp-web.tls.domains[0].main=yourdomain.com'
- 'traefik.http.routers.myapp-web.tls.domains[0].sans=*.yourdomain.com'
- 'traefik.http.services.myapp-web.loadbalancer.server.port=80'
restart: unless-stopped
networks:
- shared_net
networks:
shared_net:
external: true

The routing rule HostRegexp(\[a-z0-9-]+\.yourdomain\.com`) || Host(`yourdomain.com`)` is doing the heavy lifting here. It tells Traefik to route any request that matches either:

  1. A subdomain pattern (like tenant1.yourdomain.com or my-app.yourdomain.com)
  2. The apex domain (yourdomain.com)

Handling Multi-Tenancy in Your Application

With the infrastructure in place, your application needs to be smart about handling different subdomains. In most cases, this means extracting the subdomain from the incoming request and using it to determine which tenant’s data to serve.

Here’s a simple example of how you might handle this in a Node.js application:

app.use((req, res, next) => {
const host = req.get('host')
const subdomain = host.split('.')[0]
if (subdomain !== 'yourdomain') {
req.tenant = subdomain
}
next()
})

This middleware extracts the subdomain and makes it available throughout your application, allowing you to customize the experience for each tenant.

The Deployment Process

Getting everything running is straightforward once you have all the pieces in place:

  1. Create the shared Docker network:

    Terminal window
    docker network create shared_net
  2. Ensure your certificate storage file exists and has proper permissions:

    Terminal window
    mkdir -p data
    touch data/acme.json
    chmod 600 data/acme.json
  3. Start Traefik:

    Terminal window
    docker-compose up -d
  4. Deploy your application containers with the appropriate labels

The first time you start this setup, you’ll see Traefik reaching out to Let’s Encrypt to obtain your wildcard certificate. This process usually takes a minute or two, but once complete, all your subdomains will be automatically secured with HTTPS.

What Happens Behind the Scenes

When a request comes in for customer1.yourdomain.com, here’s what happens:

  1. Traefik receives the request and checks its routing rules
  2. The request matches your HostRegexp pattern
  3. Traefik forwards the request to your application container
  4. Your application extracts the subdomain and serves tenant-specific content
  5. The response is sent back through Traefik with proper SSL encryption

The entire process is seamless and happens in milliseconds.

Monitoring and Troubleshooting

One of Traefik’s best features is its built-in dashboard, which gives you real-time visibility into your routing rules, SSL certificates, and service health. You can access it by configuring a route to the internal API service.

When things go wrong (and they sometimes do), the logs are your friend:

Terminal window
docker-compose logs -f traefik

Common issues I’ve encountered include:

  • Certificate generation failures due to incorrect API tokens
  • Routing problems caused by network configuration issues
  • Port conflicts when applications aren’t listening on the expected ports

Performance Considerations

This setup scales remarkably well. I’ve run systems handling hundreds of subdomains without any performance degradation. Traefik’s routing is extremely efficient, and the wildcard certificate approach means you’re not hitting Let’s Encrypt’s rate limits as you add new tenants.

The main bottleneck is usually your application’s ability to handle multi-tenancy efficiently, not the proxy layer.

Security Implications

While this setup is generally secure, there are a few considerations:

  • The acme.json file contains your SSL certificates and private keys—protect it with appropriate file permissions
  • Consider implementing rate limiting and access controls for production deployments
  • The Traefik dashboard should be secured or disabled in production environments

Beyond Basic Routing

Once you have this foundation in place, Traefik opens up a world of possibilities. You can add middleware for authentication, implement circuit breakers, set up blue-green deployments, and much more. The label-based configuration system makes it easy to add these features without complex configuration files.

The Payoff

After wrestling with the initial configuration complexity, I now have a system that automatically handles SSL certificates for any subdomain I throw at it. New tenants can be onboarded instantly without any infrastructure changes. The entire setup is declarative and version-controlled, making it easy to replicate across different environments.

What started as a frustrating configuration challenge has become one of the most reliable parts of my infrastructure. And the best part? It just works, silently handling thousands of requests across dozens of subdomains without any manual intervention.

If you’re building a multi-tenant application or just need dynamic subdomain handling, this Traefik setup provides a robust foundation that scales with your needs. The upfront investment in understanding the configuration pays dividends as your application grows.