Docker containers allow for quick and easy deployment of services and applications. However, as the number of deployed applications grows, and when multiple instances of a single service are required (especially relevant for microservices architecture), we must distribute network traffic. For this purpose, you can use Traefik, a modern open-source reverse proxy server designed specifically to work with Docker containers. In this guide, we will configure Traefik as a reverse proxy for several applications running in Docker containers.
To use Traefik, the following are required:
A cloud server or a virtual machine with any pre-installed Linux distribution. We will be using Ubuntu 22.04.
Docker and Docker Compose installed. See our installation guide.
You can also use a pre-configured image with Docker. To do this, go to the Cloud servers section in your Hostman control panel, click Create server, and select Docker in the Marketplace tab.
In this guide, we will use two containers with the Nginx web server. Each container will display a specific message when accessed by its domain name. We will cover the creation of these containers further below.
Let's start by setting up Traefik:
Create a directory for storing configuration files and navigate into it:
mkdir ~/test-traefik && cd ~/test-traefik
Inside the project’s root directory, create three subdirectories: one for the Traefik configuration file and two others for the configuration files of the applications that will use Traefik:
mkdir traefik app1 app2
Create the main configuration file for Traefik named traefik.yml
in the previously created traefik directory:
nano traefik/traefik.yml
Insert the following code into the file:
entryPoints:
web:
address: ":80"
providers:
docker:
exposedByDefault: false
api:
dashboard: true
insecure: true
Let’s look closer at the parameters.
entryPoints
define the ports and protocols through which Traefik will accept requests. They specify on which port and IP address the service will listen for traffic.
web
— A unique name for the entry point, which can be referenced in routes. In this example, we use the name web.
address: ":80"
— Indicates that the entry point will listen for traffic on port 80 (HTTP) across all available network interfaces on the system.
providers
specify the sources of information about which routes and services should be used (e.g., Docker, Kubernetes, files, etc.).
docker
— Enables and uses the Docker provider. When using the Docker provider, Traefik automatically detects running containers and routes traffic to them.
exposedByDefault: false
— Disables automatic exposure of all Docker containers as services. This makes the configuration more secure: only containers explicitly enabled through labels (traefik.enable=true
) will be routed (i.e., will accept and handle traffic).
api
section contains settings for the administrative API and Traefik's built-in monitoring web interface.
dashboard: true
— Enables Traefik's web-based monitoring dashboard, which allows you to track active routes, entry points, and services. The dashboard is not a mandatory component and can be disabled by setting this to false.
insecure: true
— Allows access to the monitoring dashboard over HTTP. This is convenient for testing and getting familiar with the system but is unsafe to use in a production environment. To ensure secure access to the dashboard via HTTPS, set this to false.
Now, let's prepare the configuration files for the applications that will use Traefik as a reverse proxy. We will deploy two Nginx containers, each displaying a specific message when accessed via its address.
nano app1/default.conf
Contents:
server {
listen 80;
server_name app1.test.com;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
For the server name, we specify the local domain app1.test.com
. You can use either an IP address or a domain name. If you don't have a global domain name, you can use any name that is accessible only at the local level. Additionally, you will need to add the chosen domain to the /etc/hosts
file (explained later).
Next, create the html
directory where the index.html
file for the first application will be stored:
mkdir app1/html
Write the message "Welcome to App 1" into the index.html
file using input redirection:
echo "<h1>Welcome to App 1</h1>" > app1/html/index.html
nano app2/default.conf
Contents:
server {
listen 80;
server_name app2.test.com;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
Set the local domain name for the second application as app2.test.com
.
Create the html
directory for the second application:
mkdir app2/html
Write the message "Welcome to App 2" into the index.html
file:
echo "<h1>Welcome to App 2</h1>" > app2/html/index.html
hosts
file using any text editor:nano /etc/hosts
Add the following entries:
127.0.0.1 app1.test.com
127.0.0.1 app2.test.com
The final project structure should look like this:
test-traefik/
├── app1/
│ ├── default.conf
│ └── html/
│ └── index.html
├── app2/
│ ├── default.conf
│ └── html/
│ └── index.html
└── traefik/
└── traefik.yml
Now let's proceed with launching Traefik and the applications. To do this, create a docker-compose.yml
file in the root project directory (test-traefik
):
nano docker-compose.yml
Insert the following configuration:
version: "3.9"
services:
traefik:
image: traefik:v2.10
container_name: traefik
restart: always
command:
- "--configFile=/etc/traefik/traefik.yml"
ports:
- "80:80"
- "8080:8080"
volumes:
- "./traefik/traefik.yml:/etc/traefik/traefik.yml"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
app1:
image: nginx:1.26-alpine
container_name: nginx-app1
restart: always
volumes:
- "./app1/default.conf:/etc/nginx/conf.d/default.conf"
- "./app1/html:/usr/share/nginx/html"
labels:
- "traefik.enable=true"
- "traefik.http.routers.app1.rule=Host(`app1.test.com`)"
- "traefik.http.services.app1.loadbalancer.server.port=80"
app2:
image: nginx:1.26-alpine
container_name: nginx-app2
restart: always
volumes:
- "./app2/default.conf:/etc/nginx/conf.d/default.conf"
- "./app2/html:/usr/share/nginx/html"
labels:
- "traefik.enable=true"
- "traefik.http.routers.app2.rule=Host(`app2.test.com`)"
- "traefik.http.services.app2.loadbalancer.server.port=80"
Use the following command to launch the containers:
docker compose up -d
If Docker Compose was installed using the docker-compose-plugin
package, the command to launch the containers will be as follows:
docker-compose up -d
Check the status of the running containers using the command:
docker ps
All containers should have the status Up
.
Let's verify whether the running containers with Nginx services can handle the traffic. To do this, send a request to the domain names using the curl
utility.
For the first application:
curl -i app1.test.com
For the second application:
curl -i app2.test.com
As you can see, both services returned the previously specified messages.
Next, let's check the Traefik monitoring dashboard. Open a browser and go to the server's IP address on port 8080:
In the Routers section, you will see the previously defined routes app1.test.com
and app2.test.com
.
Today, we explored Traefik's functionality using two Nginx services as an example. With Traefik, you can easily proxy applications running in Docker containers.