イカで雲に乗る

サーバーワークス Advent Calendar 2016の9日めです。サーバーワークスといえばイカ くコ:彡 なので、今回はsquid proxyとAWSを使用した海外アクセス高速迂回経路作りを紹介したいと思います。

※ 鰤も嫌いじゃないです。

この記事が役に立ちそうな人

  • 海外との通信が激遅
  • 国内との通信はふつう
  • AWSチョットデキル
  • squidチョットデキル

背景

うちのプロバイダが年に1-2回ほど海外へのアクセスが非常に低速(500kbps以下)になる事がありまして、1週間程度ガマンすれば回復するのですが、ガマンしたくないので何とかした経験が素になっています。

今回のケースでは海外アクセスは遅くなるものの日本国内へのアクセスはそこそこの速度が出ていたので、「海外のサーバにはISPの経路ではなく別の経路を使えば回避できる」と思ったものの昔であれば打つ手がありませんでした。しかし、今は高速なバックボーンを持つAWSがいます。AWSを使えば、遅い経路を回避できます。

AWSのバックボーンについては、今年のre:Invent 2016 ナイトキーノートでJames Hamilton先生が説明されていました。その他にも非常に興味深い内容でしたので必見です。

概要

主なトラフィックはhttp(s)なので、手軽に使えるsquidを使います。Linuxボックスくらいどのご家庭でも数台あるでしょうが、もしない場合には我が家のようにbash on Windowsでsquidを運用する事も可能です (※ OSのエフェメラルポート設定変更が必要)。

簡単なネットワーク構成は下記を参照してください。

各クライアントからのアクセスは家にあるsquid(1)に集められ、ここで国内・海外に振り分けを行います。東京リージョンにいるsquid(2)を使用してもいいのですが、コンテンツプロバイダによっては東京リージョンのEIPであっても海外からのアクセスと誤認するものもあるので、その対策として国内アクセスは自宅IPアドレスからにしています。

海外宛の通信は、家のsquid(1)から東京リージョンのsquid(2)にフォワードされ、最終的に北カリフォルニアのsquid(3)からアクセスします。それぞれのEC2インスタンスはトラフィックにもよりますが、継続的にトラフィックを流さないのであればt2.nanoでもわりと平気です。お財布と相談しながらインスタンスサイズを決めてください。

また、私は北米アクセスが多いので北カリフォルニアリージョンにしていますが、ご利用状況に応じて適当なリージョンを選んでください。

構成

ネットワーク

|------- Home -----------|   |----- AWS Tokyo region ----|   |--- AWS US West region ---|
|                        |   |       |---- EC2 ---|      |   |     |---- EC2 ---|       |
| Tablet/PC --- squid(1) |---|       |  squid(2)  |      |---|     |  squid(3)  |       |
|                        |   |       |------------|      |   |     |------------|       |
|------------------------|   |---------------------------|   |--------------------------|

経路

  • 日本国内(っぽい所): 家のsquidから直接アクセス
  • 各種CDN: 家のsquidから直接アクセス
  • その他: 家 -> 東京リージョン -> 北カリフォルニアリージョンのsquidからアクセス

セキュリティグループ

セキュリティグループで、各squid間の通信を許可する必要があります。東京-北カリフォルニアリージョン間の通信はEIPで固定IPアドレスを持てるので素直にInboundの許可を書けるのですが、問題は家-東京リージョン間の許可です。

家に固定IPアドレスを持っていない場合、ISPから割り振られたIPアドレスが変わる度にセキュリティグループを変更する必要があり、手作業だと面倒です。

面倒な事をガマンしたくないので、ダイナミックDNSサービスとAnsibleを組み合わせて自動構成すると楽です。雰囲気としては ↓ な感じです。

---
- hosts:
  - localhost
  tasks:
    - name: get IP address of home
      command: dig {{ 家のFQDN }} +short
      register: homeIp

    - name: Setup security group.
      ec2_group:
        name: default
        description: default VPC security group
        region: "{{ REGION }}"
        vpc_id: "{{ VPC_ID }}"
        purge_rules: yes
        rules:
          - proto: tcp
            # squidのデフォルトポート
            from_port: 3128
            to_port: 3128
            cidr_ip: "{{ homeIp.stdout}}/32"
          - proto: tcp
            # ssh
            from_port: 22
            to_port: 22
            cidr_ip: "{{ homeIp.stdout}}/32"
          - proto: tcp
            # squidのデフォルトICPポート
            from_port: 3130
            to_port: 3130
            cidr_ip: "{{ homeIp.stdout}}/32"
          - proto: icmp
            from_port: -1
            to_port:  -1
            cidr_ip: "{{ homeIp.stdout}}/32"

squidの設定

squidの設定は特別な事はなく、ごく普通のForward proxyの設定でOKです。

dstdom_regexを使ってテキトーで雑な正規表現を書き綴っていきましょう。以下の抜粋で雰囲気をつかんでください。雰囲気をつかめなければsquidのドキュメントを読んでください、分かるまで読み続けてください。

# 日本っぽいドメインを綴る
acl jp dstdom_regex \.jp
acl 日本っぽい所 dstdom_regex 日本っぽい所の正規表現
acl amazon dstdom_regex amazon
# CDNっぽいドメイン名
acl cdn dstdom_regex cloudfront akamai

# 日本っぽい所とCDNは直接アクセス
always_direct allow jp
always_direct allow amazon
always_direct allow cdn

# その他は東京リージョン squid(2)へ
never_direct allow all

自動化

常用するのであれば手作業でもいいのですが、非常時にだけ使うのであれば自宅squidの設定変更や各リージョンでVPCやEC2を作成する作業も全てAnsibleで自動化するといいでしょう。それはまた別の話。

This post is the No.9 article of サーバーワークス Advent Calendar 2016