Traefik 2.0 With Docker Compose

In this article I will discuss using Traefik in conjunction with docker-compose to set up a multi-domain server, both with and without HTTPS support.

Use-Case

Traefik is a reverse proxy and load balancer that makes the following things easy to set up:

  • Multiple domains/subdomains served from one server, serving different applications
  • Balancing a load across multiple app servers
  • Automatic SSL/HTTPS with LetsEncrypt or other certificate authorities

I use Traefik both on my personal site, serving the following domains, among others:

However, I also use Traefik on my personal NAS. By using a PiHole as a DNS server on my LAN, I can create custom domains only visible in my network, which then are routed to the same server (my NAS). Traefik on the NAS automatically routes the different subdomains to the correct docker containers, serving several apps:

  • Heimdall (a web app dashboard)
  • Jellyfin (a media server)
  • Bookstack (a Markdown document app)
  • VS Code Server (a web IDE)
  • A static site I use for journal entries (served by hugo)
  • WikiJS (a wiki site for my personal documentation)
  • Whoami (just to test if the reverse proxy is working)

Configuration

To my knowledge, there are two main ways to configure a server running Traefik:

  1. Install Traefik on the bare-metal server, and configure it using the TOML files as shown here
  2. Use docker-compose, and configure Traefik through the docker-compose.yml. The advantage of this is the applications can be configured in the same place as the reverse proxy, and various advantages like auto-discovery of new docker-containers allowing for easily expanding the number of apps run on a server.

For simplicity, I will go over option (2). I will start with a simple HTTP-only setup like I use on my NAS, and then expand on that with an HTTPS setup which is suitable for serving applications on the open web.

HTTP-only

I have a pihole on my network, and on my router I have set the LAN DNS to the pihole’s IP. Then, in the pihole DNS settings, I have added the following entries. Note even if you don’t set up a dedicated DNS server, this may also be done by editing the Hosts file on your OS:

Domain IP
bookstack.nas.lan 192.168.1.111
heimdall.nas.lan 192.168.1.111
code.nas.lan 192.168.1.111
jellyfin.nas.lan 192.168.1.111
journal.nas.lan 192.168.1.111
wiki.nas.lan 192.168.1.111
whoami.nas.lan 192.168.1.111

Where 192.168.1.111 is the local IP of the NAS (modified here for demonstration purposes).

Once that is set up, we can start to configure the docker containers running on the NAS for all of the application containers, and for Traefik. I have a folder set up for each app, as follows:

1
2
3
4
5
6
7
8
.
├── bookstack
├── heimdall
├── jellyfin
├── journal
├── traefik
├── vscode
└── wiki

In ./traefik, I create a docker-compose.yml with the following contents and run docker-compose up -d:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
version: "3.3"

services:
traefiik:
image: traefik:v2.0
container_name: "traefik"
networks:
- discovery
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.network=discovery"
- "--log.level=DEBUG"
- "--entryPoints.web.address=:80"
ports:
- "80:80"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
restart: unless-stopped

whoami:
image: "containous/whoami"
container_name: "simple-service"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.nas.lan`)"
- "traefik.http.routers.whoami.entrypoints=web"
- "traefik.docker.network=discovery"
networks:
- discovery
restart: unless-stopped

networks:
discovery:
external: true

At this point, you should be able to test that the reverse proxy is working by navigating to whoami.nas.lan/, since we included that small app in this main docker-compose.yml file.

At this point, you can add subdomains and apps however you want, and the only thing to note is to include the traefik labels, and the “discovery” external network, as shown in the example below of my heimdall configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
version: "3.3"
services:
heimdall:
image: ghcr.io/linuxserver/heimdall
container_name: heimdall
environment:
- PUID=1000
- PGID=1000
- TZ=US/Eastern
volumes:
- /home/user/heimdall/config:/config
ports:
- 10000:80
restart: unless-stopped
networks:
- discovery
labels:
- "traefik.enable=true"
- "traefik.http.routers.heimdall.rule=Host(`heimdall.nas.lan`)"
- "traefik.http.routers.heimdall.entrypoints=web"
- "traefik.docker.network=discovery"

networks:
discovery:
external: true

Traefik should automatically discover new containers with these labels as they are spun up, and it will also find the right server port to redirect the specified subdomain.

HTTPS

There are some differences in configuration to get this to work with HTTPS, though the main idea is fundamentally the same. Modify the ./traefik/docker-compose.yml to have the following contents:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
version: "3.3"

services:
traefiik:
image: traefik:v2.0
container_name: "traefik"
networks:
- discovery
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.network=discovery"
- "--log.level=DEBUG"
- "--entryPoints.web.address=:80"
- "--entryPoints.web-secure.address=:443"
- "--certificatesResolvers.le.acme.tlsChallenge=true"
- "--certificatesResolvers.le.acme.email=your@email.com"
- "--certificatesResolvers.le.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "8080:8080"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./letsencrypt:/letsencrypt"
restart: unless-stopped

whoami:
image: "containous/whoami"
container_name: "simple-service"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.domain.com`)"
- "traefik.http.routers.whoami.entrypoints=web-secure"
- "traefik.docker.network=discovery"
- "traefik.http.routers.whoami.tls.certresolver=le"
networks:
- discovery
restart: unless-stopped

networks:
discovery:
external: true

Then, your application docker-compose.yml files will look something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
version: "3.3"

services:
code-server:
container_name: vscode
image: linuxserver/code-server
environment:
- PUID=1000
- PGID=1000
- TZ=America/Eastern
- PASSWORD=passwordhere
- SUDO_PASSWORD=sudopasswordhere
volumes:
- ./vscode-config:/config
ports:
- 9003:8443
restart: unless-stopped
networks:
- discovery
labels:
- "traefik.enable=true"
- "traefik.http.routers.vscode.rule=Host(`code.domain.com`)"
- "traefik.http.routers.vscode.entrypoints=web-secure"
- "traefik.docker.network=discovery"
- "traefik.http.routers.vscode.tls.certresolver=le"
- "traefik.http.services.vscode.loadbalancer.server.port=8443"

networks:
discovery:
external: true

Note that there is a way with Traefik to turn on HTTP->HTTPS redirecting, though not covered here yet.

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×