2020/10/12wg-quickについて追記
2021/1/18 タイトルと本文の誤字を修正しました
経緯
自宅サーバに外部からアクセスしたいが自宅サーバを直接公開するのは怖い。
ということで、借りたVPSを出島として自宅サーバとその他スマホなどの端末でVPNを構築することでアクセスできるようにした。
目的
クライアントのノートPC(Windows)やスマホ(Android)からWireGuard VPNを経由して自宅サーバーにアクセスする。
自宅サーバーを外部へ公開で済むように、中継点としてVPSを経由する。
構成について
WireGuard
VPNを構築するソフトウェアとしてWireGuardを利用した。
これにした理由は以下のような感じ
- オープンソース
- (OpenVPNとくらべ)設定が楽そう
- Linuxのカーネルに統合されている
なお、以降このVPNを構成する各サーバーまたは端末のいずれかを公式に倣ってpeer
と記載することがある。
サーバー、端末について
- VPS(AWS Lightsail)
- OS: Ubuntu 20.04
- 用途:自宅サーバにアクセスするための中継点
- グローバルIP: 198.51.100.1/24
- VPN内IP: 192.168.100.1/24, fd00::1/64
- 自宅サーバー
- OS: Manjaro
- 用途: ファイルサーバー
- VPN内IP: 192.168.100.2/24, fd00::2/64
- その他クライアント
- OS: Android/Windows
- VPN内IP: 192.168.100.3/24, fd00::3/64
- 共通事項
- ポート: 51820
以下補足
- 外部からグローバルIPでアクセスできるのはVPSのみ。
- クライアントについてはWindowsとAndroidを使っているが、とくに区別して説明する必要がなさそうだったので本記事ではまとめて
その他クライアント
として扱っている。 - IPとポートについては念のため実際のとは変えている。
- 上記のポートである
51820
はWireGuardのデフォルトらしい。
実際の構築の際はランダムに生成した別のポート番号を使っていたため、以降の例でも(デフォルトのポートではあるが)あえて明示している。 - IPv6アドレスとipV4アドレスは今回は両方設定したが、別にIPv4だけでもいい。
- ファイアーウォールについては省略
Step1 WireGuard の Install
VPS(Ubuntu 20.4)
普通にapt install
でインストールできる。
$ sudo apt install wireguard-tools
自宅サーバー(Manjaro)
$sudo pacman -S wireguard-tools
これだけだと動かなかった。
Manjaro の自宅鯖のほうは去年から運用している関係上VPSよりもカーネルが古く、そのままでは対応していない模様。
念のためカーネルの確認
$ uname -all
Linux host-name 4.19.144-1-MANJARO #1 SMP Wed Sep 9 18:43:01 UTC 2020 x86_64 GNU/Linux
host-name
の次にある4.19というのがカーネル(のはず)
4.19はそのままではWireguardに対応していないので、4.19用にDynamic Kernel Module Supportでモジュールを追加する必要がある
$ sudo pacman -S wireguard-dkms linux419-headers
これでwgコマンドが使えるようになった。
Step2: WireGuardの初期設定
鍵の生成
秘密鍵・共有鍵
$ umask 0077 # umaskでこれから作成する鍵の権限を制限する。これしないと次のコマンドがエラーになる
$ wg genkey > vps.key # 秘密鍵の生成
$ wg pubkey < vps.key > vps.pub # 公開鍵の生成
これを各端末ごとに繰り返して先に作成しておく。
事前共有鍵
任意で事前共有鍵を作成しておくことでより安全になる。
$ wg genpsk > vps-homeserver.psk # 事前共有鍵の生成(任意)
これも各組み合わせで作成しておく。
ちなみに今回のような、VPSを中継点とした構成では必要なのはVPSと各端末の組み合わせ(例:vps-homeserver.psk
、vps-smartphone.psk
)、だけで、端末間の共有鍵(例:homeserver-smartphone.psk
)は必要ない
設定
まずはサーバー自身のIP、秘密鍵、ポートを設定していく。
$ sudo ip link add dev wg0 type wireguard # wireguard用のデバイスwg0の追加
$ sudo ip addr add 10.0.0.1/24 dev wg0 # IPv4アドレスの設定
$ sudo ip addr add fdc9:281f:04d7:9ee9::1/64 dev wg0 # IPv6アドレスの設定
$ sudo wg set wg0 listen-port 51871 private-key /path/to/vps.key #ポートとプライベートキーの設定
接続先の設定
次に接続先の設定。
wg set
コマンドで宛先peer
別の設定をする。
だいぶ長々と書いているが、これらの内容は最終的には設定ファイルを直接いじれるため、このコマンド自体はそこまで必要ではなかったりする。とはいえ各オプションについては設定ファイルをいじるためにも結局把握する必要があるので省略するわけにもいかずこんな感じに…。
以下は全体像を説明するため今回使った一通りのオプションを記載しているが、実際には後述のようにサーバー・端末によって必要だったり必要なかったりする。実際のpeer
別の設定については後述する。
$ sudo wg set wg0 \
peer [接続先の公開鍵の中身] \
preshared-key /path/to/peer-otherpeer.psk \
endpoint 198.51.100.1/64:51902 \
persistent-keepalive 25 \
allowed-ips 192.168.100.2/24, fd00::2/64
以下各引数について
peer
公開鍵を指定する。接続先の名前の設定がないことから、この公開鍵が事実上の接続先を指定する名前(ID)として役割もある模様。
なぜかほかの鍵ファイルと違いパスで渡すとエラーになるのでキーの文字列を取り出して引数にとる必要がある。取り出すとわかるがSSHのキーなどと比べるとかなり短い。
preshared-key
設定しているサーバー(クライアント)と接続先との事前共有鍵。パスで指定。任意ではあるが、WireGuardの鍵は(16進数ではないためか)SSHなどほかの鍵とくらべるとかなり短いため、気分的には設定したほうが安心できる。
endpoint
グローバルIP。2つのpeer
のうちどちらかがもう一方へendpoint
宛でパケットを送れる必要がある。
今回であればVPS以外のpeer
からVPS宛にendpoint
を設定すればいい。
ちなみにこのendpoint
はパケットのやり取りを通じて自動更新されるため、気づくとVPSにスマホのendpoint
が設定されていたりする。
allowed-ips
ここに指定した宛先のパケットをこのpeer
に送る。特定のpeer
宛のIPを指定すればそのpeer
宛のパケットだけが飛ぶが、ここでネットワークを指定することで、該当ネットワークへのほかのパケットもこのpeer
へ送るようになる
具体的にいうと、192.168.100.2/32
とすると192.168.100.2/32
宛だけだが、192.168.100.0/24
とすると192.168.100.0/24
のネットワーク内のほかの端末へのアクセスもこのpeer
へ飛ぶことになる。
VPS192.168.100.1/32
経由で自宅サーバー192.168.100.2/32
へアクセスする今回のケースの場合、その他クライアントの設定でVPS宛のallowed-ips
に192.168.100.0/24
と指定することで自宅サーバー宛のパケットもVPSに飛ばせるようになる。
persistent-keepalive 25
定期的に対象のpeer
にパケットを飛ばして接続を維持させる設定。
これが必要なのは今回の自宅サーバーのように中継点を介して外部からアクセスするケース。自宅サーバーが公開されていない以上中継点側から接続を開始することができないため、自宅サーバー側から中継点へ接続を維持し続ける必要がある。
今回の場合、自宅サーバーのVPS宛の設定でのみ指定する必要がある。
起動
# ip link set wg0 up
これでつながるはず。つながらなかったらファイアーウォール
とか確認する。
なお、Lightsail
はWireGuard
が有効になってもping
が届かないので心配になるが、wg show
で最終接続時間が見れるので、接続ができていればとりあえずこれで確認できる。
IPforwardの設定
そのままだと自宅サーバーあてのパケットがVPSに届いてもそこでせき止められてしまうので、ちゃんと中継できるよう設定をする
# sysctl -w net.ipv4.ip_forward=1
# sysctl -w net.ipv6.conf.all.forwarding=1
これで中継できるようになる
この設定を永続化するには/etc/sysctl.conf
の以下をコメントアウトする。
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
設定の永続化
設定ファイルの保存、読込 (wg showconf
, wg setcnf
について)
以下のコマンドで設定が保存ができる
wg showconf wg0 > /etc/wireguard/wg0.conf
できる設定ファイルはこんな感じ
[Interface]
ListenPort = 51820
PrivateKey = [略]
[Peer]
PublicKey = [略]
PresharedKey = [略]
AllowedIPs = 192.168.100.2/32, fd00::1/128
見ての通りwg
コマンドで設定した内容がだいたいそのまま書かれているので、マニュアル通り進めていれば問題なく読めると思う。
これで設定ファイルを読み込む。
wg setconf wg0 /etc/wireguard/wg0.conf
アドレスの追記
wg showconf
で作成した設定ファイルにはサーバー自身のアドレスの記載がない。改めて上のコマンドを見返しても分かるが、ipアドレスの設定にはwgコマンドが関わっていないので、そもそもwg
コマンドの管理外の模様。
ではいちいち別でwg0
を設定しなければいけないかというとそんなことはなく、ネットワークデバイスも一緒に設定してくれるwg-quick
というコマンドがある。
これで自動でデバイスを設定できるが、そのためには以下のように[Interface]
内にAddress
を追記する必要がある。
[Interface]
Address = 192.168.100.1/24, fd00::1/64 # 追記
ListenPort = 51820
PrivateKey = [略]
[Peer]
PublicKey = [略]
PresharedKey = [略]
AllowedIPs = 192.168.100.2/32, fd00::1/128
これで設定ファイルが完成。
一度設定ファイルを作ったらあとはpeer
別に必要な個所を適宜修正して使いまわせる。
というか見比べながら設定しないとどれがどれだかわからなくなる
WindowsやAndroidのクライアントでもこの設定ファイルを読み込んで設定することになる。
wg-quickによる自動起動
/etc/wireguard/wg0.conf
がある状態で以下のコマンドでネットワークデバイスの作成とwireguardの設定をまとめて行える。
sudo wg-quick up wg0
削除するにはup
の代わりにdown
を使う
sudo wg-quick down wg0
以下でsystemctl
による自動起動ができる。
sudo systemctl enable wg-quick@wg0.service
peer別の設定ファイルの例
各項目についてはだいたい上記のコマンドで設定した通り。
唯一上記で触れていない例外はDNS
で、これはNextcloudに内部用のドメインでアクセスできるようにしたかったため、設定したがあまり必要なケースはないと思うので省略。後日DNSについて記事を書く際についでに少し触れるかもしれない。
スマホ等の端末
[Interface]
Address = 192.168.100.3/24, fd00::3/64
ListenPort = 51820
PrivateKey = [略]
DNS = 192.168.100.2,fd00::2
[Peer] ; VPS
PublicKey = [略]
PresharedKey = [略]
;ここで端末ではなくネットワークを指定することで、VPS以外の該当ネットワークへのパケットもVPSへ送るようになる
AllowedIPs = 192.168.100.0/24,fd00::/64
Endpoint = 198.51.100.1:51820 ; VPSの外部IP
VPS
[Interface]
Address = 192.168.100.1/24, fd00::1/64
ListenPort = 51820
PrivateKey = [略]
[Peer] ; 自宅サーバー
PublicKey = [略]
PresharedKey = [略]
AllowedIPs = 192.168.100.2/32, fd00::1/128
[Peer] ; スマホ
PublicKey = [略]
PresharedKey = [略]
AllowedIPs = 192.168.100.3/32, fd00::3/128
自宅鯖
[Interface]
Address = 192.168.100.2/24, fd00::2/64
ListenPort = 51820
PrivateKey = [略]
[Peer] ; VPS
PublicKey = [略]
PresharedKey = [略]
AllowedIPs = 192.168.100.1/32, fd00::1/128
Endpoint = [VPSのIP]
PersistentKeepalive = 25 ; これを入れておくことで自宅サーバから定期的にVPSへハンドシェイクを行い、通信を維持できる。
余談
IPv4かIPv6か
IPv4のほうが間違いなく無難とはいえ個人的には数が多くてランダムで設定すれば重複を気にしなくてもいいという1点でipv6アドレスのほうが好き。IPv6は端末によって対応していない可能性があるが、とはいえ最近の機器であれば大概対応しているはずだし現時点で接続したい機器は一通りつなげられたので結局のところ好みで選んでいいと思われる。
その他参考サイト
例示専用のIPアドレスとドメインを使いこなす | ギークを目指して
WireGuard - ArchWiki
IPv6アドレスにおける「インターフェース識別子」という名称の謎とModified EUI-64によるIPv6アドレス生成:Geekなぺーじ
第614回 WireGuardでVPNサーバーを構築する:Ubuntu Weekly Recipe|gihyo.jp … 技術評論社
WireGuard で VPS 経由で家庭内に入る - Qiita