Skip to content

Instantly share code, notes, and snippets.

@acidtib
Forked from ruanbekker/traefik_portainer.md
Created June 25, 2020 02:32
Show Gist options
  • Save acidtib/2fe725bfe26bcf048435aa19cce7aa9d to your computer and use it in GitHub Desktop.
Save acidtib/2fe725bfe26bcf048435aa19cce7aa9d to your computer and use it in GitHub Desktop.
Traefik with SSL + Portainer on Docker Swarm Repro

Traefik and Portainer on Docker Swarm with Letsencrypt

Reproducing a Traefik with SSL and Portainer setup on a 2 Node Docker Swarm

Install Docker:

Install Docker on both nodes with a Bootstrap Script:

$ curl https://gitlab.com/rbekker87/scripts/raw/master/setup-docker-ubuntu.sh | bash

Initialize the Swarm

Initialize Swarm on Manager (node-1):

$ docker swarm init --advertise-addr ens3
Swarm initialized: current node (jhs46c7mv0vl86v488joqazpd) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-3kgazh7s0aebjgov5tw0s85d0oz1wu4whefibiszaiuij7f7ub-3ocy5sathgputnxzpjacfypip 10.163.68.18:2377

Join Worker Node to the Swarm (node-2):

$ docker swarm join --token SWMTKN-1-3kgazh7s0aebjgov5tw0s85d0oz1wu4whefibiszaiuij7f7ub-3ocy5sathgputnxzpjacfypip 10.163.68.18:2377
This node joined a swarm as a worker.

List nodes from the Manager (node-1):

$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
jhs46c7mv0vl86v488joqazpd *   docker1             Ready               Active              Leader              18.09.7
3bzwcuokvfi7w3gitfturzw93     docker2             Ready               Active                                  18.09.7

DNS

Setup a A Record to the Manager IP:

  • meikel.rbkr.xyz -> 185.136.234.52

Setup a Wildcard Record with the value of CNAME to the previous record:

  • *.meikel.rbkr.xyz -> meikel.rbkr.xyz

Testing:

$ dig A meikel.rbkr.xyz +short
185.136.234.52

$ dig CNAME test.meikel.rbkr.xyz +short
meikel.rbkr.xyz.

Provision Traefik:

Create the compose file for treafik docker-compose.traefik.yml:

version: '3.7'
services:
  traefik:
    image: traefik:latest
    ports:
      - target: 80
        published: 80
        mode: host
      - target: 443
        published: 443
        mode: host
    command: >
      --api
      --acme
      --acme.storage=/certs/acme.json
      --acme.entryPoint=https
      --acme.httpChallenge.entryPoint=http
      --acme.onHostRule=true
      --acme.onDemand=false
      --acme.acmelogging=true
      --acme.email=${EMAIL:-root@localhost}
      --docker
      --docker.swarmMode
      --docker.domain=${DOMAIN:-localhost}
      --docker.watch
      --defaultentrypoints=http,https
      --entrypoints='Name:http Address::80'
      --entrypoints='Name:https Address::443 TLS'
      --logLevel=INFO
      --accessLog
      --metrics
      --metrics.prometheus
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - traefik_certs:/certs
    configs:
      - source: traefik_htpasswd
        target: /etc/htpasswd
    networks:
      - public
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
      labels:
        - "traefik.docker.network=public"
        - "traefik.port=8080"
        - "traefik.backend=traefik"
        - "traefik.enable=true"
        - "traefik.frontend.rule=Host:traefik.${DOMAIN:-localhost}"
        - "traefik.frontend.auth.basic.usersFile=/etc/htpasswd"
        - "traefik.frontend.headers.SSLRedirect=true"
        - "traefik.frontend.entryPoints=http,https"

configs:
  traefik_htpasswd:
    file: ./htpasswd

networks:
  public:
    driver: overlay
    name: public

volumes:
  traefik_certs: {}

Install dependency to create basic auth file:

sudo apt install apache2-utils -y

Create admin/admin credentials:

$ htpasswd -c htpasswd admin
New password:
Re-type new password:
Adding password for user admin

Set the domain and reachable email as environment variable:

$ export DOMAIN=meikel.rbkr.xyz
$ export EMAIL=your@email-domain.com

Deploy the traefik stack:

$ docker stack deploy -c docker-compose.traefik.yml proxy
Creating network public
Creating config proxy_traefik_htpasswd
Creating service proxy_traefik

List the service:

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
c4cm18zspces        proxy_traefik       replicated          1/1                 traefik:latest

Access the Traefik UI on https://traefik.meikel.rbkr.xyz

image

Portainer

Create the compose docker-compose.portainer.yml

version: '3.7'

services:
  agent:
    image: portainer/agent
    environment:
      AGENT_CLUSTER_ADDR: tasks.agent
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/docker/volumes:/var/lib/docker/volumes
    networks:
      - private
    deploy:
      mode: global
      placement:
        constraints:
          - node.platform.os == linux

  portainer:
    image: portainer/portainer
    command: -H tcp://tasks.agent:9001 --tlsskipverify
    volumes:
      - portainer-data:/data
    networks:
      - private
      - public
    deploy:
      placement:
        constraints:
          - node.role == manager
      labels:
        - traefik.frontend.rule=Host:portainer.${DOMAIN}
        - traefik.enable=true
        - traefik.port=9000
        - traefik.tags=public
        - traefik.docker.network=public
        - traefik.redirectorservice.frontend.entryPoints=http
        - traefik.redirectorservice.frontend.redirect.entryPoint=https
        - traefik.webservice.frontend.entryPoints=https

networks:
  private:
    driver: overlay
    name: private
  public:
    external: true

volumes:
  portainer-data: {}

Make sure the DOMAIN environment variable is still set:

$ env | grep DOMAIN
DOMAIN=meikel.rbkr.xyz

Deploy the stack:

$ docker stack deploy -c docker-compose.portainer.yml portainer
Creating network private
Creating service portainer_agent
Creating service portainer_portainer

Check if all the containers has checked in for the respective services:

$ docker service ls
ID                  NAME                  MODE                REPLICAS            IMAGE                        PORTS
wwu7alr6ysw0        portainer_agent       global              2/2                 portainer/agent:latest
09flw7vt80r7        portainer_portainer   replicated          1/1                 portainer/portainer:latest
c4cm18zspces        proxy_traefik         replicated          1/1                 traefik:latest

Portainer should show up on the Traefik UI as a Frontend and Backend:

image

Accessing Portainer on https://portainer.meikel.rbkr.xyz:

image

After setting up the user:

image

And having a look at the services:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment