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

  • 7
    Like
  • 0
    Comment

概要(三行でまとめると)

  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サーバが作られているという話も聞くので、楽しみに待っていたいと思います。
(そのまえに、規格化されなければなりませんが。)

参考文献・リンク

Caddy - Official Site - Caddyの頒布元
HTTP/2からQUICへ続くWebプロトコルの進化 - 非常に分かりやすいプレゼンです。(11/11 IIJ 大津さんのもの)
caddy int.d script - slav123 - caddy用のinitスクリプトを参考にしました。
(CentOS6まで)自作のサービスをchkconfigで登録する - chkconfigでのサービスの登録方法を参考にしました。