ブログに戻る
8月 19, 2026ガイド

自動HTTPS付きでCaddy Webサーバーをインストールする方法

公式リポジトリからUbuntuにCaddyを入れ、静的サイトとリバースプロキシ用のCaddyfileを書き、自動証明書、systemd、ログ、Nginxからの移行でよくある失敗を理解します。

自動HTTPS付きでCaddy Webサーバーをインストールする方法

Caddyは、既定でTLS証明書を取得・更新するWebサーバーです。1つか2つのドメインをホストする小型VPSでは、CertbotのタイマーとNginxのスニペットファイル一式が消えます。設定言語(Caddyfile)は短いです。リバースプロキシ、gzip、HTTP/2は普通の機能であり、週末がかりの追加モジュールではありません。

Nginxは、すでに実戦済みの設定がある店、または非常に特定のモジュールが必要な店では、まだ正しい選択です。このガイドはもう一方のよくあるケース向けです。includeスニペットを暗記せずに、新しいHiddence VPSで動くHTTPSが欲しい場合です。公式aptリポジトリからCaddyを入れ、Let's Encryptとのやり取りを説明し、静的サイトを出し、ローカルアプリをプロキシし、複数ドメインをホストし、ログを見、Apacheや古いNginxとのポート80の奪い合いを扱います。

Caddyが合うとき

見出しは自動HTTPSですが、日常の勝ちは動く部品が少ないことです。Caddyは80と443を待ち、HTTPをHTTPSへリダイレクトし、証明書をデータディレクトリに保存します。ドメインがVPSを指している必要は残ります。ACMEを壊さない必要も残ります(ファイアウォールの80/tcp、:80を奪う他プロセスなし)。ワイルドカード証明書にはDNSプロバイダモジュールが必要で、単一ホスト証明書より長い道です。

  • 自動のHTTP→HTTPSと証明書更新
  • 長いserverブロックではなく読みやすいCaddyfile
  • Node、Python、追加設定のPHP-FPM、Dockerバックエンド向けの十分なリバースプロキシ
  • 暗号スイートの表なしでHTTP/2と現代的なTLS既定
  • 公式パッケージのsystemdユニット

要件

CaddyがACME HTTP-01を証明できる前に、ドメインがこのVPSへ解決する必要があります。DNSがまだ伝播中だと発行に失敗して再試行します。『Caddyが壊れた』ように見えて、実際はDNSだけのことがあります。80/443を持っているなら、先にApacheまたはNginxを止めてください。

  • Ubuntu 22.04または24.04
  • VPS IPへのドメインAレコード(IPv6を使うならAAAAも)
  • ポート80と443が空いており、ファイアウォールで許可済み
  • rootまたはsudo

ステップ1:公式リポジトリからCaddyをインストールする

現行のTLSとACMEの挙動が欲しいなら、Ubuntu universeの古いCaddyを無作為に入れないでください。Caddyプロジェクトはaptソースを文書化しています。インストール後、caddyユーザーが存在し、サービスは有効になります。

bash
ssh root@YOUR_VPS_IP
apt update && apt -y install debian-keyring debian-archive-keyring apt-transport-https curl gpg

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

apt update
apt -y install caddy

caddy version
systemctl status caddy --no-pager

ステップ2:最初のCaddyfile — 静的サイト

既定のCaddyfileは /etc/caddy/Caddyfile です。自分のドメインに置き換えます。ホスト名がlocalhostでなければ、設定の読み込みと同時に証明書を取りにいきます。サイトファイルはcaddyユーザーが読めるディレクトリへ置きます(www-data風の権限が多いですが、パッケージはユーザーcaddyです)。

bash
mkdir -p /var/www/example
echo '<h1>It works</h1>' > /var/www/example/index.html
chown -R caddy:caddy /var/www/example

cat >/etc/caddy/Caddyfile <<'EOF'
example.com {
    root * /var/www/example
    file_server
    encode gzip
}
EOF

caddy validate --config /etc/caddy/Caddyfile
systemctl reload caddy

# Watch issuance:
journalctl -u caddy -f

ステップ3:ローカルアプリケーションをリバースプロキシする

Gunicorn、Node、Dockerが 127.0.0.1:8000 で待っているなら、公開プロセスはCaddyだけにすべきです。reverse_proxyディレクティブは、ほとんどのアプリに妥当な形でHostとX-Forwarded-*を転送します。アプリが絶対HTTP URLを生成するなら、アプリ側で信頼できるプロキシ / HTTPSフラグを設定します(DjangoのSECURE_PROXY_SSL_HEADER、Expressのtrust proxyなど)。

bash
app.example.com {
    encode gzip
    reverse_proxy 127.0.0.1:8000
}

# Several hosts in one file are normal:
# blog.example.com {
#     root * /var/www/blog
#     file_server
# }

ステップ4:ファイアウォールとsystemd

80と443を許可します。Caddyのユニットはcaddy.serviceです。プロセスが健全なら、Caddyfile編集後はreloadで足ります。DNSプラグイン用の環境変数を変えたなら、フル再起動の方が明確です。証明書は既定で /var/lib/caddy/.local/share/caddy/ にあります。再インストール時のレート制限が気になるなら、そのパスをバックアップに含めてください。

bash
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

systemctl enable --now caddy
systemctl reload caddy

# Backup cert storage (path may vary slightly by version):
ls -la /var/lib/caddy/

ステップ5:ログ、圧縮、ヘッダー

ボットがパスを叩いたときや404のデバッグにアクセスログが役立ちます。サイトごとにログできます。ブラウザアプリをホストするならセキュリティヘッダーを足します。巨大なヘッダーパックを理解せずコピーしないでください。HSTSは長いmax-ageを一度出すとブラウザが覚えます。

bash
example.com {
    root * /var/www/example
    file_server
    encode gzip
    log {
        output file /var/log/caddy/example.log
    }
    header {
        X-Content-Type-Options nosniff
        Referrer-Policy no-referrer-when-downgrade
        -Server
    }
}

mkdir -p /var/log/caddy
chown caddy:caddy /var/log/caddy
systemctl reload caddy

ステップ6:PHPとその他の追加

Caddyはphp_fastcgiディレクティブでPHP-FPMと話せます。多くのWordPressやLaravelホストには足りますが、php-fpmのインストールと一致するソケットパスはまだ必要です。完璧なNginx PHP設定がすでにあるなら、一晩での移行は任意です。Caddyが輝くのはリバースプロキシ + 静的 + 自動TLSです。

bash
example.com {
    root * /var/www/example
    php_fastcgi unix//run/php/php8.3-fpm.sock
    file_server
}

# Confirm FPM is running:
systemctl status php8.3-fpm

ダウンタイムの驚きなくNginxから移行する

Caddyを始める前にNginxを止めてください。そうしないと80/443を奪い合います。IPも移すなら前日にDNS TTLを下げます。Aレコードを切り替える前に、curl --resolve で新しいVPSに当ててテストします。ロールバックに備え、Nginx設定は1週間gitに残します。

  • systemctl stop nginx && systemctl disable nginx
  • Caddyを入れ、Caddyfileを検証し、Caddyを起動
  • curl -I --resolve example.com:443:NEW_IP https://example.com
  • IPが新しい場合のみ、その後にDNSを変更
  • 再発行は自動。同じホスト名に対してCertbotも動かさない

トラブルシューティング

ACMEの失敗はほぼ常にDNS、ファイアウォール、またはポート80上の別サービスです。Caddyのログ行はtls.obtainに触れます。HTTPでは動いてHTTPSでは動かないなら、発行が完了していません。証明書が多すぎるならLet's Encryptのレート制限です。テスト中は本番ではなくstaging CAを使います。

  • validate失敗: Caddyfileの構文、欠けたブレース
  • rootでpermission denied: サイトディレクトリをcaddyにchown
  • bind: address already in use — ss -tulpn | grep -E ':80|:443'
  • 証明書タイムアウト: VPSから dig +short でドメインを確認、ufw allow 80
  • 502 reverse_proxy: バックエンドダウン、またはコンテナネットワークからlocalhostへ誤ってプロキシ

セキュリティ上の注意

CaddyのTLS既定は保守的です。あなたの仕事はアプリケーションセキュリティとSSHです。Caddyの管理APIを公開インターフェースで有効にしないでください。既定の管理エンドポイントはローカルです。そのままにしてください。インターネットのCaddyfileを使うなら、すべてのmatcherを読んでください。/* を内部IPへreverse_proxyするスニペットはオープンプロキシになり得ます。

  • 管理APIを公開しない
  • パッケージを更新し続ける
  • すべてのホスト名でHTTPSが確実に動いてからHSTS
  • ACMEレート制限を守るため、テストと本番のホスト名を分ける

ヒント

  • caddy fmt --overwrite /etc/caddy/Caddyfile でファイルを読みやすく保つ
  • 似たサイトが多いときはimportスニペットを使う
  • Dockerでは、マウントしたCaddyfile付きのcaddy:alpineイメージが一般的
  • ワイルドカード証明書にはDNSモジュールとAPIトークンが必要 — そのトークンを守る
  • ファイル全体を書き直す前に journalctl -u caddy を読む

VPS上のCaddyは、公式パッケージ、短いCaddyfile、開いたポート80/443、すでにサーバーを指すDNS、編集後のsystemd reloadです。静的ファイルサーバーとして、またはGunicorn、Node、Dockerの手前のリバースプロキシとして使います。自動HTTPSは、ACMEがポート80で答えられるときに動きます。発行が失敗したら、Caddyを責める前にDNSとポート衝突を直します。よく再インストールするなら /var/lib/caddy をバックアップしてください。