LoginSignup
5
2

More than 1 year has passed since last update.

【Docker Compose】Route53管理下のドメインのウェブサイトにhttpsアクセスできるようにする

Last updated at Posted at 2021-12-18

この記事はDocker Advent Calendar 2021の18日目の記事として書かれました。

はじめに

ちょっとしたウェブアプリを独自ドメインでインターネットに公開してみた時、
httpsアクセスできるよう設定していなくて何だかなあという気持ちになったことはありませんか。
僕はたくさんあります。

ワイルドカード証明書を取得してリバースプロキシに設定しておけば、
適当なサブドメインをアプリに割り当ててhttpsアクセス可能にできそうですね。

前提

  • Amazon Route 53のパブリックホストゾーンとして登録しているドメインがある。
    ※検証目的であればfreenomがおすすめです。
  • 以下の手順はインターネット経由でアクセスできるサーバで実施する。
    なお、自分のIPからのみアクセスできるようにする等のセキュリティ設定は任意です。

環境

$ docker -v
Docker version 20.10.11, build dea9396

$ docker-compose -v
docker-compose version 1.29.2, build 5becea4c

手順

1.以下の通りの構成のディレクトリを作成

.
├── .aws
│   ├── .gitkeep
│   ├── config
│   └── credentials
├── docker-compose.yml
├── .env
└── etc
    └── nginx
        └── conf.d
            └── ssl.conf.template

2.docker-compose.ymlと.envを編集

docker-compose.yml
version: "3.3"

services:
  web:
    image: nginx:${NGINX_TAG}
    container_name: nginx
    network_mode: host
    environment:
      SERVER_NAME: ${SERVER_NAME}
      DOMAIN_NAME: ${DOMAIN_NAME}
    volumes:
      - letsencrypt:/etc/letsencrypt:ro
      - ./etc/nginx/conf.d:/etc/nginx/conf.d
    command: >
      /bin/sh -c
      "envsubst '
      $$SERVER_NAME
      $$DOMAIN_NAME
      ' < /etc/nginx/conf.d/ssl.conf.template > /etc/nginx/conf.d/ssl.conf
      && nginx -g 'daemon off;'"
  cert:
    image: certbot/dns-route53:${CERTBOT_TAG}
    container_name: certbot
    command: certonly --dns-route53 --dns-route53-propagation-seconds=300 --non-interactive --agree-tos -m ${MAIL_ADDR} -d "${DOMAIN_NAME}" -d "*.${DOMAIN_NAME}"
    network_mode: host
    volumes:
      - letsencrypt:/etc/letsencrypt
      - ./.aws:/root/.aws

volumes:
  letsencrypt:

${} で囲われている部分は docker-compose によって設定される環境変数です。
コマンド実行時、デフォルトで .env という名前のファイルを参照して、 docker-compose.yml 内の変数を書き換えます。
以下のように .env を作成します。 DOMAIN_NAME 以下はご自身の情報を入力して下さい。

.env
NGINX_TAG=latest
CERTBOT_TAG=v1.22.0
DOMAIN_NAME=hoge.com
SERVER_NAME=www.hoge.com
MAIL_ADDR=mail@hoge.com
変数名 意味
NGINX_TAG nginxコンテナのタグ latest
CERTBOT_TAG certbotコンテナのタグ v1.22.0
DOMAIN_NAME ドメイン名 hoge.com
SERVER_NAME ウェブサーバ名 www.hoge.com
MAIL_ADDR メールアドレス mail@hoge.com

3.nginxの設定ファイルのテンプレートを作成

./etc/nginx/conf.d ディレクトリ以下にファイルを作成します。

ssl.conf.template
server {
    listen 443 ssl;
    server_name ${SERVER_NAME};

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    ssl_certificate     /etc/letsencrypt/live/${DOMAIN_NAME}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAIN_NAME}/privkey.pem;
}

docker-compose.yml の以下の部分に注目します。

    command: >
      /bin/sh -c
      "envsubst '
      $$SERVER_NAME
      $$DOMAIN_NAME
      ' < /etc/nginx/conf.d/ssl.conf.template > /etc/nginx/conf.d/ssl.conf
      && nginx -g 'daemon off;'"

${SERVER_NAME}${DOMAIN_NAME} に対応する環境変数が envsubst によって注入されます。
また、注入された結果が ssl.conf として保存されます。

4.IAMユーザのアクセスキー等を.aws以下に記載

以下のポリシーを含むIAMユーザを作成します。
参考:Welcome to certbot-dns-route53’s documentation!

{
    "Version": "2012-10-17",
    "Id": "certbot-dns-route53 sample policy",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "route53:GetChange"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect" : "Allow",
            "Action" : [
                "route53:ChangeResourceRecordSets"
            ],
            "Resource" : [
                "arn:aws:route53:::hostedzone/YOURHOSTEDZONEID"
            ]
        }
    ]
}

ここで、 YOURHOSTEDZONEID はホストゾーンのIDに置き換えてください。
アクセスキーを取得できたら、.aws 以下のファイルを編集します。

./aws/config
[default]
region = ap-northeast-1
output = json
.aws/credentials
[default]
aws_access_key_id = XXXXXXXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXX

5.docker-compose を実行

ここまでできたら docker-compose.yml のある階層に戻り 、以下のように cert -> web の順でサービスを実行します。

$ docker-compose up cert

certcmd に注目します。デフォルトの entrypoint とあわせて、以下のコマンドが実行されています。

certbot certonly --dns-route53 --dns-route53-propagation-seconds=300 --non-interactive --agree-tos -m ${MAIL_ADDR} -d "${DOMAIN_NAME}" -d "*.${DOMAIN_NAME}"

つまり、ドメイン名の証明書とそのサブドメインすべてに対するワイルドカード証明書をリクエストしています。
以下のようなログが出力され、exit codeが0で終われば成功です。

certbot | Successfully received certificate.
certbot | Certificate is saved at: /etc/letsencrypt/live/ドメイン名/fullchain.pem
certbot | Key is saved at:         /etc/letsencrypt/live/ドメイン名/privkey.pem
certbot | This certificate expires on 2022-03-18.
certbot | These files will be updated when the certificate renews.
certbot | NEXT STEPS:
certbot | - The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.
certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log
certbot | 
certbot | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
certbot | If you like Certbot, please consider supporting our work by:
certbot |  * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
certbot |  * Donating to EFF:                    https://eff.org/donate-le
certbot | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
certbot exited with code 0

続けて、nginxを起動します。
exitしないプロセスなので、 -d をつけてバックグラウンドで実行させます。

$ docker-compose up -d web

こちらは以下のようにしてログを見に行きます。
"start worker process" と出ていれば、問題なく起動しています。

$ docker-compose logs -f web

nginx   | 2021/12/18 13:25:07 [notice] 10#10: using the "epoll" event method
nginx   | 2021/12/18 13:25:07 [notice] 10#10: nginx/1.21.4
nginx   | 2021/12/18 13:25:07 [notice] 10#10: built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 
nginx   | 2021/12/18 13:25:07 [notice] 10#10: OS: Linux 5.11.0-1020-aws
nginx   | 2021/12/18 13:25:07 [notice] 10#10: getrlimit(RLIMIT_NOFILE): 1048576:1048576
nginx   | 2021/12/18 13:25:07 [notice] 10#10: start worker processes

https:// をつけてアクセスし、nginxのウェルカムページが表示されれば成功です!
以下の例ではアドレスバーに錠のアイコンが出ていることがわかります。

https.png

おわりに

nginx コンテナはホストの ./etc/nginx/conf.d に対してバインドマウントしているため、
confファイルを追加してリロードすれば別のアプリをバックエンドサーバとして設定できます。

必ずしもnginxとcertbotを同じComposeファイルで管理する必要はありません、
取得した証明書を letsencrypt なるボリュームで管理してnginxとcertbotで共有すると便利なので、
今回はこのような形にしています。

ボリュームではなくバインドマウントにして、ホストに既に存在するletsencryptの証明書を
更新させるといった実現方法もあると思います。

検証したいだけのアプリに対して頑張ってSSL対応する必要もないのですが、
簡易に実現する方法があるということを知っておくことには大いに意義があると思います。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2