Caddy v2リバースプロキシ詳解ガイド
Caddy v2リバースプロキシ詳解ガイド
リバースプロキシは、モダンなWebアプリケーションのインフラにおいて不可欠なコンポーネントです。NginxやApacheが長年使われてきましたが、Caddyは自動HTTPS、シンプルな設定、モダンなアーキテクチャにより、急速に人気を集めています。
この記事では、Caddy v2を使ったリバースプロキシの設定方法を、基本から応用まで詳しく解説します。
Caddyの強み
自動HTTPS
Caddyの最大の特徴は、Let’s Encryptを使った自動HTTPS取得・更新です。設定ファイルにドメイン名を書くだけで、証明書の取得、設定、自動更新がすべて自動化されます。
example.com {
reverse_proxy localhost:3000
}
これだけで完全なHTTPS対応サイトが完成します。
シンプルな設定
Nginxと比較してみましょう。
Nginx
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Caddy
example.com {
reverse_proxy localhost:3000
}
Caddyは必要な設定を自動的に行うため、設定ファイルが驚くほどシンプルになります。
基本設定
単一バックエンド
example.com {
# 基本的なリバースプロキシ
reverse_proxy localhost:3000
}
複数ドメイン
example.com {
reverse_proxy localhost:3000
}
api.example.com {
reverse_proxy localhost:4000
}
admin.example.com {
reverse_proxy localhost:5000
}
パスベースルーティング
example.com {
# /api へのリクエストはバックエンドAPI
reverse_proxy /api/* localhost:4000
# /admin へのリクエストは管理画面
reverse_proxy /admin/* localhost:5000
# その他はフロントエンド
reverse_proxy localhost:3000
}
ヘッダー操作
example.com {
reverse_proxy localhost:3000 {
# カスタムヘッダーを追加
header_up X-Custom-Header "CustomValue"
header_up X-Request-ID {http.request.uuid}
# Hostヘッダーを保持
header_up Host {host}
# Real IPを転送
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
# レスポンスヘッダーを削除
header_down -Server
# セキュリティヘッダーを追加
header_down X-Content-Type-Options "nosniff"
header_down X-Frame-Options "DENY"
header_down X-XSS-Protection "1; mode=block"
}
}
ロードバランシング
ラウンドロビン(デフォルト)
example.com {
reverse_proxy localhost:3000 localhost:3001 localhost:3002
}
ランダム選択
example.com {
reverse_proxy localhost:3000 localhost:3001 localhost:3002 {
lb_policy random
}
}
最少接続数
example.com {
reverse_proxy localhost:3000 localhost:3001 localhost:3002 {
lb_policy least_conn
}
}
IPハッシュ(セッション維持)
example.com {
reverse_proxy localhost:3000 localhost:3001 localhost:3002 {
lb_policy ip_hash
}
}
ヘルスチェック
example.com {
reverse_proxy localhost:3000 localhost:3001 localhost:3002 {
# ヘルスチェック設定
health_uri /health
health_interval 10s
health_timeout 5s
health_status 200
# 失敗したバックエンドの再試行
lb_try_duration 5s
lb_try_interval 500ms
# パッシブヘルスチェック
fail_duration 30s
max_fails 3
unhealthy_status 500 502 503
}
}
重み付けロードバランシング
example.com {
reverse_proxy {
# サーバー1: 50%のトラフィック
to localhost:3000 {
weight 50
}
# サーバー2: 30%のトラフィック
to localhost:3001 {
weight 30
}
# サーバー3: 20%のトラフィック
to localhost:3002 {
weight 20
}
lb_policy weighted
}
}
WebSocket対応
基本WebSocket
example.com {
reverse_proxy /ws localhost:3000
}
CaddyはWebSocketを自動的に検出し、適切に処理します。
WebSocket + HTTP
example.com {
# WebSocketエンドポイント
reverse_proxy /ws localhost:3000
# 通常のHTTPリクエスト
reverse_proxy localhost:8080
}
タイムアウト設定
example.com {
reverse_proxy /ws localhost:3000 {
# WebSocketのタイムアウトを延長
transport http {
read_timeout 24h
write_timeout 24h
dial_timeout 10s
}
}
}
セキュリティ設定
基本認証
example.com {
basicauth /admin/* {
# ユーザー名: admin, パスワード: password
admin $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx7wHnxJhJUFS
}
reverse_proxy localhost:3000
}
パスワードハッシュは以下のコマンドで生成します。
caddy hash-password --plaintext 'password'
IP制限
example.com {
# 許可するIP
@allowed {
remote_ip 192.168.1.0/24 10.0.0.0/8
}
# 許可されていないIPは403
respond @allowed 403
reverse_proxy @allowed localhost:3000
}
レート制限
example.com {
# rate_limit モジュール(プラグイン)
rate_limit {
zone dynamic {
key {remote_host}
events 100
window 1m
}
}
reverse_proxy localhost:3000
}
CORS設定
example.com {
@cors_preflight {
method OPTIONS
}
header {
Access-Control-Allow-Origin "https://frontend.example.com"
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Access-Control-Allow-Headers "Content-Type, Authorization"
Access-Control-Max-Age "3600"
}
respond @cors_preflight 204
reverse_proxy localhost:4000
}
高度な設定
A/Bテスト
example.com {
@version_a {
header Cookie *version=a*
}
@version_b {
header Cookie *version=b*
}
reverse_proxy @version_a localhost:3000
reverse_proxy @version_b localhost:3001
# デフォルトはバージョンA
reverse_proxy localhost:3000
}
カナリアデプロイ
example.com {
@canary {
# 10%のトラフィックを新バージョンに
expression {rand()} < 0.1
}
reverse_proxy @canary localhost:3001
reverse_proxy localhost:3000
}
ブルーグリーンデプロイ
example.com {
@blue {
header X-Deployment "blue"
}
@green {
header X-Deployment "green"
}
reverse_proxy @blue localhost:3000
reverse_proxy @green localhost:3001
# デフォルトは現在アクティブな環境
reverse_proxy localhost:3000
}
ファイルアップロード
example.com {
reverse_proxy localhost:3000 {
# 大きいファイルのアップロードを許可
request_buffers 16KB
# タイムアウトを延長
transport http {
read_timeout 5m
write_timeout 5m
}
}
# 最大ボディサイズ
request_body {
max_size 100MB
}
}
静的ファイルとリバースプロキシの組み合わせ
example.com {
# 静的ファイルを直接配信
root * /var/www/html
# /api へのリクエストはバックエンド
reverse_proxy /api/* localhost:4000
# その他は静的ファイル、なければバックエンド
try_files {path} /index.html
}
キャッシュ
example.com {
reverse_proxy localhost:3000 {
# キャッシュヘッダーを設定
header_down Cache-Control "public, max-age=3600"
}
# 静的アセットは長期キャッシュ
@static {
path *.js *.css *.png *.jpg *.svg
}
header @static Cache-Control "public, max-age=31536000, immutable"
}
gzip圧縮
example.com {
# 自動圧縮(デフォルトで有効)
encode gzip zstd
reverse_proxy localhost:3000
}
HTTP/2 Server Push
example.com {
reverse_proxy localhost:3000
# HTTP/2 Server Push
push /style.css
push /script.js
}
ログとモニタリング
アクセスログ
example.com {
log {
output file /var/log/caddy/access.log
format json
}
reverse_proxy localhost:3000
}
構造化ログ
{
log {
format json
output file /var/log/caddy/caddy.log {
roll_size 100MB
roll_keep 10
roll_keep_days 90
}
}
}
example.com {
log {
output file /var/log/caddy/example.log
format filter {
wrap json
fields {
request>headers>Authorization delete
request>headers>Cookie delete
}
}
}
reverse_proxy localhost:3000
}
Prometheusメトリクス
{
servers {
metrics
}
}
:2019 {
metrics /metrics
}
example.com {
reverse_proxy localhost:3000
}
実践的な設定例
Next.jsアプリケーション
example.com {
# Next.jsの静的アセット
@static {
path /_next/static/*
}
header @static Cache-Control "public, max-age=31536000, immutable"
# Next.jsのAPIルート
reverse_proxy /api/* localhost:3000
# その他のリクエスト
reverse_proxy localhost:3000 {
header_up X-Forwarded-Host {host}
}
encode gzip
}
マイクロサービスアーキテクチャ
example.com {
# 認証サービス
reverse_proxy /auth/* localhost:4001
# ユーザーサービス
reverse_proxy /users/* localhost:4002
# 商品サービス
reverse_proxy /products/* localhost:4003
# 注文サービス
reverse_proxy /orders/* localhost:4004
# フロントエンド
reverse_proxy localhost:3000
}
Docker環境
{
email admin@example.com
}
app.example.com {
reverse_proxy app:3000
}
api.example.com {
reverse_proxy api:4000
}
db.example.com {
reverse_proxy db:5432
}
docker-compose.yml:
version: '3.8'
services:
caddy:
image: caddy:2-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
networks:
- web
app:
build: ./app
networks:
- web
api:
build: ./api
networks:
- web
volumes:
caddy_data:
caddy_config:
networks:
web:
デバッグとトラブルシューティング
デバッグモード
# 設定ファイルの検証
caddy validate --config Caddyfile
# デバッグログを有効にして起動
caddy run --config Caddyfile --debug
# 設定をJSON形式で表示
caddy adapt --config Caddyfile --pretty
接続テスト
# HTTPSが正しく設定されているか確認
curl -I https://example.com
# WebSocketのテスト
websocat wss://example.com/ws
# ヘッダーの確認
curl -I https://example.com -H "X-Custom-Header: test"
パフォーマンス最適化
{
# グローバル設定
servers {
protocol {
# HTTP/3を有効化
experimental_http3
}
# タイムアウト設定
timeouts {
read_body 10s
read_header 10s
write 30s
idle 2m
}
# 最大ヘッダーサイズ
max_header_size 16KB
}
}
example.com {
reverse_proxy localhost:3000 {
# コネクションプール
transport http {
max_conns_per_host 100
keep_alive 90s
}
}
}
まとめ
Caddy v2を使えば、以下のような機能を簡単に実装できます。
- 自動HTTPS: 証明書の取得・更新が完全自動
- ロードバランシング: ラウンドロビン、最少接続、IPハッシュ
- WebSocket: 自動検出と適切な処理
- セキュリティ: 基本認証、IP制限、CORS
- 高度なルーティング: A/Bテスト、カナリアデプロイ
- 監視: 構造化ログ、Prometheusメトリクス
シンプルな設定ファイル、自動HTTPS、モダンなアーキテクチャにより、Caddyは次世代のリバースプロキシとして最適な選択肢です。NginxやApacheからの移行も容易で、すぐに本番環境で使い始められます。