Microsoft Azureの仮想マシン上にTrojan-GFWを構築する

  • 投稿日:
  • by
  • Category:

中国のインターネット規制(金盾: Great Firewall)対策として、これまでMicrosoft Azure上に ShadowSocksROpenConnectといったVPNを構築してきた。

自前設置のため速度が遅く使い勝手は微妙だったが、中国渡航中にはきちんと金盾を回避してLINEやGoogleを使うことができた。

ただ、新型コロナウィルスの影響で中国への渡航が制限されて以来、自前のVPNを使う機会が無くなってしまって早3年が経過し、気が付いたら金盾やVPNを取り巻く環境も変わってしまっていた。

一言でいえば「金盾がShadowSocksを検知するようになった」ことによりSSやSSRが廃れ、より新しい"Trojan-GFW"という回避プロトコルが使われるようになっているらしい。

そこで、まだ中国への渡航の目途はたっていないが、今のうちに自前でTrojan-GFWを構築できないか模索してみた。

 

 

毎度の如くAzureで構築

こういったVPNを自分で構築する際にはコスパの良いAmazon AWSが使われることが多いが、二番煎じは面白くないのでMicrosoft Azure上に構築してみたい。

...というのは建前で、実際のところは毎月1万円分支給されているMicrosoft Azureクーポンを使いたいだけ。

Azureで自前構築したら安くても1500円はかかるから、これが無料になるのはありがたい。というかクーポンがもったいない。

なお、中国VPNは月500円程度の安い業者が複数存在しており、接続の速度や安定性などの品質は自前のものと比較にならないほど良いため、実用性を考えると自前で構築するメリットはほとんどない。ただクーポンがもったいn(略)

 

Dockerファイルを試す

ShadowSocksR構築時にDockerコンテナをもとに構築する方法が楽だったため、ここに公開されているDockerイメージをソースとしてAzureにコンテナーインスタンスを作成してみた。

001.png

プロビジョニングには成功したようなのだが、いざ起動しようとしてもエラーが出て起動しない。

原因を色々と探ってみたものの、AzureもDockerも知識が乏しくワケワカメ。

ここで時間を浪費するのも嫌なのでコンテナーで何とかするのを諦め、仮想マシンを作成して一から構築することに。

 

仮想マシンを作成する

Azure上でで仮想マシンの構築はOpenConnectでのVPN構築時に実践済みなので詳細は割愛する。

Azure PortalのGUIに従ってポチポチするだけなのでそこまで難しくはない。

OSはLinux(Ubuntu)を選択。バージョンは20.04がインストールされた。

VMシリーズはB1s (CPU1コア、メモリ1GB)で1500円/月、 B2s(CPU2コア、メモリ4GB)で6000円/月あたりが許容範囲内。
価格表と相談しながら初めは最小構成で作成して、パワー不足なら大きくしてもいいかもしれない。

あと、仮想マシンを起動する度に外向きのIPアドレスが変わるため、ドメイン(FQDN)の設定を忘れずにしておこう。

一通り設定してUbuntuマシンが起動するようになったら、こちらのサイトを参考にTrojan-GFWをインストールする。 

 

仮想マシンにTrojan-GFWをインストール

正直、上記サイトの通りにコマンドを打つだけで構築できてしまったので特筆することはないのだが、元サイトの消滅に備える意味も込めて手順を簡単に日本語訳を記載しておく。

~以下翻訳~

1. サーバー側

1.1. 前提条件
サーバーと一緒にドメイン名が必要になる。ドメイン名からサーバーを指すDNS Aレコードを設定すること。ここではドメイン名は example.com とし、ホスト名は www.example.com とする。
※訳注:AzureではFQDNの設定をするだけでいい為あまり深く考えなくてよい。
1.2. 偽装用Webサイトの作成
Nginxをインストールして起動する。
CentOS:
yum install nginx -y
systemctl enable nginx
systemctl start nginx
Debian or Ubuntu:
apt install nginx -y
systemctl enable nginx
systemctl start nginx
 
下記ファイルを開きNginxの設定ファイルを開く。
CentOS: /etc/nginx/nginx.conf
Debian or Ubuntu: /etc/nginx/sites-available/default
 
サーバー名を設定する。ホスト名が www.example.com の場合、下記のように設定する。
server_name www.example.com;
ファイルを保存してNginxを再起動する。
nginx -t
systemctl restart nginx
systemctl status nginx
 
Webサーバーにサンプルページを追加する。
CentOS:
yum install wget zip unzip -y
wget https://github.com/arcdetri/sample-blog/archive/master.zip
unzip master.zip
cp -rf sample-blog-master/html/* /usr/share/nginx/html/
Debian or Ubuntu:
apt install zip unzip -y
wget https://github.com/arcdetri/sample-blog/archive/master.zip
unzip master.zip
cp -rf sample-blog-master/html/* /var/www/html/
 
http://www.example.com にアクセスして偽装用のWebサイトが表示されることを確認する。
 
1.3. SSL証明書を取得する
Let's Encryptで無料のSSL証明書を取得する。
CentOS 8:
yum install epel-release -y
yum install certbot python3-certbot-nginx -y
certbot certonly --nginx
Debian or Ubuntu:
apt install certbot python3-certbot-nginx -y
certbot certonly --nginx
上記以外: EFF Certbotページを確認のこと。
https://certbot.eff.org/
 
Certbotプロンプトに応答する
・メールアドレスを入力する
・ a を入力して同意する
・ y or n を入力してメールアドレスの共有可否に応答する
・証明書が必要なホスト数を入力する

 

Let's EncryptのSSL証明書は90日間有効なので、90日ごとに自動更新するように設定する。
CentOS 8:
echo "0 0,12 * * * root python3 -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
Debian or Ubuntu:
certbot renew --dry-run
 
Let's Encryptの証明書と鍵を読み込み可能に設定し、Let's Encryptディレクトリを実行可能にする
chmod -R +rx /etc/letsencrypt
これでWebサーバーの設定は完了。
 
1.4. Trojanをインストールする
リポジトリからTrojanをインストールする。
CentOS 8:
yum config-manager --set-enabled PowerTools
yum install trojan -y
Debian 10+ or Ubuntu 20.04+:
apt install trojan -y
他のOSの場合はGitHubのTrojan-GFW wikiを参照のこと。

 

1.5. SystemDサービスを作成
systemd serviceファイルを /etc/systemd/system/trojan.service に作成する
[Unit]
Description=trojan
Documentation=man:trojan(1) https://trojan-gfw.github.io/trojan/config https://trojan-gfw.github.io/trojan/
After=network.target network-online.target nss-lookup.target mysql.service mariadb.service mysqld.service
 
[Service]
Type=simple
StandardError=journal
User=nobody
AmbientCapabilities=CAP_NET_BIND_SERVICE
ExecStart=/usr/bin/trojan /etc/trojan/config.json
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=1s
 
[Install]
WantedBy=multi-user.target
systemd serviceファイルを保存する。

 

1.6. Trojanを設定する
/etc/trojan/config.json にあるTrojanの設定ファイルを編集する。サンプル値は適宜置き換えること。
password1 に独自のパスワードを設定し、続くコンマを削除する
password2 の行を削除する。
certの行に証明書ファイルを指定する。例:/etc/letsencrypt/live/www.example.com/fullchain.pem
keyの行にキーファイルを指定する。例:/etc/letsencrypt/live/www.example.com/privkey.pem
ファイルを /etc/trojan/config.json に保存する。
 
1.7. Trojanの設定
再起動の度にTrojanが自動で立ち上がるよう設定する。
systemctl enable trojan
systemctl start trojan
 
Trojanがポート443を、Nginxがポート80をListenしていることを確認する。
ss -tulpn

 

2. クライアント側

2.1. Windows
ブラウザでGitHubのTrojan-GFWリポジトリを開く。
最新版のTrojan for Windows をダウンロードし、ZIPを解凍する。
trojanフォルダ内のconfig.jsonを下記のように編集する。
remote_addr にはホスト名を設定する(例: www.example.com )
password1 にはサーバー側で設定したパスワードを入力する
 
ファイルを保存してテキストエディタを閉じる。
Win+rキーを押してcmdと入力し、OKを押してコマンドプロンプトを起動する。
trojanフォルダに移動する。
cd Downloads\trojan-1.16.0-win\trojan
 
Trojanを起動する。
trojan
 
[WARN] trojan service (client) started at 127.0.0.1:1080 と表示されたら、Trojanはポート1080をListenしていることを意味する。

003.png

コマンドプロンプトを開いたまま、次のステップへ移る。
 
ブラウザの設定を変更して、ポート1080をListenしているTrojanを使うように変更する。
Firefoxでは、三本線メニューから設定を選択し、ネットワーク設定の設定を開き、手動プロキシ設定、SOCKS Host 127.0.0.1、Port 1080、SOCKS v5と設定しOKをクリックする。

002.png

Chromeでは、Chrome WebストアからSwitchyOmega by FelisCatusをインストールしてブラウザにプロキシ設定が可能。ホスト127.0.0.1、ポート1080でSOCKS5 プロキシを使用するよう設定する。

 

ブラウザでIP Chickenにアクセスし、IPアドレスがサーバーのIPアドレスであることを確認する。
Trojan使用終了後はコマンドプロンプトを閉じ、ブラウザのプロキシ設定をオフにする。

~翻訳おわり~

 

ここまでざっと通しで設定してみたところ、特に詰まることなく設定できた。

とりあえずクライアント側はWindowsだけだがすぐに使うことができた。

 

AndroidクライアントはIgniterがダメだった

Androidでは Igniterという公式(?)クライアントがあるのだが、どう設定をしても接続できなかった。

005.png

いくらトライしても接続できないかエラーが出てダメなので諦めて放置していた。

何度かトライしいるうちにアプリ側の問題のような気がしてきたので、PlayストアからTrojanHowdy Trojan VPNといった別のクライアントを使ってみたらすんなり接続ができた。

004.png

Androidからも接続元IPと位置情報がAzureのものになっていることを確認。

 

実地テストはいつになるやら

これで Trojan-GFWを使ったトンネリングは成功したが、実際に金盾を回避できるかどうかは現地に行ってみないと分からない。

これが一番の問題で、いつ現地に行けるようになるのか全く分からない。一応は国際線の本数が少しずつ増えてくるなど、非常にゆっくりではあるが入国緩和の方向に向かっているようだが、コロナ前のように自由に行き来できていた頃に戻るまではまだまだ時間がかかりそうだ。それまでに金盾が進化しないことを切に願う。

 

Let's Encryptの証明書更新

(記事を途中まで書いて下書きのまま)3か月が過ぎた今日、いきなりエラーが出てVPNに繋がらなくなった。

006.png

"certificate verify error"が出ている。何となく証明書関係の問題と想像がつく。

3か月は90日。そうだ、「Let's EncryptのSSL証明書は90日間有効」と記載があった...。

 

上の翻訳記事では、Ubuntuなら下記のコマンドでいいと書いてあったが

certbot renew --dry-run

今になって思えば、このコマンドだけで90日ごとに更新処理が走るとは思えない。

おそらくCentOSの場合と同様、crontabに登録するやら何やらしてやらないといけないだろう。

 

久々にAzure仮想マシンにログイン

とりあえず作業するためにログインを...と思ったが、どうやってログインするか忘れてしまっていた。

「接続」タブからSSH接続するんだっけ?

010.png

でもネットワークセキュリティの設定を変更してSSHの許可をしないといけないらしい。

前回そんな設定したっけ?してないよなぁ・・・。

011.png

あ、左メニューの一番下に「シリアルコンソール」があるんだった。これだ。

んで、ログインして......ログインユーザーもパスワードも忘れちゃった。不覚。

007.png

左メニューの「テンプレートのエクスポート」から"osProfile"を探し、"adminUsername"にユーザー名があることを知る。

パスワードは根性で思い出した。

実は左メニューの「パスワードのリセット」から新しい管理者ユーザーの作成やリセットができる。

リセットするつもりでここにパスワードを入力してみたら最低文字数があることに気づき、それをヒントに思い出すことができた。それでもダメならリセットすればいいし。

 

諸々を更新する

ようやくログインしたら「更新があるからupdateしとけよ~」とメッセージが出たので

sudo apt upgrade
sudo apt update

を実行したのだが、update時にCertbotでエラーが出る。

012.png

どうやら今のUbuntu向けのちょうどいい更新ファイルがないみたい。色々と試したが更新できなかったので一旦無視。

とりあえずapt upgradeを走らせたのでVMを再起動して、ようやく証明書の更新をすることに。

 

証明書の更新

上の翻訳記事を参考に

sudo certbot renew --dry-run

を実行したら証明書を更新することができた。かんたん。

("--dry-run"ついてるけどええんか...ええみたいやわ。不思議)

013.png

Trojanクライアントの再起動をする必要もなく、またVPN機能が元気に動き出した。

次の更新時期までにcrontab等で自動化を図りたいが、多分ズボラのまままた3か月後に同じことをするだろうな...という思いから、ちょっと詳しめに記録を残しておくことにした。

誰かの役に立てば幸いだが、多分将来の自分が読むことになるだろうな...。

コメントする