🛡️

Gluetun+Tailscaleで(強引に)VPNで保護されたExit Nodeを組む

に公開

きっかけ

普段はMullvad VPNを使っているのですが、普通にTailscaleを使うとMullvadと共存できない関係で自分のipを晒す事になってしまいます。
TailscaleはMullvadと提携しているので管理画面からMullvadを買って終わり!!でもいいですが、せっかくなら1~2台程度の最低限のマシンだけMullvadに接続して、他の家庭内・別拠点内にあるマシンはそれを経由するようにしたいです。そうすれば5台までしか使えないというMullvad VPNの制約を回避し、何十台の物理(または仮想)マシンがあってもVPNを介して通信できるようになります。
という事でそんな夢を叶えられる方法がないか調べたところ、GluetunというDocker Imageを見つけました。
Dockerコンテナ向けのvpnクライアントで、こいつを他のサービスとがっちゃんこしてやればVPN経由でなんでも通信できる!!!ってわけです。
実は結構前から試行錯誤しながら実験しまくっていて、とりあえずまともに動くレベルまで持っていけたので記事として残しておこうと思います。

試行錯誤している間に色んなフォーラムなりGithubのディスカッションなりを参考にしまくりました。感謝感謝。

材料

docker-compose.ymlを用意

docker-compose.yml
services:
  gluetun:
    container_name: Gluetun
    hostname: GluetunTS
    image: qmcgaw/gluetun
    cap_add:
      - NET_ADMIN
    ports:
      - 1090:1090 #socks5
    devices:
      - /dev/net/tun:/dev/net/tun
    environment:
      - VPN_SERVICE_PROVIDER=custom
      - VPN_TYPE=wireguard
      - WIREGUARD_ENDPOINT_IP=123.456.7.89
      - WIREGUARD_ENDPOINT_PORT=52001
      - WIREGUARD_PUBLIC_KEY=eW91dHViZS5jb20vd2F0Y2g/dj1kUXc0dzlXZ1hjUQ=
      - WIREGUARD_PRIVATE_KEY=eW91dHViZS5jb20vd2F0Y2g/dj1RRGlhM2UxMmN6Yw=
      - WIREGUARD_ADDRESSES=10.20.300.400/32
      - TZ=Asia/Tokyo
  tailscale:
    container_name: TailScale
    image: tailscale/tailscale:latest
    depends_on:
      gluetun:
        condition: service_healthy
    environment:
      - TS_HOSTNAME=tsvpn
      - TS_OUTBOUND_HTTP_PROXY_LISTEN=:1090
      - TS_ACCEPT_DNS=true
      - TS_AUTHKEY=tskey-auth-xxxxxxxxxxxx
      - TS_EXTRA_ARGS=--advertise-exit-node --accept-routes
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_USERSPACE=true
      - TS_ROUTES=192.168.1.0/24
    volumes:
      - ${PWD}/tailscale-nginx/state:/var/lib/tailscale
    devices:
      - /dev/net/tun:/dev/net/tun
    cap_add:
      - net_admin
    restart: unless-stopped
    network_mode: service:gluetun

まずGluetunが接続を試みて、接続完了でhealthyになったらTailscaleが立ち上がるようになっています。まあDockerゴリゴリに扱ってる人間からすれば当たり前の事なんでしょうけど、私はこの設定ファイルを書くために色々調べている間に初めて知りました。便利ですね〜

設定する環境変数

Gluetun

Mullvadの場合、VPN_SERVICE_PROVIDER=mullvadを使うようにWiki上では指示されていますが、それだと動かなかったので、customにしてゴリ押してます。
https://mullvad.net/ja/account/wireguard-config から接続用の設定ファイルを生成して、ダウンロードしてください。ポートなりプロトコルなり、細かい設定はお任せします。

ダウンロードした設定ファイルを見ながら、以下の変数を設定してください。

  • WIREGUARD_ENDPOINT_IP[Peer]内のEndpointにあるip
  • WIREGUARD_ENDPOINT_PORT[Peer]内のEndpointにあるport
  • WIREGUARD_PUBLIC_KEY[Peer]内のPublicKey
  • WIREGUARD_PRIVATE_KEY[Interface]内のPrivateKey
  • WIREGUARD_ADDRESSES[Interface]内のAddress

その他の変数設定はお好みで。国外在住であればTZいじるなりなんなり。

Tailscale

以下のとおりに設定。

  • TS_AUTHKEY管理画面で生成したキーをコピペ
  • TS_ROUTES ▶ マシンが設置されているネットワークのCIDRを設定
  • TS_OUTBOUND_HTTP_PROXY_LISTEN ▶ httpプロキシのポートを指定(:を忘れずに)

他はお好きに。HOSTNAMEいじるなりなんなり。

起動

そういえばdocker-compose.ymlってファイル名の場合は-fオプション付けなくても立ち上がるらしいです。(前書いた記事では付けてた)
なので

sudo docker compose up

これだけで動きます。うひょ〜
管理画面に表示されていればOK。

Subnet routesとExit nodeの設定

ボタンポチポチするだけです。
管理画面から先程のマシンを見つけ、...をクリック
Edit route settings...からSubnet routesExit nodeにある項目にチェックを入れてSave
おわり!

接続テスト

お好きな端末でTailscaleにログインして、exit nodeを見つけて接続してみてください。pingなりページを開くなりして繋がれば成功です。

致命的な問題

確かにつながりはしたけど...
でも...

めっちゃ遅い!!!!(環境による差はあり)
私の場合は1.1.1.1へのpingが100msを超え、下りは脅威の0.6mbpsを叩き出しました。もちろんvpnは国内にあるサーバーを選んでいます。

「リレーを経由しているのでは?」
いいえ。sudo docker exec -it TailScale tailscale ping {端末名}を叩いてもリレーは一切経由せず直接接続されている事がわかります。(リレー経由の場合、via DERP(osk) in **msという表記になります。)

これに関してはいくつかの問題があります。

1. 無駄が多い

Gluetun+Tailscaleという構成なのもあり、表面上はVPNのIPしか見えていません。
つまり、こうなっているわけです。(Mermaidムズカチイ)

クライアントがexample.comへHTTPなり何かしらのリクエストを送りたい場合、

  1. Exit NodeへVPNのIPを経由して接続しリクエストを送信(Client ▶ VPN ▶ Node)
  2. Exit NodeはVPNを経由してリクエストを宛先へ送信(Node ▶ VPN ▶ Destination)
  3. レスポンスを受け取る(Destination ▶ VPN ▶ Node)
  4. 受け取ったレスポンスをクライアントへ送信(Node ▶ VPN ▶ Client)

という手順を辿ります。

家の中であればVPNを経由せずに Client ▶ Node とつながるようにしたいですね。

2. そもそもTailscaleのExit Nodeが遅い?(多分?)

試しにGluetunを抜いてみましょう。

docker-compose.yml
services:
  tailscale:
    container_name: TailScale
    image: tailscale/tailscale:latest
    environment:
      - TS_HOSTNAME=TSSingle
      - TS_AUTHKEY=tskey-auth-xxxxxxxxxx
      - TS_EXTRA_ARGS=--advertise-exit-node --accept-routes
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_USERSPACE=false
      - TS_ROUTES=192.168.1.0/24
    volumes:
      - ${PWD}/tailscale-nginx/state:/var/lib/tailscale
    devices:
      - /dev/net/tun:/dev/net/tun
    cap_add:
      - net_admin

この状態でsudo docker exec -it TailScale tailscale ping {lan内の端末名}なりしてみると、lan内で直接つながりました。
じゃあスピードの方はというと、下り上り両方とも20mbpsほどです。普段は400mbps近く出るのですが、Exit Nodeを経由すると一気にスピードが落ちました。
フォーラムでも「同じ様な問題が発生する」だの「いいや、私の環境では正常だ」だのと言い争っているので、恐らく環境によってここは変わると思います。

(2025/07/04 追記) 東京リージョンのVPSを買ったのでTailscaleを入れてExit Node化してみました。なんと上り下り 400mbps という結果を叩き出しました。やはり環境によってここら辺の差は生じそうです。(特に東京都外に住んでいる場合は影響を受けそうです。)

HTTP Proxyで接続!

外出する予定がない人間であれば、家の中でhttp proxyを使って接続するのが手っ取り早いです。
先程TS_OUTBOUND_HTTP_PROXY_LISTENを設定しましたね!!もう準備は整っているので、あとはクライアント側で設定するだけです!!

(プロキシの設定は端末によって異なるので省略します)

スピードを測ってみると...

200~300mbpsほど出ました!!大成功です!!

もちろんTailscale内にある他のマシンへの接続も可能です!

外出先でも、一応Dockerを動かすことができれば同じ事ができます。
(ちょっぴり面倒ですが...)

おわりに

結構強引なところもありますが、やりたいことはできたので満足です。
他のイメージと組み合わせて認証付きプロキシ化したり、もう一個WireguardのVPNを生やすなり、色々やれることはあると思います。
ぜひお試しあれ。

Discussion