How to securely host website with Docker and Traefik?
30 minutes
DevOps/Developer
Junior
Get to know Docker in a few simple steps

What is Traefik?
What is Traefik?
Traefik is a modern reverse proxy and load balancer that was created for dynamic management of network traffic in microservice environments. Unlike traditional tools, Traefik is designed to integrate seamlessly with modern tools and platforms such as Docker and Kubernetes.
Traefik key features
- Automatic configuration - One of the main features of Traefik is its ability to automatically discover services and configure routes (DNS). Thanks to integration with systems such as Kubernetes or Docker, Traefik automatically updates its settings when new services are added, changed or removed.
- Support for multiple protocols - Traefik supports both TCP and UDP protocols, so it can be used in a wide range of applications. Additionally, it offers the ability to create middlewares that allow for increased control over applications.
- Easy SSL setup - Traefik automatically manages SSL certificates using Let's Encrypt. This makes it possible to easily and quickly implement secure HTTPS connections without the need to manually manage certificates.
- Loadbalancer - Traefik offers advanced load balancing features that enable even distribution of network traffic between different service instances.
- Label based routing - In order to host the application on our domain, all we need to do is add the appropriate label to the container in the file docker-compose.yml
Why choose Traefik and not e.g. Docker Reverse Proxy?
Traefik, although it may seem difficult to use at first glance, will actually allow us to manage our container applications in a much simpler way than using e.g. Docker Reverse Proxy. If we use Traefik, we do not have to configure SSL certificates ourselves, worry about HTTP to HTTPS redirects, and we can also use Middleware quickly and easily. Additionally, the platform itself offers many advanced plug-ins that are worth considering for selected projects.
Traefik basic configuration
How to configure Traefik?
Below is a minimalist compose.yml file containing the basic Traefik configuration for Development.
Traefik Dashboard (Development Only)
In the example below, we are running a Traefik container with the Traefik Dashboard active. This approach is highly dangerous due to the need to run the Traefik API, which, if left unsecured, can lead to many security issues with hosted applications.
Treat The following example is strictly educational, later you will also find a safe implementation.
Configuration file traefik-compose.yml (Development - Traefik Dashboard)
services: traefik: image: traefik:latest ports: - "80:80" - "443:443" command: - "--api.dashboard=true"Enable Traefik Dashboard - "--providers.docker.exposedbydefault=false"Do not expose Docker containers by default - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.myresolver.acme.tlschallenge=true"Enable ACME TLS Challenge - "--certificatesresolvers.myresolver.acme.email=EMAIL"Define Email for ACME - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"Define Storage for ACME volumes: - "var/run/docker.sock:/var/run/docker.sock"Expose Docker Socket (DANGEROUS!!!) - "./letsencrypt:/letsencrypt"Volume for SSL Certs labels: - "traefik.enable=true"Enables Traefik Routing - "traefik.http.routers.traefik.rule=Host(`example.domain`)"Define domain for Traefik Dashboard - "traefik.http.routers.traefik.entrypoints=websecure"Host Traefik Dashbord Over HTTPS - "traefik.http.routers.traefik.service=api@internal"Enable Traefik API - Need for Traefik Dashbord - "traefik.http.routers.traefik.tls.certresolver=myresolver"Enable ACME TLS Challenge
In the above example, we have defined the Traefik service with the following parameters:
- We have provided ports 80 and 443 for our Traefik Reverse Proxy
- We have created a volume for SSL certificates
- We have provided access to our Docker Socet for the Traefik website (UNSAFE)
- In the commands section, we configured ports and SSL certificates, and additionally launched Traefik Dashboard
- In the labels section, we have assigned access to our Traefik Dashboard at the URL example.domain and
In order to test the above configuration, you must have a purchased domain. If you have one, point it to your VPS server. Below is an example configuration of my domains.

Launch Traefik Dashboard
docker compose upordocker compose -f compose-file-name.yml up
Go to the domain of your choice, if everything works correctly, you will find the Traefik Dashboard here.
Traefik Secure Configuration
Why is the above configuration not safe?
Now that we know the basic configuration of the Traefik website, it would be worth finding out what it should look like in a safe way. The above solution has several problems:
- We provide direct access to the Docker socket, which we should NEVER do unless we know how to do it
- We provide the Traefik API, which is additionally not protected in any way, so the attacker can view all our information
- Traefik Dashboard itself is also available to the public and is not password protected.
Traefik safe configuration example
Below we will configure Traefik to use Docer Socet via proxy and completely disable access to Traefik Dashboard.
Configuration file traefik-compose.yml (Development - Traefik Dashboard)
services: socket-proxy: --New Service - Socket Proxy image: "tecnativa/docker-socket-proxy" container_name: "socket-proxy" environment: - CONTAINERS=1 networks: - "traefik-socket-proxy" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" traefik: --Modified Traefik Service image: "traefik:latest" depends_on: - "socket-proxy" ports: - "80:80" - "443:443" networks: - "traefik-socket-proxy"--Connect to Socket Proxy - "traefik-external"--Traefick Network command: - "--providers.docker.endpoint=tcp://socket-proxy:2375"--Use Socket Proxy - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.myresolver.acme.tlschallenge=true" - "--certificatesresolvers.myresolver.acme.email=EMAIL" - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" volumes: - "./letsencrypt:/letsencrypt" labels: - "traefik.enable=true"networks: traefik-socket-proxy: --Internal Network for Socket Proxy name: "traefik-socket-proxy" traefik-external: -- Network that host External Websites name: "traefik-external"
Compare the safe example above with the previous one. The current solution does not provide Traefick Dashboard and uses an additional service called Socket-Proxy, which allows for limited communication between our Traefick and the Docker Socket. If necessary, you can additionally make a more restrictive proxy configuration using environment variables.
Traefik website hosting
Traefik Configuration File Structure
As we have noticed in the above examples, Traefik's configuration is not complicated, however, when we start defining our websites, we must meet one important requirement. Analyze the following example carefully...

Service - Labels
Pay attention to the code fragments marked in yellow. We defined a service called "testing", and then in the "labels" section we used its name right after the phrase "routers".
This is the way to assign service names to labels using Traefik. If you make a mistake here, Traefik will not be able to locate your container.
Remember to always assign the assignment as in the example above, appropriately to the names of your websites.
- image: traefik/whoami - Our Application Image
- container_name: "testing" - Our Container Name
- traefik.enable=true" - Starts Routing for a given container
- traefik.http.routers.SERVICE_NAME.rule=Host(`example.com`)" - Specifies the URL address where the application is to be located
- traefik.http.routers.SERVICE_NAME.entrypoints=websecure" - Tells Traefik to host the application via port 443 (HTTPS)
- traefik.http.routers.SERVICE_NAME.certesolver=myresolver" - Tells Traefik to use our SSL (Let's Encrypt) agent
- traefik.http.routers.SERVICE_NAME.middlewares=waf@docker" - Informs Traefik that the given application should use the specified middleware
- networks: - In this section, let's connect the application to the Traefik-External network (Public network) created by us
The entire Traefik configuration file with the HTTP page connected
Below is the entire configuration file containing the running website.
Sample secure Traefik configuration with one website
services: socket-proxy: --Socket Proxy image: "tecnativa/docker-socket-proxy" container_name: "socket-proxy" environment: - CONTAINERS=1 networks: - "traefik-socket-proxy" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" traefik: --Traefik Service image: "traefik:latest" depends_on: - "socket-proxy" ports: - "80:80" - "443:443" networks: - "traefik-socket-proxy" - "traefik-external" command: - "--providers.docker.endpoint=tcp://socket-proxy:2375" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.myresolver.acme.tlschallenge=true" - "--certificatesresolvers.myresolver.acme.email=EMAIL" - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" volumes: - "./letsencrypt:/letsencrypt" labels: - "traefik.enable=true" your-app: -- Our Website image: "traefik/whoami" container_name: "your-app" labels: - "traefik.enable=true" -- Enable Traefik on your app - "traefik.http.routers.your-app.rule=Host(`whoami.jakubwojtysiak.online`)" -- Replace with your domain - "traefik.http.routers.your-app.entrypoints=websecure" -- Host webiste on 443 (HTTPS) - "traefik.http.routers.your-app.tls.certresolver=myresolver" -- Use Lets Encrypt Cert Resolver networks: - "traefik-external" -- Attach website to external network, so Traefik can discover it (We have to use it as we decided to use Traefik Socket Proxy)networks: traefik-socket-proxy: name: "traefik-socket-proxy" traefik-external: name: "traefik-external"
Run compose.yml file
docker compose up -d
After switching to the domain of your choice, you should see a simple application that will display information about your query sent to the server. In exactly the same way you will be able to run any web applications.