さくらのVPSにWireGuard入れて個人用途のVPN環境作った
ネットワーク図
- 個人VPN作った目的は、「高速でセットアップが簡単なVPN」としてオープンソースで提供されているWireGuardが、サービス提供者による個人情報収集に対する現実的な解になりうるかどうかを実験してみたかったから。
- 最終的に以下のようになりました。
- インターネット側のサービスからは、さくらのネットワークからのアクセスに見えるため、私の自宅やスマートフォンに割り当てられたIPアドレスは見えません。
- DNSクエリは自前のサーバーに対して行い、上位へのクエリは、さくらのVPSから行われるので、クエリ内容と私の個人情報は結びつきません。
- [自宅 | スマートフォン]と、さくらのVPSの間はVPNによって暗号化されているので盗聴される可能性は限りなく低いです。
- なお、IPアドレスによる位置情報の特定もできなくなります。私の所在地は島根ですが、IPアドレスから特定された、おおよその位置は東京になってました(石狩じゃないんだ...)
- ただし、アプリやブラウザのGPSによる位置情報を使われた場合は、このとおりではありません。
*)ちなみに、さくらVPSにはWireGuard機能を提供するVPCルータを使用することができます。ただし、こちらは最も低スペックなスタンダードプランでも ¥2619/月 するため、個人ユースであれば価格の安さでVPS上にサーバーを立てるのもありだと思います。
サーバーの用意
- クラウドかVPSでサーバーを探し、最終的にデータ転送に課金されず、かつサーバー代金の安いさくらのVPSに決めた。
- さくらのVPSは使ったことなかったので、新たにさくらに会員登録して、一番安い月額600円台のプランでサーバー起動した。
- 拠点は用途を考えると東京が良いかなと思ったけど、まあとりあえず一番安い石狩でやってみる。
- 注意事項として、さくらのVPSは登録後2週間は無料でサーバーを使うこともできるが、それだと最大転送速度が20Mbpsに制限されるので、今回のような用途ならはじめから本契約して有料サーバーを使ったほうが良いと思う。
パッケージのインストール
$ sudo apt install wireguard
サーバー側の秘密鍵を作成
$ wg genkey > private
$ cat private
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
インターフェイスの作成(sudo vim /etc/wireguard/wg0.conf)
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
一旦起動。
$ sudo wg-quick up /etc/wireguard/wg0.conf
ネットワークインターフェイスに新たに wg0
が追加されたことを確認。
$ ip addr
...
5: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 10.0.0.1/24 scope global wg0
valid_lft forever preferred_lft forever
システム起動時に自動起動するように設定
$ sudo systemctl enable wg-quick@wg0
サーバーのネットワーク設定
さくらのVPSにはAWSのようなマネージドなアクセス制御はなさそうなので、iptables を使って手動設定する。
転送許可設定
/etc/sysctl.conf
を修正してフォワードを許可
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
設定を反映。
$ sudo sysctl -p
iptablesの設定
さくらのVPSではネットワークインターフェイスがeth0ではなくens3だったので、ens3に設定する。
まずは初期設定として、
- 入ってくるパケットは拒否
- 出ていくパケットは許可
- 転送は拒否
を入れるが、これらの設定をすると即座につながらなく可能性があるので、一旦 INPUT を ACCEPTにして設定した上で、最後に INPUT を DROPにする。
$ sudo iptables -P INPUT ACCEPT
$ sudo iptables -P OUTPUT ACCEPT
$ sudo iptables -P FORWARD DROP
続いて、今回の用途等に必要な許可を入れていく。ついでに外部からの不正なアクセスを遮断する。
$ iptables -A INPUT -i lo -j ACCEPT
$ sudo iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
$ sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$ sudo iptables -I INPUT 2 -p tcp ! --syn -m state --state NEW -j DROP
$ sudo iptables -I INPUT 2 -p tcp --tcp-flags ALL ALL -j DROP
$ sudo iptables -t nat -I POSTROUTING 1 -s 10.0.0.0/24 -o ens3 -j MASQUERADE
$ sudo iptables -I INPUT 1 -i ens3 -p udp --dport 51820 -j ACCEPT
$ sudo iptables -I INPUT 1 -i wg0 -j ACCEPT
$ sudo iptables -I FORWARD 1 -i ens3 -o wg0 -j ACCEPT
$ sudo iptables -I FORWARD 1 -i wg0 -o ens3 -j ACCEPT
$ sudo iptables -I FORWARD 1 -i wg0 -o wg0 -j ACCEPT
最後の $ sudo iptables -I FORWARD 1 -i wg0 -o wg0 -j ACCEPT
によって、同じWireGuardのVPNに参加しているクライアント同士で通信ができるようになります。
全て設定したら INPUT を DROP に。
$ sudo iptables -P INPUT DROP
設定を保存するために iptables-persistent
をインストールする。
$ sudo apt install iptables-persistent
保存。次回起動時にも自動的に読み込まれる。
$ sudo /etc/init.d/netfilter-persistent save
インターネットからのSSH接続を拒否
なお、後述のクライアントからの接続等も確認できたら、SSH(22)ポートへの接続許可はwireguard経由のものだけにし、インターネットからの直接の接続は拒否するようにする。
$ sudo iptables -A INPUT -i wg0 -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
$ sudo iptables -A INPUT -i ens3 -m state --state NEW -m tcp -p tcp --dport 22 -j DROP
$ sudo iptables -D INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
Linuxクライアントの設定
自宅のマシンがLinux Mintなので。
まずは、サーバー側と同じようにwireguardをセットアップする
なお、クライアント側はIPアドレスを 10.0.0.2
とする。
また、iptablesによるアクセス制御は特に必要ない。
サーバーと同様に秘密鍵を生成。
$ wg genkey > private
$ cat private
BBBBBBBBBBBBBBBBBBBBBBBBBBBB
生成した秘密鍵を使って /etc/wireguard/wg0.conf
は一旦以下のように。
[Interface]
Address = 10.0.0.2/24
ListenPort = 51820
PrivateKey = BBBBBBBBBBBBBBBBBBBBBBBBBBBB
一旦起動
$ sudo wg-quick up /etc/wireguard/wg0.conf
サーバー側にクライアントを登録。
クライアントの公開鍵を確認
以下のコマンドをクライアントで実行して、クライアント側の公開鍵を確認。
$ sudo wg show
interface: wg0
public key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
private key: (hidden)
listening port: 51820
クライアント側の公開鍵は XXXXXXX.....
のようだ。
サーバーにLinuxクライアントを登録
サーバー側の /etc/wireguard/wg0.conf
に [Peer]
を登録する。
PublicKey には先程のクライアント側の公開鍵を。
AllowedIPs にはクライアント側で設定したIPアドレスを設定する。
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[Peer]
PublicKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
AllowedIPs = 10.0.0.2/32
サーバー側のwireguardを再起動する。
$ sudo wg-quick down /etc/wireguard/wg0.conf
$ sudo wg-quick up /etc/wireguard/wg0.conf
Linuxクライアントにサーバーを登録
今度はサーバー側の公開鍵を確認する。サーバー上で以下を実行。
$ sudo wg show
interface: wg0
public key: YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
private key: (hidden)
listening port: 51820
peer: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
allowed ips: 10.0.0.2/32
サーバー側の公開鍵は YYYY...
のようなので、これをLinuxクライアントの /etc/wireguard/wg0.conf
の Peerに登録。
編集後の /etc/wireguard/wg0.conf
は以下のようになった。
[Interface]
Address = 10.0.0.2/24
ListenPort = 51820
PrivateKey = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
[Peer]
PublicKey = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
AllowedIPs = 10.0.0.0/24
Endpoint = 153.126.131.xxx:51820
クライアントにはEndpoint という項目があり、ここにはサーバー側のグローバルアドレスとwireguardが待機しているUDPポート番号を設定している。
Linuxクライアントのwireguardを再起動する。
$ sudo wg-quick down /etc/wireguard/wg0.conf
$ sudo wg-quick up /etc/wireguard/wg0.conf
クライアント側から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 時間=119 ミリ秒
64 バイト応答 送信元 10.0.0.1: icmp_seq=2 ttl=64 時間=57.8ミリ秒
無事つながったようだ。この時点では 10.0.0.0/24
へのパケットはwireguardのサーバーへ流れ、それ以外のパケットはインターネットに直接出ていきます。
すべてのトラフィックがVPN(wireguard)を通って出ていくように設定する
この場合、クライアント側の AllowedIPs
に、全ての宛先( 0.0.0.0/0
)がwireguard側に流れるように指定すれば良い。
クライアント側の /etc/wireguard/wg0.conf
を以下のように設定する。
[Interface]
Address = 10.0.0.2/24
ListenPort = 51820
PrivateKey = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
[Peer]
PublicKey = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
AllowedIPs = 0.0.0.0/0, ::0/0
Endpoint = 153.126.131.xxx:51820
上記設定をしてwireguardを再起動すると、全てのトラフィックがVPN(wireguard)を抜けていくようになる。
自宅Linuxから traceroute で google.com
までの経路を確認すると、 10.0.0.1
を通り、さくらのネットワークから出ていっている様子がわかる。
$ traceroute google.com
traceroute to google.com (172.217.161.46), 30 hops max, 60 byte packets
1 10.0.0.1 (10.0.0.1) 55.886 ms 56.246 ms 56.854 ms
2 153.126.130.2 (153.126.130.2) 57.688 ms 58.970 ms 58.957 ms
3 192.168.107.1 (192.168.107.1) 57.585 ms 57.558 ms 58.869 ms
4 iskrt301b-vps-is1a-rt01-1.sakura.ad.jp (103.10.115.113) 57.111 ms 57.439 ms 57.401 ms
5 iskrt1s-rt301b.bb.sakura.ad.jp (103.10.113.125) 57.371 ms 57.345 ms...
6 iskrt3-rt301s.bb.sakura.ad.jp (103.10.113.205) 57.288 ms iskrt3-rt1s.bb.sakura.ad.jp...
7 tkort4-iskrt3.bb.sakura.ad.jp (157.17.131.33) 72.142 ms tkert1-iskrt301.bb.sakura.ad.jp...
8 as15169.ix.jpix.ad.jp (210.171.224.96) 72.461 ms tkort4-ert1.bb.sakura.ad.jp (157.17.130....
...
ms nrt12s23-in-f14.1e100.net (172.217.161.46) 73.673 ms
自分専用のDNSキャッシュサーバーをセットアップする
- 上記で一応、プライベートな高速VPN環境ができたが、企業等が個人情報を収集する上で結構使われてるんじゃないかな〜と思うのがDNS。
- 現在は通信がTLSにより暗号化されているので、そこからなにか情報を盗むのは難しい。
- しかし通常、DNSへのクエリは暗号化されないし、仮に暗号化されていてもDNSサーバー自体には、どのホストをクエリしたかはわかるので、企業から提供されているDNSはかっこうの情報収集装置になり得る。
というわけで野良DNSキャッシュサーバーを仕立て上げる。
WireGuardを仕込んだサーバーにDNSキャッシュサーバー Unbound をインストールする。
$ sudo apt install unbound
インストールは成功するけど、さくらのVPSはポート53を使っているようで起動に失敗する。
unboundはwireguardのネットワークからのクエリに応答してくれればいいので、以下のファイルを作って 11.0.0.1で接続待機するように設定する。
$ sudo vi /etc/unbound/unbound.conf.d/listen.conf
ファイルの中身はこう
server:
interface:10.0.0.1
do-ip4:yes
do-ip6:no
access-control:0.0.0.0/0 deny
access-control:10.0.0.0/24 allow
unboundを再起動する。
$ sudo systemctl restart unbound
LinuxクライアントがDNSにunboundを使うように設定する
Linuxクライアント側の /etc/wireguard/wg0.conf
に DNS
行を追加して再起動すれば、先程セットアップした unbound をDNSキャッシュサーバーとして使うようになる。
[Interface]
Address = 10.0.0.2/24
ListenPort = 51820
PrivateKey = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
DNS = 10.0.0.1
[Peer]
PublicKey = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
AllowedIPs = 0.0.0.0/0, ::0/0
Endpoint = 153.126.131.xxx:51820
最初は何もキャッシュされておらず、その都度上位に問い合わせるので結構遅いと感じると思う。
iPhoneの通信がVPN(WireGuard)を通り、自前のDNS( Unbound )を使うようにする
iPhone側の設定
- まずは AppStore で WireGuard をインストールする。
- インストールした WireGuardアプリを起動し、右上の + マークをタップし、「空の状態から作成」をタップ。
- 名前は
sakura
のように適当に決める。 -
キーペアの生成
をタップし、キーペアを生成する。- ここで仮に、生成された公開鍵が
ZZZZZZZZZZZZZZZZZZZZZZZZZZ
だとする。
- ここで仮に、生成された公開鍵が
- IPアドレスは今回は
10.0.0.3/32
とする。 - 待受ポートは
51820
- DNSサーバーは
10.0.0.1
-
ピアを追加
をタップ。 - 公開鍵には サーバー側で
$ sudo wg show
して表示されたPublicKey
を貼り付け。 - エンドポイントにはサーバー側のエンドポイント(この場合は
153.126.131.xxx:51820
)を設定。 - Allowed IPs には
0.0.0.0/0
を設定。
サーバーへiPhoneを登録
先程のiPhoneのwireguardアプリの設定画面で、生成した公開鍵をコピーし、 /etc/wireguard/wg0.conf
に登録する。
最初に登録したLinuxクライアントと合わせると以下のような感じ。
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[Peer]
PublicKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
AllowedIPs = 10.0.0.2/32
[Peer]
PublicKey = ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
AllowedIPs = 10.0.0.3/32
wireguardを再起動した上で、wiregaurdアプリで先程の設定を 有効
にする。
以上で全てのトラフィックはwireguardを通過するようになる。