Wireguard でサーバーと家のPCをつなぐ
インターネットの向こうにある検証用サーバーを使うときに、検証なのでインターネットにさらしたくないが、自分のPCのブラウザからは見られるようにしたい。自宅のIPアドレスは固定ではないのでIPで制限かけるのは微妙だし、HTTPSならBASIC認証とか設定すればいいけど検証なので設定増えると面倒。LANにあるマシンのように気楽に使いたい。
そういうことで、PCとサーバーをVPNでつなぐことにした。サーバーのグローバルインターフェースはVPNのポートだけ許可し、VPNインターフェースは制限無しにすることで、ローカル環境のサーバーのように気楽に扱える。
簡単に設定できるWireguardを使った。設定後も普通のインターフェースのように扱えるので楽ちん。
環境
サーバーの設定
Wireguardをインストールする
$ sudo apt install wireguard $ sudo reboot
Wireguardの鍵を作る
private keyはroot以外読めないようにする。
$ sudo sh -c 'cd /etc/wireguard; wg genkey | tee privatekey | wg pubkey > publickey' $ sudo chmod 660 /etc/wireguard/privatekey
Wiregaurd設定ファイルを作る
システム起動時に自動的にupするよう、wg-quickサービスを使う。パラメーターっぽいものは以下。
- インターフェース名: wg0
- VPN InterfaceのIP: 10.0.0.1
- Listen port: 47474
- PCのVPN InterfaceのIP: 10.0.0.2
- AllowedIPsは/32でピアのIPを指定
- Hub-and-SpokeではなくPeer-to-Peer
$ sudo vi /etc/wireguard/wg0.conf [Interface] SaveConfig = false Address = 10.0.0.1/24 ListenPort = 47474 PrivateKey = {/etc/wiregaurd/privatekeyの内容} PostUp = /etc/wireguard/postup.sh %i 47474 PostDown = /etc/wireguard/postdown.sh %i 47474 [Peer] PublicKey = {PC側で設定したIFのpublic key} AllowedIPs = 10.0.0.2/32
Peer (自宅PC)はNAPTの向こうにいるので、ポートは書かない。サーバー側のポートが固定なのでOK。
PostUp, PostDownで使うスクリプトを作る。GWインターフェース(グローバルIPが振られているインターフェース)にWireguardのlisten portを追加し、Wiregaurdのインターフェース(wg0)は全ての通信を許可する。
$ sudo vi /etc/wireguard/postup.sh IF=$1 PORT=$2 GW_IF=$(ip -j route list default | python3 -c 'import sys,json; print(json.load(sys.stdin)[0]["dev"])') ufw allow in on $GW_IF to any port $PORT proto udp ufw allow in on $IF ufw status verbose
$ sudo vi /etc/wireguard/postdown.sh IF=$1 PORT=$2 GW_IF=$(ip -j route list default | python3 -c 'import sys,json; print(json.load(sys.stdin)[0]["dev"])') ufw delete allow in on $GW_IF to any port $PORT proto udp ufw delete allow in on $IF ufw status verbose
$ sudo chmod 755 /etc/wireguard/post{up,down}.sh
サービスを有効にし、起動する
$ sudo systemctl enable --now wg-quick@wg0.service
wg-quick@{hoge}.service は /etc/wireguard/{hoge}.conf を読み込む。そのへんの仕組みは /lib/systemd/system/wg-quick@.service
とか man systemd.unit
の template unit あたりを参照。
状態確認
$ sudo wg show wg0 interface: wg0 public key: xxxx private key: (hidden) listening port: 47474 peer: xxxx endpoint: 198.51.100.1:56243 allowed ips: 10.0.0.2/32 latest handshake: 1 hour, 35 minutes, 45 seconds ago transfer: 26.16 KiB received, 24.44 KiB sent
PCの設定
Wiregaurdアプリケーションでトンネル設定
Add Empty Tunnel から設定を作成する。自動的にprivate/public keyが作られるので、public keyの文字列をサーバーの設定ファイル wg0.conf
にコピペする。
[Interface] PrivateKey = {自動で作られる} Address = 10.0.0.2/24 [Peer] PublicKey = {サーバーのpublic key} AllowedIPs = 10.0.0.1/32 Endpoint = 203.0.113.1:47474
接続
サーバーとPC側でインターフェースを有効にする/activateするだけでは何も通信は発生せず、実際に通信が発生したときにハンドシェイクするようだ。PCはNAPTの奥にいるので、PCからサーバーに通信を投げる必要がある。
補足: dockerとiptatbles
dockerでportをpublishすると、ufwで許可していないはずなのに、外からアクセスできてしまう。これは、dockerのポート宛ての通信はINPUTチェーンではなく、FORWARDチェーンを通るため。
dockreのドキュメントに書いてあるように( Docker and iptables | Docker Documentation
)、DOCKER-USERチェーンにルールを追加する必要がある。グローバルインターフェース(eno1)からdockerのポート宛ての通信を全て拒否する場合、以下の設定を入れる。
$ sudo iptables -I DOCKER-USER -i eno1 -o docker0 -j DROP
Wireguardでつないでいる場合、10.0.0.1へのアクセスはwg0インターフェース経由での通信になるので、上の制限は効かず、アクセスできる。