WebサーバをNginxから証明書自動更新に対応したCaddy 2に移行した

こんにちは、 @p1ass です。

最近、運用していたWebサーバをNginxからCaddyに移行しました。この記事ではCaddyの特徴や移行してみた感想などを書きたいと思います。

What is Caddy?

CaddyはのデフォルトでHTTPSに対応しているOSSのWebサーバです。

Caddy

つい先日(2020/05/04)、v2にメジャーバージョンアップされ アーキテクチャが刷新されました。

Caddyは様々な特徴があるのですがいくつかピックアップして紹介します。(v2からの新機能というわけではないです。)

デフォルトかつ自動でHTTPSに対応

CaddyはLet’s Encryptの証明書を自動で取得し、適用してくれます。そのため、ユーザ側が証明書のことを気にする必要がありません。 また、80から443へのリダイレクトも自動で行われるのでユーザが設定する必要がありません。

Nginxの場合は、これらを実装するために多くのコンフィグを書いていたことを考えると、かなりの作業を省略できます。

Nginxにあった基本的な機能をカバー

一般的なユースケースで必要となる機能は大体カバーしています。

他にも面白い機能として、

などもあります。

シンプルに設定を記述できるCaddyfile

Caddyの設定の反映方法は2通り用意されており、ユーザが用途に合わせて選べるようになってます。

一つ目は Caddyfile というファイルで設定する方法で、Nginxのコンフィグに似た書き方で記述できます。

# https://hoge.p1ass.comにきたリクエストをlocalhost:8080にプロキシ
hoge.p1ass.com {
  reverse_proxy /* localhost:8080
}

# バーチャルホストで複数のドメインを設定できる
fuga.p1ass.com {
  reverse_proxy /* localhost:3000
}

後は起動時にファイルを指定すれば完了です。

$ caddy run --config ./Caddyfile --adapter caddyfile

公式で、

Caddyfiles to be ~15% the size of a less capable nginx.conf!

と謳われているように、Nginxと似た文法ながらもシンプルに記述することが可能です。

JSON API経由での設定変更

2つ目はAPI経由で設定をアタッチする方法です。 Caddyは80番と443番以外に2019番もListenしていて、管理用のAPIが提供されています。

例えば、現在の設定は GET /config で取得できます。

$ curl -s localhost:2019/config | jq
{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [
            ":443"
          ],
          "routes": [
            {
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "handler": "reverse_proxy",
                          "upstreams": [
                            {
                              "dial": "localhost:8080"
                            }
                          ]
                        }
                      ],
                      "match": [
                        {
                          "path": [
                            "/*"
                          ]
                        }
                      ]
                    }
                  ]
                }
              ],
              "match": [
                {
                  "host": [
                    "hoge.p1ass.com"
                  ]
                }
              ],
              "terminal": true
            },
              {
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "handler": "reverse_proxy",
                          "upstreams": [
                            {
                              "dial": "localhost:3000"
                            }
                          ]
                        }
                      ],
                      "match": [
                        {
                          "path": [
                            "/*"
                          ]
                        }
                      ]
                    }
                  ]
                }
              ],
              "match": [
                {
                  "host": [
                    "fuga.p1ass.com"
                  ]
                }
              ],
              "terminal": true
            }
          ]
        }
      }
    }
  }
}

これと同じ形式で POST /load にJSONを投げれば動的に設定を変更できます。なお、デフォルトではJSONですが、Content-Type: text/caddyfile とすればそのままCaddyfile を投げることもできます。

また、この設定の変更はACIDを保証しています。

Atomic: Multiple changes in a single request are treated as a single unit; any failed change aborts all the other changes.
Consistent: No invalid configurations can be loaded; your server will never break if a problem is detected at config load.
Isolated: No config changes rely on another. (It helps that HTTP is a stateless protocol!)
Durable: Caddy automatically persists the current, valid configuration to disk and can safely resume it after a power cycle if the –resume flag is used.

無効な設定がPOSTされたとしてもサーバが止まる心配はありません。

余談: 設定方法の使い分け

CI・CDパイプラインに組み込みたいならAPI経由での設定がオススメです。 Caddyfileを使うか、JSONを使うかは悩みどころですが、

かなぁと個人的に思っています。

NginxからCaddyへの移行のモチベーション

このように様々な機能があるのですが、Caddyへの移行の最も大きなモチベーションになったのは「HTTPSの自動対応」でした。

今まではNginx+certbotという組み合わせで運用していたのですが、証明書のためだけにバッチ処理を走らせるのも面倒で、Nginx単体で完結しないかなぁと思っていました。

そのNginxもHTTPSに対応するには、実際の動作とはあまり関係のない非本質的な記述を大量に書く必要があります。HTTPSが当たり前になってきたこのご時世に合ってないと感じていました。

その点、Caddyは証明書の更新は内部でやってくれて、設定の記述もシンプルです。メンテナンス性を考慮するとCaddyは非常に魅力的でした。

移行してみた感想

CaddyにはNginxのコンフィグをそのまま読み込むアダプターが存在するのですが、今回は1からでCaddyfileを書きました。

動作に関しては概ね問題ないです。セットアップが完了してから一度もプロセスは死んでないし、メモリリークなどもなさそうです。

そして当初の目論見通り、メンテナンスのしやすさは非常に向上しました。バーチャルホストを新しく切るのに3行追加するだけというのは非常に楽でした。

細かいところで言うと、 caddy fmtCaddyfile のフォーマットができるのも良いポイントでした。

おわりに

合わせて読みたい

Top