※本ページには広告(アフィリエイトプログラム等)が含まれます。
さくらのVPSでnginxを立てたら、次に必ずやるのがSSL証明書の導入だ。Let’s Encryptは無料でドメイン認証(DV)証明書を発行してくれる認証局で、certbotを使えば取得から自動更新まで一通り自動化できる。証明書は90日しか有効でないため、自動更新の仕組みが正しく動いているかまで確認するのがこの記事のゴールだ。環境はDebian 12/13・nginx・PHP 8.3を想定している。
Let’s Encryptの特徴をざっくり押さえる
Let’s Encryptは無料だが、その代わり証明書の有効期間が90日と短い。有料の証明書(1〜2年有効)に慣れているとこの短さに驚くが、これは意図的な設計で「短命だから自動更新前提で運用しろ」というポリシーだ。裏を返せば、自動更新さえ組んでおけば手動更新の手間からは解放される。EV証明書のような組織認証はできないが、一般的なWebサイトやAPIサーバーであればDV証明書で実用上困ることはない。
certbotの導入(apt版)
certbotにはsnap版とapt版があるが、この記事はDebianの標準リポジトリに入っているapt版で統一する。snapはDebianサーバーだと余計な依存が増えがちで、うちの運用では使っていない。
apt update
apt install -y certbot python3-certbot-nginx
python3-certbot-nginxがnginx用のプラグインで、これを入れておくとcertbotがnginxの設定ファイルを自動で書き換えて証明書のパスを差し込んでくれる。設定を手で書く手間がないので、素直にプラグインを使うのが楽だ。
nginxプラグインで証明書を取得する
対象ドメインのserver_blockがnginxにすでに存在している状態で、次のコマンドを実行する。
certbot --nginx -d [example.com] -d www.[example.com]
初回実行時は対話式でメールアドレスの入力と利用規約への同意を求められる。メールアドレスは証明書の期限切れ間近やセキュリティ通知が届く先になるので、実際に読める運用アドレスを入れておく。取得が成功すると、証明書一式は次のパスに配置される。
/etc/letsencrypt/live/[example.com]/fullchain.pem
/etc/letsencrypt/live/[example.com]/privkey.pem
certbotはnginxの設定ファイルにこの2つのパスを差し込み、80番から443番へのリダイレクトも一緒に設定してくれる。手動で書き換える場合よりミスが少ない。
自動更新の仕組みと確認方法
最近のcertbot(apt版)はインストール時にsystemdのtimerを自動登録する。手でcronを書く必要はなく、次のコマンドで登録済みか確認できる。
systemctl list-timers | grep certbot
1日2回程度の頻度でcertbot renew相当の処理が走るようになっているはずだ。実際に期限切れ間近になった証明書だけを選んで更新してくれるので、90日ごとに毎回手作業する必要はない。ただし「本当に動くか」は自分の目で確かめておきたい。dry-runオプションで実際には更新せず、更新処理が通るかだけを検証できる。
certbot renew --dry-run
ここでエラーが出るなら、本番の更新でも同じエラーで失敗する。放置せず原因を潰しておく。
更新後にnginxをreloadするフック
証明書を更新しただけではnginxのワーカープロセスは新しい証明書を読み込まない。reloadが必要になるので、deploy-hookで自動化しておく。
certbot renew --deploy-hook "systemctl reload nginx"
一度このオプション付きで実行しておけば、certbotはフックの内容を設定ファイルに記憶してくれるので、以降のsystemd timer経由の自動更新でも同じフックが働く。これを忘れると「証明書は更新されているのにブラウザは古い証明書のまま」という地味に気づきにくい事故になる。
ECDSA鍵で取得したい場合
デフォルトはRSA鍵だが、鍵長を抑えつつ同等の強度を得たい場合は--key-type ecdsaを付けて取得する。
certbot --nginx -d [example.com] --key-type ecdsa
ECDSA鍵はRSAより鍵サイズが小さく、TLSハンドシェイクのオーバーヘッドがわずかに減る。とはいえ一般的なVPS用途で体感できるほどの差ではないので、特にこだわりがなければデフォルトのRSAのままで問題ない。
ワイルドカード証明書について
*.[example.com]のようなワイルドカード証明書が欲しい場合、HTTP-01チャレンジでは取得できず、DNS-01チャレンジが必須になる。DNSのTXTレコードを操作できるプラグイン(DNSプロバイダ用のcertbotプラグイン、またはAPI経由の手動チャレンジ)が必要で、単純に--nginxを付けるだけでは通らない。サブドメインを都度発行する運用で済むなら、無理にワイルドカードにこだわらずHTTP-01のままの方がシンプルだ。
ハマりどころ
- HTTP-01チャレンジは80番ポートへの到達性を検証する。ファイアウォール(ufwやさくらのVPSのパケットフィルタ)で80番を閉じたままだと、この検証段階で必ず失敗する。取得前に
curl -I http://[example.com]/が外部から通ることを確認しておく。 - Let’s Encryptには発行レート制限がある。同一ドメインへの発行が週あたりの上限を超えると、しばらく新規発行ができなくなる。検証中に何度も取得し直すと引っかかりやすいので、テスト段階ではステージング環境(
--stagingオプション)を使うのが安全だ。 - 複数のserver_blockが同じドメイン名を待ち受けていると、certbotがどちらを書き換えるべきか判断を誤ることがある。nginxの設定はドメインごとに1ファイルに整理しておくと事故が減る。
まとめ
certbotのnginxプラグインを使えば、証明書の取得も自動更新もほぼ手離れする。ポイントは取得時の設定より、むしろrenew --dry-runで自動更新が本当に機能するかを確認しておくことと、deploy-hookでreloadを仕込んでおくことの2点だ。ここさえ押さえておけば、90日ごとの更新を意識せずに運用できる。
