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

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

注:Ubuntu MinimalではなくUbuntu Serverを選ぶこと。

VMシリーズ

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

ネットワーク

仮想マシンの作成が完了したら、ドメイン(FQDN)の設定を忘れずにしておこう。

マシンの概要「DNS 名」の所に値が表示されていればOK。

注:例えば「example.japaneast.cloudapp.azure.com」など。

また、「ネットワーク」の受信ポートの規則にHTTPとHTTPSの受信を許可する設定もしておこう。

network.png

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

 

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

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

※各コマンドは管理者権限が必要な場合があるため、適宜頭に「sudo」をつけて実行している。

 

~以下翻訳~

 

1. サーバー側

1.1. 前提条件
サーバーと一緒にドメイン名が必要になる。ドメイン名からサーバーを指すDNS Aレコードを設定すること。ここではドメイン名は example.com とし、ホスト名は www.example.com とする。
※訳注:Azureでは設定したFQDN(DNS名)=ドメイン名=ホスト名と考えればいい。
1.2. 偽装用Webサイトの作成
Nginxをインストールして起動する。
CentOS:
yum install nginx -y
systemctl enable nginx
systemctl start nginx
Debian or Ubuntu:
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx
注:インストールできない場合、先に sudo apt-get update を実行するとよい。
 
下記ファイルを開きNginxの設定ファイルを開く。
CentOS: /etc/nginx/nginx.conf
Debian or Ubuntu: /etc/nginx/sites-available/default
 
サーバー名を設定する。ホスト名が www.example.com の場合、下記のように設定する。
server_name www.example.com;
注:ファイルを開いて「server_name」で検索すると当該箇所を発見できる。

 

ファイルを保存してNginxを再起動する。
sudo nginx -t
sudo 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:
sudo 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/
注:コピー時にPermission deniedエラーが出る場合、頭にsudo をつける
 
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:
sudo apt install certbot python3-certbot-nginx -y
sudo 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
CentOS 8と同じコマンドでよい
 
Let's Encryptの証明書と鍵を読み込み可能に設定し、Let's Encryptディレクトリを実行可能にする
sudo 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+:
sudo 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が自動で立ち上がるよう設定する。
sudo systemctl enable trojan
sudo systemctl start trojan
 
trojanが正常に実行されていることを確認する
systemctl status 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使用終了後はコマンドプロンプトを閉じ、ブラウザのプロキシ設定をオフにする。

~翻訳おわり~

 

上手く行かない場合、手動でtrojanを起動してみる

admin@U2204:~$ trojan
Welcome to trojan 1.16.0
[2023-09-02 07:33:15] [FATAL] fatal: bind: Permission denied
[2023-09-02 07:33:15] [FATAL] exiting. . . 

↑sudoをつけてないためエラーが出ているが、systemctl から起動する場合はroot権限で実行されるため問題ないはず。

rootで動かしても上記エラーになる場合は、下記コマンドの実行漏れでLet's Encryptの証明書と鍵ファイルにアクセスできていない可能性あり。

sudo chmod -R +rx /etc/letsencrypt

 

他のエラー

admin@U2204:~$ trojan
Welcome to trojan 1.16.0
[2023-09-02 08:02:43] [FATAL] fatal: /etc/trojan/config.json(9): expected value
[2023-09-02 08:02:43] [FATAL] exiting. . . 

↑このエラーは /etc/trojan/config.json 編集時にpassword1の後のカンマを消し忘れている等、jsonファイルの書き方がおかしい時に出る。

 

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か月後に同じことをするだろうな...という思いから、ちょっと詳しめに記録を残しておくことにした。

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

コメントする