Self-Host Traefik: Automatic HTTPS Reverse Proxy in 15 Minutes
Manually configuring Nginx for every new container gets old fast. Copy-pasting SSL certificate commands, editing vhosts, reloading services — it is repetitive, error-prone, and every new subdomain means another config file.
Traefik solves this. It is a modern reverse proxy and load balancer that discovers your Docker containers automatically, handles SSL certificates via Let's Encrypt, and routes traffic without you ever touching a config file for each new service.
In this guide, you will deploy Traefik with Docker Compose, enable automatic HTTPS, and proxy your first container — all in about 15 minutes.
What You Need
- A VPS or server with Docker and Docker Compose installed
- A domain name pointing to your server (A record to your VPS IP)
- Ports 80 and 443 open on your firewall
- About 512 MB RAM minimum (Traefik is lightweight)
Step 1: Create the Docker Network
Traefik and your services need to share a Docker network so Traefik can discover them.
docker network create traefik-public
Step 2: Prepare the Directory Structure
mkdir -p ~/traefik/{letsencrypt,logs}
cd ~/traefik
Step 3: Create the Docker Compose File
Create docker-compose.yml:
version: "3.8"
services:
traefik:
image: traefik:v3.1
container_name: traefik
restart: unless-stopped
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email=admin@yourdomain.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--log.level=INFO"
- "--accesslog=true"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
- ./logs:/logs
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$H6uskkk7$$IgXLP6ewTrSuBkTrqE8wj/"
networks:
traefik-public:
external: true
Replace these values:
[email protected]— your real email for Let's Encrypttraefik.yourdomain.com— your subdomain for the Traefik dashboard
The basic auth password above is admin/admin. Generate your own with:
htpasswd -nb admin yourpassword | sed -e s/\$/\$\$/g
Step 4: Start Traefik
docker compose up -d
Check the logs:
docker logs -f traefik
You should see Traefik starting up and registering the Docker provider.
Step 5: Verify the Dashboard
Open https://traefik.yourdomain.com in your browser. You will get a basic auth prompt — use admin / admin (or your custom credentials). The Traefik dashboard shows active routers, services, and middlewares.
Step 6: Route Your First Container
Here is the magic. Add any container to the traefik-public network and add three labels. Traefik handles the rest.
Example — deploy a simple whoami service:
version: "3.8"
services:
whoami:
image: traefik/whoami
container_name: whoami
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.yourdomain.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
networks:
traefik-public:
external: true
Run it:
docker compose up -d
Within seconds, Traefik detects the container, requests an SSL certificate, and routes https://whoami.yourdomain.com to it. No Nginx config. No certificate commands. No reloads.
How It Works
- Docker provider: Traefik watches the Docker socket and reads container labels to build routing rules dynamically.
- Let's Encrypt resolver: Automatically requests and renews SSL certificates via the TLS-ALPN-01 challenge.
- Entrypoints: Web (port 80) redirects to websecure (port 443). All traffic is HTTPS by default.
- Labels as config: Each container declares its own routing rules. No central config file to maintain.
Common Labels Reference
| Label | Purpose |
|---|---|
traefik.enable=true | Expose this container to Traefik |
traefik.http.routers.name.rule=Host(...) | Match incoming requests by domain |
traefik.http.routers.name.entrypoints=websecure | Use HTTPS entrypoint |
traefik.http.routers.name.tls.certresolver=letsencrypt | Enable automatic SSL |
traefik.http.routers.name.middlewares=rate-limit | Apply middleware (rate limiting, auth, etc.) |
Next Steps
- Add rate limiting with the
ratelimitmiddleware - Protect services with Authelia or Authentik for SSO
- Load balance across multiple container replicas
- Add TCP and UDP routing for non-HTTP services
- Monitor Traefik metrics with Prometheus and Grafana
Once Traefik is running, deploying new services becomes as simple as adding three labels. No more Nginx boilerplate. No more certificate management. Just Docker Compose up and go.