nginx-proxy(+acme-companion)からTraefikに移行してみる

こんにちは。[nginx-proxy](https://hub.docker.com/r/nginxproxy/nginx-proxy)と[acme-companion](https://hub.docker.com/r/nginxproxy/acme-companion)で構成していたリバースプロキシを、前から気になっていた[Traefik](https://doc.traefik.io/traefik/)に移行してみました。

# nginx-proxyの構成について

現在は以下の`docker-compose.yml`で示すような構成でした。

他の`docker-compose.yml`で作成したコンテナを参加させられるように、既定のネットワークは使わずに`nginx-proxy`という名前のネットワークを作成しています。

```yaml
# nginx-proxy/docker-compose.yml
# 参考: https://github.com/nginx-proxy/acme-companion/blob/main/docs/Docker-Compose.md
version: "3.9"

services:
  nginx-proxy:
    image: "nginxproxy/nginx-proxy"
    container_name: "nginx-proxy"
    environment:
      DHPARAM_GENERATION: "false"
    networks: ["nginx-proxy"]
    ports: ["80:80", "443:443"]
    restart: "always"
    volumes:
      - "/var/run/docker.sock:/tmp/docker.sock:ro"
      # nginx-proxy
      - "certs:/etc/nginx/certs"
      - "dhparam:/etc/nginx/dhparam"
      - "vhost:/etc/nginx/vhost.d"
      # acme-companion
      - "html:/usr/share/nginx/html"
  acme-companion:
    image: "nginxproxy/acme-companion"
    container_name: "acme-companion"
    depends_on: ["nginx-proxy"]
    environment:
      DEFAULT_EMAIL: "master@mail.example.com"
    networks: ["nginx-proxy"]
    restart: "always"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "acme:/etc/acme.sh"
    volumes_from: ["nginx-proxy"]

networks:
  nginx-proxy:
    name: "nginx-proxy"

volumes:
  # nginx-proxy
  certs:
    name: "nginx-proxy-certs"
  dhparam:
    name: "nginx-proxy-dhparam"
  vhost:
    name: "nginx-proxy-vhost"
  # acme-companion
  acme:
    name: "acme-companion-acme"
  html:
    name: "acme-companion-html"
```

WordPress等のコンテナをリバースプロキシの対象にするには、`nginx-proxy`ネットワークに参加させます。

```yaml
# wordpress-nginx-proxy/docker-compose.yml
# ※データベースコンテナなどの無関係な部分は省略しています。
services:
  wordpress:
    environment:
      LETSENCRYPT_HOST: "www.example.com,example.com"
      VIRTUAL_HOST: "www.example.com,example.com"
    networks: ["default", "nginx-proxy"]

networks:
  default:
    name: www-example-com
  nginx-proxy:
    external: true
    name: "nginx-proxy"
```

# Traefikの構成について

Traefikを実行するための`docker-compose.yml`は次のようになりました。

基本的な使い道はnginx-proxyの時と同じで、リバースプロキシを使いたいコンテナを`traefik`ネットワークに参加させて、ドメイン等の設定をします。

特筆すべきところとして、`--providers.docker.exposedByDefault=false`を指定していない状態で尚且つLet's Encryptの設定をしていると、起動時に無効なドメインでLet's Encryptしまくってリクエストレート上限に引っかかるので注意しましょう。

```yaml
# traefik/docker-compose.yml
version: "3.9"

services:
  traefik:
    image: "traefik:3.0"
    container_name: "traefik"
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedByDefault=false" # `traefik.enable=true`を指定したコンテナのみ対象にする。
      - "--providers.docker.network=traefik" # 対象とするネットワークを明示的に指定する。
      # `http`エントリポイントの設定をする。
      - "--entryPoints.http.address=:80"
      - "--entryPoints.http.http.redirections.entryPoint.permanent=true"
      - "--entryPoints.http.http.redirections.entryPoint.scheme=https"
      - "--entryPoints.http.http.redirections.entryPoint.to=https"
      # `https`エントリポイントの設定をする。
      - "--entryPoints.https.address=:443"
      - "--entryPoints.https.http.tls.certResolver=letsencrypt"
      # `letsencrypt`証明書リゾルバにLet's Encryptの設定をする。
      - "--certificatesResolvers.letsencrypt.acme.email=master@mail.example.com"
      - "--certificatesResolvers.letsencrypt.acme.httpChallenge.entrypoint=http"
      - "--certificatesResolvers.letsencrypt.acme.storage=acme.json"
    networks: ["traefik"]
    ports: ["80:80", "443:443"]
    restart: "always"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./acme.json:/acme.json"

networks:
  traefik:
    name: "traefik"
```

同じように、`wordpress`コンテナを`traefik`ネットワークに参加させて諸々の設定をしています。

```yaml
# wordpress-traefik/docker-compose.yml
# ※データベースコンテナなどの無関係な部分は省略しています。
services:
  wordpress:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.www-example-com.rule=Host(`www.example.com`) || Host(`example.com`)"
      - "traefik.http.routers.www-example-com.tls=true"
      - "traefik.http.routers.www-example-com.tls.certResolver=letsencrypt"
    networks: ["default", "traefik"]

networks:
  default:
    name: "www-example-com"
  traefik:
    external: true
    name: "traefik"
```

# 感想

この項は『解説』にしようと思っていたのですが、表題の移行作業だけだと解説すべき箇所が無かったので感想になりました。

逆に言えば、Traefikはそれくらいシンプルで洗練された仕組みを提供しているので、Traefikに興味が出た方はぜひ導入してみてください。

- [`traefik` - Official Image | Docker Hub](https://hub.docker.com/_/traefik)
- [Traefik Proxy Documentation - Traefik](https://doc.traefik.io/traefik/)