Traefik: Difference between revisions

From Leo's Notes
This page was last edited on 31 December 2021, at 22:29.
m Updated categories
No edit summary
Line 1: Line 1:
<br />
Traefik is an open source HTTP reverse proxy and load balancer written in golang. It can be integrated into various infrastructures such as Docker and Kubernetes or used as a standalone service. Traefik comes with lots of automation features such as dynamic configuration through container labels and automatic SSL certificate renewals using the ACME protocol.


==Docker==
==Docker integration==
The traefik docker backend is configured by labeling your docker containers.  
Traefik can be used as the reverse proxy for all web-related services on a Docker host. The added benefit with this approach is that new web services that are added can be automatically configured through docker labels and SSL certificates are automatically obtained provided that the DNS names already resolve.  


===Traefik v2===
Extra care is required when using Traefik and Docker since Traefik needs to have access to the Docker socket in order to see container events for its automatic configuration. Since having access to the Docker socket is pretty much equivalent to owning the Docker host, from a security stand-point, it's best to have an intermediate Docker container proxy the Docker socket so that it can only be read from but not written to. More on this set up below.
You must have separate routers for each entrypoint. Listing them as <code>entrypoints=http,https</code> doesn't work.  
 
===Setting up Traefik with Docker Compose===
Create a new 'traefik' Docker network. This network will be used by any other containers on the host that needs to be reverse proxied by Treafik.
{{Highlight
| code = # docker network create traefik
| lang = terminal
}}
Next, we will set up the Traefik docker-compose stack. Traefik should be configured to work with Docker. We'll also restrict Traefik from exposing containers unless they are explicitly labeled.  Review the [https://doc.traefik.io/traefik/providers/docker/ Traefik Docker documentation] for all the available Docker related options.
 
Included here is the socket-proxy which we'll use to restrict what Traefik can do to Docker in case it gets compromised.
{{Highlight
| code = version: '3.3'
 
services:
  traefik:
    image: traefik:latest
    restart: always
    command: --web --docker --docker.watch --docker.exposedbydefault=false --providers.docker.endpoint=tcp://socket-proxy:2375
    volumes:
      - ./config/traefik.yml:/traefik.yml
      - ./config:/config
      - /var/log/traefik:/var/log/traefik
    networks:
      - traefik
      - internal
    environment:
      - "TZ=MST7MDT,M3.2.0,M11.1.0"
    ports:
      - "80:80"
      - "443:443"
 
  # https://github.com/Tecnativa/docker-socket-proxy
  socket-proxy:
    build:
      context: ./socket-proxy
      dockerfile: Dockerfile
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      CONTAINERS: 1
    networks:
      - internal
    expose:
      - "2375"
 
networks:
  internal:
  traefik:
    name: traefik
    external: true
| lang = yaml
}}
Bring the entire stack up and when everything comes up, you're done.  
{{Highlight
{{Highlight
| code = labels:
| code = # docker-compose up -d
| lang = terminal
}}
 
=== Using Traefik with your Docker containers ===
With the the Traefik container set up, we can now create containers to take advantage of Traefik as the ingress controller for the Docker host. This can be done through just container labels. 
Containers should be labeled with the following labels.
{| class="wikitable"
!Description
!Label (example)
|-
|Enable Traefik for this container
|<code>traefik.enable=true</code>
|-
|Define the Docker network that Traefik needs to use to connect to this container
|<code>traefik.docker.network=traefik</code>
|-
|Define a new service to this container. For example, if your container is listening on port 8888, define a new Traefik service that listens on port 8888.
|<code>traefik.http.services.my-new-service.loadbalancer.server.port=8888</code>
|-
|Expose your container using the service created previously via the HTTPS entrypoint.
This will make Traefik forward HTTPS data matching your virtual host to this container.
 
SSL certificates are handled with Let's Encrypt.
|<code>traefik.http.routers.new-service-router-https.entrypoints=https</code>
<code>traefik.http.routers.new-service-router-https.rule=Host(`my-new-service.example.com`)</code>
 
<code>traefik.http.routers.new-service-router-https.service=gitlab-service</code>
 
<code>traefik.http.routers.new-service-router-https.tls=true</code>
 
<code>traefik.http.routers.new-service-router-https.tls.certresolver=letsencrypt</code>
|-
|You can also expose your container via HTTP.
Be sure that your router name is distinct.
|<code>traefik.http.routers.new-service-router.entrypoints=http</code>
 
<code>traefik.http.routers.new-service-router.rule=Host(`my-new-service.example.com`)</code>
 
<code>traefik.http.routers.new-service-router.service=gitlab-service</code>
|-
|If you want your HTTP traffic redirected to the HTTPS version, create a new middleware that redirects to the HTTPS scheme.
|<code>traefik.http.routers.new-service-router.entrypoints=http</code>
 
<code>traefik.http.routers.new-service-router.rule=Host(`my-new-service.example.com`)</code>
 
<code>traefik.http.routers.new-service-router.middlewares=new-service-redirect</code>
 
<code>traefik.http.middlewares.new-service-redirect.redirectscheme.scheme=https</code>
|}
If your container exposes multiple services, you can define multiple services and routers in your labels. Just make sure things are named uniquely.
 
Here's the configuration for one of my test Wiki containers using Traefik.
{{Highlight
| code = wiki:
    image: mediawiki:1.37
    labels:
       - traefik.enable=true
       - traefik.enable=true
       - traefik.docker.network=traefik
       - traefik.docker.network=traefik
       # service
      - traefik.http.middlewares.wiki-https-redirect.redirectscheme.scheme=https
       - traefik.http.services.gitlab-service.loadbalancer.server.port=8888
       # http
       - traefik.http.routers.wiki.entrypoints=http
      - traefik.http.routers.wiki.rule=Host(`wiki-test.example.com`)
      - traefik.http.routers.wiki.middlewares=wiki-https-redirect
       # https
       # https
       - traefik.http.routers.gitlab-https.entrypoints=https
       - traefik.http.routers.wiki-https.entrypoints=https
       - traefik.http.routers.gitlab-https.rule=Host(`gitlab.example.com`)
       - traefik.http.routers.wiki-https.rule=Host(`wiki-test.example.com`)
       - traefik.http.routers.gitlab-https.tls=true
       - traefik.http.routers.wiki-https.tls=true
       - traefik.http.routers.gitlab-https.tls.certresolver=letsencrypt
       - traefik.http.routers.wiki-https.tls.certresolver=letsencrypt
       - traefik.http.routers.gitlab-https.service=gitlab-service
       - traefik.http.routers.wiki-https.service=wiki-https
      # http
       - traefik.http.services.wiki-https.loadbalancer.server.port=8080
       - traefik.http.routers.gitlab.entrypoints=http
    networks:
      - traefik.http.routers.gitlab.rule=Host(`gitlab.example.com`)
       - traefik
      - traefik.http.routers.gitlab.service=gitlab-service
    expose:
| lang = text
       - "8080"
}}If you wish to have http redirect to the https version, create and use a redirect middleware.
    restart: always
{{Highlight
| lang = terminal
| code = # http
       - traefik.http.routers.gitlab.entrypoints=http
      - traefik.http.routers.gitlab.rule=Host(`gitlab.example.com`)
       - traefik.http.routers.gitlab.middlewares=gitlab-https-redirect
      - traefik.http.middlewares.gitlab-https-redirect.redirectscheme.scheme=https
| lang = text
}}
}}


== Tasks ==
==Tasks==


=== Reverse proxy to a server using virtual hosts ===
===Reverse proxy to a server using virtual hosts===
You can specify custom request headers by injecting a middleware. This is sometimes necessary if your DNS doesn't reflect the internal server being proxied for example. For example, to forward requests for public.example.com via an internal IP address:
You can specify custom request headers by injecting a middleware. For example, when reverse proxying HTTP traffic for a website, you may wish to have the reverse proxy provide the 'Host' header. To do this, we can add the following dynamic config.
{{Highlight
{{Highlight
| code = http:
| code = http:
Line 54: Line 160:
           - url: "http://10.1.2.200"
           - url: "http://10.1.2.200"


  middlewares:
     public:
     public:
       headers:
       headers:
Line 61: Line 168:
}}
}}
{{Navbox Linux}}
{{Navbox Linux}}
{{Navbox Web}}[[Category:WebApp]]
{{Navbox Web}}
[[Category:WebApp]]
[[Category:Linux]]
[[Category:Linux]]

Revision as of 22:29, 31 December 2021

Traefik is an open source HTTP reverse proxy and load balancer written in golang. It can be integrated into various infrastructures such as Docker and Kubernetes or used as a standalone service. Traefik comes with lots of automation features such as dynamic configuration through container labels and automatic SSL certificate renewals using the ACME protocol.

Docker integration

Traefik can be used as the reverse proxy for all web-related services on a Docker host. The added benefit with this approach is that new web services that are added can be automatically configured through docker labels and SSL certificates are automatically obtained provided that the DNS names already resolve.

Extra care is required when using Traefik and Docker since Traefik needs to have access to the Docker socket in order to see container events for its automatic configuration. Since having access to the Docker socket is pretty much equivalent to owning the Docker host, from a security stand-point, it's best to have an intermediate Docker container proxy the Docker socket so that it can only be read from but not written to. More on this set up below.

Setting up Traefik with Docker Compose

Create a new 'traefik' Docker network. This network will be used by any other containers on the host that needs to be reverse proxied by Treafik.

# docker network create traefik

Next, we will set up the Traefik docker-compose stack. Traefik should be configured to work with Docker. We'll also restrict Traefik from exposing containers unless they are explicitly labeled. Review the Traefik Docker documentation for all the available Docker related options.

Included here is the socket-proxy which we'll use to restrict what Traefik can do to Docker in case it gets compromised.

version: '3.3'

services:
  traefik:
    image: traefik:latest
    restart: always
    command: --web --docker --docker.watch --docker.exposedbydefault=false --providers.docker.endpoint=tcp://socket-proxy:2375
    volumes:
      - ./config/traefik.yml:/traefik.yml
      - ./config:/config
      - /var/log/traefik:/var/log/traefik
    networks:
      - traefik
      - internal
    environment:
      - "TZ=MST7MDT,M3.2.0,M11.1.0"
    ports:
      - "80:80"
      - "443:443"

  # https://github.com/Tecnativa/docker-socket-proxy
  socket-proxy:
    build:
      context: ./socket-proxy
      dockerfile: Dockerfile
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      CONTAINERS: 1
    networks:
      - internal
    expose:
      - "2375"

networks:
  internal:
  traefik:
    name: traefik
    external: true

Bring the entire stack up and when everything comes up, you're done.

# docker-compose up -d

Using Traefik with your Docker containers

With the the Traefik container set up, we can now create containers to take advantage of Traefik as the ingress controller for the Docker host. This can be done through just container labels. Containers should be labeled with the following labels.

Description Label (example)
Enable Traefik for this container traefik.enable=true
Define the Docker network that Traefik needs to use to connect to this container traefik.docker.network=traefik
Define a new service to this container. For example, if your container is listening on port 8888, define a new Traefik service that listens on port 8888. traefik.http.services.my-new-service.loadbalancer.server.port=8888
Expose your container using the service created previously via the HTTPS entrypoint.

This will make Traefik forward HTTPS data matching your virtual host to this container.

SSL certificates are handled with Let's Encrypt.

traefik.http.routers.new-service-router-https.entrypoints=https

traefik.http.routers.new-service-router-https.rule=Host(`my-new-service.example.com`)

traefik.http.routers.new-service-router-https.service=gitlab-service

traefik.http.routers.new-service-router-https.tls=true

traefik.http.routers.new-service-router-https.tls.certresolver=letsencrypt

You can also expose your container via HTTP.

Be sure that your router name is distinct.

traefik.http.routers.new-service-router.entrypoints=http

traefik.http.routers.new-service-router.rule=Host(`my-new-service.example.com`)

traefik.http.routers.new-service-router.service=gitlab-service

If you want your HTTP traffic redirected to the HTTPS version, create a new middleware that redirects to the HTTPS scheme. traefik.http.routers.new-service-router.entrypoints=http

traefik.http.routers.new-service-router.rule=Host(`my-new-service.example.com`)

traefik.http.routers.new-service-router.middlewares=new-service-redirect

traefik.http.middlewares.new-service-redirect.redirectscheme.scheme=https

If your container exposes multiple services, you can define multiple services and routers in your labels. Just make sure things are named uniquely.

Here's the configuration for one of my test Wiki containers using Traefik.

wiki:
    image: mediawiki:1.37
    labels:
      - traefik.enable=true
      - traefik.docker.network=traefik
      - traefik.http.middlewares.wiki-https-redirect.redirectscheme.scheme=https
      # http
      - traefik.http.routers.wiki.entrypoints=http
      - traefik.http.routers.wiki.rule=Host(`wiki-test.example.com`)
      - traefik.http.routers.wiki.middlewares=wiki-https-redirect
      # https
      - traefik.http.routers.wiki-https.entrypoints=https
      - traefik.http.routers.wiki-https.rule=Host(`wiki-test.example.com`)
      - traefik.http.routers.wiki-https.tls=true
      - traefik.http.routers.wiki-https.tls.certresolver=letsencrypt
      - traefik.http.routers.wiki-https.service=wiki-https
      - traefik.http.services.wiki-https.loadbalancer.server.port=8080
    networks:
      - traefik
    expose:
      - "8080"
    restart: always

Tasks

Reverse proxy to a server using virtual hosts

You can specify custom request headers by injecting a middleware. For example, when reverse proxying HTTP traffic for a website, you may wish to have the reverse proxy provide the 'Host' header. To do this, we can add the following dynamic config.

http:
  routers:
    public:
      rule: Host(`public.example.com`)
      service: public
      entrypoints:
        - http
      middlewares:
        - public

  services:
    public:
      loadBalancer:
        servers:
          - url: "http://10.1.2.200"

  middlewares:
    public:
      headers:
        customRequestHeaders:
          Host: "public.example.com"