LinuxでSSL/TLS証明書を生成とインストールする完全ガイド

LinuxでHTTPSを構成するときは、公開サイト用の認証局発行証明書と、手元の検証用自己署名証明書を分けます。OpenSSLで証明書ファイルを作っただけでは、ブラウザーが信頼する公開証明書にはなりません。この記事ではSAN、秘密鍵、証明書チェーン、Apache/Nginxへの反映、更新後の確認まで順に整理します。

実際に管理権限を持つ検証環境から作業し、本番の設定・証明書・鍵を上書きする前に復旧手順を準備してください。以下のexample.comは説明用です。公開証明書の申請では、自分が管理する実際のドメインへ置き換えます。

目次

証明書・秘密鍵・CSR・チェーンの違い

秘密鍵はサーバー側で保管する機密情報です。CSR(証明書署名要求)には公開鍵や申請情報を含め、認証局へ送ります。証明書は名前と公開鍵を結び付けるもので、TLSはその認証と鍵交換を使って通信を保護します。DV・OV・EVは確認する情報の違いで、証明書があるだけでサイト内容や運営の安全性を保証するものではありません。

中間証明書はサーバー証明書から信頼された認証局へつなぐためのものです。通常、配信ファイルはサーバー証明書を先頭に中間証明書を続けます。秘密鍵をこのチェーンへ混ぜたり、リポジトリ・チャット・公開Web領域へ置いたりしないでください。HTTPSを導入するだけで検索順位やアクセス増が保証されるわけでもありません。

OpenSSLはディストリビューションの保守済みパッケージを使う

openssl version -a
command -v openssl

古いOpenSSL 1.1.1kを「最新版」としてダウンロードし、sudo make installでOSのライブラリを置き換える手順は使いません。OS提供パッケージは独自に修正がバックポートされることもあるため、単純な上流版番号だけで安全性を判断せず、ディストリビューションの保守状況を確認します。

# Debian / Ubuntu系
sudo apt update
sudo apt install openssl

# Fedora / RHEL系の対応環境
sudo dnf install openssl

実際のOSに合う一方だけを実行します。ソースビルドが必要な場合は、公式の対応版と署名・検証方法、OS標準ライブラリから分離した配置、更新責任を設計します。証明書作成の入門作業としてシステムOpenSSLの置換は必要ありません。

公開サイトではACME/Certbotなどの正式な発行手順を選ぶ

公開サイトには、管理するドメインの所有・制御を認証局の手順で確認して発行を受けます。Certbotは対応するWebサーバープラグイン等を使って取得・更新できますが、OSと導入方法でパッケージや自動更新の仕組みが異なります。既存の証明書管理ツールと二重運用せず、公式のインストール案内を使います。

# 導入済みで、対象プラグインと設定が確認できている場合の例
sudo certbot --nginx -d example.com
# Apacheを使う環境では上の代わりにこちら
sudo certbot --apache -d example.com

これは取得だけでなくWebサーバー設定を変更し得るコマンドです。設定のバックアップと差分確認を行います。HTTP-01なら認証局から対象ドメインのHTTP検証先へ到達できること、DNS-01なら必要なTXTレコードを設定できることなど、選ぶ方式の要件を確認してください。公開用にlocalhostを申請する手順ではありません。DNS認証用のAPI資格情報は最小権限で保護します。

検証用:SAN付き自己署名証明書を作る

以下はlocalhostと127.0.0.1だけを対象とするOpenSSL 3系のローカル検証例です。既存の鍵と混ざらない専用の空ディレクトリで実行します。-noencは鍵を暗号化しない指定なので、権限と保管場所を厳格に管理します。本番の鍵管理方針を置き換える例ではありません。

umask 077
openssl req -x509 -newkey rsa:2048 -noenc   -keyout localhost.key -out localhost.crt -sha256 -days 7   -subj '/CN=localhost'   -addext 'subjectAltName=DNS:localhost,IP:127.0.0.1'   -addext 'basicConstraints=critical,CA:FALSE'   -addext 'extendedKeyUsage=serverAuth' 

接続名はCommon Nameだけに依存せず、SAN(Subject Alternative Name)へ設定します。IPアドレスへ接続するならDNS名ではなくIP型のSANが必要です。自己署名証明書は標準の信頼ストアで信頼されないため、警告が出ても「正常だから無視して進む」という運用にしません。検証クライアントへ対象を明示する方法や、組織管理の内部CAを使う方法を選びます。

openssl x509 -in localhost.crt -noout -subject -issuer -dates -ext subjectAltName
openssl verify -CAfile localhost.crt -verify_hostname localhost localhost.crt
openssl verify -CAfile localhost.crt -verify_hostname wrong.example localhost.crt
openssl x509 -in localhost.crt -noout -checkend 86400

このローカル例はOpenSSL 3.5.7で作成・SAN表示・正しいホスト名の検証・誤ったホスト名の失敗・1日以内に期限切れにならないことを確認しました。誤った名前の検証は失敗することが期待結果です。-CAfileで自作証明書を明示したテストであり、公開ブラウザーの信頼や本番サーバー動作を検証した意味ではありません。生成した検証用鍵はテスト終了後に削除しています。

手動で認証局へ依頼する場合のCSR

認証局がCSRを求める場合は、指定された鍵方式・SAN・組織情報の要件に従います。次は暗号化RSA鍵とSANを含むCSRの例です。対話で入力するパスフレーズをコマンド引数や履歴へ書かないでください。既存ファイルへ上書きしないよう専用ディレクトリで実行します。

umask 077
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -aes-256-cbc -out server.key
openssl req -new -key server.key -out server.csr   -subj '/CN=example.com'   -addext 'subjectAltName=DNS:example.com,DNS:www.example.com'
openssl req -in server.csr -noout -text -verify

CSRへSANを指定しても、発行された証明書へ必ずそのまま採用される保証はありません。認証局から受領した証明書のSAN・期限・用途を再確認します。CSRを自分で署名し直すことは公開証明書の更新ではありません。暗号化鍵はサーバーの無人起動時に解錠が必要になるため、サービス側の対応と鍵管理を設計します。

Nginxへ設定する例:fullchainと秘密鍵を分ける

次は既存serverブロックに組み込むTLS関連部分です。Webサイト全体の設定ではありません。Certbotが管理する証明書名がexample.com-0001などの場合もあるため、certbot certificatesで実際のパスを確認します。

server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    # 既存のroot、locationなどはサイト要件に従って保持する
}

証明書ファイルはサーバー証明書が先、続いて中間証明書です。秘密鍵は起動に必要なプロセスだけが読めるようにし、エラー解消のためにchmod 777や全体読み取り可へ広げません。コンテナや非root構成では読取主体が異なります。

sudo nginx -t && sudo systemctl reload nginx

systemdでnginxサービスを運用している場合の例です。構文テストが失敗したらリロードせず、元の設定との違いとエラーを確認します。実際の証明書配信まで成功したとは限らないので、後述の外部確認も行います。

Apacheへ設定する例

Apache 2.4.8以降ではSSLCertificateFileに中間証明書を含むファイルを指定できます。古いSSLCertificateChainFileの手順を新しい構成へ機械的に追加しません。SSLモジュールと443番ポートの待受け、既存VirtualHostも確認します。

<VirtualHost *:443>
    ServerName example.com
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    # DocumentRootなど既存サイト設定を保持する
</VirtualHost>

構文テストとサービス名はディストリビューションで異なります。Debian/Ubuntu系でapache2を使う場合の例は次のとおりです。RHEL系ではhttpdやapachectlなど実環境の手順を確認し、両方を続けて実行しません。

sudo apache2ctl configtest && sudo systemctl reload apache2

更新は「再発行・配置・読み込み・実配信確認」まで行う

証明書の有効期間を「いつも365日」など固定値で考えず、現在の証明書のnotAfterと認証局の条件に従います。Certbotの導入時にtimerなどが設定されている場合は重複cronを足す前に確認してください。

sudo certbot certificates
sudo certbot renew --dry-run

dry-runはテスト用の更新確認です。成功しても本番証明書を更新した意味ではありません。更新後の反映がプラグインで処理されるか、成功時のdeploy hookが必要かを確認します。deploy hookは通常のdry-runでは実行されないため、フックの検証範囲も分けて記録します。手動DNS認証は自動化フックなしでは無人更新できない場合があります。

更新失敗、期限接近、Webサーバーの読み込み失敗を監視します。別の場所へ証明書をコピーする構成では、更新した元ファイルだけでなく配信先への反映も必要です。暗号化鍵の入力待ちや証明書と鍵の不一致で無人処理が止まらないか確認します。

実際に配信されている証明書を確認する

openssl s_client -connect example.com:443 -servername example.com   -verify_hostname example.com -verify_return_error -showcerts </dev/null

SNI用の-servernameとホスト名検証用の-verify_hostnameは目的が異なります。-showcertsで表示できたというだけでは検証成功ではありません。信頼ストア、名前、有効期間、検証エラーを確認します。内部CAの場合は承認済みCAファイルを-CAfileで指定し、検証を無効化して成功扱いにしないでください。

CDNやロードバランサーが前段にある場合、外部に見える証明書はオリジンサーバーのものとは限りません。対象の各層を分けて確認します。SSL Labs SSL Testなど第三者サービスへ検査を依頼する場合は、対象ホスト名を外部へ渡すことと、公開サービス向けであることを確認してください。内部ホストを無断で送信しません。

よくある問題と切り分け

名前の不一致ならアクセスしたホスト名とSAN、信頼されない場合は発行元と中間証明書、期限切れなら更新履歴と配信側の読み込み、起動失敗なら鍵との組合せ・ファイル権限・設定構文を確認します。中間証明書の欠落は、手元のブラウザーだけで再現しないこともあります。

ログは運用方式に合わせてjournalctl -u nginx、journalctl -u apache2、または設定で指定されたerror logを確認します。秘密鍵や認証情報をログへ出さず、複数の強い変更を同時に行わないでください。SELinuxが原因の可能性があっても無効化で済ませず、正しい配置・ラベル・ポリシーを管理者が確認します。

公式資料

OpenSSLのリリース・保守方針 / openssl req / openssl s_client / NginxのHTTPS設定 / Apache mod_ssl / Certbot User Guide

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次