Let's Encrypt 無料SSL証明書設定完全ガイド - HTTPS導入実践
Let's Encrypt Free SSL Certificate Complete Setup Guide
はじめに:HTTPSはもはや選択ではなく必須
2026年現在、HTTPSはWebサイトに不可欠な要素です。Google Chrome、Firefox、Safariなどすべての主要ブラウザはHTTPサイトに「保護されていない通信」という警告を表示し、GoogleはHTTPSサイトに検索順位の加点を与えています。さらに、HTTP/2、HTTP/3、Service Workerといった最新のWeb技術はHTTPSでのみ動作します。
かつてSSL証明書の発行には年間数万円の費用がかかりましたが、Let's Encryptの登場で状況は一変しました。2015年に設立されたLet's Encryptは非営利の認証局(CA)で、誰でも完全無料でSSL証明書を発行できるようにしました。2026年現在、世界で最も多く利用されている無料SSL証明書であり、毎日数百万件の証明書が発行されています。
本ガイドでは、Let's Encryptを活用して実際のサービスにHTTPSを導入する全工程を解説します。Certbotのインストールから、Nginx/Apacheへの適用、ワイルドカード証明書、自動更新、そしてよくある問題とその解決方法まで、実務ですぐに活用できるよう詳しく説明します。
1. Let's EncryptとSSL証明書の基礎
1.1 Let's Encryptの特徴
- 完全無料:発行、更新、再発行すべて無料
- 自動化:ACMEプロトコルにより発行・更新を自動化可能
- 有効期間90日:商用証明書(1~2年)より短いが、自動更新で対応
- ドメイン認証(DV)のみ対応:組織認証(OV)、拡張認証(EV)は非対応
- ワイルドカード対応:
*.example.com形式の証明書発行が可能 - 主要ブラウザがすべて信頼:Chrome、Firefox、Safari、Edgeすべてで自動的に信頼される
1.2 認証方式の理解
Let's Encryptはドメイン所有権を検証するチャレンジ(Challenge)方式で証明書を発行します:
| チャレンジ種別 | 検証方式 | 用途 |
|---|---|---|
| HTTP-01 | Webサーバー上の特定パスにファイルを配置して検証 | 最も一般的、単一ドメイン |
| DNS-01 | DNS TXTレコードによる検証 | ワイルドカード証明書には必須、自動化可能 |
| TLS-ALPN-01 | TLSハンドシェイク中に検証 | 特殊な環境(ポート80遮断など) |
・単一ドメイン(example.com、www.example.com):HTTP-01(最もシンプル)
・ワイルドカード(*.example.com):DNS-01必須
・内部ネットワークサーバー、ポート80遮断環境:DNS-01
1.3 発行前の準備事項
- ドメイン所有権:実際に管理可能なドメインが必要
- DNS設定:ドメインがサーバーのIPに正しく紐付いていること
- ポート80/443の開放:HTTP-01方式ではポート80が外部から到達可能である必要あり
- root権限:証明書のインストールおよびWebサーバー設定の変更に必要
2. Certbotのインストール
CertbotはEFF(Electronic Frontier Foundation)が開発したLet's Encrypt公式クライアントで、証明書の発行と管理を自動化してくれます。
2.1 Ubuntu/Debianのインストール
# snap方式(公式推奨)
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# または apt方式(手軽)
sudo apt update
sudo apt install certbot -y
sudo apt install python3-certbot-nginx -y # Nginxプラグイン
sudo apt install python3-certbot-apache -y # Apacheプラグイン(必要に応じて)
# バージョン確認
certbot --version
2.2 RHEL/Rocky Linux/CentOSのインストール
# EPELリポジトリの有効化(RHEL/CentOS 7)
sudo yum install epel-release -y
sudo yum install certbot python3-certbot-nginx -y
# RHEL 9 / Rocky Linux 9
sudo dnf install epel-release -y
sudo dnf install certbot python3-certbot-nginx -y
# snap方式(全バージョン共通)
sudo dnf install snapd -y
sudo systemctl enable --now snapd.socket
sudo ln -s /var/lib/snapd/snap /snap
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
3. NginxへのSSL証明書適用
3.1 自動設定(最も簡単な方法)
CertbotのNginxプラグインを使えば、証明書発行とNginx設定の変更を一度に処理できます:
# 前提条件:Nginxに該当ドメインのserverブロックが既に存在している必要あり
# 例:server_name example.com www.example.com;
# 証明書の発行 + Nginxの自動設定
sudo certbot --nginx -d example.com -d www.example.com
# 実行すると以下の情報を尋ねられます:
# 1. メールアドレスの入力(有効期限通知の受信用)
# 2. 利用規約への同意(Y)
# 3. EFFニュースレター受信(Nでも可)
# 4. HTTP → HTTPSリダイレクト設定(2番を推奨)
成功すると以下のようなメッセージが表示されます:
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 2026-07-05.
Deploying certificate
Successfully deployed certificate for example.com
Successfully deployed certificate for www.example.com
Your existing server block has been modified to redirect HTTP traffic to HTTPS.
3.2 手動設定(証明書のみ発行)
Nginx設定を自分で書きたい場合は、証明書のみを発行し設定は手動で記述することも可能です:
# webroot方式(Nginxが稼働している状態で)
sudo certbot certonly --webroot -w /var/www/example.com/html \
-d example.com -d www.example.com
# standalone方式(Nginxを一時停止して発行)
sudo systemctl stop nginx
sudo certbot certonly --standalone -d example.com -d www.example.com
sudo systemctl start nginx
# 手動Nginx設定の例
# /etc/nginx/conf.d/example.com.conf
# HTTP → HTTPSリダイレクト
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# HTTPSメイン設定
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# Let's Encrypt 証明書パス
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL 最適設定
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
# HSTS(HTTPS強制)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
root /var/www/example.com/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
# 設定を検証して適用
sudo nginx -t
sudo systemctl reload nginx
4. ApacheへのSSL証明書適用
4.1 自動設定
# Apache SSLモジュールの有効化(Ubuntu/Debian)
sudo a2enmod ssl
sudo a2enmod headers
sudo systemctl reload apache2
# Certbot Apacheプラグインによる自動設定
sudo certbot --apache -d example.com -d www.example.com
4.2 Apacheの手動設定
# /etc/apache2/sites-available/example.com-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/html
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# SSLプロトコル(TLS 1.2以上)
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLSessionTickets off
# OCSP Stapling
SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
# HSTS
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
ErrorLog ${APACHE_LOG_DIR}/example.com-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-ssl-access.log combined
</VirtualHost>
</IfModule>
# HTTP → HTTPSリダイレクト
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
# サイトの有効化
sudo a2ensite example.com-ssl.conf
# 設定を検証して適用
sudo apachectl configtest
sudo systemctl reload apache2
5. ワイルドカード証明書の発行(DNS-01)
ワイルドカード証明書(*.example.com)は、1枚の証明書ですべてのサブドメイン(app.example.com、api.example.comなど)をカバーできるため非常に便利です。ただし、DNS-01チャレンジのみサポートされます。
5.1 手動DNS-01による発行
# 手動DNSチャレンジ
sudo certbot certonly --manual --preferred-challenges=dns \
-d example.com -d "*.example.com"
# Certbotが以下のようなメッセージを出力:
# Please deploy a DNS TXT record under the name:
# _acme-challenge.example.com
# with the following value:
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# 上記TXTレコードをDNS管理パネルに手動で登録
# 登録後、伝播確認(Enterを押す前に)
dig -t txt _acme-challenge.example.com
# DNS伝播が確認できたらEnterを押して検証を進める
digコマンドで先に伝播状況を確認してからEnterを押してください。早すぎると検証に失敗します。
5.2 DNS APIによる自動化(Cloudflareの例)
Cloudflare、Route53、Google Cloud DNSなどを利用している場合、APIで自動化できます:
# Cloudflareプラグインのインストール
sudo snap install certbot-dns-cloudflare
# または
sudo apt install python3-certbot-dns-cloudflare -y
# Cloudflare APIトークンの保存(/root/.secrets/cloudflare.ini)
sudo mkdir -p /root/.secrets
sudo cat > /root/.secrets/cloudflare.ini << 'EOF'
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
EOF
sudo chmod 600 /root/.secrets/cloudflare.ini
# ワイルドカード証明書の自動発行
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d "*.example.com"
# Route53プラグイン(AWS)
sudo snap install certbot-dns-route53
sudo certbot certonly \
--dns-route53 \
-d example.com -d "*.example.com"
# (IAM認証情報が環境変数または ~/.aws/credentials に設定されている必要あり)
6. 証明書の自動更新
Let's Encrypt証明書は90日ごとに更新が必要です。Certbotは自動更新を標準でサポートしています。
6.1 自動更新の確認
# 自動更新のテスト(実際の更新を伴わないシミュレーション)
sudo certbot renew --dry-run
# 強制更新(有効期限まで30日以上残っている場合でも)
sudo certbot renew --force-renewal
# 特定ドメインのみ更新
sudo certbot renew --cert-name example.com
# 自動更新タイマーの状態(systemd)
sudo systemctl status certbot.timer
# cron方式(snap版は自動設定)
systemctl list-timers | grep certbot
6.2 自動更新の仕組み
Certbotはインストール時に自動更新の仕組みを構成します:
- systemdタイマー:
/etc/systemd/system/certbot.timer(snap/最新インストール) - cron:
/etc/cron.d/certbot(aptインストール) - 実行頻度:1日2回(12時間ごと)
- 更新条件:有効期限まで30日以内の証明書のみ実際に更新
# 手動でcronに登録(必要な場合)
sudo crontab -e
# 毎日午前3時に自動更新チェック
0 3 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"
# 更新後に特定のコマンドを実行(hook)
sudo certbot renew --post-hook "systemctl reload nginx"
sudo certbot renew --deploy-hook "systemctl reload nginx"
6.3 更新失敗通知の設定
# 通知メールアドレスの変更
sudo certbot update_account --email new@example.com
# 更新失敗時にスクリプトを実行
# /etc/letsencrypt/renewal-hooks/deploy/notify.sh
#!/bin/bash
echo "Certificate renewed: $RENEWED_DOMAINS" | mail -s "SSL Renewal" admin@example.com
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/notify.sh
7. 証明書管理コマンド
7.1 よく使うCertbotコマンド
# 発行済み証明書の一覧確認
sudo certbot certificates
# 特定の証明書を削除
sudo certbot delete --cert-name example.com
# 証明書の再発行(別のドメインを追加)
sudo certbot certonly --expand -d example.com -d www.example.com -d blog.example.com
# ECDSA鍵の使用(RSAより高速で小さい)
sudo certbot certonly --nginx --key-type ecdsa --elliptic-curve secp384r1 \
-d example.com -d www.example.com
# 特定のメールアドレスで登録
sudo certbot register --email admin@example.com --agree-tos
# 証明書の詳細情報を確認
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -text -noout
# 有効期限の確認
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -dates
7.2 証明書ファイルの構造
| ファイル名 | 説明 |
|---|---|
cert.pem |
サーバー証明書のみ(単体) |
chain.pem |
中間CA証明書チェーン |
fullchain.pem |
サーバー証明書+中間チェーン(Nginx/Apache用) |
privkey.pem |
秘密鍵(絶対に公開禁止!) |
privkey.pemは絶対にGitリポジトリ、共有フォルダ、外部サービスなどにアップロードしてはいけません。漏洩した場合は直ちに証明書を再発行し、既存の証明書を失効(revoke)する必要があります。
8. HTTPS設定の検証と最適化
8.1 オンラインSSLチェックツール
- SSL Labs (Qualys):https://www.ssllabs.com/ssltest/ - 最も権威あるSSLチェックツール。A+等級が目標。
- Mozilla Observatory:https://observatory.mozilla.org/ - 総合的なセキュリティスコア
- testssl.sh:ローカルで実行可能なCLIツール
- SSL Configuration Generator:https://ssl-config.mozilla.org/ - 最適設定を自動生成
# testssl.shでローカル検査
git clone https://github.com/drwetter/testssl.sh.git
cd testssl.sh
./testssl.sh https://example.com
# 証明書チェーンの確認
curl -vI https://example.com 2>&1 | grep -i "SSL\|certificate"
# プロトコル/暗号化の確認
nmap --script ssl-enum-ciphers -p 443 example.com
8.2 A+等級のための追加設定
# Strong DH Parametersの生成(時間がかかる)
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
# Nginx設定への追加
ssl_dhparam /etc/nginx/dhparam.pem;
# セキュリティヘッダー(SSL Labs A+要件)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
8.3 HSTS Preloadへの登録
HSTS preloadに登録すると、サイトに初めてアクセスするユーザーに対してもブラウザが無条件でHTTPSで接続するよう強制できます:
# 登録条件(すべて満たす必要あり)
1. 有効な証明書を保持
2. HTTP → HTTPSリダイレクト
3. すべてのサブドメインでHTTPSを提供
4. HSTSヘッダーに max-age=63072000(2年)以上
5. HSTSヘッダーに includeSubDomains を含める
6. HSTSヘッダーに preload を含める
# 登録サイト:https://hstspreload.org/
9. よくある問題と解決方法
9.1 「Connection refused」エラー
Problem: Failed authorization procedure.
example.com (http-01): urn:ietf:params:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://example.com/.well-known/acme-challenge/xxx: Connection refused
原因:ポート80が外部からアクセス不可
解決:
- ファイアウォールでポート80を許可:
sudo ufw allow 80/tcp - クラウドのSecurity GroupでHTTPを許可
- ドメインが正しいIPを指しているか確認:
dig example.com
9.2 Rate Limit超過
Problem: too many certificates already issued for exact set of domains
原因:Let's Encryptの発行制限に到達
Let's Encryptの主なRate Limit:
- 同じドメインセットに対して週5回の重複発行制限
- 同じ登録済みドメインあたり週50個の証明書
- 検証失敗の試行は1時間あたり5回
解決:
- テスト環境では
--stagingオプションを使用(制限なし) - 時間を置いてから再試行(通常1週間)
- ドメインを追加してセットを変更
# ステージング環境でテスト
sudo certbot --nginx --staging -d example.com
# ステージング証明書は実ブラウザでは信頼されない
# 設定完了後に本番発行:
sudo certbot --nginx --force-renewal -d example.com
9.3 DNS検証の失敗
Problem: DNS problem: NXDOMAIN looking up TXT for _acme-challenge.example.com
原因:DNS TXTレコードが伝播していない
解決:
# TXTレコードの確認
dig -t txt _acme-challenge.example.com
# Google DNSで確認
dig -t txt _acme-challenge.example.com @8.8.8.8
# Cloudflare DNSで確認
dig -t txt _acme-challenge.example.com @1.1.1.1
# すべてで同じ値が出れば伝播完了
9.4 混在コンテンツ(Mixed Content)警告
HTTPSページからHTTPリソース(画像、スクリプトなど)を読み込むとブラウザが警告します。
解決:
- HTML内の
http://を//(プロトコル相対)またはhttps://に変更 - CSPヘッダーによる自動アップグレード:
upgrade-insecure-requests
# Nginxでの自動アップグレード
add_header Content-Security-Policy "upgrade-insecure-requests" always;
9.5 証明書更新の失敗
# 更新ログの確認
sudo journalctl -u certbot.timer
sudo cat /var/log/letsencrypt/letsencrypt.log
# よくある原因
# 1. Webサーバー設定エラー → nginx -t / apachectl configtest
# 2. ファイアウォール遮断 → ufw status / firewall-cmd --list-all
# 3. ディスク容量不足 → df -h
# 4. DNS変更 → dig example.com
# 手動での強制更新
sudo certbot renew --force-renewal --cert-name example.com
10. 実運用チェックリスト
10.1 証明書発行後の確認事項
- ✅ ブラウザアクセス確認:
https://example.comが警告なしで開くか - ✅ 鍵マーク確認:アドレスバーに鍵マークが表示されるか
- ✅ HTTPリダイレクト確認:
http://example.comが自動でHTTPSに遷移するか - ✅ SSL Labs等級の確認:最低A等級、可能ならA+
- ✅ 自動更新のテスト:
certbot renew --dry-runが成功するか - ✅ 証明書有効期限の監視:期限30日前の通知設定
- ✅ バックアップ:
/etc/letsencrypt/ディレクトリの定期バックアップ
10.2 証明書モニタリングスクリプト
#!/bin/bash
# /usr/local/bin/check_ssl_expiry.sh - 証明書有効期限モニタリング
DOMAINS=("example.com" "api.example.com" "blog.example.com")
WARNING_DAYS=30
ALERT_EMAIL="admin@example.com"
for domain in "${DOMAINS[@]}"; do
expiry_date=$(echo | openssl s_client -servername "$domain" \
-connect "$domain:443" 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2)
expiry_epoch=$(date -d "$expiry_date" +%s)
now_epoch=$(date +%s)
days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
echo "$domain: $days_left days remaining"
if [ $days_left -lt $WARNING_DAYS ]; then
echo "WARNING: $domain expires in $days_left days!" | \
mail -s "SSL Expiry Alert: $domain" "$ALERT_EMAIL"
fi
done
# 実行権限の付与とcron登録
sudo chmod +x /usr/local/bin/check_ssl_expiry.sh
# 毎朝9時に実行
sudo crontab -e
# 0 9 * * * /usr/local/bin/check_ssl_expiry.sh
まとめ:Let's Encryptですべてのウェブサイトに HTTPS を
Let's Encryptは無料SSL証明書という概念を超え、ウェブ全体のセキュリティレベルを引き上げたイノベーションです。かつてはコストの問題でHTTPS導入を諦めていた多くのサイトが、いまやすべて安全なHTTPSで提供されるようになり、これはユーザーとサービス提供者双方にとって有益な変化です。
本ガイドで扱った重要ポイントを改めて整理すると:
- Certbotで自動化せよ - 手動の発行と更新はミスの余地が多くあります。Certbotの自動更新を必ず活用してください。
- ワイルドカードはDNS-01で - 複数のサブドメインを運用するならワイルドカード証明書がはるかに便利です。
- モニタリングを設定せよ - 自動更新を設定していても失敗する可能性があるため、有効期限の監視は必須です。
- SSL Labs A+等級を目標に - 単にHTTPSを適用するだけでなく、最適化されたSSL設定まで併せて適用しましょう。
- HSTSは慎重に - 一度有効化すると戻すのが難しいため、すべての設定が完璧な段階で適用してください。
- 秘密鍵は徹底的に保護せよ -
privkey.pemは絶対に外部に漏らしてはいけません。
Let's EncryptとCertbotを活用すれば、数分でプロダクションレベルのHTTPSを構築できます。本ガイドの例を皆さんの環境に合わせて適用し、安全なWebサービスの運用にお役立てください。