Edited at

CentOS7上でnginxとDockerとLetsEncryptでSSLをごにょごにょする話

More than 3 years have passed since last update.

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の設定と再起動

すでにインストールされている前提なので、インストールは省略。


/etc/nginx/conf.d/virtual.conf

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を編集する。


/etc/nginx/conf.d/virtual.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のサービスを起動する設定にしておくのがコツ。


Dockerfile

FROM centos:centos7

RUN systemctl enable httpd
RUN systemctl enable crond
EXPOSE 80