Docker stack file :: Traefik - API enabled, behind basic auth and SSL

traefik_stack.yml

This basically is a setup which redirects http to https by default. ACME enabled. The API is enabled and accessible only after basic authentication and from predefined source IP(-range)s.

version: "3.7"

volumes:
  sslcerts:
    driver: local
  traefik:
    driver: local

networks:
  traefik:
    driver: overlay

configs:
  traefik_toml:
    external: true

services:
  proxy:
    image: traefik
    deploy:
      replicas: 1
      labels:
      - traefik.enable=true
      - traefik.docker.network=traefik_traefik
      - traefik.frontend.rule=Host:traefik.virtualix.nl
      - traefik.backend.loadbalancer.stickiness=true
      - traefik.frontend.passHostHeader=true
      - traefik.port=8080
      placement:
        constraints:
        - node.role == manager
        - node.hostname == myfirstdocker.virtualix.nl
      restart_policy:
        condition: on-failure
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock
    - sslcerts:/ssl
    networks:
    - traefik
    ports:
    - target: 80
      protocol: tcp
      published: 80
      mode: host #to pass client ip to containers
    - target: 443
      protocol: tcp
      published: 443
      mode: host #to pass client ip to containers
    - target: 8080
      protocol: tcp
      published: 8080
      mode: host #to pass client ip to traefik for API whitelist
    configs:
    - source: traefik_toml
      target: /etc/traefik/traefik.toml
      mode: 444

traefik.toml

I've been trying to wrap my head around this one for quite some time. At first i tried to make this work via the Docker labels in the stack file, but after a while i gave up. Everything between immediate crashing traefik containers to looping API requests and >30 seconds response times has been crossing my path, until i moved to using the toml file.

The basic auth pops up before the whitelist kicks in. I'd like to see this the other way around, but haven't had time to dive into this a bit deeper.

################################################################
# Global configuration
################################################################

# Enable debug mode
#
# Optional
# Default: false
#
# debug = true

# Log level
#
# Optional
# Default: "ERROR"
#
# logLevel = "DEBUG"

# Entrypoints to be used by frontends that do not specify any entrypoint.
# Each frontend can specify its own entrypoints.
#
# Optional
# Default: ["http"]
#
defaultEntryPoints = ["http", "https"]

################################################################
# Entrypoints configuration
################################################################

# Entrypoints definition
#
# Optional
# Default:
[entryPoints]
  [entryPoints.http]
    address = ":80"
    compress = true
    whitelistTrustProxy = ["10.255.0.2",]
    [entryPoints.http.redirect]
      entryPoint = "https"
  [entryPoints.https]
    address = ":443"
    compress = true
    whitelistTrustProxy = ["10.255.0.2",]
    [entryPoints.https.tls]
[entryPoints.traefik]
  address = ":8080"
  [entryPoints.traefik.whiteList]
    useXForwardedFor = true
    whitelistTrustProxy = ["10.255.0.2",]
    sourceRange = ["192.168.1.0/24",]
  [entryPoints.traefik.auth]
    [entryPoints.traefik.auth.basic]
      users = ["<user>:<bcrypt_hash_created_with_htpasswd",
               "test:$apr1$G2JtG6vr$lP7849rQU/O1WeTqLHsJo1"] 
               # example: username/password is test/test


################################################################
# Traefik logs configuration
################################################################

# Traefik logs
# Enabled by default and log to stdout
#
# Optional
#
[traefikLog]

# Sets the filepath for the traefik log. If not specified, stdout will be used.
# Intermediate directories are created if necessary.
#
# Optional
# Default: os.Stdout
#
# filePath = "log/traefik.log"

# Format is either "json" or "common".
#
# Optional
# Default: "common"
#
format = "common"

################################################################
# Access logs configuration
################################################################

# Enable access logs
# By default it will write to stdout and produce logs in the textual
# Common Log Format (CLF), extended with additional fields.
#
# Optional
#
[accessLog]

# Sets the file path for the access log. If not specified, stdout will be used.
# Intermediate directories are created if necessary.
#
# Optional
# Default: os.Stdout
#
# filePath = "/path/to/log/log.txt"

# Format is either "json" or "common".
#
# Optional
# Default: "common"
#
format = "common"

################################################################
# ACME configuration
################################################################

[acme]
email = "thisaddressdoesnotexist@virtualix.nl"
storage = "/ssl/acme.json"
entryPoint = "https"
onHostRule = true
acmeLogging = true
onDemand = false
#caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
[acme.httpChallenge]
  entryPoint = "http"


################################################################
# API and dashboard configuration
################################################################

# Enable API and dashboard
[api]

  # Name of the related entry point
  #
  # Optional
  # Default: "traefik"
  #
entryPoint = "traefik"

  # Enabled Dashboard
  #
  # Optional
  # Default: true
  #
dashboard = true

  [api.statistics]
    recentErrors = 50

################################################################
# Ping configuration
################################################################

# Enable ping
[ping]

  # Name of the related entry point
  #
  # Optional
  # Default: "traefik"
  #
  # entryPoint = "traefik"

################################################################
# Docker configuration backend
################################################################

# Enable Docker configuration backend
[docker]

# Docker server endpoint. Can be a tcp or a unix socket endpoint.
#
# Required
# Default: "unix:///var/run/docker.sock"
#
# endpoint = "tcp://10.10.10.10:2375"

watch = true
swarmmode = true

# Default domain used.
# Can be overridden by setting the "traefik.domain" label on a container.
#
# Optional
# Default: ""
#
domain = "virtualix.nl"

# Expose containers by default in traefik
#
# Optional
# Default: true
#
exposedByDefault = false

I've put it in a swarm config, to use it in the container:

docker config create traefik_toml ./traefik.toml

And the deploy

docker stack deploy -c ./traefik_stack.yml traefik