なうびるどいんぐ

脳みそ常時-3dB

WSL2のDockerでOpenVPN接続したFirefoxを使う

      2021/03/17    HimaJyun

WSL2の上で動くDockerでOpenVPNを使ってVPN接続されたFirefoxを使います。ちなみにheadlessでもGUI有でもOK。

「は?」と思った方、おそらくあなたの感覚は正しい。

スポンサーリンク

動機

動機は特にないです。「こういうこと出来るかな?」と思ったら試さずには居られなくなるんです。

しいて言うなら、ローカルからじゃなくてインターネットから動作確認したいサービスがある時に役に立つかも知れません。

(一般のご家庭なら2本目の光回線があるはずですし、いまどきはテザリングも当たり前に使えるので、そういう使い道にもあまり役に立たない)

「できますよ」という話です。どう役立てるかは自分で考えてどうぞ😎

前提条件

WSL2の上でDockerが動いているだけなので、そこから先はどんなOSでも同じです。要するにOepnVPNに接続したFirefoxの入ったDockerイメージを作ろうという話なので。

前提条件は「Dockerが動くこと」です。そこさえ満たせれば後は何でもいい。

GUIで利用する場合はホスト側にX11が必要になります。WindowsならMobaXtermのポータブル版がインストール不要で使えるので良いと思います。

十分にパワフル💪なパソコンで実行する事を推奨。Docker≒CPUレンダリングになるのでクソザコCPUでは話になりません、Ryzen 7 3700Xで最低限使えるレベルなのでたぶんAtomとかでは論外です。(コンテナにGPUを接続できれば高速化できるかも?)

並列実行+異なるVPN接続先を利用することも可能ですが、コンテナ1個につき最低300MBはメモリを消費します。今どきは32GBが基本的人権なのでこちらは大丈夫かな?

OpenVPNの所をSoftetherとかWireGuardとかstrongSwanにしたり、Firefoxの所をChromeとかChromiumにする事も可能だと思います。知らんけど😎

OpenVPN接続したFirefoxが動くDockerコンテナ

OpenVPNコンテナを建てて--net="container:名前"みたいにする手法もありますが、今回は全部入りのコンテナを作成します。

主な手順は以下の通り。

  1. コンテナに入る
  2. aptミラーの変更
  3. パッケージのインストール
  4. ルーティングテーブルの変更
  5. 起動

この記事では手順(コマンド)を1個ずつ実行してるだけなので、自動化のためのスクリプトやDockerfileは自分で考えてください🤗

コンテナに入る

コンテナに入りましょう。ネットワーク関係の特権が必要です。

docker run --rm -it --cap-add=NET_ADMIN --device /dev/net/tun ubuntu:20.04

(20.04を指定してますが、たぶんlatestでも大丈夫です。Debian:10.7でも可能でしたが心なしかUbuntuの方が動作が良い気がする……)

timezoneの調整とか、shmの拡大とか、ファイルを共有するためのマウントとかがあるので実際はこんな感じになるはず。

docker run --rm -it \
  -e TZ=Asia/Tokyo \
  --shm-size=256mb \
  -v ./firefox:/root/Downloads \
  --cap-add=NET_ADMIN --device /dev/net/tun \
  ubuntu:20.04

WSL2のDockerの場合は-vのホスト側のパス指定はフルパスで指定する必要があります。(例: -v C:\firefox:/firefox)

あと、PowerShellは改行のエスケープが`です。つまりWSL2+PowerShellならこう。

docker run --rm -it `
  -e TZ=Asia/Tokyo `
  --shm-size=256mb `
  -v C:\firefox:/root/Downloads `
  --cap-add=NET_ADMIN --device /dev/net/tun `
  ubuntu:20.04

Bashの構文で動くPowerShellが求められている😖

aptミラーの変更

(Debianの場合は何もしなくても高速なのでやらなくて良いと思います)

Firefoxやその依存関係で約1GBのデータをダウンロードする必要があるのでaptのミラーを先に変更しておきます。それかイギリスに移住してください。

sed -i "s@archive.ubuntu.com@jp.archive.ubuntu.com@g" /etc/apt/sources.list

ちなみにjp.archive.ubuntu.comの実体はubuntutym.u-toyama.ac.jpです。(2021/01/22現在)

より高速な(もしくは、お気に入りの)ミラーがあるのならそれを指定してもよし。(ミラーリストを参考に)

# JAIST
sed -i "s@archive.ubuntu.com@ftp.jaist.ac.jp/pub/Linux@g" /etc/apt/sources.list
# 理研
sed -i "s@archive.ubuntu.com@ftp.riken.jp/Linux@g" /etc/apt/sources.list
# ミラーリスト
sed -i "s@http://archive.ubuntu.com/ubuntu/@mirror://mirrors.ubuntu.com/mirrors.txt@g" /etc/apt/sources.list

更新したミラーを適用する

apt-get update

一部のミラー(httpsを使っている所)はca-certificatesがないとNo system certificates available.が出るので入れておきましょう。

apt-get install -y ca-certificates

余談ですが、security.ubuntu.comは書き換えない方が良いでしょう。

security.ubuntu.comの実体はarchive.ubuntu.comと同じため、ミラーサーバーを指定しても動作はします。

ただ、最新のパッケージがミラーに同期されるまでにはタイムラグがあったり、ミラーが落ちていたりすることがあるため、セキュリティアップデートは別ドメインとすることでミラーを使用した高速化と迅速なパッチ適用を両立しよう……という事らしい。(SecurityTeam/FAQ - Ubuntu Wikiにそう書かれています)

(archive.ubuntu.comから配信するスタイルだと巷にあるapt高速化用ワンライナーsedで一緒に書き換えられてしまうので別ドメインとした……という事だと思う)

Docker環境でそんなこと気にする必要があるか?と聞かれると微妙だが……

パッケージのインストール

FirefoxとOpenVPNをインストールしましょう。

DEBIAN_FRONTEND=noninteractive apt-get install -y \
  openvpn \
  firefox xserver-xorg fonts-takao

DEBIAN_FRONTEND=noninteractiveを付けないと途中で選択肢が出てきて自動化で困ります。

OpenVPNはそれ1つで完結しますが、FirefoxにはX11と日本語フォントが必要になります。

ちなみにDebianの場合はFirefoxのパッケージ名がfirefox-esrになります。

ルーティングテーブルの変更

(OpenVPNを使わない=ただFirefoxをDockerで動かしたいだけならこの手順は不要です)

普通のGUIアプリだとexport DISPLAY=host.docker.internal:0.0とかってすると思うんですが、OpenVPNを動かすとルーティングテーブルを書き換えられるのでこれが使えなくなります。

という訳で、それの対策として自分でhost.docker.internalのIPアドレスを解決してルーティングテーブルに追加します。

この手順にはdig(dnsutils)とip(iproute2)が必要なので入れましょう。(iproute2はOpenVPNと一緒に入ってるはず)

apt-get install -y dnsutils iproute2

dig host.docker.internalでホストのIPを確認、ip routeでデフォルトゲートウェイを確認、ルーティングテーブルに追加しましょう。つまりこういう事です。

host=$(dig host.docker.internal A +short)
gateway=$(ip route | grep "default" | cut -f 3 -d " ")
ip route add "${host}/32" via "${gateway}" dev eth0
#ip route add 192.168.65.2/32 via 172.17.0.1 dev eth0

(/tmp/.X11-unix/とかをマウントしてる場合は上記手順を省略可能)

もう一つ問題点があって、/etc/resolv.confで指定されているDNSも解決できなくなるのでこいつもルーティングテーブルに入れましょう。

※ 以下の例はnameserverが複数指定されてると正しく動かない

dns=$(grep "nameserver" /etc/resolv.conf | cut -f 2 -d " ")
ip route add "${dns}/32" via "${gateway}" dev eth0
#ip route add 192.168.65.1/32 via 172.17.0.1 dev eth0

(外部DNSをdockerコマンドで指定している場合は上記手順を省略可能)

当たり前なんですがこんな事をすると名前解決にホストのネットワーク(=暗号化されていない経路)が使われるので、その辺に不都合がある人は自由インターネットを手に入れるために他の方法が必要です。

例えばこうやってDNSを変えるとか (DNS自体が暗号化されてないって問題もあるんですがね、それは本題から逸れるのでこの記事では扱わない)

echo "nameserver 1.1.1.1" > /etc/resolv.conf

まぁ、とにかく、OpenVPNに接続した状態でもホストとDNSの解決はできるようにしておきましょう。

DISPLAY環境変数の設定をお忘れなく。

export DISPLAY="${host}:0.0"
#export DISPLAY=192.168.65.2:0.0
# DNSを変えていないならこれも可
#export DISPLAY=host.docker.internal:0.0

X11とOpenVPNとDockerの共存はこの辺りが厄介🥺

起動

まずはOpenVPNを起動します。

openvpn --config "vpn.ovpn" &

接続先設定(vpn.ovpn)の用意は人によってやり方が違うと思うのでここでは解説しません。ファイルをマウントするのでもcurlでダウンロードするのでも良い。

&でバックグラウンド化します、本当はSupervisorとか使ってちゃんとした方が良いと思います。今回は面倒なのでこの方法で行きます。

Firefoxを起動します。その前にホストのX11を起動しておくのをお忘れなく。(特にWindows)

firefox --new-instance

動いたよね?(乱暴)

はまりどころ、問題点

とりあえず最低限動くようにしただけなので色々問題点はあります。

別コンテナで起動

別々のコンテナで異なる接続先を使ってFirefoxを起動する事ができます。

……が、その時に--new-instanceを付けないと既に起動している他のコンテナで新しいウインドウが開くという変な挙動になる。

ふしぎ、なんで?

ダウンロードしたファイルの保存先

Firefoxはデフォルトで~/Downloadsにファイルをダウンロードします。

なので、rootの~/Downloads(=/root/Downloads)にホストのディレクトリをマウントしてやると設定変更をせずともダウンロードしたファイルを共有できるようになります。

重い

そこそこ重いです、あくまで実験用。

ブラウジングがままならないって程ではないですが、ぐいんぐいん動くようなコンテンツは厳しいです。

GPUを繋ぐ方法があれば高速化できるかも。(WSL2でもそういう事を出来るようにする的な開発が行われているらしいので、そのうち出来るようになるかも)

音出ません

でません🔈

PulseAudioで頑張れば行けるかもしれない、がんばって👍

日本語打てません

めんどくさいので研究しませんでした。(本質から逸れるし)

ホストでメモ帳か何かに打ってコピペすれば良いでしょみたいな頭になってます。

可能だが実験用

やってみた感じ、実験用って感じです。

何よりも重いのがネック、こんな事をしてブラウジングをする意味もないし。

1つのNICで簡単に大量のIPを持てるので、用途があるとしたらそれくらいかな……

 - プログラミング , ,