Overview
This tutorial shows how to deploy Traefik v3 as a modern Docker reverse proxy with automatic Let’s Encrypt TLS certificates on Ubuntu 24.04. You will set up secure HTTPS for any containerized web app using Docker Compose, with zero manual certificate handling. The guide uses the HTTP-01 challenge for public A-record domains and includes a note on switching to the DNS-01 challenge for wildcard certificates.
Prerequisites
- A fresh Ubuntu 24.04 server with sudo access.
- A domain name with an A record pointing to your server’s public IP (for example, whoami.example.com).
- Ports 80 and 443 open on the server firewall and any upstream firewall or cloud security group.
Step 1: Install Docker Engine and the Compose plugin
Install Docker using the official repository to get current packages. This also installs the docker compose plugin.
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu noble stable" | \
sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
newgrp docker
Step 2: Prepare directories, permissions, and a Docker network
Create a project folder for Traefik and a persistent location to store ACME data. The acme.json file must be readable only by the Traefik process to keep private keys safe.
sudo mkdir -p /opt/traefik/letsencrypt
sudo touch /opt/traefik/letsencrypt/acme.json
sudo chmod 600 /opt/traefik/letsencrypt/acme.json
sudo chown -R $USER:$USER /opt/traefik
docker network create proxy
cd /opt/traefik
Step 3: Create an .env file
Store reusable variables in a .env file. Replace the placeholders with your real email and domain. The email is used by Let’s Encrypt for certificate notices.
cat > .env << 'EOF'
[email protected]
DOMAIN=example.com
EOF
Step 4: Write the Docker Compose file
The Compose file below pulls Traefik v3, configures HTTP-to-HTTPS redirection, enables the Docker provider, and uses the HTTP-01 challenge on port 80 to issue certificates. It also deploys a sample “whoami” app behind TLS at whoami.your-domain.
cat > docker-compose.yml << 'EOF'
version: "3.9"
networks:
proxy:
external: true
services:
traefik:
image: traefik:v3.0
container_name: traefik
command:
- --api.dashboard=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --certificatesresolvers.le.acme.email=${LETSENCRYPT_EMAIL}
- --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.le.acme.httpchallenge=true
- --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
ports:
- "80:80"
- "443:443"
volumes:
- ./letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- proxy
restart: unless-stopped
whoami:
image: traefik/whoami:v1.10
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=Host(`whoami.${DOMAIN}`)
- traefik.http.routers.whoami.entrypoints=websecure
- traefik.http.routers.whoami.tls.certresolver=le
- traefik.http.services.whoami.loadbalancer.server.port=80
networks:
- proxy
restart: unless-stopped
EOF
Step 5: Start the stack and verify HTTPS
Bring the services online and watch Traefik’s first-run logs. The proxy will request and store certificates in acme.json. Ensure your DNS A record for whoami.example.com points to this server before you start.
docker compose up -d
docker logs -f traefik
When the logs show that certificates were obtained, browse to https://whoami.example.com. You should see a simple page from the whoami container over HTTPS. You can also test from the terminal:
curl -I https://whoami.example.com
Optional: Use DNS-01 for wildcard certificates
If you need a wildcard like *.example.com, switch to the DNS-01 challenge. This requires a DNS provider API token. As an example, for Cloudflare you would add two flags and an environment variable. Consult Traefik’s documentation for the exact variable names supported by your DNS provider.
# In docker-compose.yml, replace the HTTP-01 lines with:
- --certificatesresolvers.le.acme.dnschallenge=true
- --certificatesresolvers.le.acme.dnschallenge.provider=cloudflare
# And add, under the traefik service:
environment:
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
# Then define it in .env (use a least-privilege token scoped to DNS edit):
CF_DNS_API_TOKEN=your_cloudflare_dns_token
After changing the challenge type, remove the old acme.json or start with a fresh file, then redeploy so Traefik can issue new certificates using DNS-01.
Security and maintenance tips
- Keep the Docker socket mount read-only, as shown, to reduce risk. Consider using a socket proxy if you expose Traefik to untrusted networks.
- Do not expose the Traefik dashboard publicly without authentication. If needed, put the dashboard behind a router with basic auth middleware and IP allowlists.
- Back up /opt/traefik/letsencrypt/acme.json. It contains your issued certificates and keys.
- Use a process manager (Compose restart policy is already set) and keep Traefik updated to the latest v3 patch release.
Troubleshooting
- If Let’s Encrypt fails, confirm that ports 80 and 443 are reachable from the internet and that your DNS A record is correct. The HTTP-01 challenge requires port 80 to reach the server.
- Check logs with docker logs -f traefik for clear error messages (rate limiting, challenge timeouts, or permission issues).
- Ensure acme.json permissions remain 600. Incorrect permissions can prevent Traefik from writing certificates.
- If labels do not seem to apply, verify that the whoami container is on the same Docker network named proxy and that exposedbydefault is false (which requires explicit traefik.enable=true).
You now have a production-ready reverse proxy on Ubuntu 24.04 with automatic HTTPS, simple app onboarding via labels, and a clean path to wildcard certificates when needed.
Comments
Post a Comment