Let's Encrypt で取得したサーバ証明書を Nginxに設定するための手順。
確認した環境は次の通り。
- OS: CentOS 7.2
- Nginx 1.11
Let's Encrypt 導入の事前準備
証明書を取得したいドメインでアクセスできるサーバを立てておく。
アプリケーションやHTTPサーバのインストールは必ずしも必要ないが、次の2点が必要。
- 取得したいドメインがDNSで名前解決できる
- 80番ポートでアクセスできる
以下の操作はそのサーバ上で行う。
certbot のインストール
まず、Let's Encrypt のクライアントcertbot
をインストール。
インストールと言っても、git で cloneするだけ。
以下の例では、/usr/local にインストールしているが、場所はどこでもよい。
$ cd /usr/local
$ git clone https://github.com/certbot/certbot
$ cd certbot
$ ./certbot-auto --help
Usage: certbot-auto [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
to both this script and certbot will be downloaded and installed. After
ensuring you have the latest versions installed, certbot will be invoked with
all arguments you have provided.
Help for certbot itself cannot be provided until it is installed.
--debug attempt experimental installation
-h, --help print this help
-n, --non-interactive, --noninteractive run without asking for user input
--no-self-upgrade do not download updates
--os-packages-only install OS dependencies and exit
-v, --verbose provide more output
上の例の様に -h
オプションでヘルプが表示されればひとまずOK。
証明書の取得
以下に次の環境の証明書の取得の手順を示す。HTTPサーバも用意する必要がないスタンドアローンモードを利用する例である。
- ドメイン:www.hogehoge.com
$ ./certbot-auto certonly --standalone -t
初回実行時には不足パッケージのインストールを促される。
yesと答えてインストールする。
不足パッケージのインストールが終わると、次の様にメールアドレスを聞いてくるので入力する。
Creating virtual environment...
Installing Python packages...
Installation succeeded.
Enter email address (used for urgent notices and lost key recovery) (Enter 'c' to cancel): xxxx@hogehoge.com
メールアドレスの次は、ライセンスに Agreeするかを聞いてくる。
-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf. You must agree
in order to register with the ACME server at
https://acme-v01.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: A
上の様にA
を入力してAgreeすると続いて次の様にドメインを訪ねてくる。
取得したいドメインを入力する。そしてこのドメイン名で操作しているサーバが名前解決できる必要がある。
Please enter in your domain name(s) (comma and/or space separated) (Enter 'c' to cancel):www.hogehoge.com
この例では スタンドアローンモードを指定しているので、certbot-auto
は自前でHTTPサーバを起動し、認証用のファイルを取りにこさせる。この時点でTCP/80をバインドするプロセスがあればエラーで止まる。
ファイルを取らせることができれば認証成功。次の様に「Congratulations!」とメッセージが表示される。
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/www.hogehoge.com/fullchain.pem. Your cert
will expire on 2016-11-11. To obtain a new or tweaked version of
this certificate in the future, simply run certbot-auto again. To
non-interactively renew *all* of your certificates, run
"certbot-auto renew"
- If you lose your account credentials, you can recover through
e-mails sent to xxxx@hogehoge.com.
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
インタラクティブなやり取りはしたくない場合
上記のようにプロンプトに入力を求められることなく、証明書を発行したい時には次のオプションを付けて実行する。Ansible等で設定したい時には入力を求められた時点で止まってしまうので、--agree-tos
をつけると良い。利用規約にAgreeして処理が進む。
./certbot-auto certonly --standalone -d www.hogehoge.com -m admin@www.hogehoge.com --agree-tos -n
取得した証明書一式
cert-botにより取得した証明書一式は /etc/letsencrypt/
以下に次のようなディレクトリ構成で保存されている。
webサーバの設定で指定するのは/etc/letsencrypt/live/
以下にあるシンボリックリンク。
/etc/letsencrypt/
├── accounts/ # アカウント情報
├── archive/ # 取得した証明書の実体がドメインごとのサブディレクトリに保存されている
│ └── www.hogehoge.com/
├── csr
├── keys
├── live/ # 最新の証明書へのシンボリックリンクが作られる。
│ └── www.hogehoge.com
│ ├── cert.pem -> ../../archive/www.hogehoge.com/cert2.pem
│ ├── chain.pem -> ../../archive/www.hogehoge.com/chain2.pem
│ ├── fullchain.pem -> ../../archive/www.hogehoge.com/fullchain2.pem
│ └── privkey.pem -> ../../archive/www.hogehoge.com/privkey2.pem
└── renewal/ # 証明書更新のための設定が保存されている。
└── www.hogehoge.com.conf
Nginxの設定
取得した証明書をNginxに設定してSSLを有効にする。
次の例は、最低限、追加する必要がある設定。
server {
...
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/www.hogehoge.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.hogehoge.com/privkey.pem;
...
}
ssl_certificate
にはサーバ証明書と中間証明書が結合されたfullchain.pem
のパスを設定する。
ssl_certificate_key
には証明書と対の秘密鍵であるprivkey.pem
のパスを指定する。
証明書を指定する場合、実体の/etc/letsencrypt/archive/
以下のファイルは後述の証明書の更新をするとファイル名が変わってしまうので、/etc/letsencrypt/live/
以下のシンボリックリンクを指定する。
設定したら Nginxを restartして反映する。
上記の設定は最低限のもの。SSL Server Test (Powered by Qualys SSL Labs)のスコアでAとかA+を取りたいなら、次のサイト(検証付きで設定を解説してくれている)を参考に設定を追加すれば良い。
とりあえず、ここまでで、Let's EncryptによるSSL化は終了。
証明書の更新
Let's Encryptで取得できる証明書は有効期限が3ヶ月と短い。なので、定期的に更新する必要がある。
そのために、certbot-auto
にはrenew
サブコマンドがある。
実行してみると次のような結果となる。
$ ./certbot-auto renew
-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/www.hogehoge.com.conf
-------------------------------------------------------------------------------
The following certs are not due for renewal yet:
/etc/letsencrypt/live/www.hogehoge.com/fullchain.pem (skipped)
No renewals were attempted.
上記のようにまだ、更新するほど古くないのでスキップしたよって表示されればOK。
renew
の結果にもあるように /etc/letsencrypt/renewal/www.hogehoge.com.conf
に記録されている設定にしたがって、証明書を更新しようとする。このエントリの例では--standalone
を指定したので、renew
でも--standalone
で動作する。が、実運用するNginxがある場合、ちょっと困ったことになる。certbot-auto
が80番ポート利用するために、Nginxが80番ポートをバインドしている場合に止めなければならなくなる。
それを避けるには--webroot
を利用する。このモードはドキュメントルート以下に/.well-known/acme-challenge/
というディレクトリを作ってその中に認証用のファイルを書き出し、letsencryptのサイトから取らせることにより認証しようとする。サービスで使っているNginxを利用するため止める必要がなくなる。
一旦、--standalone
で実行して作成された設定ファイル/etc/letsencrypt/renewal/www.hogehoge.com.conf
を--webroot
のものに書き換えるには次の様に--webroot
を指定し、force-renewal
をつけて実行すると設定ファイルが上書きされる。
./certbot-auto certonly --webroot -w /var/www/hogehoge -d www.hogehoge.com --agree-tos --force-renewal -n
--webroot
を利用する場合には、認証ファイルを取れる状態にNginxを設定しておく必要がある。
renew
の結果にAll renewal attempts failed.
と表示されて失敗するときには、認証用ファイルが取れる状態かどうかを確認すると良い。
うまくいかない時には次のようなlocationを追加してみる。
server {
...
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root {{doc_root}};
}
...
}
昨今の常時HTTPS化の流れで、HTTPでアクセスされたら HTTPSにリダイレクトするなどHTTPS通信を強制する場合も多くなっていると思う。
ただ、Let's Encryptの証明書の認証ファイルのチェックは常に HTTP でアクセスしてくる。したがって--webroot
で更新しようとするなら、次のように /.well-known/acme-challenge/
から始まるパスへのリクエストはHTTPで受けつつ、その他はすべてHTTPSにリダイレクトするようにすれば良い。
server {
listen 80 default_server;
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root {{doc_root}};
}
location / {
# Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
return 301 https://$host$request_uri;
}
}
更新の自動化
./certbot-auto renew
で失敗しないなら次のようなcronを設定して更新を自動化する。
0 4 1 * * /usr/local/certbot/certbot-auto renew && /bin/systemctl reload nginx
これは毎月1日の4:00に更新する例。
証明書の更新後、Nginxをリロードして反映することを忘れずに。
最後に
運用時には --webroot
で renewal できるようにしたほうが良いと思う。でも、最初の証明書取得は--standalone
のほうがやりやすいのではないかと思う。
--webroot
で証明書を取得するには、Nginxを起動する必要があるが、ssl_certificate
やssl_certificate_key
で指定したファイルが存在しないとエラーで起動しない。でもまだ証明書はない。このジレンマ。
だったら、最初は--standalone
で取得して、SSL設定した後でNginxを起動したほうが楽じゃないかなと思う。で、renewalは--webroot
で行う。
参考:renewal用の設定ファイルの内容
standalone用
# renew_before_expiry = 30 days
version = 0.8.1
cert = /etc/letsencrypt/live/www.hogehoge.com/cert.pem
privkey = /etc/letsencrypt/live/www.hogehoge.com/privkey.pem
chain = /etc/letsencrypt/live/www.hogehoge.com/chain.pem
fullchain = /etc/letsencrypt/live/www.hogehoge.com/fullchain.pem
# Options used in the renewal process
[renewalparams]
authenticator = standalone
installer = None
account = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
webroot_path = /var/www/hogehoge,
[[webroot_map]]
webroot 用
# renew_before_expiry = 30 days
version = 0.8.1
cert = /etc/letsencrypt/live/www.hogehoge.com/cert.pem
privkey = /etc/letsencrypt/live/www.hogehoge.com/privkey.pem
chain = /etc/letsencrypt/live/www.hogehoge.com/chain.pem
fullchain = /etc/letsencrypt/live/www.hogehoge.com/fullchain.pem
# Options used in the renewal process
[renewalparams]
authenticator = webroot
installer = None
account = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
webroot_path = /var/www/hogehoge,
[[webroot_map]]
www.hogehoge.com = /var/www/hogehoge
サブコマンド・オプションの説明
このエントリで使った certbot-auto
のサブコマンドとオプションをざっくり説明する。
詳しくはコマンド解説 - Let's Encrypt 総合ポータルを見ると良い。
-
certonly
:証明書の取得だけを行うコマンド。- 他にインストールまでしてくれる
run
コマンドなどがある。
- 他にインストールまでしてくれる
-
--webroot
:webサーバのドキュメントルートに書き出される認証用ファイルで認証を行う。- 他に
--standalone
があるが、これは80番ポートをバインドしている他のプロセス(webサーバなど)を止める必要があるのでwebサーバのために証明書を取得するときには--webroot
を使うと良い。
- 他に
-
-w
:ドキュメントルートを指定する。renew
の時、ドキュメントルート以下の/.well-known/acme-challenge/
ディレクトリに認証用 -
-d
:取得する証明書のドメインを指定する。このドメインでアクセスできるwebサーバが必要なので先に準備しておく。 -
-t
:TUIを使わずにテキストベースで設定することを指定する。- これを指定しない場合、TUIが起動する。(
certbot-auto
はTUIがデフォルト)
- これを指定しない場合、TUIが起動する。(
-
--agree-tos
:ACME 利用規約に同意する。インタラクティブに尋ねられないのでスクリプト等を使って設定する場合には便利。 -
-n
: ユーザの入力を求められないノンインタラクティブモードで実行される。-d
、-w
、-m
等必須なパラメータを付ける必要がある。足りない場合にはつけるように促すエラーメッセージが表示される。 -
--force-renewal
: 証明書の更新を強制する。これをつけなければ有効期限が十分ある場合、更新されない。