Google Cloud Always Free プロダクトではHDD容量が30GBまでしか使えない制限がある。自宅にあるLinuxマシンをサーバにすればこの制限はなくなるが、マンション住まいのネット環境ではオプション料金を払わないとグローバルIPアドレスがアサインされないという制約がある。ところが、こちらのサイトで最小構成のレンタルサーバを使ってVPN経由で必要なサービスを自宅サーバに接続し外部ネットワークからアクセス可能とするといった話を見つけた。これと同じ方法で、Google Cloud Always Free プロダクトのサーバにVPNをインストールして、自宅のLinuxマシンのHDDをnfsマウントできるかどうか試した見た。

VPNは色々とあるが、WireGuardというVPNサーバが良さそうだった。WireGuardはLinuxカーネルツリーに統合されているVPNサーバではあるが、デベロッパーがコードやプロトコルは今のところ試験段階にあるとしているといった情報もある。今回はサーバの能力が低いので、軽めでパフォーマンスが高いことを優先してこれを使うこととした。wireguardをインストールは、こちらのサイトを参照して行った。

$ sudo su
# apt install wireguard

続いてサーバ用の鍵ペアを作成。

# wg genkey | tee /etc/wireguard/server.key
# chmod 600 /etc/wireguard/server.key

続いて,秘密鍵から公開鍵を作成。

# cat /etc/wireguard/server.key | wg pubkey | tee /etc/wireguard/server.pub
# chmod 600 /etc/wireguard/server.pub

クライアント側のマシンでも、同様にWireGuardのインストールと鍵の作成を行う。

$ sudo su
# apt install wireguard
# wg genkey | tee /etc/wireguard/client.key
# cat /etc/wireguard/client.key | wg pubkey | tee /etc/wireguard/client.pub
# chmod 600 /etc/wireguard/client.key /etc/wireguard/client.pub

サーバ側に戻ってWireGuardの設定ファイル/etc/wireguard/wg0.confを作成し、以下の内容を記述。PersistentKeepaliveの値はほとんどのファイヤーウォールで25で大丈夫とあったが、心配なら少し短い値に設定しても良いかもしれない。

[Interface]
PrivateKey = サーバの秘密鍵
Address = サーバのIPアドレス (10.0.0.1 など)
ListenPort = VPN接続に使用するポート番号

[Peer]
PublicKey = クライアントの公開鍵
AllowedIPs = 許可するIPアドレスブロック (10.0.0.2/32 など)
PersistentKeepalive = 25 (常時接続を維持するために必要)

/etc/wireguard/wg0.confのパーミッションを600にしておく。
複数台のクライアント接続する場合は、[Peer]のセクションが複数個になる。
また、Google Cloud Platformのファイアウォールの設定で、ここで指定したポート番号へのアクセス(udp)を許可しておく。

# chmod 600 /etc/wireguard/wg0.conf

クライアント側でもWireGuardの設定ファイル/etc/wireguard/wg0.confを作成し、以下の内容を記述。

[Interface]
PrivateKey = クライアントの秘密鍵
Address = クライアントのIPアドレス (10.0.0.2 など)

[Peer]
PublicKey = サーバの公開鍵
EndPoint = サーバのIPアドレス:VPN接続に使用するポート番号
AllowedIPs =  WireGuardを経由して通信する先のIPアドレスブロック (10.0.0.0/24 など)
PersistentKeepalive = 25 (常時接続を維持するために必要)

/etc/wireguard/wg0.confのパーミッションを600にしておく。

# chmod 600 /etc/wireguard/wg0.conf

サーバ上でWireGuardのサービスを起動

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

ipコマンドでインターフェイスが生成されていることを確認。

# ip a

wg0のインターフェースが作成されていればOK。
クライアントからVPNへ接続する。

# wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.0.0.2 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] ip -4 route add 10.0.0.0/24 dev wg0

ipコマンドでインターフェイスが生成されていることを確認。

# ip a

wg0のインターフェースが作成されていればOK。
クライアントからサーバーに対してPingを打って、応答が返ってくることを確認しておく。

# ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56(84) バイトのデータ
64 バイト応答 送信元 10.0.0.1: icmp_seq=1 ttl=64 時間=102 ミリ秒
64 バイト応答 送信元 10.0.0.1: icmp_seq=2 ttl=64 時間=103 ミリ秒
64 バイト応答 送信元 10.0.0.1: icmp_seq=3 ttl=64 時間=103 ミリ秒

サーバー上でwgコマンドを実行し、現在のコネクションの状態が表示する。
ハンドシェイクが成功し、データの送受信が発生していれば成功。

# wg
interface: wg0
  public key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (サーバの公開鍵)
  private key: (hidden)
  listening port: VPN接続に使用するポート番号

peer: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (クライアントの公開鍵)
  endpoint: クライアントのグローバルIPアドレス:クライアントのポート
  allowed ips: 10.0.0.2/32
  latest handshake: 8 minutes, 16 seconds ago
  transfer: 1.33 KiB received, 1.21 KiB sent

クライアント側もWireGuardのサービスを起動するように設定しておく。

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

以上でGoogle Cloud Flatformから自宅のLinuxマシンへのVPN接続は完了。
とりあえずVPN接続が有効な状態で自宅のHDDをnfsマウントできることを確認。これでグローバルIPを持たない自宅サーバのHDDをGCPのグローバル固定IPアドレスで参照できるようになる。