---
title: localhost を使った開発で TLS を有効にする方法
description: ローカル開発環境で HTTPSを使うため、自己署名 CA を作って localhost 用の証明書を発行する手順
image: localhost-tls-development.jpg
date: 2026-05-05 04:14:00
---

HTTPS、いわゆるSSLが実質必須になって長いこと経つが、開発用のローカルサーバについてはHTTP(Sのつかない方)を使うのが普通だ。盗聴されたり通信先を偽装されたりする心配がないので安全上はそれで問題ないのだが、アプリケーションにとって自分に飛んでくるリクエストがHTTPSなのかHTTPなのかを全く気にする必要がないかというと微妙にそうでない時もあり、HTTPSを用いて本番と近い環境をローカルで検証しなければならない時もたまにある。

かといって Let's Encryptはlocalhostに証明書を発行してくれないので、

- 自分のCAを作る
- ↑の証明書を「信頼済み」としてOSまたはブラウザに登録する
- 自分のCAで localhostの証明書を作る
- ↑を開発用Webサーバにセットする

ということを行う必要がある。

普通は2番目のステップで作成した自分用のCAをユーザー個別にブラウザレベルで信頼すればいいのだが、そのプロジェクト専用の開発VMを立てて複数ユーザーを切って開発しているといったような環境ではいちいち個別に登録するのは面倒なので、ここではOSレベルで信頼済みCAを登録してしまう手順をまとめる。

## ローカル CA 証明書の生成

Linuxディストリビューションによって異なるが、以降は下記を前提にする。作業にはroot権限が必要。

- /usr/local/share/ca-certificates : 自分用CA証明書の置き場
- /etc/ssl/private : 秘密鍵の置き場

10年有効なCA 証明書を作成

```sh
mkdir -p /usr/local/share/ca-certificates
openssl req -x509 -newkey rsa:4096 \
  -keyout /etc/ssl/private/ca.key \
  -out /usr/local/share/ca-certificates/ca.crt \
  -days 3650 -nodes \
  -subj "/C=JP/ST=Tokyo/O=MyOrg/CN=MyLocalCA"
```

## システムトラストストアへの追加

信頼する証明書を下記コマンドで、作成した CA 証明書を「信頼済み」としてシステムに認識させる

```sh
update-ca-certificates
```

または(ディストリビューションによる)

```sh
update-ca-trust
```

これで自分のCA が信頼済みとして追加され、curl、wget、Python requests など OpenSSL を使うツールはこの CA が発行した証明書を信頼するようになる。

## OpenSSLではなくNSSを使用しているソフトウェア(Chrome) への反映

Linuxディストリビューションによってはp11-kit経由でOpenSSL用のトラストストアをNSSにも共有するよう設定されているのだが、そうでない場合は手動でその措置をする必要がある。

- Fedora / RHEL 系: `update-alternatives` 経由で `libnssckbi.so` が `p11-kit-trust.so` を指すよう標準で設定済み。コマンドは `update-ca-certificates` ではなく `update-ca-trust` を使う
- Arch Linux: NSS の PKCS#11 モジュールリストに `p11-kit-trust.so` が自動登録される形で統合済み。`update-ca-trust` で反映される
- Debian / Ubuntu / Gentoo: p11-kit 連携はされていないので`libnssckbi.so` を `p11-kit-trust.so` へのシンボリックリンクに置き換える（※後述、自己責任）必要あり

`p11-kit-trust.so` は NSS の `libnssckbi.so` と同じ PKCS#11 インターフェースを実装しており、システムトラストストアを読んで返す。NSSの`libnssckbi.so` をこれへのシンボリックリンクに置き換えることで、`update-ca-certificates` の結果を Chrome にも反映できる。（※自己責任）

```sh
ln -sf /usr/lib64/pkcs11/p11-kit-trust.so /usr/lib64/libnssckbi.so
```

## サーバー証明書の発行

自分用のローカルCAをシステムに信頼させたら、そのCAで `localhost` 用のサーバー証明書を発行する。ついでに好きな名前でバーチャルホスト分けもできるようにワイルドカードで `*.dev.localhost`も使えるようにしておく[^1]。

[^1]:`localhost` は Public Suffix List (PSL) の扱いにより、単一ラベルドメインとして TLD 相当に扱われるので、その直下のワイルドカードは不適当としてブラウザに拒否される。仕方ないので `.dev`を挟んでいる

最近のブラウザは SAN (Subject Alternative Name) のない証明書を拒否するため、`-addext` で明示的に指定する。

```sh
openssl genrsa -out /etc/ssl/private/dev.localhost.key 2048

openssl req -new \
  -key /etc/ssl/private/dev.localhost.key \
  -subj '/CN=*.dev.localhost' \
  -addext 'subjectAltName=DNS:*.dev.localhost,DNS:dev.localhost,DNS:localhost' \
| openssl x509 -req \
  -CA /usr/local/share/ca-certificates/ca.crt \
  -CAkey /etc/ssl/private/ca.key \
  -CAcreateserial \
  -out /etc/ssl/certs/dev.localhost.crt \
  -days 3650 -copy_extensions copy
```

こうして作成した証明書を開発用のWebサーバにセットすることで、ブラウザから警告を受けることなくHTTPSで`localhost`ないし`*.dev.localhost`の閲覧ができるようになる。

## 関連記事

- [opensslコマンドでCSRや証明書の内容を表示し、鍵との対応を確認する方法](describe-ssl-csr.md)
- [Let's Encryptの証明書が更新されているかどうかをZabbixで監視する](zabbix-watch-letsencrypt.md)
- [Let's EncryptのルートCA期限切れで OpenSSL 1.0.2が思わぬ事故を起こす件](openssl-102-letsencrypt-crisis.md)
