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

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で利用する。

## ホスト側の操作

### 共有用のフォルダを作成する

```lang:
$ sudo mkdir /etc/nginx/cert
```
まあ、どこでもいいのだが、nginxのところに作った。

### コンテナのエクスポートとインポート

```lang:
$ sudo docker stop <container_id>
$ sudo docker export <container_id> > container_name.tar
$ sudo cat container_name.tar | docker import - <repository>:<tag>
```
一旦止めてファイルに書き出して、イメージとしてインポートする必要がある。

### コンテナの起動

```lang:
$ 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の設定と再起動

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

```lang:/etc/nginx/conf.d/virtual.conf
server {
    listen 80;
    server_name www.hogehoge.com;
    location / {
        proxy_pass http://127.0.0.1:20080;
    }
}
```
nginxを再起動する。

```lang:
$ sudo systemctl reload nginx
```

## コンテナの操作

### コンテナでLetsEncryptをインストールする

すでにコンテナでHTTPサーバが起動している前提。

```lang:
$ 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を設定する

```lang:
$ sudo crontab -e
```
```lang:
00 03 01 * * /root/letsencrypt/letsencrypt-auto certonly --webroot --webroot-path /var/www/html -d www.hogehoge.com --renew-by-default
```
毎月1日の午前3時にcronが動いて、証明書を更新する。

## 再度ホスト側の操作

### 証明書があることを確認する

```lang:
$ 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を編集する。

```lang:/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を再起動する。

```lang:
$ sudo systemctl reload nginx
```

### ホスト側でもcronを走らせる

```lang:
$ sudo crontab -e
```
```lang:
00 04 01 * * /usr/bin/systemctl reload nginx
```
毎月1日の午前4時にcronが動いて、nginxを再起動する。

これで作業完了

# 補足

コンテナのDockerfileでは、以下のようにhttpdとcrondのサービスを起動する設定にしておくのがコツ。

```lang:Dockerfile
FROM centos:centos7
RUN systemctl enable httpd
RUN systemctl enable crond
EXPOSE 80
```