nginx
docker
HTTPS

Dockerコンテナで起動するnginxをLets encryptを利用してHTTPS化する

More than 1 year has passed since last update.

修正点

6/28 再度試したところ、letsencryptで証明書を取得するところの選択肢1,2が逆転していました・・・十分注意して確認の上操作していただければと思います。
3/14 letsencryptの証明書を取得するときの引数が一つ抜けていたので修正。大変失礼致しました。

はじめに

前回の続きでnginxコンテナをhttps化対応させます。
証明書はみんな大好きLet's encryptを利用します。

構成

構成の検討

  • はじめはローカルにクライアントソフトを入れて、とか考えてたんですが、DockerイメージでLet's encryptの証明書を取得できる物があるようなので、それを利用する事を考えます。
  • let's encryptで証明書を取得する時、そのホストが該当するDNS名でアクセスできる必要があります。
  • アクセスするポートは80番か、443番でいいようなので、80番をlet's encrypt用、443をnginx用となるように構成を変更します。

構成イメージ

Kobito.MhEsn0.png

設計

フォルダ構造

項目 備考
コンフィグの置き場所 $(pwd)/nginx/etc/nginx/ 以下にconf.dをフォルダを用意しておき、マウントさせます。
証明書の置き場所 /etc/letsencrypt このディレクトリ以下に取得した証明書を配置します。
コンテンツの置き場所 $(pwd)/www コンテンツはカレントディレクトリ直下のwwwディレクトリに配置します。

nginx

  • あまり難しい設定は実施せず、最低限のもののみ投入します。
項目 備考
listen 443 ssl default_server 80番はlistenせず、443のみ待ち受けるものとします。
ssl_certificate /etc/letsencrypt/live/ドメイン名/fullchain.pem 証明書のパスを指定します
ssl_certificate_key /etc/letsencrypt/live/ドメイン名/privkey.pem 証明書のパスを指定します。
server_name ドメイン名 指定したドメイン名で待ち受けるようにします。
root /usr/share/nginx/html コンテナ内のドキュメントルートを/usr/share/nginx/htmlとします。
index index.html インデックスファイルはindex.htmlのみとします。

Docker

  • 同様に最低限のものとします。(前回書いた共通の項目はここには記載しません)
項目 備考
-v $(pwd)/nginx/etc/nginx/conf.d:/etc/nginx/conf.d:ro conf.dディレクトリをマウントします。
-v $(pwd)/www:/usr/share/nginx/html:ro カレントディレクトリ直下にあるwwwディレクトリを/usr/share/nginx/htmlにマウントします。
-v /etc/letsencrypt:/etc/letsencrypt:ro let's encryptで取得した証明書ディレクトリをコンテナ側にマウントします。

設定

let's encrypt証明書の取得

  • 一旦nginxコンテナを止めた上で、該当するDNS名が設定されているホスト上で下記を実行します。
$ docker run -it --rm -p 80:80 --name letsencrypt ¥
      -v "/etc/letsencrypt:/etc/letsencrypt" ¥
      -v "/var/lib/letsencrypt:/var/lib/letsencrypt" ¥
      quay.io/letsencrypt/letsencrypt:latest certonly --preferred-challenges http-01
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Failed to find apache2ctl in PATH: /opt/certbot/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

How would you like to authenticate with the ACME CA?
-------------------------------------------------------------------------------
1: Place files in webroot directory (webroot)
2: Spin up a temporary webserver (standalone)
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel):対象のドメイン名を入力
Obtaining a new certificate
Performing the following challenges:
tls-sni-01 challenge for 対象のドメイン名
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0000_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0000_csr-certbot.pem

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/対象のドメイン名/fullchain.pem. Your
   cert will expire on 2017-06-08. To obtain a new or tweaked version
   of this certificate in the future, simply run certbot again. To
   non-interactively renew *all* of your certificates, run "certbot
   renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
  • これでホスト側の/etc/letsencrypt配下に証明書が生成されてますね!

  • ちなみに更新するときは、下記でいけるようです。(実際には期限が来ていないのでまだ更新はできていません。)

$ docker run -it --rm -p 80:80 --name letsencrypt ¥
      -v "/etc/letsencrypt:/etc/letsencrypt" ¥
      -v "/var/lib/letsencrypt:/var/lib/letsencrypt" ¥
      quay.io/letsencrypt/letsencrypt:latest renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/対象のドメイン名.conf
-------------------------------------------------------------------------------
Cert not yet due for renewal

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/対象のドメイン名/fullchain.pem (skipped)
No renewals were attempted.
  • 自動更新のcronを仕込んでも良いのですが、初回は手動でやりたいので、一旦は仕込みません。

nginxの設定

  • /etc/nginx/conf.d/default.confは下記のような設定とします。
server {
    listen 443 ssl default_server;
    ssl_certificate /etc/letsencrypt/live/ドメイン名/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ドメイン名/privkey.pem;

    server_name ドメイン名;

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

コンテナの起動

  • --logXXX系のオプションは前回のfluentdの名残なので、不要であれば消して貰えればと思います。
$ docker run --name nginx -v /etc/localtime:/etc/localtime:ro ¥
      -p 443:443 -v $(pwd)/nginx/etc/nginx/conf.d:/etc/nginx/conf.d:ro ¥
      -v $(pwd)/www:/usr/share/nginx/html:ro ¥
      -v /etc/letsencrypt:/etc/letsencrypt:ro ¥
      --log-driver=fluentd --log-opt=fluentd-address=XX.XX.XX.YY:24224 ¥
      --log-opt=tag=docker.{{.FullID}} -d nginx

最後に

  • 簡単に証明書の取得ができるletsencryptは素晴らしいですね。
  • 今回はDockerホストが1つだったため考慮してませんが、実際には証明書をnfs等に配置しておいて、ホストがコケたときは別のホスト上でnginxを再起動することなどを考慮したほうが良いかと思います。

参考