SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor

Ubuntu 24.04でApacheにCertbotをインストールする方法

Ubuntu 24.04のApacheにLet's Encrypt証明書を1コマンドで導入します。snap不要でapt版Certbot 2.9.0を使い、発行を妨げるServerName未設定の罠も確認できます。

構築するもの

Ubuntu 24.04 上で稼働する Apache サイトを構築します。HTTPS で応答し、Certbot が発行する、ブラウザーが信頼する無料の Let's Encrypt 証明書を使用します。証明書は、以後意識する必要のない systemd timer によって自動更新されます。実行するコマンドは 1 行です。問題が発生するとすれば、すべてその行を実行する前です。例えば、ServerName のない vhost、プロバイダーのファイアウォールで閉じられた port 80、古いサーバーを指したままの DNS などです。そのため、このガイドでは前提条件の確認に多くの時間を割き、それぞれのミスで表示される正確なエラー文字列を示します。

対象範囲について、2 点補足します。Web サーバーが nginx の場合も手順の流れは同じですが、プラグインと設定は異なります。その場合は nginx 版のこのガイドを使用してください。また、証明書を設定する対象が内部専用の場合、例えばプライベートアドレス上の管理パネルや、外部からアクセスされない staging サーバーの場合、認証局は必要ありません。自己署名証明書のほうが構成が簡単で、オフラインでも使用できます。

前提条件と、Certbot の実行前に失敗する3つの原因

  • Apache がすでにサイトを平文 HTTP で提供していること。 Certbot の Apache プラグインは既存のサイト設定を編集します。サイトを作成するものではありません。素の VPS から始める場合は、まず Ubuntu 24.04 で LAMP スタックを構築する を完了してから戻ってきてください。このガイドは、その手順に不足している TLS の章です。
  • VPS のアドレスを指す A レコードを持つパブリックドメイン。 Let's Encrypt の HTTP-01 チャレンジでは、検証サーバーがインターネット経由でサーバーへ接続します。ポートフォワーディングのない NAT 配下のホームラボでは利用できません。.local の名前も使用できません。HTTP-01 はベア IP を検証できますが、Let's Encrypt が IP 証明書を発行するのは、オプトインの shortlived プロファイルを使用した場合だけです。この証明書の有効期間は 160 時間です。また、apt の Certbot 2.9.0 は ACME プロファイルも IP アドレスも要求できません。そのため、このガイドにはドメイン名が必要です。dig +short example.com は VPS のアドレスを返す必要があります。直近の1時間以内に DNS を変更した場合は、発行前に以前のレコードの TTL が切れるまで待ってください。
  • AAAA レコードが存在する場合は、正しい値であること。 AAAA レコードが公開されている場合、Let's Encrypt は必ず IPv6 を最初に試します。その接続がタイムアウトすると IPv4 で再試行しますが、それ以外のエラーにはこの再試行が適用されません。接続を拒否するアドレスや、このサーバーではない稼働中のサーバーを指す AAAA があると、curl が、通常は IPv4 経由で、ノート PC から正常に動作していても検証に失敗します。正しい AAAA を公開するか、AAAA を公開しないでください。

ufw とプロバイダーのネットワークファイアウォールの両方で、ポート 80 および 443 を開く必要があります。多くのホスティングパネルには、OS から認識できない別のファイアウォールがあります。HTTP-01 はポート 80 でのみ検証するため、443 のみで運用することはできません。

sudo ufw allow "Apache Full"
sudo ufw status

これらを準備すれば、作業全体は15分で完了します。そのうち10分は読み取りにかかります。

Snap と apt のどちらで Certbot を導入するか。24.04 では apt で問題ありません

Certbot が数年前に snap での配布へ移行したのには、明確な理由がありました。ディストリビューションのパッケージが長期間更新されなかったためです。Ubuntu 20.04 では Certbot 0.40 が提供され、その後更新されませんでした。プロジェクト側も、5 年前のバグの調査を続けることに疲れていました。24.04 ではその理由はなくなりました。アーカイブには、現行の 2.x 系列に属する 2024 年 2 月リリースの Certbot 2.9.0 が含まれており、unattended-upgrades により Ubuntu が公開するセキュリティ更新も適用されます。上流プロジェクトはその後 5.x 系列へ移行しましたが、このガイドに必要な機能は含まれています。この OS では apt を推奨します。snapd デーモンを使わずに済み、Apache plugin も同じトランザクションでインストールされ、更新タイマーも通常の Debian 方式で systemd と統合されます。

sudo apt update
sudo apt install -y certbot python3-certbot-apache
certbot --version

正しい結果は certbot 2.9.0 です。python3-certbot-apache パッケージは Apache の設定を読み取り、編集する plugin です。これがないと、certbot --apache は The requested apache plugin does not appear to be installed で失敗します。

次の 2 つの場合は、現在も snap が適しています。Certbot がリリースされた当日に最新版を使いたい場合、または snap でのみ配布されている DNS plugin が必要な場合です。certbot-dns-* の provider plugin のいくつかは、snap でのみ配布されています。その場合は、次のようにします。

sudo apt remove -y certbot python3-certbot-apache
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

どちらを選ぶ場合も、両方を実行してはいけません。2 つのインストールがあると、2 つの更新スケジューラーが /etc/letsencrypt をめぐって競合します。また、シェルが PATH で見つける certbot が、証明書を管理している方とは限りません。上記の apt remove 行は、単なる装飾ではありません。

Certbot が編集する vhost は事前に存在している必要があります。ServerName がすべての基準です

certbot --apache は、渡された各 -d ドメインについて、ServerName または ServerAlias が一致するポート 80 の virtual host を探し、その vhost を使ってドメインの管理権限を証明し、その vhost の SSL 用コピーを作成します。一致する ServerName がなければ検出できません。また、Ubuntu のデフォルトの 000-default.conf では ServerName がコメントアウトされています。このコメントアウトされた 1 行が、このガイドの大きなコマンド 1 つが失敗する最も一般的な原因です。

そのため、Certbot を実行する前に、サイト用の適切な名前ベースの vhost を用意します。/etc/apache2/sites-available/example.com.conf を作成します。

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>

有効化した後、Apache が設定を解析でき、名前をその vhost に振り分けることを確認します。

sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
sudo apache2ctl -S

configtest は Syntax OK を出力する必要があります。AH00558: apache2: Could not reliably determine the server's fully qualified domain name も出力される場合、それは global ServerName に関する警告です。vhost の問題ではないため、ここでは無害です。echo "ServerName $(hostname -f)" | sudo tee /etc/apache2/conf-available/servername.conf && sudo a2enconf servername && sudo systemctl reload apache2 によって警告を抑制できます。

重要なのは -S の出力です。alias www.example.com を伴う port 80 namevhost example.com (/etc/apache2/sites-enabled/example.com.conf:1) のような行が必要です。Apache が報告するのは、実際に読み込んだ sites-enabled のシンボリックリンクであり、sites-available で編集したファイルではありません。ポート 80 に対して example.com が表示されなければ、Certbot も検出できません。

証明書を発行する: certbot --apache

sudo certbot --apache -d example.com -d www.example.com

初回実行時には、3 つの確認があります。メールアドレス、Let's Encrypt の規約への同意、メールアドレスを EFF と共有するかどうかです。Let's Encrypt は現在、メールアドレスを ACME アカウントに保存せず、有効期限の警告も送信しないため、更新の監視は自分で行う必要があります。リダイレクトに関する確認はありません。Certbot 1.0 以降、Apache installer はデフォルトで HTTP から HTTPS へリダイレクトします。この確認自体も 1.4 で削除されました。これは通常、必要な動作です。HTTP のままコンテンツを提供する必要がある場合だけ、--no-redirect を指定してください。

成功すると、次のように表示されます。流し読みせず、内容を確認してください。

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2027-01-09.

Deploying certificate
Successfully deployed certificate for example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Successfully deployed certificate for www.example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Congratulations! You have successfully enabled HTTPS on https://example.com and https://www.example.com

このメッセージの背後で、Certbot は 4 つの処理を行っています。Apache の ssl module がまだ有効でなければ有効化します。次に、元の vhost のコピーを *:443 に example.com-le-ssl.conf として作成し、SSLEngine on と証明書のパスを追加します。その vhost を有効化し、元の port-80 vhost に RewriteRule block を追加して、すべての通信を 301 で HTTPS へリダイレクトします。元の vhost file は置き換えられず、編集されます。SSL 用の vhost はその隣に配置されるため、追加された各行を確認できます。

証明書が実際に保存される場所と、決してコピーしてはいけない理由

すべてのファイルは /etc/letsencrypt/live/example.com/ 配下に保存されます。fullchain.pem は証明書と中間証明書チェーンで、サーバーはこれを参照します。privkey.pem は private key で、root だけが読み取れます。ソフトウェアによっては証明書と private key を個別に指定するため、cert.pem と chain.pem も使用します。これらは /etc/letsencrypt/archive/ 内のファイルを指すシンボリックリンクです。この間接参照が更新の仕組みです。更新時には archive/ に新しいファイルが書き込まれ、シンボリックリンクの参照先が変更されます。ほかのソフトウェアでは live/ のパスを指定してください。これにより、更新が自動的に反映されます。ファイルを別の場所へコピーすると、90 日後に障害が発生する構成を自分で作ることになります。

もう 1 つ確認しておくべきファイルは /etc/letsencrypt/renewal/example.com.conf です。このファイルには、証明書の発行方法、authenticator = apache、installer = apache、ドメインが記録されています。そのため、Apache の再読み込みを含め、更新処理を無人で同じ手順により繰り返せます。

更新はすでにスケジュールされています。新しく作成せず、確認してください

Let's Encrypt の証明書は設計上、現在 90 日間有効です。apt パッケージは必要な仕組みもすでにインストールしています。systemd timer が 1 日 2 回、ランダムな時刻に Certbot を実行し、有効期限まで 30 日以内の証明書を更新します。これに加えて cron ジョブを作成しないでください。スケジューラーを 2 つにしても、ログが増え、レート制限にかかる可能性が増すだけです。Let's Encrypt は、2027 年 2 月 10 日から、新しい証明書の有効期間をデフォルトで 64 日間にすると発表しています。30 日の更新期間はその場合も機能します。更新時期が 60 日目付近から 34 日目付近に変わるだけなので、このサーバーで変更する必要はありません。

systemctl list-timers certbot.timer
sudo certbot renew --dry-run

最初のコマンドでは timer が active であることを確認します。NEXT には、今後 24 時間以内の時刻が表示されます。スケジュールは 1 日 2 回で、ランダムな遅延があるため、正確な実行時刻は意図的に予測できません(snap でインストールした場合、timer は snap.certbot.renew.timer です)。dry run では、Let's Encrypt の staging 環境に対して更新を完全にリハーサルします。実際の challenge は実行しますが、証明書は発行されず、レート制限も消費しません。正常な結果は次で終わります。

Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

dry run が失敗する場合、約 60 日後の実際の更新も同じ理由で失敗します。現在の証明書が有効期間を十分に残しているうちに、今すぐ修正してください。よくある原因は、証明書の発行後に追加したファイアウォールルールによって port 80 が再び閉じられていることです。

curl で確認し、鍵アイコンに表示される内容

curl -sI http://example.com | head -n 3
curl -I https://example.com
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -issuer -dates

1 つ目は HTTP/1.1 301 Moved Permanently を返し、Location: https://example.com/ ヘッダーを含むはずです。これは Certbot が設定したリダイレクトです。2 つ目は HTTP/1.1 200 OK を返し、curl から TLS に関する警告が出ないはずです。3 つ目は発行者を表示します。O = Let's Encrypt の行には、YE1 または YE2(ECDSA keys)、YR1 または YR2(RSA keys)のような短い CN が表示されます。また、notAfter はおおむね 90 日後の日付になります。Let's Encrypt が古い中間証明書を廃止する前に発行された証明書では、次回更新まで R12 や E7 のような CN が表示されることがあります。これはエラーではありません。ブラウザーでは鍵アイコンが表示され、クリックすると同じ発行者を確認できます。curl が正常に動作してブラウザーが警告を表示する場合、証明書の問題ではなく、キャッシュされたページを見ているか、誤ったホスト名を使用している可能性がほぼ確実です。

複数サイト: 1 つの SAN 証明書にまとめるか、サイトごとに 1 つの証明書を発行するか

どちらも使用できます。更新方法も同じです。同じサーバー上で無関係なサイトを運用する場合は、サイトごとに issue コマンドを 1 回ずつ実行します。各サイトには live/ 配下に専用ディレクトリと専用の更新設定が作成されます。1 つのドメインで問題が発生しても、他のドメインの更新が妨げられることはありません。これを基本構成にします。

1 つのサイトで複数の名前を使用する場合は、1 つの SAN 証明書にまとめます。1 つの証明書には最大 100 個の名前を含められます。上の例では、すでに example.com と www.example.com を使ってこの構成にしています。後から既存の証明書に名前を追加する場合は、証明書名と、追加後の完全なリストを指定して再発行します。

sudo certbot --apache --cert-name example.com -d example.com -d www.example.com -d blog.example.com

Certbot はドメインの構成が変わったことを検出し、証明書に名前を追加するか確認します。その後、同じ live/ パスの証明書をその場で置き換えるため、他の設定を変更する必要はありません。リストは追加ではなく置き換えである点に注意してください。このコマンドから www を省略すると、新しい証明書からその名前が何も表示されずに削除されます。

ワイルドカードには DNS-01 が必要です。通常、ワイルドカードは必要ありません

HTTP-01 では *.example.com を発行できません。Web サーバーにファイルを配置して証明できるのは、1 つのホスト名を管理していることだけであり、名前空間全体を管理していることは証明できません。ワイルドカードには DNS-01 チャレンジが必要です。Certbot は _acme-challenge.example.com に TXT レコードを設定します。実際には、DNS プロバイダーの API 認証情報を使用する certbot-dns-* プラグインが必要です。または、更新のたびに --manual で TXT レコードを手動編集する方法もありますが、運用は困難なため、この方法を前提にしないでください。TXT レコードの仕組みから、更新を自動実行するプラグインまでの詳しい手順は、DNS-01 による Certbot のワイルドカード証明書にあります。率直に言えば、既知のサブドメインが 4 つある場合は、4 つすべてを列挙する SAN 証明書のほうがワイルドカードより簡単です。サーバーに DNS API キーを保存する必要もありません。

障害パターンと表示される文字列

Apache の設定が壊れているため Certbot が起動しない

The apache plugin is not working; there may be problems with your existing configuration.
The error was: MisconfigurationError('Error while running apache2ctl configtest.\n\nAction \'configtest\' failed.\nThe Apache error log may have more information.\n\nAH00526: Syntax error on line 12 of /etc/apache2/sites-enabled/example.com.conf')

プラグインは変更を加える前に configtest を実行します。Apache 自体に問題があると処理を中止します。\ns がそのまま表示されるのは、Certbot が例外の repr を出力するためです。sudo apache2ctl configtest を自分で実行してください。問題のファイルと行が表示されます。多くの場合、手作業による編集ミス、存在しなくなったパスを指す SSLCertificateFile、または参照されているものの有効化されていないモジュールが原因です。Syntax OK と表示されるまで修正してから、Certbot を再実行します。

ドメインに一致する vhost がない

Unable to find a virtual host listening on port 80 which is currently the only challenge port.

これは前述の missing-ServerName エラーで、発行時に検出されます。Certbot は有効化されたすべての port-80 vhost を調べ、-d に一致する ServerName/ServerAlias を探しますが、見つけられませんでした。sudo apache2ctl -S には、Apache が実際にどのようにルーティングしているかが表示されます。正しい vhost に ServerName 行を追加し、reload してから再試行してください。近い症状として、検証が 誤った vhost に到達する場合もあります。別のサイトがリクエストを受け取るため、challenge の応答が Invalid response ... 404 になります。同じ診断方法とツールを使います。apache2ctl -S です。

検証がタイムアウトする

Certbot failed to authenticate some domains (authenticator: apache).
...
Detail: ...: Timeout during connect (likely firewall problem)

Let's Encrypt は、DNS が示すアドレスの port 80 に TCP 接続を確立できませんでした。可能性が高い順に、プロバイダーのネットワークファイアウォール(ufw とは別で、ホスティングパネルで設定します)、443 または SSH だけを許可する ufw ルールセット、DNS が以前のサーバーを指したままになっていることが原因です。古い AAAA だけが原因になることは通常ありません。IPv6 接続がタイムアウトすると、Let's Encrypt は IPv4 で再試行するためです。AAAA の問題は通常、代わりに別のサーバーからの Connection refused または Invalid response として現れます。VPS の 外部 からテストしてください。ノート PC で curl -I http://example.com を実行すると、検証サーバーが確認する内容を再現できます。

再試行を重ねてレート制限に達した

Error creating new order :: too many failed authorizations (5) for "example.com" in the last 1h0m0s, retry after ... UTC: see https://letsencrypt.org/docs/rate-limits/...

Let's Encrypt では、1 アカウントあたり、1 ホスト名あたり、1 時間に 5 回の検証失敗が許可されます。これは補充されるバケット方式で、約 12 分ごとに 1 回分の再試行枠が戻ります。ファイアウォールが壊れた状態で再試行を繰り返すと、すぐに枠を使い切ります。待てば回復しますが、本当の対策は運用方法を変えることです。失敗したら、成功するまで staging environment でデバッグしてください。

sudo certbot certonly --apache --dry-run -d example.com -d www.example.com

certonly に注意してください。--dry-run は certonly および renew サブコマンドでのみ受け付けられます。単独の certbot --apache --dry-run 形式は実行できず、--dry-run currently only works with the 'certonly' or 'renew' subcommands と表示されます。dry run では staging に対して検証します。staging には独自の十分な制限があり、実際の証明書は発行されないため、そこで何度失敗しても問題ありません。実際のコマンドは、staging で成功してから再実行してください。その他の制限である、登録済みドメインあたり週 50 枚の証明書、同じ名前セットの重複証明書は週 5 枚という制限に達するのは、スクリプトがループして再発行している場合だけです。

HTTPS が利用可能になっても、証明書が保護するのは 通信 であり、サーバー自体ではないことを忘れないでください。port 22 では、今も 1 日中パスワードを推測する接続が続いています。Ubuntu 24.04 で Fail2ban を設定する と組み合わせるのが、次の 30 分で行う自然な作業です。

FAQ

Ubuntu 24.04 の Apache では、Certbot を snap と apt のどちらでインストールすべきですか?

apt を使用します。Ubuntu 24.04 には Certbot 2.9.0 が含まれており、このガイドの内容には十分新しく、Ubuntu が unattended-upgrades を通じて提供するセキュリティ更新も適用され、snapd も必要ありません。最新リリースをすぐに使用する必要がある場合、または snap だけで提供される DNS プラグインが必要な場合に限り snap を選択してください。切り替える場合は、2 つの更新スケジューラーが同時に動作しないよう、最初に apt remove certbot python3-certbot-apache を実行します。

Certbot が「Unable to find a virtual host listening on port 80」と表示する場合、どう修正すればよいですか?

-d で渡したドメインに一致する ServerName または ServerAlias を持つ、ポート 80 用の有効な vhost がないことが原因です。Ubuntu のデフォルト vhost では ServerName がコメントアウトされています。sudo apache2ctl -S を実行し、名前を担当する vhost を見つけるか作成して、ServerName example.com を追加します。その後 Apache を reload し、Certbot を再実行します。

「Timeout during connect (likely firewall problem)」を修正するにはどうすればよいですか?

Let's Encrypt が、DNS で公開されているアドレスのポート 80 に接続できませんでした。ufw だけでなく、プロバイダーの管理パネルにあるネットワークファイアウォールも確認してください。dig +short example.com がこの VPS を返すことを確認し、古い AAAA レコードがあれば修正または削除します。検証では IPv6 が先に試行され、タイムアウト後に IPv4 へフォールバックするためです。curl -I http://example.com を使ってサーバー外部から修正を確認し、実際に発行する前に sudo certbot certonly --apache --dry-run -d example.com でテストします。

Ubuntu 24.04 では、Certbot は証明書を自動的に更新しますか?

はい。apt パッケージは certbot.timer をインストールします。これは 1 日 2 回実行される systemd timer で、有効期限まで 30 日以内の証明書を更新し、その後 Apache を reload します。snap は同じ処理に snap.certbot.renew.timer を使用します。systemctl list-timers certbot.timer で確認し、sudo certbot renew --dry-run でテストしてください。独自の cron ジョブを追加して重複させないでください。

Certbot と Apache でワイルドカード証明書を取得するにはどうすればよいですか?

ワイルドカードには DNS-01 チャレンジが必要です。Certbot は _acme-challenge.example.com に TXT レコードを配置する必要があるため、DNS プロバイダーの API 認証情報を使用する certbot-dns-* プラグインが必要です。--manual の方法では、更新のたびに TXT レコードを手動で編集する必要があります。既知のサブドメインが少数だけの場合は、それらを明示的に列挙する SAN 証明書の方が簡単で、DNS API キーをサーバー上に置かずに済みます。