Using Traefik in Docker as a Reverse Proxy for Docker Containers
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.
Prerequisites Copy link
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.
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.
Configuring Traefik Copy link
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.ymlin the previously created traefik directory:
nano traefik/traefik.ymlInsert 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.
entryPointsdefine 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.
-
providersspecify 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).
-
- The
apisection 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.
-
Preparing Configuration Files for Applications Copy link
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.
- Create the Nginx configuration file for the first application:
nano app1/default.confContents:
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/htmlWrite 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- Repeat the same steps for the second application, but use values specific to the second app:
nano app2/default.confContents:
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/htmlWrite the message "Welcome to App 2" into the index.html file:
echo "<h1>Welcome to App 2</h1>" > app2/html/index.html- Since we used local domain names, they need to be registered in the system. To do this, open the
hostsfile using any text editor:
nano /etc/hostsAdd 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

Launching Traefik and Applications Copy link
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.ymlInsert 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 -dCheck 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.

Conclusion Copy link
Today, we explored Traefik's functionality using two Nginx services as an example. With Traefik, you can easily proxy applications running in Docker containers.