How to Set Up Traefik with Docker Compose for Self-Hosted Apps and Automatic HTTPS
If you run self-hosted apps and want HTTPS without the complexity, learning how to set up Traefik with Docker Compose is one of the best things you can do for your stack. Traefik acts as a reverse proxy that sits in front of your containers, handles routing by reading Docker labels, and automatically gets free SSL certificates from Let’s Encrypt.
This guide will show you how to set up Traefik with Docker Compose on Ubuntu, and you will get automatic HTTPS, proper folder structure, a working sample app, and basic hardening, all without Kubernetes.
Table of Contents
Prerequisites to Set Up Traefik with Docker Compose
Before you begin to set up Traefik with Docker Compose, make sure to prepare these prerequisites:
- A Linux VPS or dedicated server running Ubuntu 22.04 or 24.04. You can easily deploy your reverse proxy stack on a PerLod Linux VPS.
- Docker and Docker Compose are installed. A public domain name with DNS access.
- Ports 80 and 443 are open on your server’s firewall.
- An email address for Let’s Encrypt registration.
DNS Setup
Before Traefik can get a certificate, your domain must point to your server’s IP. If you don’t have a Domain, you can register a Domain on PerLod.
You can create an A record like this in your DNS panel:
Type: A
Name: @ (or your subdomain, e.g. whoami)
Value: YOUR_SERVER_IP
TTL: 300
Let DNS propagate before running Traefik. You can verify it with:
dig +short yourdomain.com
Folder Structure
It is better to keep things clean and organized. Here is the folder layout used in this guide:
/opt/traefik/
├── docker-compose.yml
├── acme.json
└── data/
└── traefik.yml # (optional static config file)
/opt/apps/
└── whoami/
└── docker-compose.yml
Run this to create the required folders and permissions for Traefik:
mkdir -p /opt/traefik /opt/apps/whoami
touch /opt/traefik/acme.json
chmod 600 /opt/traefik/acme.json
Remember to set the correct permission; Traefik will refuse to start if acme.json has loose permissions.
Once you are done with these prerequisites, you can proceed to the following steps to set up Traefik with Docker Compose.
Step 1: Create the Shared Docker Network
Traefik needs to communicate with your app containers. You must create a shared external network that all services will join:
docker network create traefik-proxy
All containers that Traefik should route to must be on this network.
Step 2: Set Up Traefik with Docker Compose
This is the core step where you set up Traefik with Docker Compose for the first time. Use the command below to create the Traefik compose file:
nano /opt/traefik/docker-compose.yml
Paste the following content into the file with your actual email and with your real domain:
networks:
traefik-proxy:
external: true
services:
traefik:
image: traefik:v3.7
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
command:
- --api.dashboard=true
- --log.level=INFO
- --accesslog=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --providers.docker.network=traefik-proxy
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.websecure.address=:443
- --certificatesresolvers.letsencrypt.acme.email=yo**@***il.com
- --certificatesresolvers.letsencrypt.acme.storage=/acme.json
- --certificatesresolvers.letsencrypt.acme.tlschallenge=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /opt/traefik/acme.json:/acme.json
networks:
- traefik-proxy
labels:
- traefik.enable=true
- traefik.http.routers.dashboard.rule=Host(`traefik.yourdomain.com`)
- traefik.http.routers.dashboard.entrypoints=websecure
- traefik.http.routers.dashboard.tls.certresolver=letsencrypt
- traefik.http.routers.dashboard.service=api@internal
- traefik.http.routers.dashboard.middlewares=dashboard-auth
- traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$REPLACE_THIS_HASH
You can use the command below to generate the password hash and then replace it in the above config. Remember to double every $ sign when pasting into a compose file:
echo $(htpasswd -nbB admin "YourSecurePassword") | sed -e s/\\$/\\$\\$/g
If you need Apache utils, you can install them first:
apt install apache2-utils -y
Explore key settings in the Traefik Docker Compose file:
| Setting | What It Does |
|---|---|
| security_opt: no-new-privileges:true | Prevents container processes from gaining extra Linux privileges. |
| providers.docker.exposedbydefault=false | Traefik ignores containers unless they have traefik.enable=true. |
| providers.docker.network=traefik-proxy | Traefik only reads the shared proxy network, not all container networks. |
| tlschallenge=true | Uses TLS-ALPN-01 challenge for certificates (port 443 only, no port 80 needed for cert). |
| /var/run/docker.sock:ro | Mount as read-only, Traefik only needs to read Docker events. |
| HTTP → HTTPS redirect | All port 80 traffic automatically redirects to 443. |
Step 3: Start Traefik
Once you are finished creating the Docker Compose, you can use the command below to bring up the Traefik stack:
cd /opt/traefik
docker compose up -d
Check that it started cleanly with the command below:
docker logs traefik --tail 30
You should see lines like Configuration loaded from flags and no errors. After 30 to 60 seconds, visit:
https://traefik.yourdomain.com
You should get a login prompt for the dashboard.
Step 4: Deploy a Sample App with Traefik Whoami
Now you will see why it is so easy to set up Traefik with Docker Compose for multiple apps. Each new app just needs Docker labels and no Traefik config edits required.
For example, create the whoami app compose file with the command below:
nano /opt/apps/whoami/docker-compose.yml
Add the following content with your actual subdomain and make sure its A record points to your server IP:
networks:
traefik-proxy:
external: true
services:
whoami:
image: traefik/whoami
container_name: whoami
restart: unless-stopped
expose:
- "80"
networks:
- traefik-proxy
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
- traefik.http.services.whoami.loadbalancer.server.port=80
Start it with the commands below:
cd /opt/apps/whoami
docker compose up -d
Now visit your subdomain:
https://whoami.yourdomain.com
Traefik will request a certificate automatically, and you will see the whoami output with your request headers.
How Docker Labels Work for Traefik
When you set up Traefik with Docker Compose, each label tells Traefik something specific about how to route traffic. Here are the labels and what they do:
1. Tell Traefik to watch this container:
traefik.enable=true
2. Route requests for this hostname to this container:
traefik.http.routers.whoami.rule=Host(`whoami.yourdomain.com`)
3. Only accept traffic on the HTTPS entrypoint port 443:
traefik.http.routers.whoami.entrypoints=websecure
4. Use Let’s Encrypt to get and renew the certificate automatically:
traefik.http.routers.whoami.tls.certresolver=letsencrypt
5. Forward traffic to port 80 inside the container:
traefik.http.services.whoami.loadbalancer.server.port=80
Note: You do not publish ports on the app container; only Traefik exposes ports 80 and 443. App containers expose only their ports for internal Docker networking.
Verify Your Traefik Setup with Docker Compose
When you are finished setting up Traefik with Docker Compose, you must verify everything works correctly.
1. Check the certificate with the command below:
curl -v https://whoami.yourdomain.com 2>&1 | grep -i "SSL\|certificate\|issuer"
In the output, you must see:
issuer: C=US; O=Let's Encrypt
2. Check HTTPS redirect with:
curl -I http://whoami.yourdomain.com
You should get 301 Moved Permanently with:
Location: https://whoami.yourdomain.com
3. Check Traefik dashboard:
Open the following URL in your browser, log in with the credentials you set up, and you should see your routers and services listed under the HTTP section:
https://traefik.yourdomain.com
4. Check Traefik logs with:
docker logs traefik --follow
Look for any level=error lines. A healthy setup shows only level=info or level=debug messages.
Basic Hardening Tips To Set Up Traefik with Docker Compose for Production
When you set up Traefik with Docker Compose for production, these hardening steps matter a lot:
- Never expose port 8080: This is the insecure dashboard port. This guide routes the dashboard through HTTPS with basic auth instead.
- Mount the Docker socket as read-only,
:roat the end of the volume line: Traefik only needs to watch events, not control Docker. - Use
security_opt: no-new-privileges:true: Stops container processes from escalating privileges. - Set
exposedbydefault=false: Prevents accidentally exposing containers without labels. - Keep Traefik updated: The project releases security patches regularly. Pin to a minor version like traefik:v3.7 and update on new releases.
- Use strong passwords for basic auth and consider replacing it with an SSO solution like Authentik or Authelia for the dashboard.
- Enable access logs: The
--accesslog=truegives you visibility into all traffic hitting your proxy.
How To Add More Apps to Traefik
The power of this setup is that adding a new self-hosted app is just a matter of joining it to the Traefik Proxy network and adding the right labels. Here is the template for any new service:
networks:
traefik-proxy:
external: true
services:
myapp:
image: myapp:latest
container_name: myapp
restart: unless-stopped
expose:
- "3000" # the port your app listens on internally
networks:
- traefik-proxy
labels:
- traefik.enable=true
- traefik.http.routers.myapp.rule=Host(`myapp.yourdomain.com`)
- traefik.http.routers.myapp.entrypoints=websecure
- traefik.http.routers.myapp.tls.certresolver=letsencrypt
- traefik.http.services.myapp.loadbalancer.server.port=3000
Note: No changes to the Traefik container needed; it detects new containers automatically.
Conclusion
With Traefik Docker Compose setup, you get automatic HTTPS and dynamic routing through Docker labels, all without touching Nginx configs or managing certificates manually. Once the traefik-proxy network is ready and Traefik is running, adding a new app takes less than a minute.
We hope you enjoy this guide. To see all Docker labels and providers, you can check the official Traefik Docker Provider Documentation.
FAQs
Do I need to open any ports for the Traefk whoami app container?
No. Only Traefik needs ports 80 and 443 exposed. App containers only use expose: which is internal to Docker.
What happens when my Traefik SSL certificate expires?
Nothing, Traefik renews Let’s Encrypt certificates automatically before they expire. No action needed on your part.
Do I need a domain to set up Traefik with Docker Compose?
Yes. Let’s Encrypt requires an accessible domain.