[自分用メモ][container][docker]reverse proxyとしてTraefikを使用し、docker環境でLet’s Encryptを使用する。

AIX、UNIX、LinuxContainer

はじめに

docker環境で、HTTPS対応のリバースプロキシ環境を利用する場合、いくつか選択肢があると思います。

自分は今まで以下のNginxを使用しLet’s EncryptによるHTTPSプロキシを作るというものを利用していました。

JrCs/docker-letsencrypt-nginx-proxy-companion: LetsEncrypt companion container for nginx-proxy

しかし、最近はk8s (kubernetes)などが流行していることもあり、そちらでよく利用されるTraefikでも、リバースプロキシとしての機能はもちろん、Let’s Encrypt機能も使えるということを知ってから、こちらを利用してみることにしました。

この記事執筆時点ではv1系での設定になります。

Traefik Labs: Say Goodbye to Connectivity Chaos
Reimagine your application connectivity and API management with Traefik's unmatched approach to cloud native.
Traefik Proxy Documentation - Traefik
Traefik Proxy, an open source Edge Router, auto-discovers configurations and supports major orchestrators, like Kubernet...

Traefikを利用して、Docker環境にLet’s Encryptを使用する方法については、公式ドキュメントでも項目が用意してあります。

https://docs.traefik.io/user-guide/docker-and-lets-encrypt/

Traefikの良いところは、Traefikが利用するネットワークに、HTTPSでリバースプロキシしてもらいたいcontainerを所属させておけば、再起動しなくても自動的にリバースプロキシ配下に組み込んでくれる点にあります。

containerがスケールしても、自動的にリバースプロキシに組み込んでくれるので、手がかからなくて良いです。また、振り分けのルールも柔軟に設定できる点や、TraefikにUIが用意されているため、簡易的にではありますが、パフォーマンスなどを確認できる点も良いと思います。

前置きが長くなりましたが手順を書いておこうと思います。

手順:

まずは、コンテナ同士の通信に使用するネットワークを作成する。

$ docker network create https-network

次にロードバランサーとして使用するTraefikを設定するディレクトリを用意します。

$ mkdir -p /opt/traefik

このディレクトリ内に、以下の3つのファイルを作ります。

$ touch /opt/traefik/docker-compose.yml
$ touch /opt/traefik/acme.json && chmod 600 /opt/traefik/acme.json
$ touch /opt/traefik/traefik.toml

特に、touch /opt/traefik/acme.json && chmod 600 /opt/traefik/acme.jsonをしておかないと、acme.jsonなディレクトリが作成されてしまうので注意が必要です。(最初、これの意味が分からなくて困っていました)

docker-compose.yml を以下のように記述します。

version: '3'
services:
  reverse-proxy:
  image: traefik:latest
  container_name: traefik
  restart: always
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock
    - ./traefik.toml:/traefik.toml
    - ./acme/acme.json:/acme.json
  networks:
    - https-network
networks:
  https-network:
    external: true
  • ports: 外部に公開するポート(Traefikがサービスとして提供する)を指定します。ここではhttpとhttpsを指定します。
  • network: 先程準備したdocker内のネットワーク名を指定する(つまりこのネットワークを使用して振り分けなどを行う)。
  • volumes: コンテナの追加や削除を検知するための記述と、Traefikの設定ファイル、Let’s Encrypt用の設定ファイルをマウントする。

Traefik container を起動する前に、設定ファイルを用意します。

logLevel = "ERROR"
defaultEntryPoints = ["https", "http"]
[entryPoints]
  [entryPoints.http]
  address = ":80"
    [entryPoints.http.redirect]
    entryPoint = "https"
  [entryPoints.https]
  address = ":443"
    [entryPoints.https.tls]
[retry]
[api]
[acme]
email = "[email protected]"
storage = "acme.json"
onHostRule = true
#caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
caServer = "https://acme-v02.api.letsencrypt.org/directory"
entryPoint = "https"
acmeLogging = true
  [acme.httpChallenge]
  entryPoint = "http"
[docker]
endpoint = "unix:///var/run/docker.sock"
watch = true
domain = "example.com"
exposedByDefault = false

httpのアクセスはhttpsにリダイレクトするように設定しています。
尚、[acme]セクションのemailについては、本物のメールアドレスを指定する必要があります。架空のメールアドレスだとLet’s Encryptの設定に失敗します(真正性の証明ができないため)。
取得できたSSL証明書は、acme.jsonに保管されます。

ここでcaServerというパラメータが2つありますが、最初はコメントアウトしているhttps://acme-staging-v02.api.letsencrypt.org/directoryを使用した方が良いと思います。

というのも、Let’s Encryptによる証明書発行について、Rate Limitが厳しく設定されているため、設定にミスなどがありやり直しを何回もしようとすると発行が一時停止される恐れがあるためです。
最初はステージングサーバを指定しておき、Fakeの形で証明書を発行するようにし、失敗がないことを確認しながら実施した方が良いと思います。

CN=Fake LE Intermediate X1
Tried renewing our certs on a box today and seeing the following issuer: CN=Fake LE Root X1 Any ideas what’s going on?

ここまで準備できたら、Traefikを起動します。

$ cd /opt/traefik
$ docker-compose up -d

あとは、同じネットワーク内にアプリケーションcontainerを立ち上げればOKです。

適当なディレクトリに以下の内容で docker-compose.yml を用意してください。(例えば、bitwarden rustの場合)

version: '3'
services:
  bitwarden:
  image: mprasil/bitwarden:alpine
  restart: always
  volumes:
    - ./bw-data/:/data/
  ports:
    - 1024:1024
  environment:
    ROCKET_PORT: "1024"
    WEBSOCKET_ENABLED: "true"
    SIGNUPS_ALLOWED: "false"
    ADMIN_TOKEN: ""
    DOMAIN: "https://bitwarden.example.com"
    SMTP_HOST: ""
    SMTP_FROM: "<[email protected]>"
    SMTP_PORT: "true"
    SMTP_SSL: "true"
    SMTP_USERNAME: ""
    SMTP_PASSWORD: ""
  labels:
    traefik.docker.network: "https-network"
    traefik.enable: "true"
    traefik.basic.port: "1024"
    traefik.basic.frontend.rule: "Host:bitwarden.example.com"
    traefik.basic.protocol: "http"
  networks:
    - https-network
networks:
  https-network:
    external: true

※ドメインやネットワークなどは適宜自分の設定に読み替えてください。

ポイントは、「labels」セクションです。Traefikに対して、このコンテナへ接続する仕様を伝えます。

  • “traefik.enable=true”
    このコンテナがTraefikを使用することを宣言します。
  • “traefik.docker.network=https-network”
    このコンテナはhttps-networkネットワークを使用してTraefikと通信する。
  • “traefik.frontend.rule=Host:bitwarden.example.com”
    このコンテナは、ここで指定したドメイン宛のリクエストを受け付けます。つまり、ここで設定したHost名(bitwarden.example.com)でアクセスがあった場合、このcontainerにTraefikはアクセスを振り分けます。
  • “traefik.port=1024”
    1024番ポートでリクエストを受け付ける。(アプリケーションが稼働するcontainerのportを指定)
  • “traefik.protocol=http”
    通信のプロトコルは、httpであることを宣言する。

TraefikでSSLの処理をすべて行ってくれるので、アプリケーションコンテナではSSLの処理が不要となります。

準備ができたら、アプリケーションコンテナを起動します。

$ docker-compose up -d

以上で、TraefikがLet’s Encryptによる証明書を利用する形で配下のcontainerにhttpsによるサービスを提供できるようになるはずです。

参考:

この記事を書いた人

kometchtech

うつ病を患いながら、IT業界の末席にいるおっさんエンジニア。科学計算をしたことがないのに、HPC分野にお邪魔している。興味のある分野で学習したことをblogにまとめつつ、うつ病の経過症状のメモも置いておく日々。じつはRouterboard User Group JPの中の人でもある。 Amazon欲しいものリスト / Arm板を恵んでくれる人募集中

kometchtechをフォローする
タイトルとURLをコピーしました