証明書発行 + リバースプロキシ Caddy を試す curl https://localhost とかいう哲学

最近Cloudflare Tunnel経由でWordPressが異様に遅い気がしていて、そろそろ自前の環境にするかと重い腰をあげ、証明書発行 + リバースプロキシという顧客が本当に必要だったものみたいなセットを提供してくれるCaddyを試すことにした。

ConoHa VPSのまっさらな環境から立ち上げる。

目次

構築手順

  • 1GB, 2コアの時間課金
  • Ubuntu 24.04.3アプデ
  • セキュリティグループでIPv4v6-SSHIPv4v6-Webを追加。
    • rootかつSSH鍵認証だけど、すぐ作ってすぐ壊すのでとりあえずヨシ

インストール

いつもの。

sudo apt update
sudo apt upgrade
sudo apt install emacs  # 呪い

公式のインストールはネイティブとコンテナがある。やることを考えるとコンテナ使うとややこしいかなぁと思ったので、Ubuntuパッケージをそのまま使う。

Install — Caddy Documentation

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

そのまんまsystemdにサービス登録されるので、動作確認。

curl localhost:2019/config

レスポンス。

<a href="/config/">Moved Permanently</a>.

デフォルトで2019番つかうらしい。以下で停止。

caddy stop  # 停止
caddy start  # 再開. bgで起動する。テスト用

ここで、systemd使ってるのにcaddy runとかすると二重起動しておかしくなるっぽい。

チュートリアル

いけたら「Getting Started — Caddy Documentation」でざっと概念を学ぶ。以下復習用(by Gemini)。というかもしかするとこのAIまとめをざっと読んでからGetting Started読んだほうがわかりやすいか。

1. Caddyの本質:すべてはAPIである

Caddyの最も重要な概念は、「設定ファイルはAPIを叩くための手段に過ぎない」という点です。

  • Admin API: デフォルトで localhost:2019 で待機しています。
  • Under the hood: caddy run で設定ファイルを読み込むとき、内部的にはその内容をAPI経由で自分自身に POST しています。
  • ゼロダウンタイム: API経由で設定をロードするため、サーバーを再起動(Stop/Start)することなく設定を瞬時に切り替えられます。

2. JSON vs Caddyfile:使い分けの基準

Caddyには2つの顔があります。

特徴JSON (Native)Caddyfile (Adapter)
役割フル機能。人間が読み書きするための「皮」。
生成プログラムやスクリプトから生成しやすい。手動での管理に最適。
変換そのまま実行。caddy adapt でJSONに変換されてから実行。
柔軟性全機能にアクセス可能。一部の高度な設定は書けないことがある。

Tip: 複雑なことをしたくなったら caddy adapt --config Caddyfile --pretty を実行して、自分のCaddyfileがどんなJSONに化けているか確認するのが上達の近道です。

3. 実行コマンドの使い分け

コマンド一つで挙動が変わるため、用途に合わせて使い分けます。

  • caddy run:
    • フォアグラウンドで実行(画面がロックされる)。
    • 本番環境(Systemdなど)で推奨。 ログが追いやすく、プロセスの生存確認が容易なため。
  • caddy start:
    • バックグラウンドで実行。
    • ローカルでのちょっとしたテストに便利。止める時は caddy stop が必要。
  • caddy reload:
    • Caddyfileを書き換えた後、ダウンタイムなしで設定を反映させる。

4. ワークフローの選択(APIかCLIか)

チュートリアルでは両方紹介されていますが、混乱を避けるためどちらかに寄せるのが一般的です。

  • Caddyfile + CLI: * 一般的なWebサーバーとしての運用。設定ファイルをGitで管理し、caddy reload するスタイル。
  • JSON + API: * SaaSの基盤など、動的にサイトやドメインを追加・削除したい場合。外部プログラムからHTTPリクエストで設定を流し込むスタイル。

5. 重要なエンドポイント

APIを直接触る際に覚えておくと便利なパスです。

  • GET /config/: 現在適用されている設定をJSONで確認。
  • POST /load: 新しい設定(JSON)を流し込む。
  • POST /stop: サーバーを停止させる。

これらはすべて localhost:2019 を介して行われます。

ローカルHTTPSを試す

試すと言うかデフォルトでlocalhostだと自動で自己証明書でHTTPS使えるようだ。すごい。楽。「Caddyfile Quick-start — Caddy Documentation」よりCaddyfileを編集。

localhost

respond "Hello, world!"

いったん caddy stopしてcaddy startする。

curl https://localhost

https://localhostわろた。この無意味さ完全に現代って感じ。

「俺と俺の会話は暗号化されているので安全です」
「なるほど、その暗号化は誰がやるのか?」
「俺です」
「なるほど、それが正しいと誰が証明するのか?」
「俺です」

このイノベーションの虚無さはおいといて、実務的には普通に助かる。

なおテストサーバなのでroot権限でやっているが、ウェルノウンポートなので、普通ユーザなら sudo -E caddy startするかlocalhost:2080とか1024以上のポートにしようね、とのことだった。

複数サイトあるときはブロック{}使う。

localhost {
	respond "Hello, world!"
}

localhost:2016 {
	respond "Goodbye, world!"
}

フォーマットできてないと怒られる。

caddy fmt --overwrite

でなおる。

ひととおりわかったので、実ドメインで試す。

独自ドメインで検証

DNSの設定

ここまでのとおりなのだが、まずDNSのほうでAレコードをVPSに向ける。AAAAレコードも設定すれば証明書やってくれる模様だが、とりあえずIPv4でやる。

まっさらならいいが、既に値があるなら反映まで時間がかかると思われ、最初にやるのがよい。設定したら頃合いを見て以下を実行する。

dig 独自ドメイン
dig 独自ドメイン @8.8.8.8

8.8.8.8はGoogle Public DNS。両方でIPアドレスがきちんと向いていれば、まぁ大丈夫だろう。

セキュリティグループ

ConoHaの設定になるわけだが、セキュリティグループでWebを開けていることを確認する。

ファイアウォール

80/443を開ける。Let's Encryptのチャレンジで80必須。

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# 確認
sudo ufw status

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
80/tcp                     ALLOW       Anywhere                  
443/tcp                    ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
80/tcp (v6)                ALLOW       Anywhere (v6)             
443/tcp (v6)               ALLOW       Anywhere (v6) 

Caddyfileの編集

Caddyfileを以下のようにする。

独自ドメイン

respond "hello!"

編集したら caddy reloadするか、caddy stopcaddy start

curl https://独自ドメイン

helloされたらとりあえずOK。

設定ファイル

もうちょっとちゃんとやる。とりあえずテスト用のHTMLを作成する。

sudo mkdir -p /var/www/html
echo "<h1>Hello from 独自ドメイン (HTTPS)</h1>" | sudo tee /var/www/html/index.html

caddyをネイティブでインストールしたら、systemdで有効化されているわけだが、Caddyfileのパスは /etc/caddy/Caddyfileとなっている。ここで、さっき作ったのを見に行くようにする。

独自ドメイン {
    root * /var/www/html
    
    # 静的ファイルを返す設定
    file_server
}

Aiがテスト用の記述をしてくれました。

systemctl restart caddyするなりrebootするなりして、設定した独自ドメインにブラウザでアクセスして、表示されることを確認する。

起きたトラブル

接続するたびに結果が変わる -> 二重起動

lsof -i :ポートで確認したら競合していた。systemdで動いているのと caddy runで動いているのが別々であったと思われる。rebootしたらなおった。

ブラウザ「このサイトへの接続は保護されていません」

証明書ミスをやらかすと、ブラウザにキャッシュが残って言われる。シークレットウィンドウ開いて確認したらOK。

所感

とても楽だった。curl https://localhostは何か哲学的な感じがした。現代の闇。

要領はわかったので、是非このブログのあるVPSにも導入して脱Cloudflare Tunnelといきたいところだが、めんどくさいことにJitsi Meetをインストールしており、そちらのWeb UIが80/443ポートを使ってしまっているため、その対処をしたうえで移行しないといけない。ちょっと今日はもういいや。

まぁ何はともあれ、これとTailscaleを組み合わせることで、VPSと自宅サーバをVPN接続することもできるし、非常にめでたい。

この記事をいいなと思っていただけた方、よければ高評価・チャンネル登録……はないので、コメント・SNSでシェア・ブックマーク、RSSフィード登録を、よろしくお願い致します。

コメント

コメントする

目次