Docker Swarm Mode and Distributed Traefik proxy with HTTPS

Intro

  • Handle connections.
  • Expose specific services and applications based on their domain names.
  • Handle multiple domains (if you need to). Similar to “virtual hosts”.
  • Handle HTTPS.
  • Acquire (generate) HTTPS certificates automatically (including renewals) with Let’s Encrypt.
  • Add HTTP Basic Auth for any service that you need to protect and doesn’t have its own security, etc.
  • Get all its configurations automatically from Docker labels set in your stacks (you don’t need to update configuration files).

Background

Overview

Redundancy

User Interface

How it works

About Consul

  • Store the Traefik configurations in a distributed manner.
  • Make sure configurations are synchronized among Consul services across the cluster.
  • Store HTTPS certificates for Traefik.

Set up environment variables

  • Connect via SSH to a manager node in your cluster (you might have only one node) that will have the Traefik service.
  • Create a network that will be shared with Traefik and the containers that should be accessible from the outside, with:
docker network create --driver=overlay traefik-public
  • Create an environment variable with your email, to be used for the generation of Let’s Encrypt certificates:
export EMAIL=admin@example.com
  • Create an environment variable with the domain you want to use for the Traefik UI (user interface) and the Consul UI of the host, e.g.:
export DOMAIN=sys.example.com
  • Create an environment variable with a username (you will use it for the HTTP Basic Auth for Traefik and Consul UIs), for example:
export USERNAME=admin
  • Create an environment variable with the password, e.g.:
export PASSWORD=changethis
  • Use openssl to generate the "hashed" version of the password and store it in an environment variable:
export HASHED_PASSWORD=$(openssl passwd -apr1 $PASSWORD)
  • You can check the contents with:
echo $HASHED_PASSWORD
$apr1$89eqM5Ro$CxaFELthUKV21DpI3UTQO.
  • Create an environment variable with the number of replicas for the Consul service (if you don’t set it, by default it will be 3):
export CONSUL_REPLICAS=3
export CONSUL_REPLICAS=0
  • Create an environment variable with the number of replicas for the Traefik service (if you don’t set it, by default it will be 3):
export TRAEFIK_REPLICAS=3
export TRAEFIK_REPLICAS=$(docker node ls -q | wc -l)
export TRAEFIK_REPLICAS=1

Create the Docker Compose file

  • Download the file traefik.yml:
curl -L dockerswarm.rocks/traefik.yml -o traefik.yml
  • …or create it manually, for example, using nano:
nano traefik.yml
  • And copy the contents inside:
version: '3.3'services:
consul-leader:
image: consul
command: agent -server -client=0.0.0.0 -bootstrap -ui
volumes:
- consul-data-leader:/consul/data
environment:
- CONSUL_BIND_INTERFACE=eth0
- 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}'
networks:
- default
- traefik-public
deploy:
labels:
- traefik.frontend.rule=Host:consul.${DOMAIN}
- traefik.enable=true
- traefik.port=8500
- traefik.tags=${TRAEFIK_PUBLIC_TAG:-traefik-public}
- traefik.docker.network=traefik-public
# Traefik service that listens to HTTP
- traefik.redirectorservice.frontend.entryPoints=http
- traefik.redirectorservice.frontend.redirect.entryPoint=https
# Traefik service that listens to HTTPS
- traefik.webservice.frontend.entryPoints=https
- traefik.frontend.auth.basic.users=${USERNAME}:${HASHED_PASSWORD}
consul-replica:
image: consul
command: agent -server -client=0.0.0.0 -retry-join="consul-leader"
volumes:
- consul-data-replica:/consul/data
environment:
- CONSUL_BIND_INTERFACE=eth0
- 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}'
networks:
- default
- traefik-public
deploy:
replicas: ${CONSUL_REPLICAS:-3}
placement:
preferences:
- spread: node.id
traefik:
image: traefik:v1.7
ports:
- 80:80
- 443:443
deploy:
replicas: ${TRAEFIK_REPLICAS:-3}
placement:
constraints:
- node.role == manager
preferences:
- spread: node.id
labels:
- traefik.frontend.rule=Host:traefik.${DOMAIN}
- traefik.enable=true
- traefik.port=8080
- traefik.tags=traefik-public
- traefik.docker.network=traefik-public
# Traefik service that listens to HTTP
- traefik.redirectorservice.frontend.entryPoints=http
- traefik.redirectorservice.frontend.redirect.entryPoint=https
# Traefik service that listens to HTTPS
- traefik.webservice.frontend.entryPoints=https
- traefik.frontend.auth.basic.users=${USERNAME}:${HASHED_PASSWORD}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: >
--docker
--docker.swarmmode
--docker.watch
--docker.exposedbydefault=false
--constraints=tag==traefik-public
--entrypoints='Name:http Address::80'
--entrypoints='Name:https Address::443 TLS'
--consul
--consul.endpoint="consul-leader:8500"
--acme
--acme.email=${EMAIL}
--acme.storage="traefik/acme/account"
--acme.entryPoint=https
--acme.httpChallenge.entryPoint=http
--acme.onhostrule=true
--acme.acmelogging=true
--logLevel=INFO
--accessLog
--api
networks:
- default
- traefik-public
depends_on:
- consul-leader

volumes:
consul-data-leader:
consul-data-replica:
networks:
traefik-public:
external: true

Deploy it

docker stack deploy -c traefik.yml traefik-consul

Check it

  • Check if the stack was deployed with:
docker stack ps traefik-consul
ID             NAME                              IMAGE           NODE                DESIRED STATE   CURRENT STATE          ERROR   PORT
xvyasdfh56hg traefik-consul_traefik.1 traefik:v1.7 dog.example.com Running Running 1 minute ago
j3ahasdfe0mr traefik-consul_consul-replica.1 consul:latest cat.example.com Running Running 1 minute ago
bfdasdfasr92 traefik-consul_consul-leader.1 consul:latest cat.example.com Running Running 1 minute ago
ofvasdfqtsi6 traefik-consul_traefik.2 traefik:v1.7 snake.example.com Running Running 1 minute ago
tybasdfqdutt traefik-consul_consul-replica.2 consul:latest dog.example.com Running Running 1 minute ago
3ejasdfq2l3g traefik-consul_traefik.3 traefik:v1.7 cat.example.com Running Running 1 minute ago
w0oasdfqsv33 traefik-consul_consul-replica.3 consul:latest snake.example.com Running Running 1 minute ago
  • You can check the Traefik logs with:
docker service logs traefik-consul_traefik

Check the user interfaces

Updating

What’s next

Technical Details

About me

--

--

--

Creator of FastAPI and Typer. Dev at Exposion AI. APIs, Deep Learning/Machine Learning, full-stack distributed systems, SQL/NoSQL, Python, Docker, JS, TS, etc.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Best DirectAdmin VPS Hostings

You might not need WebReports: So when should you use WebReports

Patching windows servers through Ansible

Rachel Andrew for Barcelona Code School

Deploy Scalable Php application in kubernetes cluster with Mysql database integration with Nginx…

How to Run Cypress Tests in Parallel | BrowserStack

Why should you integrate software? | LiveAgent

Mobile — devices, operating systems and stores

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sebastián Ramírez

Sebastián Ramírez

Creator of FastAPI and Typer. Dev at Exposion AI. APIs, Deep Learning/Machine Learning, full-stack distributed systems, SQL/NoSQL, Python, Docker, JS, TS, etc.

More from Medium

Part-of-Speech Tag a String, Filter to Adjectives in Go

Storing and processing real-time time-series data with Influx DB

Migrate your local database to Docker container: Step-by-Step guide.

Build and monitor your FastAPI microservice with Docker, Prometheus and Grafana. [Part-1]