※本記事にはアフィリエイト広告(PR)を含みます。
社内の監視システムや管理コンソールにアクセスすると、ブラウザが「この接続ではプライバシーが保護されません」「証明書が信頼されていません」と警告を出す場面は、インフラ運用をしていれば一度は目にする。詳細設定から「安全でないページに移動」をクリックして終わり、という運用も珍しくないが、褒められた状態ではない。
本稿では、検証環境や社内クローズドなシステムを前提に、OpenSSLで自己署名証明書(またはプライベートCA)を作りHTTPS化する手順と、押さえるべきSAN(Subject Alternative Name)の要点、クライアントに証明書を信頼させる方法、本番環境で自己署名を避けるべき理由を整理する。
自己署名証明書とは何か、どんな場面で使うか
自己署名証明書とは、外部の認証局(CA)ではなく自分の秘密鍵で自分自身の証明書に署名したものだ。証明書チェーンをたどっても信頼されたCAに行き着かないため、ブラウザやOSは「知らない発行者の証明書」と判断し警告を出す。証明書が壊れているのではなく、「誰も保証していない証明書」であることを正直に警告しているだけである。
妥当な用途は、インターネットに公開しない検証・開発環境や、社内の管理コンソール・APIサーバなど、アクセスする相手が限定され証明書を配布・管理できる範囲に閉じている場合だ。不特定多数が使う公開サービスや、外部の取引先・顧客が接続するシステムには向かない。警告を都度無視させる運用になり、フィッシングサイトの警告と見分けがつかなくなる副作用もある。
OpenSSLで作る
OpenSSLでの作り方は大きく二つある。コマンド一発で秘密鍵と自己署名証明書をまとめて作る方法と、自前のプライベートCAでサーバ証明書に署名する方法だ。前者は手軽だが証明書ごとに信頼設定が必要になる。後者は最初の手間はかかるが、CAのルート証明書さえクライアントに信頼させておけば、以降発行するサーバ証明書は個別対応が要らない。複数システムをHTTPS化するなら後者の方が結局は楽になることが多い。
1本だけ素早く作る場合
検証用に1台だけ確認したいなら、秘密鍵と自己署名証明書をまとめて生成できる。ポイントは、CN(コモンネーム)だけでなくSAN(subjectAltName)にホスト名やIPアドレスを明示することだ。今のブラウザはCNを見ておらず、SANに書かれた名前でしか一致確認をしない。Google Chromeは2017年のバージョン58でCNベースのホスト名照合を廃止し、Firefoxも同様の対応を先行していた。SANのない証明書は、警告が「信頼されていない」から「ホスト名が一致しない」に変わるだけなので、必ずSANを入れる。
openssl req -x509 -newkey rsa:2048 -nodes -sha256 \ -keyout server01.example.local.key \ -out server01.example.local.crt \ -days 825 \ -subj "/CN=server01.example.local" \ -addext "subjectAltName=DNS:server01.example.local,IP:192.0.2.10"
-addextでSANを直接指定できるのはOpenSSL 1.1.1以降の機能で、現行の主要Linuxディストリビューションなら標準で使える。より古い環境では[req]・[v3_req]セクションを持つ設定ファイルを-configと-extensionsで読み込ませる。自己署名やプライベートCA発行の証明書に公的CAのような有効期間上限規制はないため、-daysは運用上更新を忘れにくい範囲(825日や1095日など)で決めればよい。
プライベートCAを立てて署名する場合
複数サーバをHTTPS化するなら、まず自分たちのプライベートCAを作る。CAの秘密鍵とルート証明書は長めの有効期限で一度だけ作ればよい。
openssl genrsa -out ca.key 4096 openssl req -x509 -new -key ca.key -sha256 -days 3650 \ -subj "/CN=Example Internal Root CA" \ -out ca.crt
次に、サーバごとに秘密鍵とCSR(証明書署名要求)を作る。
openssl genrsa -out server01.example.local.key 2048 openssl req -new -key server01.example.local.key \ -subj "/CN=server01.example.local" \ -out server01.example.local.csr
SANはCA署名時に明示するのが確実なので、拡張定義ファイル(san.cnf)にSANを書いておく。
[v3_req] subjectAltName = DNS:server01.example.local, IP:192.0.2.10
このCA(ca.crt/ca.key)でCSRに署名し、サーバ証明書を発行する。
openssl x509 -req -in server01.example.local.csr \ -CA ca.crt -CAkey ca.key -CAcreateserial \ -out server01.example.local.crt -days 825 -sha256 \ -extfile san.cnf -extensions v3_req
落とし穴がある。openssl x509 -reqはCSRの拡張情報(SANを含む)を自動的には証明書へコピーしない。-extfileと-extensionsを明示しないと、署名自体は成功してもSANのない証明書ができ、結局ブラウザに弾かれる。「CAで署名したのに警告が消えない」場合は大抵このSAN抜けが原因だ。-CAcreateserialは、CAの通し番号ファイル(ca.srl)がなければ自動生成するオプションで、同じCAで発行を続けるなら必要になる。
サーバに設定する
証明書と秘密鍵ができたら、Webサーバ側にTLS設定を入れる。ディレクティブ名を押さえれば迷わない。
Nginxの場合
server {
listen 443 ssl;
server_name server01.example.local;
ssl_certificate /etc/nginx/ssl/server01.example.local.crt;
ssl_certificate_key /etc/nginx/ssl/server01.example.local.key;
}
listenディレクティブにsslパラメータを付け、ssl_certificateとssl_certificate_keyで証明書と秘密鍵のパスを指定する。証明書ファイルは公開情報なので権限は緩めでよいが、秘密鍵ファイルはnginxのマスタープロセスが読める範囲で絞る。
Apacheの場合
<VirtualHost *:443>
ServerName server01.example.local
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/server01.example.local.crt
SSLCertificateKeyFile /etc/httpd/ssl/server01.example.local.key
</VirtualHost>
mod_sslを有効にし、SSLEngine onとSSLCertificateFile、SSLCertificateKeyFileを設定する。以前はSSLCertificateChainFileで中間証明書を別ファイル化していたが、Apache 2.4.8以降はSSLCertificateFileにチェーンをまとめて書けるため非推奨になった。自己署名やシンプルなプライベートCA構成では中間証明書自体が存在しないことが多く、通常はこの2行で足りる。
クライアントに信頼させる
証明書とサーバ設定ができても、クライアント側が証明書を信頼していなければ警告は消えない。ブラウザは接続のたびに、発行者が信頼ストアのCAか、アクセス先ホスト名がSANに含まれるか、有効期限内かを確認する。自己署名証明書やプライベートCAは最初の時点で「知らないCA」として引っかかるため、警告を消すにはルート証明書(自己署名なら証明書そのもの、プライベートCAならca.crt)をアクセス端末の信頼ストアに入れる必要がある。
Windowsなら、証明書ファイルをMMC(証明書スナップイン、対象がサーバ自体ならcertlm.msc)から「信頼されたルート証明機関」ストアにインポートする。GUIを使わず配布したい場合は、PowerShellでも同じことができる。
Import-Certificate -FilePath "C:\certs\ca.crt" ` -CertStoreLocation Cert:\LocalMachine\Root
Windows側だけで自己署名証明書を作るなら、PowerShellのNew-SelfSignedCertificateが使える。既定でSSLServerAuthentication用の証明書が作られ、-DnsNameで指定した名前がSAN(先頭の1つはSubjectにも)に設定される。
New-SelfSignedCertificate -DnsName "server01.example.local" ` -CertStoreLocation "Cert:\LocalMachine\My" ` -NotAfter (Get-Date).AddYears(2)
-DnsNameはDNS名前提のパラメータで、IPアドレスをSANに含めたい場合は-TextExtensionでSAN拡張(OID 2.5.29.17)にIPAddressトークンを指定する方法がMicrosoftの公式サンプルにもある。
台数が多いなら1台ずつの手作業配布は現実的ではない。Active Directory環境なら、グループポリシーでドメイン参加端末全台にルート証明書を自動配布できるので、プライベートCAをActive Directory Certificate Services(AD CS)として構築する選択肢も検討する価値がある。
本番では自己署名を避ける理由と代替
ここまでの手順は検証・社内クローズド環境が前提で、インターネット公開の本番システムや社外の利用者・取引先が接続するサービスには使うべきではない。自己署名証明書もプライベートCAも、管理下にない端末からは「信頼できないCA」としか見えず、相手のブラウザに毎回警告を出すか、相手側にルート証明書のインストールを依頼する運用になり、現実的にスケールしない。秘密鍵漏えい時の失効の仕組み(CRLやOCSP)も自前運用では整備しにくく、いざというときの止め方が弱いという弱点もある。
本番環境では、有償の公的認証局(商用CA)から証明書を購入するか、無料で自動更新の仕組みまで用意されたLet’s Encryptを使うのが基本になる。公的CAのルート証明書は主要なOS・ブラウザに標準で組み込まれているため、利用者側は何も設定せず警告なしに接続できる。ただしLet’s Encryptの証明書は有効期間が約90日と短く、certbotなどの自動更新の仕組みとセットで運用するのが前提だ。実在のドメインを所有しDNSを操作できるなら、外部非公開のサーバでもDNS-01チャレンジでLet’s Encrypt証明書を取得できる場合があり、「社内だから公的CAは使えない」と決めつける前に検討の余地はある。
Active Directory環境を前提にできるなら、AD CSで社内プライベートCAを構築し、グループポリシーでルート証明書を自動配布する方法も現実的だ。この場合も、証明書自体はCN任せにせず必ずSANを入れる点は変わらない。
自己署名証明書やHTTPS設定を試すなら、すぐ用意できるVPSの検証サーバーが便利です。SANや各種設定を安全に確認できます。
![]()
まとめ
自己署名証明書やプライベートCAは、検証環境や社内クローズドなシステムのHTTPS化には十分実用的だ。ただし今のブラウザはCNではなくSANでホスト名を照合するため、証明書には必ずSAN(subjectAltName)を明示すること、CAで署名する場合はCSRの拡張情報が自動的には引き継がれない点に注意することが欠かせない。この2つを外すと「作ったのに警告が消えない」状態になる。クライアント側は、自己署名証明書またはCAのルート証明書を信頼ストアに登録して初めて警告が消える仕組みも理解しておきたい。外部公開の本番システムでは、公的CAの証明書かLet’s Encrypt、社内規模が大きければAD CSのような仕組みに乗せるのが妥当な選択になる。
最終更新:2026年7月

