dokku-letsencryptでHTTPSのwebサービスの構築が捗る件

※プロンプトで表示しているURL類は、基本的にgithubを除いて全部自分の確認用のURLから改変したものです

最近ちょこちょこdokku[^1]をいじったりしています。
昨年末ごろに、Let's Encrypt[^2]がオープンベータになって以降、SSLサーバ証明書の作成が非常に楽になっています。

で、dokkuにはLet's Encryptをさらに手軽に扱えるようになる、dokku-letsencrypt-pluginが存在するので、後で「証明書どうしよう」といった考慮も全く必要なく気軽にHTTPSなWebサービスの構築が捗りそうです。

## インストールしてみる

[ここ](https://github.com/dokku/dokku-letsencrypt) そのまんま。簡単

```shell-session:インストール
$ sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
```

これだけ。


## 使ってみる

(dokkuのドキュメントでおなじみのruby-rails-sampleを使用)


```shell-session:アプリ用意してみる
$ dokku apps:create sample
Creating sample... done
(中略)
$ dokku letsencrypt sample
=====> Let's Encrypt sample...
 !     ERROR: Cannot request a certificate without an e-mail address!
 !       please provide your e-mail address using
 !       dokku config:set --no-restart sample DOKKU_LETSENCRYPT_EMAIL=<e-mail>
```

Let's EncryptはSSL証明書発行時にメールアドレスが必須になるので、dokkuのアプリにあらかじめ環境変数にメールアドレスを登録する必要があります。
提示してくれるコマンドに`--no-restart`オプションでコンテナ再起動をさせる必要をなくしているのは優しさ

```shell-session:メールアドレスを登録して再度進める
$ dokku config:set --no-restart sample DOKKU_LETSENCRYPT_EMAIL=attakei@example.com
-----> Setting config vars
       DOKKU_LETSENCRYPT_EMAIL: attakei@example.com
$ =====> Let's Encrypt sample...
-----> Updating letsencrypt docker image...
latest: Pulling from m3adow/letsencrypt-simp_le

4d06f2521e4f: Already exists
a3ed95caeb02: Already exists
8d87d7d66444: Already exists
87187c773fd1: Already exists
Digest: sha256:66269a4cc647c9847a7f4f8ba39ba98caeb3b1b824d4f28ccb7dcc7b21351f25
Status: Image is up to date for m3adow/letsencrypt-simp_le:latest
       done
-----> Enabling ACME proxy for sample...
-----> Getting letsencrypt certificate for sample...
        - Domain 'sample.dokku.example.com'
darkhttpd/1.11, copyright (c) 2003-2015 Emil Mikulic.
listening on: http://0.0.0.0:80/
2016-03-17 03:32:17,571:INFO:__main__:1202: Generating new account key
2016-03-17 03:32:21,819:INFO:requests.packages.urllib3.connectionpool:758: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-03-17 03:32:22,106:INFO:requests.packages.urllib3.connectionpool:758: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-03-17 03:32:22,374:INFO:requests.packages.urllib3.connectionpool:758: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-03-17 03:32:22,651:INFO:requests.packages.urllib3.connectionpool:758: Starting new HTTPS connection (1): letsencrypt.org
2016-03-17 03:32:23,807:INFO:requests.packages.urllib3.connectionpool:758: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-03-17 03:32:24,113:INFO:requests.packages.urllib3.connectionpool:758: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-03-17 03:32:24,487:INFO:requests.packages.urllib3.connectionpool:207: Starting new HTTP connection (1): sample.lab.attakei.net
2016-03-17 03:32:24,784:INFO:__main__:1294: sample.lab.attakei.net was successfully self-verified
2016-03-17 03:32:24,834:INFO:requests.packages.urllib3.connectionpool:758: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-03-17 03:32:25,115:INFO:__main__:1302: Generating new certificate private key
2016-03-17 03:32:32,681:INFO:requests.packages.urllib3.connectionpool:758: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-03-17 03:32:32,938:INFO:requests.packages.urllib3.connectionpool:758: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-03-17 03:32:33,291:INFO:requests.packages.urllib3.connectionpool:758: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-03-17 03:32:33,547:INFO:__main__:385: Saving account_key.json
2016-03-17 03:32:33,548:INFO:__main__:385: Saving fullchain.pem
2016-03-17 03:32:33,548:INFO:__main__:385: Saving chain.pem
2016-03-17 03:32:33,555:INFO:__main__:385: Saving cert.pem
2016-03-17 03:32:33,556:INFO:__main__:385: Saving key.pem
-----> Certificate retrieved successfully.
-----> Symlinking let's encrypt certificates
-----> Setting config vars
       DOKKU_NGINX_SSL_PORT: 443
-----> Configuring SSL for sample.example.com...(using /var/lib/dokku/plugins/available/nginx-vhosts/templates/nginx.ssl.conf.template)
-----> Creating https nginx.conf
-----> Running nginx-pre-reload
       Reloading nginx
-----> Disabling ACME proxy for sample...
       done
```

Let's EncryptクライアントのDockerイメージをプルしたのちに、勝手に取得をしてくれる。取得するだけでなく、dokkuのフロント部分に証明書のセットアップをしてくれて、さらにhttpでアクセスするとhttpsにリダイレクトしてくれるという、至れり尽くせり感がすごいですね。

## 後日談：更新してみる

最近になって3ヶ月が経過したらしく、証明書の期限が切れてしまっていたので更新しました。

```shell-session:1コマンド
$ dokku letsencrypt sample
=====> Let's Encrypt sample...
-----> Updating letsencrypt docker image...
latest: Pulling from m3adow/letsencrypt-simp_le
Digest: sha256:9882d95a88d2cea4a92eb87f43a543ada7b94a09ce65e8c8bbc47f152980b034
Status: Image is up to date for m3adow/letsencrypt-simp_le:latest
       done
-----> Enabling ACME proxy for sample...
sudo: unable to resolve host ip-172-24-0-201
-----> Getting letsencrypt certificate for sample...
        - Domain 'sample.example.com'
darkhttpd/1.12, copyright (c) 2003-2016 Emil Mikulic.
listening on: http://0.0.0.0:80/
2016-07-04 10:02:57,651:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:02:58,157:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:02:58,397:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:02:58,638:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:02:58,904:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:02:59,128:INFO:requests.packages.urllib3.connectionpool:213: Starting new HTTP connection (1): sample.example.com
2016-07-04 10:02:59,210:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): sample.example.com
2016-07-04 10:02:59,253:ERROR:acme.challenges:256: Unable to reach http://sample.example.com/.well-known/acme-challenge/RoDaskPNr_hcTMVTCFm6mt_G_G4L2j8zlpJ4iHHRvYQ: ("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",)
2016-07-04 10:02:59,253:WARNING:__main__:1303: sample.example.com was not successfully self-verified. CA is likely to fail as well!
2016-07-04 10:02:59,639:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:02:59,859:INFO:__main__:1313: Generating new certificate private key
2016-07-04 10:03:00,119:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:03:00,376:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:03:04,635:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:03:04,837:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:03:05,054:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:03:05,362:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-07-04 10:03:05,630:INFO:__main__:391: Saving fullchain.pem
2016-07-04 10:03:05,632:INFO:__main__:391: Saving cert.pem
2016-07-04 10:03:05,632:INFO:__main__:391: Saving key.pem
-----> Certificate retrieved successfully.
-----> Symlinking let's encrypt certificates
-----> Configuring SSL for sample.example.com...(using /var/lib/dokku/plugins/available/nginx-vhosts/templates/nginx.ssl.conf.template)
-----> Creating https nginx.conf
-----> Running nginx-pre-reload
       Reloading nginx
sudo: unable to resolve host ip-172-24-0-201
-----> Disabling ACME proxy for sample...
sudo: unable to resolve host ip-172-24-0-201
       done
```

メールアドレスの設定などがすでに終わっているので、1コマンド入れてぼーっとしているだけで更新完了。便利です

[^1]: http://dokku.viewdocs.io
[^2]: http://letsencrypt.org