セカイノカタチ

世界のカタチを探求するブログ。関数型言語に興味があり、HaskellやScalaを勉強中。最近はカメラの話題も多め

DockerとLet's encryptを組み合わせて運用する

f:id:qtamaki:20160422161818p:plain

Let's encryptが正式サービスになったみたいですね。

今時は、サーバー立てるにしてもDockerが当たり前だと思いますので、Dockerを利用して、Let's encryptの証明書を発行、運用することにしました。

ここでは、僕が細々と運営している、marblewords.comというサービスを例に方法を説明したいと思います。

マーブルワーズ | 言葉つながる魔法のアイディアノート

前提

以下は前提です。

dockerはインストール済みとする

ubuntuなら下記の感じでインストールします。

sudo apt-get install docker.io
sudo gpasswd -a youraccount docker

nginxのコンテナはすでに稼働している

Dockerがあれば、こんな感じで起動できます。

docker run -it --name nginx1 -p 80:80 -p 443:443 -v `pwd`/conf.d:/etc/nginx/conf.d:ro -v `pwd`/../lets/etc/letsencrypt:/letsencrypt:ro -d nginx

対象ドメインを所有している

Let's encryptを動かす前提が、letsencrypt-autoコマンドの実行サーバーが、対象ドメインのAレコードになっている必要があります。

ドメインを所有していて、Webサービスを動かす予定のサーバーにDNSのAレコードを設定して実行してください。

なお、その際にhttpサービスは停止しておく必要があります。

これは、Let's encryptの証明書発行スクリプトが内部でwebサーバーを起動して、接続を受け付けることで、ドメインの所有権を確認するためです。

起動サーバーのhttpサービスのDocument rootを渡して(その下になんか書き込むことで)所有権を確認するモードもあるようですが、試してません。

ツリー

ざっくりと下記のようなツリーを想定しています。

.
├── lets # Let's encryptの操作に使う
│   ├── etc
│   │   └── letsencrypt
│   └── var
│       └── lib
│           └── letsencrypt
└── nginx # nginxの環境
    └── conf.d

下記の説明は、特に明示やcdがなければ、トップディレクトリからの操作ということになります。

証明書の生成

DockerでLet's encryptを動かす設定は、こちらのサイトを参照しました。

User Guide — Let's Encrypt 0.6.0.dev0 documentation

スタート用のshellを作る

$ cd lets
$ cat > makecert.sh
#!/bin/sh

mkdir -p etc/letsencrypt var/lib/letsencrypt

docker run -it --rm -p 443:443 -p 80:80 --name letsencrypt \
            -v "$(pwd)/etc/letsencrypt:/etc/letsencrypt" \
            -v "$(pwd)/var/lib/letsencrypt:/var/lib/letsencrypt" \
            quay.io/letsencrypt/letsencrypt:latest \
            auth --standalone -d marblewords.com

$ chmod 755 makecert.sh
$ ./makecert.sh

起動すると、メールアドレスの入力を促され、利用規約にagreeを求められます。この手順は自動化できないみたいです。

スクリプトで大量の証明書を発行されないように対策が入っているのでしょうか?

無事に処理が終了すると、./lets/etc/letsencrypt/live/[ドメイン名]の下に証明書が生成されます。

ただし、liveのパーミッションが、rootのみのread onlyになっているため、通常ユーザーでは中身を見ることができません。

sudo ls./lets/etc/letsencrypt/live

みたいな感じで確認することができます。注意してください。

nginxの設定

nginxに設定を入れます。

$ cat > nginx/conf.d/ssl-default.conf
server {
    listen 443;
    server_name  marblewords.com;

    ssl on;
    ssl_certificate /letsencrypt/live/marblewords.com/fullchain.pem;
    ssl_certificate_key /letsencrypt/live/marblewords.com/privkey.pem;

    root /three-d-mind/public;

    try_files $uri @unicorn;

    location @unicorn {
      proxy_set_header Host $http_host;
      proxy_pass http://unicorn;
    }
    error_page 500 502 503 504 /500.html;
}

要するに下記三行を追記します。

ssl on;
ssl_certificate /letsencrypt/live/marblewords.com/fullchain.pem;
ssl_certificate_key /letsencrypt/live/marblewords.com/privkey.pem;

ディレクトリは、docker起動時にボリュームマウントするディレクトリ次第ですが、下記のように起動する想定です。

$ cd nginx
$ docker run -it --name nginx1 -p 80:80 -p 443:443 -v `pwd`/conf.d:/etc/nginx/conf.d:ro -v `pwd`/../lets/etc/letsencrypt:/letsencrypt:ro -d nginx

以上で、Let's encrypt化完了です。

証明書を更新する

Let's encryptの証明書は、90日と証明期間が短いです。

その代わり、証明書の更新もスクリプトで自動的に行えるらしいので、スクリプトを準備します。

$ cd lets
$ cat > renewcert.sh
#!/bin/sh

docker stop nginx1

docker run -it --rm -p 443:443 -p 80:80 --name letsencrypt \
            -v "$(pwd)/etc/letsencrypt:/etc/letsencrypt" \
            -v "$(pwd)/var/lib/letsencrypt:/var/lib/letsencrypt" \
            quay.io/letsencrypt/letsencrypt:latest renew

docker start nginx1

$ chmod 755 renewcert.sh
$ ./makecert.sh

一旦nginxを止めないと行けないところが、ちょっとアレですが仕方ない。

実行すると下記のようになりました。

どうやら、まだ更新が必要な期間に入っていないということみたいです。今発行したばかりなので当然ですね。(^^;

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/marblewords.com.conf
-------------------------------------------------------------------------------

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/marblewords.com/fullchain.pem (skipped)
No renewals were attempted.

これを、「cronで毎日できればランダムな時間に実行しろ」と公式ドキュメントに書いてある気がします。

期限30日以内にならないと、実際にはリクエストが飛ばないようです。

また、60日ぐらい経ったら確認する必要がありますね。

以上。自分へのメモも兼ねて、取り急ぎご報告となります。