Nginx SSL/TLS 証明書管理

作成日:
Nginx SSL TLS HTTPS infrastructure Certbot

概要

Nginx で HTTPS を有効にするには、SSL/TLS 証明書の取得と設定が必要。Let’s Encrypt + Certbot を使えば無料で自動化可能。

証明書管理の基本概念

SSL/TLS 証明書とは

  • 公開鍵証明書: サーバーの身元を証明し、暗号化通信を実現
  • 認証局(CA): 証明書を発行する第三者機関
  • Let’s Encrypt: 無料で証明書を発行する認証局

必要なファイル

ファイル説明
fullchain.pemサーバー証明書 + 中間証明書
privkey.pem秘密鍵(厳重に管理)
chain.pem中間証明書のみ
cert.pemサーバー証明書のみ

Certbot による証明書取得

インストール

# Ubuntu/Debian
sudo apt update
sudo apt install -y certbot python3-certbot-nginx

取得方法の比較

方法説明適したケース
Nginx プラグインNginx 設定を自動更新最も簡単、推奨
Webroot既存のドキュメントルートを使用Nginx 設定を手動管理したい
Standalone一時的に :80 を占有Nginx 未起動時
DNS-01DNS レコードで認証ワイルドカード証明書

Nginx プラグイン方式(推奨)

# 基本的な取得コマンド
sudo certbot --nginx -d example.com -d www.example.com

# 対話なし(自動化向け)
sudo certbot --nginx -d example.com \
  --non-interactive \
  --agree-tos \
  --email admin@example.com

このコマンドは以下を自動で行う:

  1. 証明書の取得
  2. Nginx 設定に SSL 設定を追加
  3. HTTP → HTTPS のリダイレクト設定

Webroot 方式

# 証明書のみ取得(Nginx 設定は手動)
sudo certbot certonly --webroot \
  -w /var/www/html \
  -d example.com

Nginx での SSL 設定

基本設定

server {
    listen 80;
    server_name example.com;
    
    # HTTP → HTTPS リダイレクト
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    # 証明書のパス
    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_prefer_server_ciphers off;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;

    # HSTS(オプション、慎重に)
    # add_header Strict-Transport-Security "max-age=63072000" always;

    root /var/www/example.com;
    index index.html;
}

複数サイトの証明書管理

# site-a.conf
server {
    listen 443 ssl http2;
    server_name site-a.example.com;
    
    ssl_certificate     /etc/letsencrypt/live/site-a.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/site-a.example.com/privkey.pem;
    
    root /var/www/site-a;
}

# site-b.conf
server {
    listen 443 ssl http2;
    server_name site-b.example.com;
    
    ssl_certificate     /etc/letsencrypt/live/site-b.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/site-b.example.com/privkey.pem;
    
    root /var/www/site-b;
}

ワイルドカード証明書(DNS-01)

# Cloudflare DNS を使用する例
sudo apt install python3-certbot-dns-cloudflare

# API トークンを設定
cat > ~/.secrets/cloudflare.ini << 'EOF'
dns_cloudflare_api_token = YOUR_API_TOKEN
EOF
chmod 600 ~/.secrets/cloudflare.ini

# 証明書取得
sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
  -d "*.example.com" \
  -d example.com

ワイルドカード証明書のメリット:

  • 1つの証明書で全サブドメインをカバー
  • 新しいサブドメイン追加時に証明書更新不要

自動更新

仕組み

Certbot は systemd タイマーで自動更新を行う(APT 版)。

# タイマーの確認
systemctl status certbot.timer
systemctl list-timers | grep certbot

# 手動テスト(ドライラン)
sudo certbot renew --dry-run

更新後のリロード

Nginx プラグインで取得した場合、更新後に自動でリロードされる。

Webroot 方式の場合は、更新フックを設定:

# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/bash
systemctl reload nginx
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

証明書ファイルの配置場所

なぜ VPS/サーバーに証明書を配置するのか

TLS/SSL 終端の仕組み:

  • HTTPS 通信では、クライアント(ブラウザ)とサーバー間で暗号化が行われる
  • この暗号化を解除(終端)するのは、秘密鍵を持つサーバー
  • 秘密鍵はサーバー上になければ暗号化通信を復号できない

証明書配置が必要な理由:

  1. 暗号化の復号: 秘密鍵がないと HTTPS リクエストを処理できない
  2. 身元証明: 証明書でドメイン所有者であることを証明
  3. リアルタイム参照: TLS ハンドシェイク時に証明書を提示する必要

CDN/クラウドサービス利用時:

  • Cloudflare などの CDN を使う場合、CDN がエッジで TLS 終端する
  • この場合、CDN 側で証明書を管理し、オリジンサーバーとの間は別の暗号化
  • それでもオリジンサーバー側でも証明書を持つのが推奨(エンドツーエンド暗号化)

Let’s Encrypt のファイル構造

/etc/letsencrypt/
├── live/
│   └── example.com/
│       ├── fullchain.pem  → ../archive/example.com/fullchain1.pem
│       ├── privkey.pem    → ../archive/example.com/privkey1.pem
│       ├── cert.pem       → ../archive/example.com/cert1.pem
│       └── chain.pem      → ../archive/example.com/chain1.pem
├── archive/
│   └── example.com/
│       ├── fullchain1.pem
│       ├── privkey1.pem
│       ├── cert1.pem
│       └── chain1.pem
└── renewal/
    └── example.com.conf
  • live/ はシンボリックリンク → 更新後も同じパスで参照可能
  • archive/ に履歴が残る
  • renewal/ に更新設定が保存される

セキュリティのベストプラクティス

秘密鍵の保護

# パーミッション確認
ls -la /etc/letsencrypt/live/example.com/

# 秘密鍵は root のみ読み取り可能にする
sudo chmod 600 /etc/letsencrypt/live/example.com/privkey.pem

SSL 設定の強化

# 推奨設定(Mozilla SSL Configuration Generator 参照)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

SSL 設定のテスト

# SSL Labs でテスト
# https://www.ssllabs.com/ssltest/

# コマンドラインでテスト
openssl s_client -connect example.com:443 -servername example.com

トラブルシューティング

よくある問題

証明書が見つからない:

# パスを確認
sudo ls -la /etc/letsencrypt/live/
sudo certbot certificates

更新に失敗:

# ログを確認
sudo cat /var/log/letsencrypt/letsencrypt.log

# 手動で更新を試行
sudo certbot renew --force-renewal

Nginx が起動しない:

# 設定をテスト
sudo nginx -t

# よくある原因:証明書パスの間違い、パーミッション

Traefik との比較

観点Nginx + CertbotTraefik
設定方法手動(設定ファイル)自動(Docker ラベル)
証明書取得Certbot コマンド自動(設定のみ)
更新systemd タイマー自動(内蔵)
複雑さ中程度低い(Docker 環境)
柔軟性高いDocker 環境に最適化

Docker 環境では Traefik の方が簡単だが、非 Docker 環境や細かいチューニングが必要な場合は Nginx + Certbot が適している。

関連トピック