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 aroot
user, 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 toDEBUG
for detailed output.entryPoints
: Definesweb
entry point to listen on port80
for HTTP traffic.providers
: This tells Traefik to load dynamic configuration (such as routes and services) from therules.yml
file, 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.com
toservice1
.router2
: Routes traffic requests forapache.example.com
toservice2
.
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:8082
has a weight of2
. - The Apache server at
http://127.0.0.1:8083
has 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 80
is 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 (web
for HTTP,websecure
for HTTPS).traefik.http.routers.[service].tls.certresolver
: Configures TLS with themyresolver
certificate resolver, which we’ll define in thetraefik.yml
file 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
httpChallenge
is configured to solve TLS challenges over HTTP (port 80).
- The
- providers.docker: Enables Docker as the provider for dynamic routing, but
exposedByDefault: false
ensures 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
web
entrypoint. - The
web
entrypoint is configured to redirect all traffic to thewebsecure
entrypoint using HTTPS. - The
websecure
entrypoint 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/app1
and 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/app2
and 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.com
with your actual domain name. - The
PathPrefix
rule will match any path that starts with the specified prefix. For example,/app1
will 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
/app1
from 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.