VPSとVPN(WireGuard)を使用したグローバルIPの割り当てがない環境でのサーバー構築
背景
グローバルIPが割り当てられない環境(マンション, 職場, 研究室)に機械学習サーバーを設置したい。でも、グローバルIPがないとLAN外から接続できませんね。そこで、VPSを借りてVPNサーバーとして利用し、出先のラップトップからVPSのグローバルIPを踏み台として、機械学習サーバーに接続できます。
ネットで調べるとVPNのフレームワークとして、主にopenvpn, wireguard, softetherの3つが主流のようです。今回は特にモダンでシンプルと評判のwireguardを使用したVPN環境構築を行います。
ネットワーク図
以下のようなネットワーク構成になります。今回はクライアントがWindowsと想定して行います。また、機械学習環境をWSLにセットアップすることを想定し、WSLに接続する方法も紹介します。
下準備
- VPSサーバーを借りる
- デスクトップPCにWSLを入れる
VPN環境構築
サーバーサイド(VPS)のセットアップ その1
-
Wireguardのインストール
sudo apt install wireguard -y
-
鍵の生成
sudo -i <<EOF cd /etc/wireguard/ wg genkey | tee private_key | wg pubkey > public_key exit EOF
-
鍵の閲覧
sudo -i <<EOF cd /etc/wireguard/ cat private_key cat public_key exit EOF
-
接続設定
sudo nano /etc/wireguard/wg0.conf
# /etc/wireguard/wg0.conf [Interface] PrivateKey = <Server Private Key Value> Address = 10.10.10.1/24 PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE ListenPort = <portnumber> [Peer]
-
ファイアウォールとフォワーディング設定
sudo ufw allow <portnumber>/udp sudo ufw reload
sudo nano /etc/sysctl.conf
# /etc/sysctl.conf net.ipv4.ip_forward = 1
sudo sysctl -p
クライアントサイド(PC without a global IP)のセットアップ
- GUIアプリのインストール
https://www.wireguard.com/install/ からインストールできます。 - 接続設定
アプリを起動して、左下のAdd Tunnel -> Add Empty Tunnelをクリックし以下を記載[Interface] PrivateKey = <Client Private Key Value> Address = 10.10.10.2/24 DNS = 1.1.1.1 [Peer] PublicKey = <Server Public Key Value> EndPoint = <Global IP of Server>:<portnumber> AllowedIPs = 10.10.10.0/24 PersistentKeepalive = 25
クライアントサイド(Laptop)のセットアップ
- クライアントサイド(PC without a global IP)のセットアップと同様ですが、割り当てるアドレスは変えてください
[Interface] PrivateKey = <Client Private Key Value> Address = 10.10.10.3/24 DNS = 1.1.1.1 [Peer] PublicKey = <Server Public Key Value> EndPoint = <Global IP of Server>:<portnumber> AllowedIPs = 10.10.10.0/24 PersistentKeepalive = 25
サーバーサイド(VPS)のセットアップ その2
- クライアント情報の追加
[Interface] PrivateKey = <Server Private Key Value> Address = 10.10.10.1/24 PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE ListenPort = <portnumber> [Peer] PublicKey = <Client1 Public Key Value> AllowedIPs = 10.10.10.2/32 [Peer] PublicKey = <Client2 Public Key Value> AllowedIPs = 10.10.10.3/32
VPN接続とそのテスト
-
サーバーサイド(VPS)の接続開始
sudo wg-quick up wg0
-
クライアントサイド(PC without a global IP / Laptop)の接続開始
Activateボタンをクリック -
サーバーサイド(VPS)から接続テスト
ping 10.10.10.2
ping 10.10.10.3
-
クライアントサイド(PC without a global IP)から接続テスト
ping 10.10.10.1
ping 10.10.10.3
-
クライアントサイド(Laptop)から接続テスト
ping 10.10.10.1
ping 10.10.10.2
LaptopからWSL(機械学習サーバー)に接続
- PC without a global IPでOpen SSHサーバーを構築
- WSLでOpen SSHサーバーを構築
- PC without a global IPでポートフォワード設定
netsh interface portproxy add v4tov4 listenaddress=10.10.10.2 listenport=22 connectaddress=localhost connectport=22
- LaptopからWSL(機械学習サーバー)に接続
ssh user@10.10.10.2
- ホストの登録
鍵の登録も済ましたら以下のようにホストを登録すると、ホスト名で接続できるようになります。# C:\Users\<name>\.ssh Host WSL_Server HostName 10.10.10.2 Port XXX User <name> IdentityFile C:\Users\<name>\.ssh\id_rsa
ssh WSL_Server
まとめ
以上を持って無事、グローバルIPのないパソコンの仮想環境に構築した機械学習サーバーに、VPSを踏み台として、出先のノーパソから接続できるようになりました。快適なリモート環境を楽しんでください。
あとがき
VS Codeの拡張機能であるRemote SSHは、現時点ではLinuxかMacでのみリモート上でDockerコンテナを開くことができます。つまり、WindowsのDocker Desktopを使用してDevcontainer環境をリモートから利用することは難しいです。
私は意地でもDevcontainerを使用したいと考えていたため、WSLにDockerをインストールし、最初はWSLがWireguardクライアントとしてVPN接続することで解決できると思っていました。しかし、Wireguardはopenresolvコマンドを使用する一方で、WSLはopenresolvを使用しない特殊な仕組みを持っているため、WSLからのVPN接続はできないことがわかりました。
そのため、WindowsがWireguardでVPN接続し、内部でポートフォワードを行うことで、環境構築を完了させました。WSLのネットワークの特殊さに悩まされました。
付録
クライアントを増やす
クライアントはもっと増やせます。その場合サーバーサイドの設定ファイルにクライアントを追記するだけです。
# /etc/wireguard/wg0.conf
[Interface]
...
[Peer]
PublicKey = <ClientN Public Key Value>
AllowedIPs = 10.10.10.X/32
もしもクライアントがLinuxだったら
クライアントがLinuxの場合でも同様に行えます。
-
Wireguardのインストール
sudo apt install wireguard -y
-
鍵の生成
sudo -i <<EOF cd /etc/wireguard/ wg genkey | tee private_key | wg pubkey > public_key exit EOF
-
鍵の閲覧
sudo -i <<EOF cd /etc/wireguard/ cat private_key cat public_key exit EOF
-
接続設定
sudo nano /etc/wireguard/wg0.conf
# クライアント(Linux)サイド /etc/wireguard/wg0.conf [Interface] PrivateKey = <Client Private Key Value> Address = 10.10.10.X/24 DNS = 1.1.1.1 [Peer] PublicKey = <Server Public Key Value> EndPoint = <Global IP of Server>:<portnumber> AllowedIPs = 10.10.10.0/24 PersistentKeepalive = 25
-
サーバーにPeer追加
# サーバーサイド /etc/wireguard/wg0.conf [Interface] ... [Peer] PublicKey = <ClientN Public Key Value> AllowedIPs = 10.10.10.X/32
-
接続開始
sudo wg-quick up wg0
すべての通信をVPN経由で行いたい場合
今回、クライアントは10.10.10.X
に当てた通信だけをVPN経由で行いました。しかしながら、出先ではブラウジングもVPN経由で行いたいはずです。すべての通信をVPN経由で行うためには、クライアントの設定ファイルのAllowedIPsを0.0.0.0/0
に変更してください。
[Interface]
...
[Peer]
...
AllowedIPs = 0.0.0.0/0
...
Discussion