私のWireguardを利用したVPNのセットアップ

2023/05/24に公開

背景

グローバルIPが割り当てられない環境(マンション, 職場, 研究室)に機械学習サーバーを設置したい。でも、グローバルIPがないとLAN外から接続できませんね。そこで、クラウドサービスでVPNサーバーを建てて、出先のラップトップからVMのグローバルIPを踏み台として、機械学習サーバーに接続できるようにしたいと思います。

ネットで調べるとVPNのフレームワークとして、主にopenvpn, wireguard, softetherの3つが主流のようです。今回は特にモダンでシンプルと評判のwireguardを使用したVPN環境構築を行います。

ネットワーク図

以下のようなネットワーク構成になります。今回は接続先がWSL(Windows Subsystem for Linux), 接続元がChromebookと仮定し、VPNサーバーとしてGCPのGCE(Ubuntu)を利用した手順を紹介します。

下準備

  1. GCP, AWS等でVMのインスタンスを建てる
    私はGCP派なので、例えばGCEを建てる際は以下のとおりに設定するとよいです。
    • UDPの51820を開く
    • イメージはUbuntuで作成
    • エフェメラルIPではなく固定IPを使用
    • SSH keyを登録
  2. デスクトップPCにWSLを入れる

VPNサーバーのセットアップ

  1. Wireguardのインストール

    sudo apt update -y
    sudo apt upgrade -y
    sudo apt autoremove -y
    
    sudo apt install wireguard -y
    
  2. サーバー鍵の生成

    sudo -i <<EOF
    cd /etc/wireguard/
    wg genkey | tee server_private_key | wg pubkey > server_public_key
    chmod 400 server_private_key server_public_key
    exit
    EOF
    
  3. サーバーの設定

    sudo tee /etc/wireguard/wg0.conf > /dev/null <<EOF
    [Interface]
    PrivateKey = $(sudo cat /etc/wireguard/server_private_key)
    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 = 51820
    EOF
    
  4. ポートフォワーディング設定

    sudo tee /etc/sysctl.conf> /dev/null <<EOF
    net.ipv4.ip_forward = 1
    EOF
    sudo sysctl -p
    
  5. クライアントの追加
    以下のコードを実行し、クライアントIDを入力すればクライアントの追加ができます。今回は、クライアントを2台追加するため、2度実行してください。

    read -p "Enter client ID (2-254): " client_id
    if ! [[ $client_id =~ ^[2-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-4]$ ]]; then
        echo "Error: Client ID must be between 2 and 254"
        exit 1
    fi
    
    # Check if client configuration file already exists
    client_conf="/etc/wireguard/client${client_id}.conf"
    if [ -f "$client_conf" ]; then
        echo "Configuration file for client ${client_id} already exists: $client_conf"
        read -p "Do you want to overwrite it? (y/n) " overwrite
        if [[ $overwrite != "y" ]]; then
            echo "Aborting..."
            exit 0
        fi
    fi
    
    sudo -i <<EOF
    cd /etc/wireguard/
    wg genkey | tee client${client_id}_private_key | wg pubkey > client${client_id}_public_key
    chmod 400 client${client_id}_private_key client${client_id}_public_key
    exit
    EOF
    
    sudo tee -a /etc/wireguard/wg0.conf > /dev/null <<EOF
    [Peer]
    PublicKey = $(sudo cat /etc/wireguard/client${client_id}_public_key)
    AllowedIPs = 10.10.10.${client_id}/32
    EOF
    
    sudo tee /etc/wireguard/client${client_id}.conf > /dev/null <<EOF
    [Interface]
    PrivateKey = $(sudo cat /etc/wireguard/client${client_id}_private_key)
    Address = 10.10.10.${client_id}/24
    DNS = 1.1.1.1
    
    [Peer]
    PublicKey = $(sudo cat /etc/wireguard/server_public_key)
    EndPoint = $(curl ifconfig.me):51820
    AllowedIPs = 10.10.10.0/24
    PersistentKeepalive = 25
    EOF
    
    
  6. クライアントの設定ファイルを閲覧
    下記のコードで、後の設定に必要な設定ファイルを閲覧できます。

    sudo cat /etc/wireguard/client${client_id}.conf
    
  7. VPNサーバーの起動

    sudo systemctl enable wg-quick@wg0
    sudo systemctl start wg-quick@wg0
    

    もし新しくクライアントを追加した場合は、以下のコマンドで再起動する必要があります。

    sudo wg-quick down wg0
    sudo wg-quick up wg0
    sudo systemctl start wg-quick@wg0
    
  8. 接続できているかテスト
    以下のようにしてpingコマンドで接続できるか確認できます。ちなみに、Windowsはpingを返答してくれません。

    ping 10.10.10.X
    

クライアントサイドのセットアップ(Windowsの場合)

  1. GUIアプリのインストール
    https://www.wireguard.com/install/ からインストールできます。
  2. 接続設定
    アプリを起動して、左下のAdd Tunnel -> Add Empty Tunnelをクリックし、先程のクライアントの設定ファイルをコピペします。

クライアントサイドのセットアップ(Chromebookの場合)

  1. GUIアプリのインストール
    https://www.wireguard.com/install/ に記載されている、PlayStoreからインストールできます。
  2. 接続設定
    アプリを起動し、先程のクライアントの設定ファイルを参考に接続先を追加します。設定ファイルを.confという拡張子でテキストファイルとして保存すれば、import from a fileから簡単に追加できます。

WSLに直接SSHする

このままでは、Windowsに接続できるようになりましたが、WSLに接続はできていません。私の別記事を参考にしてください。

まとめ

以上を持って無事、グローバルIPのないパソコンの仮想環境に構築した機械学習サーバーに、VPNサーバーを踏み台として、出先のノーパソから接続できるようになりました。快適なリモート環境を楽しんでください。

あとがき

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接続し、内部でポートフォワードを行うことで、環境構築を完了させました。

付録

クライアントサイドのセットアップ(Linuxの場合)

クライアントがLinuxの場合でも同様に行えます。

  1. Wireguardのインストール

    sudo apt install wireguard -y
    
  2. 接続設定

    sudo nano /etc/wireguard/wg0.conf
    

    に設定ファイルをコピペしてください。

  3. 接続開始

    sudo systemctl enable wg-quick@wg0
    sudo systemctl start wg-quick@wg0
    

すべての通信をVPN経由で行いたい場合

今回、クライアントは10.10.10.Xに当てた通信だけをVPN経由で行いました。しかしながら、出先ではブラウジングもVPN経由で行いたいはずです。すべての通信をVPN経由で行うためには、クライアントの設定ファイルのAllowedIPsを0.0.0.0/0に変更してください。

[Interface]
...

[Peer]
...
AllowedIPs = 0.0.0.0/0
...

Discussion