created_at
updated_at
tags
toc

ローカル HTTPS 開発専用ツール SPTTH を公開した

Intro

http://localhost:3000 での開発には限界がある。

しかし、本番と同じように https://example.com でアクセスできる環境をローカルに作るには、ドメインの解決、証明書の発行、443 での起動など、少し手間がかかる。

そこで、必要な全てを 1 つのツールで行い、様々な開発環境を再現するためのツールを開発したので、紹介する。

sptth logo

localhost の罠

localhost はあまりにも特別なホストであるため、権限などの挙動は、本番ドメインにデプロイすると変わる。

また、本番ドメインとは Origin が異なるため、連携のためのあらゆるセキュリティ境界も変わる。

もし、複数のサービスの中で、1 サービスだけ手元で動かし、他は本番を参照したいような開発があっても、localhost ではうまく再現できない場合が多い。

つまり、ある程度複雑なサービスを開発していれば、http://localhost:3000 での開発など、早々に限界を迎えるのだ。

もし本番が https://example.com ならば、ローカルでも同じく https://example.com で開発したい。

しかも、自己署名証明書で起動し、ブラウザが出す証明書エラーを無視しながら開発するのもやめたい。

どうしたら良いだろうか?

3 つの sudo

手法自体は知られている。以下の 3 つを行えば、ローカルで起動したサーバに https://example.com でアクセスできるようになる。

  1. /etc/hosts を修正し、example.com を 127.0.0.1 にする
  2. mkcert でローカル CA を立て、example.com の証明書を発行する
  3. 443 でサーバを起動する

そして、この 3 つのステップ全てに sudo が必要だ。

なぜならどれも、システムにとって重要な操作をしているからだ。

これらを手順書だけでやり遂げるのは、開発慣れしていない人には難しい場合もある。

ここまでやっても、アプリサーバ自体が証明書を使って HTTPS を受けるようになっている必要があるが、通常サーバが直接 HTTPS を喋るようには作らないだろう。基本的に TLS の終端は LB や CDN などで行い、アプリサーバは平文で受け付ける構成が一般的だからだ。

筆者はずっと、この 3 つを 1 つのツールで 1 回の sudo で実行できないか、と考えていた。

Requirement

要件はこうだ。

  1. ローカル DNS を立ち上げ、名前解決を 127.0.0.1 にする。
  2. ローカルに CA を立ち上げ、動的に証明書を発行する。
  3. プロキシを 443 で立ち上げ、ローカルサーバには平文で転送する。

全てを 1 つのコマンドにし、一回の sudo で起動できれば、認証も一回で済みローカルへの影響も最小限にできる。

と、頭では思いついていたが、手を動かすとなると相応の時間がかかる。

しかも、DNS と CA と Reverse Proxy を実装するとなると、それなりに面倒だ。

しかし時代が変わり一晩で動くところまでいけたため、公開することにした。

それが sptth だ。

SPTTH

以下のような設定を TOML に記述する。

[dns]
listen = "127.0.0.1:53"
upstream = ["1.1.1.1:53", "8.8.8.8:53"]

[[record]]
domain = "example.com"
A = ["127.0.0.1"]
AAAA = ["::1"]

[[record]]
domain = "example.net"
A = ["127.0.0.1"]
AAAA = ["::1"]

[tls]
ca_dir = "~/.config/sptth/ca"
cert_dir = "~/.config/sptth/certs"

[[proxy]]
domain = "example.com"
listen = "127.0.0.1:443"
upstream = "localhost:3000"

[[proxy]]
domain = "example.net"
listen = "127.0.0.1:443"
upstream = "localhost:4000"

そして、以下のように実行する。

$ sudo sptth config.toml

初回起動時にローカル CA を立ち上げるので、それを許可する。

あとは、OS の DNS 設定を 127.0.0.1 に変えるだけだ。

ブラウザから https://example.com にアクセスすれば http://localhost:3000 に、https://example.net にアクセスすれば http://localhost:4000 にアクセスできる。ローカル CA で署名した正しい証明書なので、URL バーも赤くならない。

sudo が一個になり、設定も一箇所にまとめて、複数のサービスを デプロイしたときと同じブラウザの状態 で操作することができるようになる。ブラウザが持つ Permission も Origin も Security Surface も、本番と同じ条件で開発できるのだ。

Architecture

基本的には、DNS、CA、LB を 1 つのツールに詰め込んだだけだ。

DNS は 53 (sudo) で起動し、toml に書いたドメインだけ、指定した A/AAAA レコードを返し、それ以外は upstream に移譲するようになる。

CA は、初回起動時にルート証明書を OS の証明書ストアに入れる(sudo)。その上で、毎回 toml に書かれたドメインの証明書を発行する。

LB は、443 (sudo) で起動し、リクエストを受けたら upstream のローカルサーバに転送する。したがって、ローカルで開発しているサーバは今まで通り localhost:3000 などで開発すれば良い。

以上を 1 つのコマンドにしているため、sudo が一回で済み、toml を変えるまでは起動しっぱなしでよくなる。

必要な設定は、OS の DNS 設定の変更だけだ。

Install

現在、ビルドを GitHub で配布している状態なので、それをダウンロードして実行して欲しい。

https://github.com/Jxck/sptth/releases

ツールの性質上、悪意があれば DNS クエリをすべて抜き取ったり、任意の証明書を発行して Person in the Middle 攻撃が可能だ。そこで、署名などはきちんと付けるようにしている。必要に応じて検証して欲しい。

一応 Linux / Windows にも対応してはいるが、環境がないので試していない。

ちなみに、ローカル環境を壊しても責任は取れないので AT YOUR OWN RISK で使用することを前提に公開している。

心配であれば、最初に書いた旧来の環境構築を自分で行うことをおすすめする。

Implementation

プロトタイプはすべて Codex App の音声入力だけで開発した。

コードは一行も書かず、読んでない。

とはいえ、プランの段階でだいぶ脱線する場面もあるので、任せきりにはしていない。こちらには、かなり明確に方針とアーキテクチャが浮かんでいるため、そのキャリブレーションには相応の時間をかけている。

今後の開発はこうなると思うので、そのうえでクオリティを担保するような方法を探る意味でも、様々な取り組みを試す場としている。

特に Codex と Claude の相互レビューや、クオリティ担保系の Skill はある程度ワークしているように思う。

Claude Code Security も解放されたら試したいが、それ相当のものを自分で Skill として組み、コマンドとしても使えるようにしている。

引き続き、「書いてない読んでないコードのクオリティをどう担保できるか」を試す場にしたい。

Contribution

各地で見られるように、AI による PR も増えてきたが、レビューする気はない。

代わりに、Issue template にプロンプトを書けるようにした。

AI で実装するためのプロンプトをもらい、そのプロンプトをこちらで兼用しながら、こちらのガバナンスの元で実行して開発し、チェックしてリリースする方針だ。

もちろん、プロンプト無しで、単に困った部分を Issue にファイルしてくれても構わない。

Outro

頭に描いたものを、可処分時間を過度に浪費せずに実現できるようになったのは、非常にありがたい。

そして、長年なんとかしたかった問題も解決できたので、非常に満足度が高い。

あと 10 年早く欲しかった。