[Linux] LAN内HTTPS完全ガイド:mkcert・nginx・Apacheの実践手順

1. public_html vs HTTPS

  • public_html はコンテンツの置き場所
    (ApacheのDocumentRootやmod_userdir、nginxのroot)。

  • HTTPS は通信の暗号化&相手の真正性確認鍵と証明書をサーバに設定する作業
     (nginxならssl_certificate/ssl_certificate_key、ApacheならSSLCertificateFile/SSLCertificateKeyFile)。

つまり「public_html か mkcert か」ではなく、どちらも必要
public_html にサイトを置き、mkcert等で作った証明書をサーバ設定に組み込む

2. なぜ LAN では mkcert が速くてラク?

mkcert はローカルCA(認証局)を生成し、そこから**SAN(Subject Alternative Name)**入りのサーバ証明書を即席で発行します。
SANに IP(例:192.168.0.1)やホスト名(nas.home.arpa / localhost) を複数登録できるので、ブラウザの「CNのみはNG」チェックにも引っかかりません。

mkcert の基本手順

  1. CAを作り各OSの信頼ストアへ登録:
 mkcert -install
  1. サーバ用の証明書を発行(IPやホスト名を全部入れる):
 mkcert 192.168.0.1 localhost nas.home.arpa
 # => 例: 192.168.0.1+2.pem / 192.168.0.1+2-key.pem
  1. 生成した 証明書(.pem)と秘密鍵(-key.pem) をサーバの安全な場所へ配置し、Webサーバに設定。

コツ:
mkcert -CAROOT でローカルCAの格納ディレクトリがわかります。
そこで rootCA.pem を取り出し、他端末に配布して信頼させます(後述)。

3. 代替パターンと選び方(ざっくり)

  • 完全ローカル(社内/LAN限定)

    • もっとも簡単 → mkcert
    • モバイルアプリ等、ユーザーCAを信頼しないクライアントが混ざるなら後述のDNS-01や組織CAも検討。
  • LANだが“公的に信頼される証明書”を使いたい

    • Let’s EncryptのDNS-01自分のドメイン名の証明書を取得→LAN内DNS(スプリットDNS)でそのFQDNをプライベートIPに解決。
    • 長所:配布不要で多くのクライアントが即信頼。短所:DNS更新の自動化が必要。
  • 組織的に運用(更新自動化・失効管理・mTLS等)

    • step-ca(Smallstep)社内ACMEサーバを立てる。
    • Caddy内部CA機能でローカル自動HTTPS。
    • Traefik + mkcert で開発環境を束ねる、など。

注意:Let’s EncryptはlocalhostやプライベートIP(192.168.x.xなど)には発行しません。 2025年にIPアドレス証明書が始まりつつありますが、主にパブリックIP向けで超短命(短期間)プロファイル。LANのプライベートIP用途には不向きです。したがって、LANでサクッとやるなら mkcert が現実解です。


4. nginx 設定例(HTTP→HTTPSリダイレクト+HTTP/2)

証明書を /etc/nginx/certs/lan.pem、鍵を /etc/nginx/certs/lan-key.pem に置いた例。

# 80番は常にHTTPSへ
server {
    listen 80;
    server_name 192.168.0.1 nas.home.arpa localhost;
    return 301 https://$host$request_uri;
}

# 443番(TLS)
server {
    listen 443 ssl http2;
    # HTTP/3 も使うなら(nginx 1.25+ & http_v3_module ビルド必須)
    # listen 443 quic reuseport;  # 実装状況により調整
    # add_header Alt-Svc 'h3=":443"; ma=86400' always;

    server_name 192.168.0.1 nas.home.arpa localhost;

    ssl_certificate     /etc/nginx/certs/lan.pem;
    ssl_certificate_key /etc/nginx/certs/lan-key.pem;

    # モダンTLSの素振り
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;

    root /var/www/public_html;  # ← 置き場所(public_html 等)
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}

ディレクトリ構成を変えたいなら root を、バーチャルホスト名を変えたいなら server_name を調整。**public_html は単なる“置き場所”**で、HTTPSの有無とは独立です。

再起動

sudo nginx -t && sudo systemctl reload nginx

5. Apache 設定例(mod_ssl+HTTP/2)

証明書・鍵は /etc/apache2/certs/ に配置した例。mod_ssl と mod_http2 を有効化します。

sudo a2enmod ssl http2
<VirtualHost *:80>
  ServerName 192.168.0.1
  Redirect permanent / https://192.168.0.1/
</VirtualHost>

<IfModule mod_ssl.c>
<VirtualHost *:443>
  ServerName 192.168.0.1
  DocumentRoot "/var/www/public_html"

  SSLEngine on
  SSLCertificateFile    "/etc/apache2/certs/lan.pem"
  SSLCertificateKeyFile "/etc/apache2/certs/lan-key.pem"

  # HTTP/2 を有効化
  Protocols h2 http/1.1

  <Directory "/var/www/public_html">
    Require all granted
    Options Indexes FollowSymLinks
    AllowOverride All
  </Directory>
</VirtualHost>
</IfModule>

Per-Userのpublic_html(mod_userdir) を使う場合でも、HTTPSは同様に443のVirtualHost側でSSLEngine onと証明書を指定します。置き場所の考え方は変わりません。

再起動:

sudo apachectl configtest && sudo systemctl reload apache2

6. クライアントに“信頼”を配る(macOS / Windows / iOS / Android)

mkcertを実行した端末は -install 済みなのでOK。他の端末で証明書警告が出る場合、rootCA.pem をインストール&“信頼”に設定します。

  • macOS
  • rootCA.pem をダブルクリック→**キーチェーン(システム)**に追加→証明書の詳細で「常に信頼」。
  • Windows:MMCの**「Trusted Root Certification Authorities」**にインポート。
  • iOS / iPadOS:rootCA.pem を端末に配布してプロファイルとしてインストール→設定 > 一般 > 情報 > 証明書信頼設定フル信頼をON。
  • Android:設定 > セキュリティ > 認証情報のインストール でユーザーCAとしてインポート。ただし多くのアプリ(API 24+)は“ユーザーCA”を既定で信頼しませんブラウザはOKでもアプリがNGというのは普通に起きます。→ 公的証明書(DNS-01)か、社内CA(step-ca)+MDM配布を検討。

セキュリティ:rootCA.pemの乱配布は厳禁。意図しない端末にインストールすると、その端末は**“あなたのCAが発行した全サイト”を信用してしまいます。用途ごとにCAを分け、不要になったら各端末から削除**しましょう。


7. LANでも“公的”証明書を使いたい場合(Let’s Encrypt / DNS-01)

  • FQDN(例:nas.example.com)を用意。
  • DNSプロバイダのAPIやacme-dnsを使って DNS-01チャレンジで検証→証明書取得。
  • スプリットDNSで、社内からnas.example.comはプライベートIPに解決させる。
  • これなら配布いらずでモバイルアプリもほぼ問題なく動きます。

ただし localhostやプライベートIPは対象外。IPアドレス証明書の一般提供が広がっても、LANのRFC1918アドレス向けは現実的ではありません。


8. もっと本格的に:社内CA / 自動化

  • step-ca(Smallstep):自社ドメイン向けのプライベートACME。短期証明書・mTLS・失効・ロールベース運用まで柔軟。
  • Caddy:tls internal で内部CAから自動発行。ローカルの自動HTTPSが超手軽。
  • Traefik + mkcert:複数サービスのローカル開発を一括HTTPS化。

9. ネーミングの話(.localの落とし穴)

  • .local は**mDNS(Bonjour)**用途で特殊。衝突や解決順の問題が出やすい。
  • 無難なのは home.arpa(家庭内用途)か、自分の保有ドメインのサブドメイン
  • ドキュメント/テスト専用には .test/.example/.invalid/.localhost などのSpecial-Useも。

10. よくある落とし穴と対処

  • SAN不足:IPやホスト名を全部mkcertに渡す。CNだけは不可。
  • HSTSを安易に有効化:開発/LANでは**preloadやincludeSubDomainsは避ける**。消しづらい“常時HTTPS縛り”でハマる元。
  • HTTP/3を一気に導入:nginxはビルドやlistenパラメータに癖。まずはHTTP/2で十分。
  • 混在コンテンツ:HTTPの画像/JSを呼んでブロックされがち。相対パスかHTTPSに統一。
  • 秘密鍵の権限:chmod 600などで最小権限。Git等に絶対入れない。

11. 動作確認ワンライナー

# 証明書のSAN/チェーンを確認
openssl s_client -connect 192.168.0.1:443 -servername 192.168.0.1 -showcerts </dev/null

# HTTP/2 で応答するか
curl -I --http2 https://192.168.0.1/

付録:

最小 nginx / Apache パス差し替えメモ

  • nginx:root で置き場所(/var/www/public_html 等)を指定。
  • Apache:DocumentRoot または mod_userdir(UserDir public_html)。HTTPSは*:443のVirtualHost側に証明書を指定。

参考・出典(主要な根拠)

  • mkcert の使い方・CA 配布:公式 README(インストール/-CAROOT/モバイル注意)。
  • nginx の HTTPS/証明書設定(ssl_certificate 等)&サンプル。
  • Apache の SSL 設定(SSLCertificateFile ほか)と HTTP/2 有効化(Protocols h2 http/1.1)。 (LinuxBabe)
  • Let’s Encrypt のチャレンジ種別(DNS-01 はサーバ非公開でもOK/IPアドレス検証は不可)。 (Let’s Encrypt)
  • localhost には発行できない(Let’s Encrypt FAQ)。 (Let’s Encrypt)
  • Let’s Encrypt の IP アドレス証明書(2025/07 公開;短命・段階的提供、主にパブリックIP向け)。 (Let’s Encrypt)
  • Caddy のローカル自動 HTTPS(内部CA)。 (HTTPS-Only Standard)
  • 社内CA/ACME の選択肢:Smallstep step-ca 概要。 (Smallstep)
  • Android の「ユーザーCAは既定で信頼しない」設計(Network Security Config)。 (Android Developers)
  • iOS の「フル信頼」有効化手順。 (Appleサポート)
  • .local は mDNS 用の特殊ドメイン(衝突しやすい)/Special-Useドメイン。 (IETF Datatracker)
  • 家庭内なら home.arpa が無難(RFC 8375)。 (RFC エディタ)