筆者にとってこの作業は当たり前すぎていたため、メモを残すのを失念していました。
概要
Webサイトを公開する際に必須と言っていいSSL証明書を、Let's Encrypt(certbot)を用いて無料で発行する手順です。
今回用意するのはワイルドカード証明書です。
「*.example.com」という証明書を取得することで、
- aaa.example.com
- bbb.example.com
- supercalifragilisticexpialidocious.example.com
など、サブドメインすべてに有効な証明書を1回で発行できます。
実施環境
- Ubuntu 24.04
前提条件
- ワイルドカー証明書を発行したいドメインに対してDNSの操作が行えること
- できない場合は本手順そのものを無視してください。
- 備考として、別サーバでも配布しやすいように、オリジナルの
/etc/letsencrypt/live/
ではなく、任意の作業ディレクトリに証明書一式を保存する運用を行っています。 - 別サーバへの配布の際は注意してください。
さっくりとした手順
- certbotをインストールします。
- certbotでワイルドカード証明書を発行します。
- 証明書を発行します。
- 所定の位置に格納します。
certbotインストール
※すでにcertbotがインストール済の場合は、この手順はスキップして構いません。
- snapによるインストール
sudo snap install --classic certbot
- コマンド化
sudo ln -s /snap/bin/certbot /usr/bin/certbot
- コマンド確認
which certbot
/usr/bin/certbot
を確認します。
root昇格
性質上、rootで実行します。操作は慎重に行ってください。
sudo su -
作業ディレクトリ作成
- ディレクトリ作成
mkdir /hoge/example.com_ssl$(date +%Y%m)
任意のディレクトリを指定します。$(date +%Y%m)オプションをつけているのは、Let's Encryptの有効期限が90日間と短いため、定期的に更新するためです。
- ディレクトリ移動
cd /hoge/example.com_ssl$(date +%Y%m) && pwd
指定したディレクトリにいることを確認します。
ワイルドカード証明書の手動発行
※ ドメイン名やメールアドレスの打ち間違いは特に注意してください。このコマンドをコピー&ペーストし、自分のドメインやメールアドレスで間違いないように確認後に発行してください。
certbot certonly --manual \
--preferred-challenges dns \
--server https://acme-v02.api.letsencrypt.org/directory \
-m あなたの有効なメールアドレス@example.com \
-d "*.example.com" \
-d "example.com"
--manual
モードは非自動化のため、証明書更新のたびに手動でTXTレコード登録が必要です。自動化したい場合はDNS API対応のプラグインを検討してください(例:certbot-dns-cloudflare)。certonly
は証明書の取得だけを行い、Webサーバ設定などには手を加えないモードです。
以下のように実施します。
- コマンド発行後、TXTレコードの登録指示があります。
- 管理しているDNSサーバにて、指示があったTXTレコードを登録します。
- 以下のコマンドで結果が返ってくるまでしばらく待ちます。
nslookup -type=TXT _acme-challenge.example.com
→ 結果が返ってきたらEnter。証明書が作成されます。
証明書一式を作業ディレクトリにコピー
- 証明書を作業ディレクトリにコピー
cp -pi /etc/letsencrypt/live/example.com/fullchain.pem ./example.com.crt.$(date +%Y%m)
※root権限のためsudo
を用いないことに注意
- 秘密鍵を作業ディレクトリにコピー
cp -pi /etc/letsencrypt/live/example.com/privkey.pem ./example.com.key.$(date +%Y%m)
(通例、証明書はroot権限でしか読めないように制限されています。読み取り時は注意してください)
証明書の整合性を確認
- 90日の有効期限であることを確認します。
以下、自分が発行したドメインに基づく証明書や秘密鍵に読み替えます。
openssl x509 -noout -dates -subject -in example.com.crt.$(date +%Y%m)
notBefore=May 17 04:35:55 2025 GMT
notAfter=Aug 15 04:35:54 2025 GMT
のように90日間であることを確認します。
- 確認1. 証明書から公開鍵データを確認
openssl x509 -pubkey -in example.com.crt.$(date +%Y%m) -noout | openssl md5
- 確認2. 秘密鍵から公開鍵を取得
openssl pkey -pubout -in example.com.key.$(date +%Y%m) | openssl md5
→ 確認1/確認2で出てきた公開鍵のハッシュ値が一致していればOKです。
- 証明書のチェーンを確認
openssl crl2pkcs7 -nocrl -certfile example.com.crt.$(date +%Y%m) | openssl pkcs7 -print_certs -outform PEM | awk 'BEGIN {c=0;} /BEGIN CERTIFICATE/ {c++} { print > "cert" c ".pem"}' && openssl verify -CAfile cert2.pem cert1.pem
openssl verify -CAfile cert2.pem cert1.pem
cert1.pem: OK
となることを確認します。
確認後、
exit
でrootから抜けます。
証明書の配置
※Let's Encryptは3ヶ月(90日)しか有効期限がありません。
そこで、証明書更新の際にApacheの設定ファイルを修正することなく行えるように、証明書/秘密鍵ファイルにシンボリックリンクを張り、ファイル名.202507等とすることで「最後に発行したのはいつか」を確認します。
ディレクトリを作成します。
sudo mkdir /etc/certs
証明書を格納するディレクトリです
sudo mkdir /etc/private
秘密鍵を格納するディレクトリです
ディレクトリに証明書と秘密鍵を格納します。
- SCPやSFTPでアップロードして対象ディレクトリに配置する
- Let's Encryptなどで作成したファイルをそれぞれ対象ディレクトリにコピー/移動する
など、適当な方法を用います。(割と効率的なのがcat
でファイル内容を開き、それを別サーバに貼り付ける方法です)
秘密鍵格納後、
sudo chmod 600 /etc/private/hoge.sample.com.key.202507
として、アクセス権を厳密にします。
上記、取得した*.example.com
の証明書と秘密鍵を
- /etc/certs (証明書)
- /etc/private (秘密鍵)
に格納したとして手順を進めます。
証明書のシンボリックファイルを作成します。
cd /etc/certs && pwd
/etc/certs
にいることを確認
sudo ln -sf hoge.sample.com.crt.202507 hoge.sample.com.crt
ls -l hoge.sample.com.crt
リンクの向き先がhoge.sample.com.crt.202507であることを確認します。
例
lrwxrwxrwx 1 root root 31 7月 2 14:35 hoge.sample.com.crt -> hoge.sample.com.crt.202507
秘密鍵のシンボリックファイルを作成します。
cd /etc/private && pwd
/etc/private
にいることを確認
sudo ln -sf hoge.sample.com.key.202507 hoge.sample.com.key
ls -l hoge.sample.com.key
リンクの向き先がhoge.sample.com.crt.202507であることを確認します。
後は、お使いのWebサーバに適用していきます。この方式であれば、
SSLCertificateFile 【/etc/certs/hoge.example.com.crt】
# SSL証明書を指定します
SSLCertificateKeyFile 【/etc/private/hoge.example.com.key】
# 秘密鍵を指定します
とすることで、.confファイルをいじることなく更新作業を行えます。
以下、Redmineでの設定例です。
https://atelier.ryza.jp/projects/zettel/knowledgebase/articles/20