タイトル: Let's Encryptを利用したSSL化 (nginx編)
SEOタイトル: Let's Encrypt + Nginx SSL 化完全ガイド
| この記事の要点 |
|
前提条件
| 項目 | 必須条件 |
|---|---|
| ドメイン | 公開可能な FQDN(例: example.com) |
| DNS | A / AAAA レコードがサーバ IP を指している |
| ポート | 80 / 443 を開放(HTTP-01 チャレンジで 80 必須) |
| Nginx | 稼働中で http://example.com が反応する |
| root 権限 | sudo 利用可 |
1. certbot のインストール
snap(推奨・最新版)
# snapd を入れる(Ubuntu/Debian/CentOS で共通)
sudo apt install -y snapd # Ubuntu/Debian
sudo dnf install -y snapd # RHEL/AlmaLinux
# certbot をインストール
sudo snap install --classic certbot
# シンボリックリンク
sudo ln -s /snap/bin/certbot /usr/bin/certbot
certbot --version
apt(Ubuntu/Debian)
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
dnf(RHEL/AlmaLinux 9)
sudo dnf install -y epel-release
sudo dnf install -y certbot python3-certbot-nginx
2. 証明書取得 + Nginx 自動設定
certbot は Nginx 設定を読み取り、ssl_certificate 等を自動で書き加えてくれます:
sudo certbot --nginx \
-d example.com -d www.example.com \
--email admin@example.com \
--agree-tos \
--redirect \
--no-eff-email
# オプション意味:
# --nginx : Nginx プラグイン経由で自動設定
# -d : 対象ドメイン(複数可)
# --email : 失効通知メール
# --agree-tos : 利用規約同意
# --redirect : HTTP→HTTPS 強制リダイレクトも追加
# --no-eff-email : EFF からのメール拒否
取得される証明書
/etc/letsencrypt/live/example.com/
├── cert.pem ← サーバ証明書
├── chain.pem ← 中間証明書
├── fullchain.pem ← サーバ + 中間(Nginx で使う)
├── privkey.pem ← 秘密鍵
└── README
有効期限: 取得から 90 日
3. 自動更新の設定
snap 版 certbot はsystemd timer で自動更新を既に登録済み。手動で確認するなら:
# 自動更新タイマー確認(snap 版)
sudo systemctl list-timers | grep certbot
# certbot.timer snap.certbot.renew.service
# 手動で更新確認(実際には更新しない、dry run)
sudo certbot renew --dry-run
# 強制更新(テスト用)
sudo certbot renew --force-renewal
# 期限まで残り何日か
sudo certbot certificates
cron でやる場合(apt 版)
# /etc/cron.d/certbot に標準で入る
sudo cat /etc/cron.d/certbot
# 自前で書く例
sudo tee /etc/cron.d/certbot-renew >/dev/null <<'EOF'
0 3 * * * root certbot renew --quiet --post-hook "systemctl reload nginx"
EOF
4. Nginx 設定の中身を見る
certbot が自動で書き換えた後の典型的な設定:
# /etc/nginx/sites-available/example.com
# HTTPS
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf; # certbot 標準
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# セキュリティヘッダ
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
root /var/www/html;
index index.php;
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
# HTTP → HTTPS リダイレクト(certbot --redirect が自動追加)
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
if ($host = www.example.com) { return 301 https://$host$request_uri; }
if ($host = example.com) { return 301 https://$host$request_uri; }
return 404;
}
5. 動作確認
# 設定構文チェック
sudo nginx -t
# リロード
sudo systemctl reload nginx
# ローカルで確認
curl -I https://example.com
# HTTP/2 200
# strict-transport-security: max-age=31536000; includeSubDomains
# HTTP リダイレクト確認
curl -I http://example.com
# HTTP/1.1 301 Moved Permanently
# location: https://example.com/
# SSL Labs で評価(A+ 目指す)
# https://www.ssllabs.com/ssltest/analyze.html?d=example.com
6. ワイルドカード証明書(DNS-01 チャレンジ)
*.example.com のような証明書は HTTP-01 では取れないため、DNS-01 認証が必須:
# 対話モード(DNS に TXT レコードを手動追加)
sudo certbot certonly --manual \
--preferred-challenges dns \
-d "*.example.com" -d "example.com"
# Cloudflare API 経由で自動化
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare
# API トークンを設定
echo "dns_cloudflare_api_token = YOUR_CLOUDFLARE_TOKEN" | \
sudo tee /etc/letsencrypt/cloudflare.ini
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d "*.example.com" -d "example.com"
# Route53 / Google DNS / DigitalOcean 等も同様にプラグインあり
7. よくあるトラブル
| 症状 | 原因 | 対処 |
|---|---|---|
| Timeout during connect (port 80) | FW で 80 が閉じている | セキュリティグループ / iptables 開放 |
| DNS problem: NXDOMAIN | A レコード未設定 | DNS 設定 + 伝搬待ち |
| Too many failed authorizations | 同一ドメインでリトライ過多 | 1 時間〜数時間待つ |
| Rate limited (1 週 50 件) | 1 週間の取得上限 | staging 環境でテスト後本番 |
| HSTS 後に証明書失効 | 期限切れで HTTPS 不可、HSTS で HTTP も不可 | HSTS を一時的に max-age=0、再発行 |
staging 環境でテスト
# 本番のレート制限を消費せずにテスト
sudo certbot certonly --nginx \
--staging \
-d example.com
# 取得後、本物に置き換えるなら
sudo certbot certificates # staging の証明書を確認
sudo certbot delete --cert-name example.com
sudo certbot --nginx -d example.com # 本番再取得
8. 強固な SSL 設定(Mozilla Intermediate)
# /etc/nginx/conf.d/ssl.conf
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:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 1.1.1.1 8.8.8.8 valid=60s;
resolver_timeout 2s;
FAQ
Q: 90 日の有効期限を延ばせる?
A: できません。Let's Encrypt の方針として 90 日固定。自動更新を必ず設定してください。
Q: 商用利用してよい?
A: OK。サブスクリプション・商用サイト・SaaS どれも問題なし。EV 証明書が必要な金融サイトのみ別途検討。
Q: 内部用ドメイン (社内 IP) でも使える?
A: ドメイン所有確認が必要なので、外部に DNS と HTTP を露出するか、DNS-01 認証で TXT を入れる必要があります。完全クローズドなら自己署名 / プライベート CA を検討。