GCEインスタンスを経由してインターネットにアクセスする手順をまとめました。
ターミナルのほか普段使っているブラウザ(Google Chrome)でも利用できるようにします。
アクセス元情報をjsonで返してくれるサイトにアクセスし、日本国内(尾道とか!)からアクセスしてもUSとして表示されたらゴールです。
巷ではSNIフィールドを使った特定サイトのアクセス遮断がホットな話題になっているので、こういったネットワーク系の知識は少し持っていても良いかもしれません。
本題はGCEインスタンスに限った話ではないので、EC2やDigitalOceanのDropletでも同じです。
環境
今回動かした環境は次の通りです。
- OS: macOS Sierra
- プロキシサーバ: GCEインスタンス
- ブラウザ: Google Chrome
- 使うコマンド: gcloud, ssh
それでは実際にプロキシサーバを用意してみましょう。
プロキシサーバの用意
やることは次の2つだけです。
- インスタンスの作成
- SSHコマンドの実行
それでは実際にやってみます。
# インスタンスの作成
$ gcloud compute instances create --zone us-west1-a myproxy
Created [https://www.googleapis.com/compute/v1/projects/myproject/zones/us-west1-a/instances/myproxy].
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS
myproxy us-west1-a n1-standard-1 10.138.0.3 35.233.196.31 RUNNING
# プロキシサーバにする
$ gcloud compute ssh --zone us-west1-a myproxy -- -N -p 22 -D localhost:10080
Warning: Permanently added 'compute.2212974415330211298' (ECDSA) to the list of known hosts.
gcloud compute ssh
コマンドの行は--
以降がssh
コマンドのオプションになっています。
通常のssh
コマンドだとこんな感じになります。
$ ssh -N -p 22 -D localhost:10080 www.example.com
たったこれだけでプロキシサーバになっています。
-N
でリモートでのシェル実行の抑制を、-p 22
で接続先ポート番号を指定しています。
そして、-D
でlocalhost
の10080番ポートを使ってSOCKS Proxyを作成しています。
確認する
本当にこれだけでプロキシサーバとして動くのか確認してみます。
まずは通常通りcurl
を実行してみましょう。
$ curl https://api.ip2geo.pl/json/
{"db":"MaxMind","country":"JP","city":"Iwakuni","lat":"34.1500","lon":"132.1833"}
岩国からのアクセスと認識されました。わたしは尾道に住んでいるのでだいたい合ってそうです笑
続いてオプションでプロキシサーバを指定して実行してみましょう。
$ curl --proxy socks5://localhost:10080 https://api.ip2geo.pl/json/
{"db":"MaxMind","country":"US","city":"Mountain View","lat":"37.4192","lon":"-122.0574"}
"US"と表示されました!!
オプションを毎回つけるのが大変なときは、環境変数http(s)_proxy=socks5://localhost:10080
を設定するといいようです。
$ export http_proxy=socks5://localhost:10080 https_proxy=socks5://localhost:10080
$ curl https://api.ip2geo.pl/json/
{"db":"MaxMind","country":"US","city":"Mountain View","lat":"37.4192","lon":"-122.0574"}
リモートでの名前解決
プロキシとしてsocks5://
を指定するとローカルでの名前解決になりますが、socks5h://
を指定するとリモートで名前解決をリモートでしてくれるようです。
実際に試して確認してみましょう。
まず前提として、GCEでは同一プロジェクト内のGCEインスタンス同士はインスタンス名だけで名前解決してくれます。
そこでGCEインスタンスを新たに1台作成し、Webサーバを起動させておきます。
今回はWebコンソールからOSにContainer-Optimized OSを指定、Allow HTTP(S) traffic
にチェックをつけたインスタンスを作成しました。
名前はデフォルトのままinstance-1
としました。
インスタンス起動後、SSHで中に入り次のコマンドを実行すると80番ポートで待ち受けてくれます。
$ docker run --rm -it -w /usr/src/app -p 80:8080 python:3.7 python -m http.server 8080
それでは、リモートで名前解決されることを確認してみます。
環境変数をsocks5h://
に変更し、curl
を実行すると次のようにinstance-1
という名前でアクセスできます。
これでリモートにあるmyproxy
インスタンスで名前解決されていることが確認できました。
$ export http_proxy=socks5h://localhost:1080 https_proxy=socks5h://localhost:1080
$ curl instance-1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Directory listing for /</title>
</head>
<body>
<h1>Directory listing for /</h1>
<hr>
<ul>
</ul>
<hr>
</body>
</html>
ブラウザで利用する
ブラウザなどのアプリケーションでSOCKS proxyを利用するにはネットワーク設定を変更します。
macOSの場合はSystem Preferences... > Network > Wi-Fi (環境により異なる) > Advanced... > Proxies
を開いてください。
Proxiesの画面がひらけたら、SOCKS Proxy
を選択しlocalhost
と10080
を指定します。
設定を反映させたら完了です。
実際にGoogle Chromeで試すとアクセス元が"US"になっていることがわかります。
名前解決もリモートで行われているようですね。
クリーンアップ
プロキシの設定は使い終わったらオフにしてください。 このプロキシの設定は、一度設定しておけば次のコマンドでON/OFFの切り替えができます。
# SOCKS Proxyの設定をOFFにする(必要に応じてsudoで実行してください)
$ networksetup -setsocksfirewallproxystate Wi-Fi off
# SOCKS Proxyの設定をONにする
$ networksetup -setsocksfirewallproxystate Wi-Fi on
最後に作成したインスタンスを削除しておきましょう。 コマンドでやるならこんな感じになります。
$ gcloud compute instances delete --zone us-west1-a myproxy
$ gcloud compute instances delete --zone us-east1-b instance-1
まとめ
名前解決をリモートで行えるのは面白いですね。
これなら巷で話題のSNIフィールドを使った特定サイトのアクセス遮断も回避できそうな気がします(未確認)。
どこかに詳しい人がいましたら@rhoboroに教えてください笑
SSHのポートフォワーディング機能は他にも面白い使い方がたくさんあるのでこれからももっと遊んでいきたいと思います。