Why put Traefik in front of your VPS?
When you run several containerized applications on the same VPS, manually managing Nginx virtual hosts and renewing each certificate quickly becomes unmanageable. Traefik solves this problem by reading your Docker containers' labels directly: you declare a route at docker run time or in your docker-compose.yml, and Traefik configures it on the fly, generates the Let's Encrypt certificate and exposes it over HTTPS. No config file to edit, no reload: everything is dynamic.
What Traefik brings concretely on a VPS
- Automatic discovery of Docker containers via the Docker provider (routes appear without a restart)
- Let's Encrypt SSL certificates generated and renewed automatically (HTTP-01 or DNS-01)
- Routing by domain and by path, managed entirely through Docker labels
- Built-in web dashboard to visualize routers, services and middlewares in real time
- Ready-to-use middlewares: HTTPS redirection, basic auth, rate limiting, security headers
- Automatic load balancing when you scale a service to several replicas
Prerequisites
Traefik itself is very lightweight: 1 vCPU and 1 GB of RAM are amply enough for the proxy alone, the overhead coming from your applications behind it. Plan for a VPS with Docker Engine and the Docker Compose v2 plugin installed, a domain name whose A/AAAA records point to the VPS IP, and ports 80 and 443 open in your firewall (UFW). For wildcard certificates, you will also need API access to your DNS provider.
Deploy Traefik with Docker Compose
Create the network and the directory structure
Create a shared Docker network that Traefik and your applications will use: docker network create proxy. Create a traefik/ folder containing an acme.json file (the certificate storage) with the right permissions: touch acme.json && chmod 600 acme.json. Without these restricted permissions, Traefik will refuse to use it.
Configure the entrypoints and the ACME resolver
In the docker-compose.yml, declare two entrypoints (web on :80, websecure on :443) and a Let's Encrypt certificateResolver with your email and the httpChallenge challenge. Mount the Docker socket read-only (/var/run/docker.sock:/var/run/docker.sock:ro) so that Traefik discovers the containers, and the acme.json volume.
Force the HTTP to HTTPS redirection
Add a global redirection middleware on the web entrypoint via the labels: traefik.http.routers.http-catchall.middlewares=redirect-to-https. This way all cleartext traffic is automatically switched to HTTPS, the behavior expected in production.
Secure the dashboard
Expose the dashboard on a subdomain (traefik.yourdomain.com) protected by a basicauth middleware. Generate the hash with htpasswd -nb admin motdepasse and place it in the label traefik.http.middlewares.auth.basicauth.users. Never leave the --api.insecure=true flag in production.
Launch Traefik
Start the stack: docker compose up -d. Check the logs with docker compose logs -f traefik to confirm the connection to Let's Encrypt and the absence of ACME errors (beware of the Let's Encrypt rate limit during the testing phase; use the staging server).
Connect an application
To expose a service, attach it to the proxy network and add its labels: traefik.enable=true, traefik.http.routers.app.rule=Host(\app.yourdomain.com\), traefik.http.routers.app.entrypoints=websecure and traefik.http.routers.app.tls.certresolver=letsencrypt. Traefik routes and certifies the application in seconds.
To obtain a wildcard certificate (*.yourdomain.com) and avoid exposing each subdomain, switch from the httpChallenge to the dnsChallenge. Configure the DNS provider (Cloudflare, OVH, etc.) via environment variables (e.g. CF_API_EMAIL, CF_DNS_API_TOKEN): Traefik proves ownership of the domain through a TXT record, which works even for services not publicly exposed.