Caddy で HTTP/2 と php-fpm を利用する


## 概要

Caddy は HTTP/2 対応のウェブサーバーです。Let's Encrypt に対応しているだけでなく、自己証明書を自動生成する機能もあるので、開発用途に便利です。php-fpm に対応しており、PHP アプリの開発に使うことができます。2018年に仕様が発行される予定の QUIC プロトコルへの実験的な取り組みも進められています。

## 開発環境で TLS を使う動機

TLS に接する機会を増やすことで TLS の知識を深めるためです。また運用環境に近い環境にすることで、よりより検証ができます。

## インストール

macOS の場合、homebrew でインストールすることができます。

```bash
brew install caddy
```

`go` コマンドでインストールできます。

```bash
go get github.com/mholt/caddy/caddy
```

コミュニティが配布する非標準のプラグインを導入する場合、ダウンロードページの左メニューから導入したいプラグインのリストにチェックを入れた上で Caddy をダウンロードします。

## 設定ファイル

設定ファイルの Caddyfile に次の内容を保存します。

```bash
localhost:2020
tls self_signed
fastcgi / 127.0.0.1:9000 php
```

HTTP/2 を利用する場合、TLS が必須です。さまざまなプロジェクトの設定ファイルの例は [caddyserver/examples](https://github.com/caddyserver/examples) で公開されています。

## 起動

Caddyfile が存在するディレクトリで次のコマンドを実行します。

```bash
caddy
```

`index.php` を設置します。

```php
<?php

phpinfo();
```

ブラウザーで `https://localhost:2020` にアクセスしてスクリプトの結果が実行されるかどうかを確認します。

## QUIC を有効にする

サーバー起動時に QUIC を有効にすることができます。2016年の時点では試験的な機能です。

```bash
caddy -quic
```

## ベンチマーク

HTTP/2 対応のサーバーのベンチマークをとる場合、ベンチマークツールも HTTP/2 に対応している必要があります。nghttp2 付属の h2load を使う場合、次のようにコマンドオプションを指定します。

```bash
h2load -n 100000 -c 1 -m 1 https://localhost:2020/
```

homebrew で nghttp2 を導入できます。

```bash
brew install nghttp2
```

## CGI として利用する

http.cgi プラグインを導入することで、CGI として PHP を動かすこともできます。ほかの言語と一緒に組み合わせて使うときに検討するとよいでしょう。Caddyfile の例は次のようになります。

```bash:Caddyfile
localhost:2020
tls self_signed

cgi {
  match /*.php
  exec /path/to/phpwrap /path/to/{match}
  env MATCH={match}
}
```

`phpwrap` は `php-cgi` をラップした実行スクリプトです。

```bash:phpwrap
#!/bin/bash

REDIRECT_STATUS=1 SCRIPT_FILENAME="${1}" /usr/local/bin/php-cgi -c /path/to/php-cgi.ini
```

パスに対してマッチした結果はプレースホルダーの `{match}` に格納されます。値の確認のために上記の例では `env` ディレクティブで環境変数の `MATCH` に `{match}` が投入されています。`{match}` は

別の言語の例として Python を使ってみましょう。

```bash:Caddyfile
cgi /*.cgi /path/to/{match}
```

```python:python.cgi
#!/usr/bin/env python3
print("Content-Type: text/plain; charset=utf-8\n")
print("Hello World")
```

もう1つ別の事例は Lua です。Shebang を省略できるようにした設定は次の通りです。

```lua:test.lua
cgi /*.lua /usr/local/bin/lua /path/to/{match}
```

Lua の CGI スクリプトは次のように書く。

```lua:test.lua
print("Content-type: text/plain; charset=utf-8\n")
print("Hello World")
```

## ターゲットユーザー

FAQ によれば Caddy が掲げる目標はウェブサーバー利用のしきいを下げることであり、デザイナーやライターを対象としたスタティックなサイトや WordPress をセットアップするためのチュートリアルが記載されています。今後の開発予定としてリモート管理のための API や Web ベースのコントロールパネルを挙げています。

## コミュニティの評価

Hacker News で[議論](https://news.ycombinator.com/item?id=13357026) されています。評価記事によれば nginx と比べてパフォーマンスは見劣りするので、運用環境に導入する場合、Go で開発されるメリットとは何かを考える必要があるでしょう。PHP の運用環境のアーキテクチャの構成や設定例についてまとめられた [Gist](https://gist.github.com/mwpastore/f42f6f1309a7b067519f4c08e18b0b6a) が公開されています。Caddy の拡張方法には Wiki に[まとめ](https://github.com/mholt/caddy/wiki/Extending-Caddy)があります。拡張のしくみとして HTTP ミドルウェアが採用されています。

近年の HTTP サーバーの動向として私が注目しているのは認証機能です。Oauth や JWT のように従来はサーバーサイド言語で実装されていた機能がサーバーの機能として実装される事例が見られます。Lua や mruby がサーバーの組み込みの言語として活用されています。また、仕様策定中の Token Binding のように TLS の機能を活用する事例を挙げることができます。

## ほかのサーバーの選択肢

開発用途で HTTP/2 に対応したサーバーの選択肢として HHVM が挙げられます。使い方は[こちら](http://qiita.com/masakielastic/items/c632dc8548c6ae088fee)の記事をご参照ください。課題としては互換性が保たれていない可能性があります。