2026年5月24日
2026年5月24日
TLS 1.3への対応と移行方法(Nginx・Apacheの設定と古いプロトコルの止め方)
TLS 1.3 への対応は、多くのサーバーでは「OpenSSL のバージョンを確認し、Web サーバーの許可プロトコルに TLSv1.3 を加える」だけで済みます。難しいのはその後の「TLS 1.2 以前をいつ止めるか」の判断です。この記事では、現状の確認、Nginx と Apache での有効化、ログを使って古いプロトコルの利用状況を測る方法、移行で起きやすいトラブルまでを順に説明します。
TLS 1.3 で何が変わるのか
TLS 1.3 は 2018 年に RFC 8446 として標準化されたプロトコルで、TLS 1.2 と比べて主に次の点が改善されています。
- ハンドシェイクが短い:接続の確立に必要な往復が減り、初回接続の待ち時間が短くなる
- 弱い暗号方式の削除:RSA 鍵交換、CBC モード、SHA-1 など、問題が指摘されてきた方式が仕様から外され、設定ミスで弱い暗号が使われる余地が小さい
- 前方秘匿性が標準:鍵交換は常に一時鍵(ECDHE など)を使うため、将来サーバーの秘密鍵が漏れても過去の通信を復号されにくい
- 証明書の暗号化:ハンドシェイクの途中から暗号化されるため、サーバー証明書が平文で流れない
一方、TLS 1.0 と 1.1 は 2021 年の RFC 8996 で正式に非推奨となり、主要ブラウザもすでに接続を受け付けていません。現在の現実的な目標は「TLS 1.2 と 1.3 を有効にし、1.1 以前は止める」構成で、TLS 1.3 だけに絞るのは利用者や接続元を把握できている場合に限るのが無難です。
現状を確認する
サーバーが TLS 1.3 を話せるか
TLS 1.3 を使うには、Web サーバーが OpenSSL 1.1.1 以降(または同等の TLS ライブラリ)とともにビルドされている必要があります。
openssl version
nginx -V 2>&1 | grep -i openssl # "built with OpenSSL 3.x" などと表示される
apachectl -V # Apache 本体のバージョン
Apache は 2.4.36 以降で TLS 1.3 に対応しています。現在サポートが続いている主要ディストリビューションの標準パッケージであれば、多くはこの条件を満たしています(2026年10月現在)。古い OS を使い続けている場合は、Web サーバーだけを入れ替えるより OS の更新を計画したほうが、セキュリティ更新の面でも安全です。
外から実際の接続を確かめる
# TLS 1.3 で接続できるか
echo | openssl s_client -connect example.com:443 -servername example.com -tls1_3 2>/dev/null \
| grep -E "Protocol|Cipher"
# TLS 1.2 / 1.1 で接続できるか(1.1 は失敗するのが望ましい)
echo | openssl s_client -connect example.com:443 -servername example.com -tls1_2 2>/dev/null | grep Protocol
echo | openssl s_client -connect example.com:443 -servername example.com -tls1_1 2>&1 | tail -3
# curl で確認
curl -sv --tlsv1.3 https://example.com/ -o /dev/null 2>&1 | grep -E "SSL connection|TLSv"
手元の OpenSSL 3 系では、セキュリティレベルの設定によって -tls1_1 そのものがクライアント側で使えず失敗することがあります。その場合は「サーバーが拒否した」のか「手元が送れなかった」のかが区別できないため、nmap の ssl-enum-ciphers スクリプトや testssl.sh、Qualys SSL Labs などの外部診断も併用すると判断しやすくなります。
Nginx で有効にする
server {
listen 443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# TLS 1.2 用の暗号スイート(TLS 1.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;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
}
ここでつまずきやすいのが **ssl_ciphers は TLS 1.3 の暗号スイートを変えない**という点です。OpenSSL では TLS 1.3 の暗号スイートは別枠で管理されていて、既定値(AES-GCM と ChaCha20-Poly1305 の組み合わせ)のままで安全とされています。変更が必要な特別な理由がなければ、TLS 1.3 側は既定のままにしておくのがおすすめです。どうしても変える場合は、新しい Nginx で使える ssl_conf_command Ciphersuites ... で指定します。
ssl_protocols は、同じ IP とポートを共有する複数の server ブロックでは既定サーバーの値が使われることがあります。サイトごとに違う値を書くのではなく、http ブロックにまとめて書くと混乱を防げます。
暗号スイートの具体的な並びは、Mozilla の SSL Configuration Generator で「Intermediate」を選ぶと、TLS 1.2 と 1.3 の両対応の推奨値を Web サーバーとバージョンに合わせて出力できます。上の例はその考え方に沿ったものですが、採用前に最新の推奨値と見比べてください。
sudo nginx -t && sudo systemctl reload nginx
0-RTT(early data)は慎重に
TLS 1.3 には、再接続時に最初のパケットからデータを送れる 0-RTT という機能があり、Nginx では ssl_early_data on; で有効にできます。ただし 0-RTT のデータは第三者に再送(リプレイ)されうるため、ログインやフォーム送信、決済のように副作用のある処理を受けるサイトでは危険があります。WordPress のように POST を受けるサイトでは、効果とリスクを理解したうえでなければ無効のまま(既定)にしておくのが安全です。
Apache で有効にする
# mods-enabled/ssl.conf など、全体に効く場所に書くのがおすすめ
SSLProtocol -all +TLSv1.2 +TLSv1.3
# TLS 1.2 用
SSLCipherSuite 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
SSLHonorCipherOrder off
SSLSessionTickets off
Apache でも、SSLCipherSuite を通常どおり書いた場合は TLS 1.2 以前に対する指定になります。TLS 1.3 の暗号スイートを変えたいときは SSLCipherSuite TLSv1.3 ... のようにプロトコルを先頭に付けて別に指定しますが、Nginx と同じく既定のままで問題ないことがほとんどです。
SSLProtocol を VirtualHost ごとに書き分けると、名前ベースの仮想ホストでは期待どおりに効かない場合があります。全体設定に1か所だけ書く形にそろえてください。
sudo apachectl configtest && sudo systemctl reload apache2 # RHEL系は httpd
古いプロトコルを止める前にログで測る
TLS 1.3 を有効にすること自体は、古いクライアントに影響しません。影響が出るのは TLS 1.2 以前を止めるときです。止める前に、どのくらいの接続が古いプロトコルを使っているかをアクセスログで確かめておくと、判断の根拠になります。
# Nginx: http ブロック
log_format tls '$ssl_protocol $ssl_cipher $remote_addr [$time_local] '
'"$request" $status "$http_user_agent"';
access_log /var/log/nginx/tls.log tls;
# Apache
LogFormat "%{SSL_PROTOCOL}x %{SSL_CIPHER}x %h %t \"%r\" %>s \"%{User-agent}i\"" tls
CustomLog ${APACHE_LOG_DIR}/tls.log tls
数日から数週間ためたら、プロトコルごとの件数を集計します。
awk '{print $1}' /var/log/nginx/tls.log | sort | uniq -c | sort -rn
プロトコル名を行の先頭に出しているので、1列目を数えるだけで集計できます。集計で TLSv1.2 の接続が残っている場合、その相手を User-Agent や接続元 IP から確認します。古いスマートフォンやゲーム機などの閲覧者のほか、決済サービスからの通知、外部の監視サービス、社内システムからの API 呼び出しといった、ブラウザ以外の接続元が見つかることがあります。こうした相手が TLS 1.2 にしか対応していない場合、1.2 を止めると連携が止まります。
移行で起きやすいトラブル
- CDN を使っていて設定が反映されない:Cloudflare などの CDN を経由している場合、閲覧者との TLS は CDN 側で終わります。閲覧者向けの最低 TLS バージョンや TLS 1.3 の有効化は CDN の管理画面で設定し、オリジンの設定は CDN からオリジンへの接続にだけ効きます。設定項目の名称はサービスごとに異なり、変更されることもあるため、各社の最新ドキュメントで確認してください
- ロードバランサーで TLS を終端している:クラウドのロードバランサーでは、許可するプロトコルを「セキュリティポリシー」のような単位で選ぶことが多く、Web サーバーの設定は関係しません
- プロキシ・検査装置との相性:企業ネットワークの TLS 検査装置の一部は、TLS 1.3 の扱いに問題を抱えていたことがあります。特定の拠点からだけ接続できない場合は、その経路の装置も疑ってください
- WordPress から外部への通信:プラグインの更新確認や外部 API への接続は、サーバーの PHP と OpenSSL(cURL)が行います。Web サーバーの設定とは別に、PHP の OpenSSL のバージョンも
php -i | grep -i opensslで確認しておくと安心です
設定を変更する前には、現在の設定ファイルをコピーしてから作業し、可能であれば検証環境で試してから本番に反映してください。ブラウザだけでなく、curl や外部診断で再確認するところまでを1つの作業と考えると、見落としが減ります。
まとめ
- TLS 1.3 は OpenSSL 1.1.1 以降を使う Web サーバーなら設定1行で有効にでき、TLS 1.2 と併用するのが現実的な構成
- Nginx の
ssl_ciphers、Apache のSSLCipherSuiteは通常 TLS 1.2 以前にしか効かない。TLS 1.3 の暗号スイートは既定のままでよい - 0-RTT はリプレイの危険があるため、POST を受ける WordPress では有効にしないのが無難
- TLS 1.2 を止める前に、ログに
$ssl_protocolなどを出して接続元を確かめる。決済通知や監視など、ブラウザ以外の接続元に注意する - CDN やロードバランサーを使っている場合は、閲覧者向けの TLS 設定はそちらで行う