Caddyをリバースプロキシにして、QUICでのWebページ配信を試みる。

  1. リバースプロキシを活用して、既存のWebページをQUICで配信したい。
  2. CaddyというWebサーバでは、引数に-quicをつけると、試験的にQUICで配信ができる。
  3. Amazon Linux 2016.09 では、 initを用いて、Caddyをサービス化させ、自動起動させるようにできる。

QUIC (Quick UDP Internet Connection)とは

Googleの開発しているトランスポート層のネットワークプロトコルです。 標準化されているものではなく、GoogleのサーバとChromeとの間での試験運用が行われている状況です。

技術的なことは、IIJ 大津さんのスライド(HTTP/2からQUICへ続くWebプロトコルの進化)がわかりやすいです。

QUICに対応しているWebサーバは少ない

  1. Chromium
  2. Caddy

※ほかにもあるとは思いますが、Caddyを見つけたあたりから探す気がなくなりました。

Caddy ってどんなWebサーバ?

QUICをサポートしているサーバとして、名前の知らないWebサーバが出てきました。 特徴はこんな感じです。

  • Go言語で書かれている。
  • 簡単にWebサーバが立てられる。
  • FastCGIに対応している。
  • リバースプロキシやロードバランサなどの機能も搭載している。
  • Let’s Encryptのクライアントを内蔵していて、簡単に暗号化を有効にできる。
  • HTTP/2 に既定で対応している。
  • QUIC に試験的に対応している。(重要)
  • 初期設定で、Qualys SSL Server TestでA判定が取れる。

うちの環境はASP.NETなので、IIS 10.0 のリバースプロキシとして利用してみます。

Caddy を使ってみる

前提条件

実験日: 2017/02/17 同一のセキュリティーグループ内に2台のサーバーを置いて実験しました。

リバースプロキシ

AWS EC2 上のインスタンス OS: Amazon Linux 2016.09 Caddy: 0.9.5

バックエンド(セットアップ済み)

AWS EC2 上のインスタンス OS: Windows Server 2016 Datacenter IIS: 10.0 (8080ポートで待ち受け)

Caddy をダウンロードする

ここからダウンロードします。 ソースコードではなく、バイナリが直接ダウンロードできます。 1.png プラグインによって、さまざまな機能が追加できるようですが、リバースプロキシとして使う場合は、何もつけなくて大丈夫です。 2.pngこのリンクは動的に作成されるようなので、直接wgetできません。一旦、端末側でダウンロードをしてから、SCPで送りましょう。今回は、Linux 64-bitを選びます。

ダウンロードしたファイルをSCPなどで転送したら、展開します。 (以下の例は、ec2-userのホームディレクトリに転送した場合)

mkdir caddy
cd caddy
tar zxvf ../caddy_linux_amd64_custom.tar.gz
ls -l
total 15416
-rwxrwxr-x 1 ec2-user ec2-user 15730207 Feb  6 13:52 caddy
-rw-rw-r-- 1 ec2-user ec2-user    14996 Jan 24 15:38 CHANGES.txt
drwxrwxr-x 7 ec2-user ec2-user     4096 Jan 24 15:38 init
-rw-rw-r-- 1 ec2-user ec2-user    25261 Jan 24 15:38 LICENSES.txt
-rw-rw-r-- 1 ec2-user ec2-user      994 Jan 24 15:38 README.txt

このように、実行可能ファイル”caddy”が既に含まれています。

Caddy を起動させてみる

Caddyの起動方法は、簡単です。

./caddy
Activating privacy features... done.
http://:2015

これで、2015番ポートでWebサーバが動作します。 なお、ルートディレクトリやポート番号などの指定は、引数かCaddyfileを用いて指定します。 今回は、ほとんどの設定(といってもほんの少しですが)をCaddyfileに記載します。

Caddyfile を作成する

Caddyfile とは、Caddyの設定を記載するファイルです。

実行時に以下の引数を指定することで、読み込ませることができます。 -conf=path/to/Caddyfile このファイルに記載できる内容については、公式サイトのdocsを見てください。 今回は、リバースプロキシとして必要な設定のみに触れていきます。

以下が、今回設定したCaddyfileです。

https://example.jp {
proxy / ip-xxx-xxx-xxx-xxx.aws-region.compute.internal:8080 {
header_upstream Host {host}
header_upstream X-Forwarded-For {remote}
}
tls admin@mail.example.jp {
}

Caddyfile は、{}で階層化されて表現される設定ファイルです。

一行目のhttps://example.jpが、URLとなります。 Caddyでは、自動で証明書の取得が行われるので、特に間違えないようにする必要があります。 このバーチャルホストに関する設定を{}内に書いていきます。

二行目のproxyは、リバースプロキシの設定です。 この設定では、/へのアクセスが、http://ip-xxx-xxx-xxx-xxx.aws-region.compute.internal:8080/へ転送される形になります。

proxy / web1:8080 web2:8080 web3:8080

のように記述すると、Caddyはロードバランサーとして機能します。 proxyについての設定は、さらに{}内に記述します。 header_upstream Host {host} - 元のhostの情報をそのままバックエンドに送ります。 header_upstream X-Forwarded-For {remote} - 元のIPアドレスをX-Forwarded-Forヘッダでバックエンドに送ります。

六行目のtlsは、暗号化に関する設定ですが、非常にユニークです。 Caddyは、Let’s Encryptのクライアントを内蔵しているため、自動で証明書を取得します。 そのため、ここに証明書のパスを設定する必要はありません。(設定することもできる。) tlsには、次の4通りの設定ができます。

  • off - HTTP通信を行う。(暗号化しない)
  • self_signed - 自己署名証明書を作成して、それを使う。(暗号化する)
  • email - ここにメールアドレスを入力すると、Let’s Encryptから証明書を取得し、それを使う。(暗号化する)
  • /path/to/cert /path/to/private_key - 入力されたところにある証明書を使う。(暗号化する)

ここでも、細かくprotocolsやchiphersを設定できますが、初期設定のままで問題ないと思われます。 (TLS1.0が既定で無効となっているので、場合によっては注意が必要かもしれません。)

設定ファイルを読み込んでCaddyを起動する & QUIC を有効にする

ここまでQUICに関する設定はしていませんが、現在のところQUICの有効化は引数-quicでのみできるようです。 ということで、設定ファイルを読み込みつつ、QUICを有効化して起動します。

./caddy -conf=/path/to/Caddyfile -quic

この状態で、Google Chrome などからアクセスを試行して、QUICが有効になっているか確認してみてください。 (Caddyでは、httpsのみが有効なバーチャルホストに対してhttpでアクセスすると自動的にhttpsに転送されますが、TLS1.2により接続されてしまいます。httpsに転送されたのちに更新するなどして再接続するとQUICで接続されるようになります。) QUIC.PNG

デーモン化させて自動起動するようにする

あまりやる人はいないと思いますが、Caddyをデーモン化させて自動起動させてみます。 これは、ディストリビューションにより変わってきますので、Amazon Linux 2016.09 での例となります。

Amazon Linux 2016.09 では、まだsystemdに移行していませんので、initを使うことになります。 まず、/etc/init.d/以下にこのようなスクリプトを置きます。ファイル名は、caddyなどとしておくと良いでしょう。 (こちらを参考にさせていただきました。)

#!/bin/bash
# Caddy daemon
# chkconfig: 345 20 80
# description: Caddy daemon
# processname: caddy

DAEMON_PATH="/path/to/caddy/"

DAEMON='./caddy'
DAEMONOPTS="-quic -conf=/path/to/Caddyfile -log /var/log/caddy.log"

NAME=caddy
DESC="Caddy upstart"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

case "$1" in
start)
    printf "%-50s" "Starting $NAME..."
    cd $DAEMON_PATH
    PID=`$DAEMON $DAEMONOPTS > /dev/null 2>&1 & echo $!`
    echo "Saving PID" $PID " to " $PIDFILE
        if [ -z $PID ]; then
            printf "%s\n" "Fail"
        else
            echo $PID > $PIDFILE
            printf "%s\n" "Ok"
        fi
;;
status)
        printf "%-50s" "Checking $NAME..."
        if [ -f $PIDFILE ]; then
            PID=`cat $PIDFILE`
            if [ -z "`ps axf | grep ${PID} | grep -v grep`" ]; then
                printf "%s\n" "Process dead but pidfile exists"
            else
                echo "Running"
            fi
        else
            printf "%s\n" "Service not running"
        fi
;;
stop)
        printf "%-50s" "Stopping $NAME"
            PID=`cat $PIDFILE`
            cd $DAEMON_PATH
        if [ -f $PIDFILE ]; then
            kill -HUP $PID
            printf "%s\n" "Ok"
            rm -f $PIDFILE
        else
            printf "%s\n" "pidfile not found"
        fi
;;

restart)
    $0 stop
    $0 start
;;

*)
        echo "Usage: $0 {status|start|stop|restart}"
        exit 1
esac

このスクリプトファイルに実行権限を与えます。

chmod +x caddy

続いて、chkconfigでサービス登録をすれば完了です。

chkconfig --add caddy

これで、起動時に自動起動されるようになります。 また、以下のようにサービスの制御も行えるようになります。

service caddy start
service caddy status
service caddy stop

まとめ

今回は、Caddyを使って既存のWebページを無理やりQUICで配信できるようにしてみました。 したがって、実際にQUICの持つ恩恵を受けられるのかは疑問が残ります。 ただ、周囲に先駆けてQUICをサポートしているのを見せつけて楽しむことくらいはできますね。 (HTTP/2 and SPDY indicatorが緑色に光ります。) 時間があったらベンチマークなどもしてみたいですが、条件を整えるのも難しそうなのであまり優先順位は高くないです。

ネイティブにASP.NET のアプリケーションをQUICで配信するには、IIS がQUICに対応する必要があると思いますが、 実際にMicrosoft社内ではQUICによるWebサーバが作られているという話も聞くので、楽しみに待っていたいと思います。 (そのまえに、規格化されなければなりませんが。)

参考文献・リンク