Post

Traefik reverse proxy

How to setup traefik as a reverseproxy with letsencrypt.

Traefik reverse proxy

Context

I have previously worked with nginx proxy manager and i liked it. However i wanted SSO auth as middleware and that was to complicated with nginx proxy manager. Hence i shiftet to Traefik. Which might be a steep learning curve, however when you get the grip on it. It is quite easy.

The first thing to have in mind is labeling and the difference between static and dynamic files. The way i do it, is that i have Traefik running on a network, where if i put the container on that network i intent to expose it to Traefik.

Also i have it working with letsencrypt and cloudflare as dns provider.

Setup

First make sure to have docker installed. guide for installing docker and docker compose: Install guide

I like to have a directory specific for docker like /etc/docker/

  1. create a working dir for Traefik.

  2. create a compose file for Traefik:
    1
    
    touch docker-compose.yml
    
  3. Edit the file (i use nano in termial or vscode) do NOT run the container yet.

    Compose Stack:

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
45
46
47
48
49
50
51
52
53
54
networks:
  traefik-proxy:
    name: traefik-proxy

services:
  traefik:
    image: traefik:v3.6.5
    container_name: traefik
    restart: unless-stopped
    command:
     - --providers.file.filename=/traefik.yml
     - --log.level=debug
     - --certificatesresolvers.le.acme.tlschallenge=true

    environment:
      - TZ=Europe/Copenhagen # Change this to your timezone
      - CF_DNS_API_TOKEN=<cloudflare token>
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./acme.json:/acme.json
      - ./traefik.yml:/traefik.yml
      - ./dynamic:/dynamic

    networks:
      - traefik-proxy
    labels:
      - traefik.enable=true

      # Route dashboard ONLY through traefik.home.labify.dk
      - traefik.http.routers.traefik.rule=Host(`<sub.domain.local>`)
      - traefik.http.routers.traefik.entrypoints=websecure
      - traefik.http.routers.traefik.tls.certResolver=le

      # Enable Traefik internal API as a service
      - traefik.http.routers.traefik.service=api@internal

##Test container## 
  hello-world:
    image: kerwood/hello-world:latest
    container_name: hello-world
    restart: unless-stopped
    expose:
      - 3000
    networks:
      - traefik-proxy
    labels:
      - traefik.enable=true ##For Traefik to be able to read the labels
      - traefik.http.services.hello.loadbalancer.server.port=3000 ## port that the service runs on
      - traefik.http.routers.hello.rule=Host(`sub.domain.local`) ## domain to test
      - traefik.http.routers.hello.tls.certResolver=le ## which certificate resolver to use, see traefik.yml for resolvers
      - traefik.http.routers.hello.entrypoints=websecure ## entrypoint, see traefik.yml for explanation (443)

As we can see in the stack, there are som directories and files we need to make.

  1. first we need to create acme.json, this is importent as Traefik tries to create a directory and not a file ( my own experience, which is odd)

Traefik will complain about permissions if these are wrong.

1
2
touch acme.json
chmod 600 acme.json

Nothing more is needed for the acme.json file.

  1. Now we need to create the traefik.yml file
1
touch traefik.yml

edit the file so it contains:

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
api:
  dashboard: true # Optional can be disabled
  insecure: false # Optional can be disabled
  debug: true # Optional can be Enabled if needed for troubleshooting 

entryPoints:
  web:  ##namig is important here, since this name is used in the labels
    address: ":80"
  # Optional if you want to redirect all HTTP to HTTPS
    http:
      redirections:
        entryPoint:
          to: websecure
  websecure: ##namig is important here, since this name is used in the labels
    address: ":443"

#serversTransport:
#  insecureSkipVerify: true

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    watch: true
  #  network: proxy # Optional; Only use the "proxy" Docker network, even if containers are on multiple networks.
  file:
    directory: /dynamic
    watch: true

certificatesresolvers:
  le: ##namig is important here, since this name is used in the labels
    acme:
      email: <valid email>
      storage: /acme.json
      caServer: https://acme-v02.api.letsencrypt.org/directory # prod (default) they have a staging url also. 
      dnsChallenge:
        provider: cloudflare
        delayBeforeCheck: 0
        resolvers:
        - "1.1.1.1:53"
        - "8.8.8.8:53"

nothing more needs to be done with that file

  1. create the dynamic dir, this is used for hosts that are not docker (ip:port redirects)
    1
    2
    
    mkdir dynamic
    cd dynamic
    

now create the redirects you need example file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
http:
  routers:
    <name>:
      rule: "Host(`sub.domain.local)"
      service: gitea
      entryPoints:
        - websecure # or web if using HTTP
      tls:  # optional, if using HTTPS
        certResolver: le ## name from traefik.yml

  services:
    <name>: #must be same as above
      loadBalancer:
        servers:
          - url: "http://ip:port"
  1. Remeber to correct your dns to point to the sub.domain.local you have used. I have used prod.domain.local or test.domain.local and then subsub domains for each container. point the “main” domain to the ip that traefik runs on. like:

*.prod.domain.local IP

this is supported by most, if they are not consider changing your dns resolver. Hint 8.8.8.8 as resolver will work as long as your personal resolver (cloudflare or similar) points *.prod.domain.local to your wan.

Test

Now the exiting part begins.

navigate to traefik dir. run:

1
docker compose up -d

you should be able to visit your traefik dashboard and hello server know. if not run:

1
docker logs traefik

Correct mistakes.

Considerrations:

Have your dashboard behind middleware see oauth2proxy or smallsteps mtls (comming soon)

This post is licensed under CC BY 4.0 by the author.