LetsEncryptを使ってみたかった。
nginxでHTTPリクエストを受けてリバースプロキシでコンテナのHTTPサーバにproxy_passしている状態からLetsEncryptのSSL証明書を利用したい。
前提
CentOS 7.2(host)
docker 1.8
nginx 1.9
コンテナはFROM centos:centos7
でDockerfileを使って立てたもの。
課題
すでに立てているコンテナは80/tcpしか空けていない。
コンテナを作り直すのは嫌だなあ、と考えた。
実現方法
フォルダを共有する方法で、コンテナの鍵フォルダをホスト側に共有し、ホスト側で見えた鍵をnginxで利用する。
ホスト側の操作
共有用のフォルダを作成する
$ sudo mkdir /etc/nginx/cert
まあ、どこでもいいのだが、nginxのところに作った。
コンテナのエクスポートとインポート
$ sudo docker stop <container_id>
$ sudo docker export <container_id> > container_name.tar
$ sudo cat container_name.tar | docker import - <repository>:<tag>
一旦止めてファイルに書き出して、イメージとしてインポートする必要がある。
コンテナの起動
$ sudo docker run --privileged -v /etc/nginx/cert:/etc/letsencrypt/ -d --name <new_container_name> -it -p 20080:80 <repository>:<tag>
-v
オプションでコンテナの/etc/letsencrypt/をホストの/etc/nginx/certと共有するように設置した。
nginxの設定と再起動
すでにインストールされている前提なので、インストールは省略。
server {
listen 80;
server_name www.hogehoge.com;
location / {
proxy_pass http://127.0.0.1:20080;
}
}
nginxを再起動する。
$ sudo systemctl reload nginx
コンテナの操作
コンテナでLetsEncryptをインストールする
すでにコンテナでHTTPサーバが起動している前提。
$ sudo su -
$ cd ~
# git clone https://github.com/letsencrypt/letsencrypt
# cd letsencrypt/
# ./letsencrypt-auto --help
# ./letsencrypt-auto certonly --webroot --webroot-path /var/www/html -d www.hogehoge.com
# exit
大体うまくゆく。
コンテナで証明書を更新するためのcronを設定する
$ sudo crontab -e
00 03 01 * * /root/letsencrypt/letsencrypt-auto certonly --webroot --webroot-path /var/www/html -d www.hogehoge.com --renew-by-default
毎月1日の午前3時にcronが動いて、証明書を更新する。
再度ホスト側の操作
証明書があることを確認する
$ sudo ls -l /etc/nginx/cert/live/www.hogehoge.com/
合計 0
lrwxrwxrwx 1 root root 34 3月 6 00:10 cert.pem -> ../../archive/www.hogehoge.com/cert1.pem
lrwxrwxrwx 1 root root 35 3月 6 00:10 chain.pem -> ../../archive/www.hogehoge.com/chain1.pem
lrwxrwxrwx 1 root root 39 3月 6 00:10 fullchain.pem -> ../../archive/www.hogehoge.com/fullchain1.pem
lrwxrwxrwx 1 root root 37 3月 6 00:10 privkey.pem -> ../../archive/www.hogehoge.com/privkey1.pem
ホストでnginxの再設定と再起動
confを編集する。
server {
listen 80;
server_name www.hogehoge.com;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443;
server_name www.hogehoge.com;
ssl on;
ssl_certificate /etc/nginx/cert/live/www.hogehoge.com/fullchain.pem;
ssl_certificate_key /etc/nginx/cert/live/www.hogehoge.com/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDH-RSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256;
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security 'max-age=31536000;includeSubDomains;';
location / {
proxy_pass http://127.0.0.1:20080;
}
}
nginxを再起動する。
$ sudo systemctl reload nginx
ホスト側でもcronを走らせる
$ sudo crontab -e
00 04 01 * * /usr/bin/systemctl reload nginx
毎月1日の午前4時にcronが動いて、nginxを再起動する。
これで作業完了
補足
コンテナのDockerfileでは、以下のようにhttpdとcrondのサービスを起動する設定にしておくのがコツ。
FROM centos:centos7
RUN systemctl enable httpd
RUN systemctl enable crond
EXPOSE 80