certbotでLet's EncryptなSSL証明書を取得する例

certbotでLet's EncryptなSSL証明書を取得する例

はじめに

常時httpsが当たり前なんで、Let's Encryptの証明書をcertbotを使って、ちゃちゃっと設定しちゃいましょ。

書いてる人は、フロントエンドの人間なので、ツメが甘いところがあるかもしれないけれど、そのあたりはご容赦を。
また、あんまりわかってない人に対しての記事なので、「とりあえずなんとなくわかった」程度の理解度の内容でいいと思ってるので、ちょくちょく「正確ではない」表現が含まれます。


概要

能書き

イマドキのwebサイトは、裏でAPIが動いてるかどうかとか、POST投げるかどうかとか、そんなのお構いなしにとりあえずSSL対応しておこうみたいな風潮あるある。
めんどうくさいけど、httpなサービスって確かになんだかやな感じあるので、ちゃちゃっとお仕事やっつけちゃいましょ。

特にこだわりはないけど、このブログの話の流れ上、NGINXを使う前提でいます。
nginxのおはなしについては、「nginxのリバースプロキシの設定例」をみてね。

nginxのリバースプロキシの設定例
dockerなんかでいろいろ建てるのはいいけど、それらの振り分けってめんどいから、テンプレ的なのを書きつけて、あとからてきとうにコピペで時短できるようにしておくためだけの記事。

この記事では、ワイルドカードの証明書を発行するための方法は書いてないです。
そのうち書くかもしれない。

apache使う人は、取得後に/etc/httpd/conf.d/ssl.confみたいなところを編集したらいいんじゃないかな。あんまりよくわかんないけど。
postfixで使う人は、/etc/postfix/main.cf smtpd_tls_XXXXXみたいなのをぶち込むといいと思うよ。


下準備

なにはともあれインストール

コマンド打つだけでおわり。いい時代になりました。

$ sudo apt-get install certbot

CentOS系ならyumで入ると思います。

$ sudo yum install certbot

パッケージが見つからない時はアップデートするといいかも

ただし、他のパッケージが狂うこともあるから、気を付けてやろうね。

$ sudo apt-get update

または

$ sudo yum update

証明書を発行しましょ

なにはともあれ、コマンド叩いてみますか。

certbotには発行の方法がたくさんあります。
基本的にcertonlyサブコマンドをつけて-dオプションでドメイン指定する方法でよいとは思います。

ワイルドカードな証明書が欲しい人は、DNS-01チャレンジという方式で発行する必要がありますが、今回はこの方法については触れてないです。そのうちたぶん書きます。

$ certbot certonly -d ghost.example.com

叩くと、こんなのが出ます。

How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Runs an HTTP server locally which serves the necessary validation files under
the /.well-known/acme-challenge/ request path. Suitable if there is no HTTP
server already running. HTTP challenge only (wildcards not supported).
(standalone)
2: Saves the necessary validation files to a .well-known/acme-challenge/
directory within the nominated webroot path. A seperate HTTP server must be
running and serving files from the webroot path. HTTP challenge only (wildcards
not supported). (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

要するに、以下2パターンのやり方があるけど、どっちでやる?って聞かれてます。

  1. certbot内蔵のHTTPサーバでリクエストを待ち受けて発行する方式 (standalone方式)
  2. SSL化したいドメインのwebrootを入力する方式 (webroot方式)

やり方はそれぞれ下に書いとくので、どっちを選ぶかは環境次第で選んでね。

standalone方式

webサーバを(まだ)使ってないサーバの場合や、5分程度止めても大丈夫ってな場合には、standaloneの方がらくちんです。

なお、既にnginxないしapacheなんかが走ってるサーバで1を選ぶと、80番ポート使用中だよ!!!空けてきて!!!!!と言われます。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Could not bind TCP port 80 because it is already in use by another process on
this system (such as a web server). Please stop the program in question and then
try again.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(R)etry/(C)ancel: 

怒られたら、仕方がないので、

$ sudo systemctl stop nginx

でいったん止めて、「R」を押してリトライ。
すすめてくと

Simulating a certificate request for ghost.example.com

ってなログのあと、ちょっと時間が空いて、sccessみたいなのが出たら成功です。

webroot方式

こっちの方法は、やることがちょっと多いです。めんどくさいです。
めんどくさいけど、webサーバ落とさずに証明書をGETできます。

まずは、nginxの設定をさわりましょ。
SSL化しようとしているドメインのサーバ設定を開いて、

$ sudo vim /etc/nginx/sites-available/ghost.example.com

↓こんな感じに書く。

server {
    listen 80;
    listen [::]:80;
    server_name ghost.example.com;

    location / {
        root /var/www/ghost.example.com/public;
        index index.html;
    }
    location = /.well-known/acme-challenge/ {
        return 404;
    }

}

要するにwebrootを準備できればそれでいいみたいです。中身が空っぽでも大丈夫。
検査されるのは、そのルートからさらに掘ったところのファイルのようです。
また、http://ghost.example.com/.well-known/acme-challenge/にアクセスしても404を吐くようになってる。ここのデータの一覧が見えたりしたら困るからね。

$ sudo nginx -t && sudo systemctl reload nginx

ってな感じに、nginxの文法チェックの上、リロードして、

Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

さきほどの1,2の選択肢で「2」を選んでみましょ。
すると、

Input the webroot for ghost.example.com: (Enter 'c' to cancel):

ってな感じにwebrootどこ?って聞いてくるので、先ほどnginxのconfに書いたものと同じもの(つまり、/var/www/ghost.example.com/public)を書きましょう。

しばらくすると、Let's Encrypt validation serverというところからのアクセスが飛んできます。
↓こんなの。

XXX.XXX.XXX.XXX -- GET /.well-known/acme-challenge/XXXXXXXXXXXXXXXXXXXXXXXXXX HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"

success的なログが出たら発行完了です。

どちらの方法でも、成功するとこんなログ

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/ghost.example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/ghost.example.com/privkey.pem
This certificate expires on 2025-03-17.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

この時点で /etc/letsencrypt/live/のディレクトリ内に鍵が入ってるはずです。
nginxなりapacheなりpostfixなり、必要な場所に追加しましょう。

nginxの書き方に関しては、nginxのリバースプロキシの設定例で軽く触れてるので、参考にしてもいいかもしれない。

nginxのリバースプロキシの設定例
dockerなんかでいろいろ建てるのはいいけど、それらの振り分けってめんどいから、テンプレ的なのを書きつけて、あとからてきとうにコピペで時短できるようにしておくためだけの記事。

自動更新しましょ

crontab

certbotを入れた時点で/etc/cron.d/certbotが生成されているかもしれないです。
中身はこんなの。

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(43200))' && certbot -q renew --no-random-sleep-on-renew

12時間ごとにcertbotがあるかどうかを確認しつつ、スリープを入れつつ、確認してくれてるみたいですね。

もしなければ、同じようなものをいれておけばよいと思います。

renewal-hooks

証明書が入れ替わっても、nginxなりpostfixなりをリロードしてあげないといけません。
いつの間にか、リニューアルする前とか後とかに動かせるようなディレクトリが出来上がってました。

とりあえず見に行ってみましょ。

$ cd /etc/letsencrypt/renewal-hooks

ここのディレクトリには、下記3つのディレクトリが存在する。その役割はこんなの。

ディレクトリ名 いつ走るのか
pre すべての証明書の更新処理を始める前。更新されるかどうかは問わない。
deploy それぞれの証明書の更新処理が終わって、かつ、証明書の更新があった場合。
post すべての証明書の更新処理が終わった後。更新されたかどうかは問わない。

certbot renewが走る時って、コマンド1発うつだけで、certbotで管理されてる証明書全部の更新が回るんだよね。
最初に pre/内の処理が走って、証明書が更新されるたびにdeploy/が走り、全部の更新が終わったらpost/内の処理が走る、ということですね。

つまり、deploy/に、リロードするようなものを入れておけばよさそうですね。
または、自分で考えるのが面倒な人には、Certbot Nginx Reload Post Hook Scriptというものがあったりするので、そちらを参考に入れてみてもよいかもしれないです。

自動更新しとけば、手動で入れ替えするなんてことも必要なくなくなるかららくちんですね。

Let’s Encrypt Certbot post hook command for Nginx which checks the updated configuration files and reloads the server if everything validates.
Let’s Encrypt Certbot post hook command for Nginx which checks the updated configuration files and reloads the server if everything validates. - 01_nginx-reload-post-hook.sh