This guide will cover how to use Traefik as a reverse proxy to manage multiple hosts with Docker Compose.
Suppose you had deployed several microservices using Docker and you want to connect these microservices to the outside world. You will probably use some reverse proxy solution that will act as a frontend for these microservices. Nginx is the most popular and efficient reverse proxy solution, but it was written before container technology (like Docker) became so popular. The modern solution for hosting multiple hosts with Docker is now Traefik.
What is Traefik?
Traefik is a modern reverse proxy solution written in GO to meet modern containerized challenges.
Unlike a traditional reverse proxy, which requires manual configuration, Traefik uses service discovery to dynamically configure routing. Traefik supports all major protocols, leveraging a rich set of middleware for load balancing, rate-limiting, circuit-breakers, mirroring, authentication, and more. Traefik also supports SSL termination and works with ACME providers (like Letâs Encrypt) for automatic certificate generation. Source.
Traefik was developed with containerized technology in mind, which means thereâs a lot of new features available in comparison with other reverse proxy solutions. When running, Traefik does the following and more:
- Dynamically updates the configuration and loads it without a restart.
- Load balances requests from the outside world using multiple available algorithms.
- Enables HTTPS for microservices using Letâs Encrypt.
- Provides a clean web UI.
- Supports for WebSocket, HTTP/2, GRPC.
- Provides metrics to Rest, Prometheus, Datadog, Statsd, InfluxDB.

Why Use Traefik as a Reverse Proxy for Multiple Hosts?
Say, for example, you want to remove one of the microservices from the container or change its port, and, as a result, you have to edit the Nginx configuration file to reflect the new container settings. Now, consider another situation where you add, delete, or scale the microservices application several times in a dayânow, youâre editing the routes and other settings several times in the reverse proxy configuration file.
In this article, we will check how to install Traefik and configure it in a standalone and Dockerized environment, and then give examples of connecting it to your microservices in the backend.
Prerequisites to Install Traefik
- A VPS running Ubuntu 24.04. Get your Linux VPS hosting from a reputable and trustworthy provider like SSD Nodes. We offer powerful Ubuntu servers and the best deals. Take a look at our offerings and prepare for your mind to be blown đ¤Ż.
- A non-root,
sudo-enabled user. If you only have arootuser, see our SSH tutorial for details on creating new users. - A working Docker installationâfor information about how to install Docker, check out our getting started with Docker tutorial.
Using Traefik without Docker
Our first goal is to install Traefik and use it to route a few applications (backend) using Traefik configuration without Dockerizing them. To do that, weâll install Apache and Nginx and configure them to use different ports, as they will act as a backend.
First, update your system package index:
$ sudo apt update
Install Apache:
$ sudo apt install apache2
Change the port number to 8083 from 80 in /etc/apache2/ports.conf and restart Apache.
$ sudo nano /etc/apache2/ports.conf
$ sudo systemctl restart apache2
Next, install Nginx:
$ sudo apt install nginx
Create a custom welcome page for the Nginx server to distinguish between the two servers:
$ sudo mkdir /var/www/nginx_html
$ sudo echo '<!DOCTYPE html><html><body><h1>Welcome to My Nginx Page</h1></body></html>' | sudo tee /var/www/nginx_html/index.html
Next, edit the default Nginx configuration file:
$ sudo nano /etc/nginx/sites-available/default
Point Nginx to the new /var/www/nginx_html directory, and the 8082 port number:
server {
listen 8082 default_server;
listen [::]:8082 default_server;
# ...
# ...
# ...
root /var/www/nginx_html;
# ...
# ...
# ...
}
Next, restart Nginx:
$ sudo systemctl restart nginx
Now both Apache and Nginx will be available in the port number 8083 and 8082, respectively.
Step 1: Install Traefik
To install Traefik as a standalone environment, we need to download the binary and edit the Traefik configuration file and rules files.
Download the Traefik binary from the releases page:
$ wget https://github.com/traefik/traefik/releases/download/v3.1.4/traefik_v3.1.4_linux_amd64.tar.gz
Remember to replace v3.1.4 with the latest release, or another binary that is compatible with your system.
Check the integrity of the downloaded file and compare it to the value in the traefik_v3.1.4_checksums.txt file:
$ sha256sum ./traefik_v3.1.4_linux_amd64.tar.gz
Next, extract the compressed file:
$ tar -zxvf traefik_v3.1.4_linux_amd64.tar.gz
You can now use ./traefik to run Traefik configurations.
Step 2: Traefik Configuration
To host multiple websites with Traefik, youâll need to create a configuration file that routes each domain to the corresponding port.
First, weâll create a traefik.yml file that gets automatically detected by Traefik:
log:
level: "DEBUG"
entryPoints:
web:
address: ":80"
providers:
file:
filename: "./rules.yml"
watch: true
In this traefik.yml file, you have the following:
log: Sets log level toDEBUGfor detailed output.entryPoints: Defineswebentry point to listen on port80for HTTP traffic.providers: This tells Traefik to load dynamic configuration (such as routes and services) from therules.ymlfile, and watch for changes.
Step 3: Set up Traefik Rules
Next, create a rules.yml file to define dynamic routing rules:
http:
routers:
router1:
rule: "Host(`nginx.example.com`)"
service: service1
entryPoints:
- web
router2:
rule: "Host(`apache.example.com`)"
service: service2
entryPoints:
- web
services:
service1:
loadBalancer:
servers:
- url: "http://127.0.0.1:8082"
service2:
loadBalancer:
servers:
- url: "http://127.0.0.1:8083"
Here, you definerouters to define traffic rules and route them to services:
router1: Routes traffic requests fornginx.example.comtoservice1.router2: Routes traffic requests forapache.example.comtoservice2.
The services are defined as follows:
service1: Forwards traffic to the Nginx server athttp://127.0.0.1:8082.service2: Forwards traffic to Apache server athttp://127.0.0.1:8083.
Both routers listen on the web entry point, which was defined in the traefik.yml file.
Make sure you are in the Traefik directory that hosts both the Traefik binary and the traefik.yml file, then run the following command:
$ ./traefik
Now, if you navigate to your domain names, you should see two different welcome pages, one for Nginx and one for Apache:
http://nginx.example.com/
http://apache.example.com/
With this, you now have two websites on one server with Traefik as a proxy. However, these two websites are served through HTTP and are not secured with HTTPS. Weâll fix this in the next section and add a Letâs Encrypt certificate to both domains.
Step 4: Using TLS in Traefik with Letâs Encrypt
To use Letâs Encrypt with your Traefik configuration, edit traefik.yml by adding a websecure entry point that listens on port 443 , which is the default HTTPS port, and a certificatesResolvers section to define how the Letâs Encrypt certificate will be resolved:
log:
level: "DEBUG"
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
file:
filename: "./rules.yml"
watch: true
certificatesResolvers:
myresolver:
acme:
email: "[email protected]"
storage: "acme.json"
httpChallenge:
entryPoint: web
providers:
file:
filename: "./rules.yml"
watch: true
Next, update rules.yml by adding the websecure entry point and a tls option that uses the myresolver certificate resolver you defined in the traefik.yml file earlier, in addition to a tlsoptions field that specifies the TLS version.
http:
routers:
router1:
rule: "Host(`app1.your_domain.com`)"
service: service1
entryPoints:
- web
- websecure
tls:
certResolver: myresolver
options: tlsoptions
router2:
rule: "Host(`app2.your_domain.com`)"
service: service2
entryPoints:
- web
- websecure
tls:
certResolver: myresolver
options: tlsoptions
services:
service1:
loadBalancer:
servers:
- url: "http://127.0.0.1:8082"
service2:
loadBalancer:
servers:
- url: "http://127.0.0.1:8083"
tls:
options:
tlsoptions:
minVersion: VersionTLS12
Now, you can start Traefik againâbut remember to kill previous instances of it first.
$ ./traefik
With this, you are now hosting two different web services via HTTPS with Traefik. Next, youâll learn how to use Traefik as a load balancer.
Step 5: Using Traefik as a Load Balancer
With little modification to the above rules file, we can make Traefik to act as a load balancer between both Apache and Nginx instances.
$ nano rules.yml
You can replace the fileâs contents with the following:
http:
routers:
router1:
rule: "Host(`your_domain.com`)"
service: service1
entryPoints:
- web
- websecure
tls:
certResolver: myresolver
options: tlsoptions
services:
service1:
loadBalancer:
servers:
- url: "http://127.0.0.1:8082"
weight: 2
- url: "http://127.0.0.1:8083"
weight: 1
tls:
options:
tlsoptions:
minVersion: VersionTLS12
Weight determines the proportion of traffic each server will receive. In this example:
- The Nignx server at
http://127.0.0.1:8082has a weight of2. - The Apache server at
http://127.0.0.1:8083has a weight of1.
This means that for every 3 requests, 2 will go to http://127.0.0.1:8082 and 1 will go to http://127.0.0.1:8083.
Now, you can start Traefik againâbut remember you have to kill previous instances of it first.
$ ./traefik
Use your browser to visit the domain name that you entered into the rules.yml file and hit refresh. Youâll find that Traefik is both proxying load balancing the Apache and Nginx backends.
Now, letâs look at this same process, but using Docker, docker-compose, and containerized/Dockerized microservices, which is likely how many of you will end up using Traefik.
Using Traefik with Docker Compose
Step 1: Traefik Reverse Proxy Example for Docker
In this section, we'll explore an example of a Traefik reverse proxy with Docker compose.
First, letâs create a docker-compose.yml file, in which we will define services for Traefik and the other two microservicesâApache and Nginx, just like before.
$ nano docker-compose.yml
Add the following:
version: '3'
services:
reverse-proxy:
image: traefik:latest
command: --configFile=/etc/traefik/traefik.yml
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "8080:8080" # Traefik dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.yml:/etc/traefik/traefik.yml
- ./acme.json:/acme.json
networks:
- traefik
apache:
image: httpd:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.apache.rule=Host(`apache.example.com`)"
- "traefik.http.routers.apache.entrypoints=web,websecure"
- "traefik.http.routers.apache.tls.certresolver=myresolver"
- "traefik.http.services.apache.loadbalancer.server.port=80"
networks:
- traefik
nginx:
image: nginx:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx.rule=Host(`nginx.example.com`)"
- "traefik.http.routers.nginx.entrypoints=web,websecure"
- "traefik.http.routers.nginx.tls.certresolver=myresolver"
- "traefik.http.services.nginx.loadbalancer.server.port=80"
networks:
- traefik
networks:
traefik:
external: true
Three services have been defined in the above docker-compose.yml file, and they are reverse-proxy, apache and nginx.
In the port section, 8080 is the port used by Traefik for its web interface and port 80is used for all default HTTP requests. In the volume section, the Docker socket is accessed by Traefik to route requests to the right container.
We need to knit all the three services together so that they can communicate with each other, which is why we created the traefik network at the end of the file.
As for the services, we have the following:
- reverse-proxy service: This is the Traefik service acting as a reverse proxy, with ports for HTTP, HTTPS, and the Traefik dashboard.
- Apache and Nginx services: Both have labels that define routing rules for Traefik:
traefik.http.routers.[service].rule: Routes traffic based on theHost.traefik.http.routers.[service].entrypoints: Defines which entry points to use (webfor HTTP,websecurefor HTTPS).traefik.http.routers.[service].tls.certresolver: Configures TLS with themyresolvercertificate resolver, which weâll define in thetraefik.ymlfile next section.traefik.http.services.[service].loadbalancer.server.port: Defines the internal port for each service.
Step 2: Run Traefik using Docker
First, create a new traefik.yml file. This is the configuration file referenced inside docker-compose.yml in the previous section. This Traefik configuration file defines the entry points, certificate resolver, and sets the provider as Docker:
log:
level: "DEBUG" # Set log level to DEBUG for detailed logs
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
traefik:
address: ":8080" # Dashboard entry point
certificatesResolvers:
myresolver:
acme:
email: [email protected]
storage: acme.json
httpChallenge:
entryPoint: web
providers:
docker:
exposedByDefault: false
#api:
# dashboard: true # Enable the Traefik dashboard
# insecure: true # Allow access to the dashboard without authentication (for development)
Here, you have the following:
- EntryPoints: Defines the ports that Traefik will listen to for HTTP (
:80) and HTTPS (:443) traffic. - certificatesResolvers: This uses the ACME protocol to automatically generate SSL certificates for the domains (replace
[email protected]with your real email). The great thing about Traefik is that these certificates are dynamic, meaning that if you add a new domain or subdomain todocker-compose.yml, Traefik will automatically fetch the key/certificate and store them inacme.json.- The
httpChallengeis configured to solve TLS challenges over HTTP (port 80).
- The
- providers.docker: Enables Docker as the provider for dynamic routing, but
exposedByDefault: falseensures that only services explicitly enabled via labels will be exposed by Traefik.
Make sure Traefik has access to your acme.json file, which stores certificate information:
$ touch acme.json
$ chmod 600 acme.json
Create the traefik network:
$ docker network create traefik
Start the services with Docker Compose:
$ docker compose up -d
You should see the following output:
[+] Running 19/19
â reverse-proxy Pulled 19.4s
â 43c4264eed91 Pull complete 3.0s
â eee3b43fedbd Pull complete 3.5s
â e951b536ebf8 Pull complete 5.9s
â 188dd7af1135 Pull complete 3.9s
â apache Pulled 16.2s
â 62dd86107c65 Pull complete 1.3s
â 4f4fb700ef54 Pull complete 3.8s
â 509789394c2a Pull complete 3.8s
â nginx Pulled 18.7s
â a2318d6c47ec Pull complete 0.8s
â 095d327c79ae Pull complete 1.5s
â 24b3fdc4d1e3 Pull complete 2.8s
â 3122471704d5 Pull complete 3.2s
With this, youâll have two HTTPS-enabled applications served by Traefik at https://apache.your_domain.com/ and https://nginx.your_domain.com/
Step 3: Enable the Traefik Dashboard
If you want to access the Traefik dashboard, uncomment the last two lines in the traefik.yml file:
log:
level: "DEBUG"
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
traefik:
address: ":8080" # Dashboard entry point
certificatesResolvers:
myresolver:
acme:
email: [email protected]
storage: acme.json
httpChallenge:
entryPoint: web
providers:
docker:
exposedByDefault: false
api:
dashboard: true # Enable the Traefik dashboard
insecure: true # Allow access to the dashboard without authentication (for development)
Note: Allowing access to the Traefik dashboard without authentication poses a security risk, as it can expose sensitive configuration details to unauthorized users. Remember to only use this insecure option in testing environments.
You can then access the Traefik dashboard on port 8080 :
http://your_domain.com:8080/dashboard
In this dashboard, you can monitor and manage Traefik's routing, view active services, routers, middlewares, and review logs for troubleshooting.
Step 4: Access Traefik Logs
If you still can't access the dashboard, check the logs for errors:
$ docker compose logs reverse-proxy
Step 5: Set up Traefik to Redirect HTTP to HTTPS
To redirect HTTP to HTTPS with Traefik, you need to add a middleware for HTTP to HTTPS redirection and apply it to the web entrypoint. Open traefik.yml and add the following highlighted parts:
log:
level: "DEBUG" # Set log level to DEBUG for detailed logs
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
traefik:
address: ":8080" # Dashboard entry point
certificatesResolvers:
myresolver:
acme:
email: [email protected]
storage: acme.json
httpChallenge:
entryPoint: web
providers:
docker:
exposedByDefault: false
With these changes, all HTTP traffic will be automatically redirected to HTTPS. Here's a breakdown of what happens:
- When a user accesses your site via HTTP (port 80), they hit the
webentrypoint. - The
webentrypoint is configured to redirect all traffic to thewebsecureentrypoint using HTTPS. - The
websecureentrypoint handles the HTTPS traffic on port 443.
Your services (apache and nginx) are already configured to use both web and websecure entrypoints, so they will work correctly with this setup.
Remember to restart your Traefik container after making these changes:
$ docker-compose down
$ docker-compose up -d
This Traefik configuration will ensure that all HTTP traffic is redirected to HTTPS, improving the security of your web services.
Step 6: Using Traefikâs PathPrefix
Traefik's PathPrefix router rule feature allows you to route traffic based on URL paths. This is particularly useful when you want to direct requests to different services based on the URL path.
For example, you can set up requests to the /app1 URL to be served by Apache, and /app2 to be served by Nginx.
Here's an example of how to use PathPrefix with Traefik:
version: '3'
services:
reverse-proxy:
image: traefik:latest
command: --configFile=/etc/traefik/traefik.yml
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "8080:8080" # Traefik dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.yml:/etc/traefik/traefik.yml
- ./acme.json:/acme.json
networks:
- traefik
apache:
image: httpd:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.apache.rule=Host(`example.com`) && PathPrefix(`/app1`)"
- "traefik.http.routers.apache.entrypoints=web,websecure"
- "traefik.http.routers.apache.tls.certresolver=myresolver"
- "traefik.http.services.apache.loadbalancer.server.port=80"
networks:
- traefik
nginx:
image: nginx:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx.rule=Host(`example.com`) && PathPrefix(`/app2`)"
- "traefik.http.routers.nginx.entrypoints=web,websecure"
- "traefik.http.routers.nginx.tls.certresolver=myresolver"
- "traefik.http.services.nginx.loadbalancer.server.port=80"
networks:
- traefik
networks:
traefik:
external: true
In this updated configuration:
- The Apache service will handle requests to
https://example.com/app1and any subpaths (e.g.,https://example.com/app1/users,https://example.com/app1/products, etc.). - The Nginx service will handle requests to
https://example.com/app2and any subpaths.
The key changes are in the traefik.http.routers.[service].rule labels:
- For Apache:
Host(`example.com) && PathPrefix(`/app1`) - For Nginx:
Host(`example.com`)&& PathPrefix(`/app2`)
These rules combine the Host matcher with the PathPrefix matcher using the && (AND) operator. This means the rule will only match if both conditions are true.
A few important notes:
- Make sure to replace
example.comwith your actual domain name. - The
PathPrefixrule will match any path that starts with the specified prefix. For example,/app1will match/app1,/app1/,/app1/users, etc. - If you want to strip the prefix before forwarding the request to your service, you can add a middleware:
- "traefik.http.middlewares.strip-app1.stripprefix.prefixes=/app1" - "traefik.http.routers.apache.middlewares=strip-app1"This would remove
/app1from the path before sending the request to the Apache service. - If your services are serving content from subdirectories (e.g., Apache serving from
/usr/local/apache2/htdocs/app1), you might not need to strip the prefix.
Remember to restart your Docker containers after making these changes:
$ docker-compose down
$ docker-compose up -d
This configuration allows you to host multiple applications or services on the same domain, differentiated by their URL paths.
Conclusion
With this, youâre now up and running with a proxied, load-balanced, fully Dockerized reverse proxy thatâs fully HTTPS-enabled.

You installed Traefik, so now what?
Now that you have installed Traefik and run it from both the binary and using docker-compose, youâre ready to add more microservices! If you add new Docker images in the docker-compose.yml, Traefik will recognize newly added backends immediately and route the request to it without any further configuration of Traefik or restarting it.
For more configuration options, see the Traefik documentation.
Now, you might be asking, âWhat should I install behind this amazing Traefik reverse proxy?â
Well, how about you start with self-hosting NextCloud?
The options are endlessâhave fun and get more from your VPS at the same time!
A note about tutorials: We encourage our users to try out tutorials, but they aren't fully supported by our team—we can't always provide support when things go wrong. Be sure to check which OS and version it was tested with before you proceed.
If you want a fully managed experience, with dedicated support for any application you might want to run, contact us for more information.