3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WireGuardを使って固定IPアドレスが当たっていないお家サーバーにアクセスする

Posted at

はじめに

固定IPアドレスは持っていないが、お家のサーバーを公開して外部からアクセスできるようにしたい、というケースが時々あります。

最近、これはWireGuardを使うことで比較的簡単に実現できることを知ったので、まとめてみます。
自宅のマシンに固定IPアドレスが当たっている必要はありませんが、外部からアクセスするためにはどこかしらに固定IPアドレスが当たっているサーバーが必要になるため、クラウド上のサーバーを使います。なんでも良いと思いますが、今回はEC2を使います。

全体の構成としては以下のようになります。

外部クライアント <-> EC2 <- [WireGuard] -> お家サーバー

この記事では、お家サーバーでnginxを動かして、外部クライアントからのHTTPリクエストを受けられるようにします。

集合住宅などの共有回線を利用している場合、大きなトラフィックを流すと他の利用者に影響を与える可能性があるので、サーバーを公開する際には注意してください。

WireGuardとは

手軽に安全なVPNを構築できるソフトウェアです。

WireGuardのセットアップ

まずは、EC2 <-> お家サーバー間でVPN接続ができるようにWireGuardのセットアップをしていきます。
EC2、お家サーバーはともにUbuntu24.04です。

WireGuardは標準では入っていないので、それぞれにインストールします。
https://www.wireguard.com/install/

$ sudo apt update && sudo apt install -y wireguard

セットアップは公式のQuick Start 通りです。
以下の手順をEC2、お家サーバーの双方で行います。

通信を暗号化するための鍵を生成します。

$ wg genkey > private.key
$ wg pubkey < private.key > public.key

WireGuardでVPN通信をするためのネットワークインターフェースを作成します。

$ sudo ip link add dev wg0 type wireguard

$ ip addr show wg0
3: wg0: <POINTOPOINT,NOARP> mtu 1420 qdisc noop state DOWN group default qlen 1000
    link/none

ネットワークインターフェースに対してIPアドレスを割り当てます。

このIPアドレスは、WireGuardを用いてVPN通信をするpeerと同一セグメント内にある必要があります。
今回は、EC2が192.168.0.1/24で、お家サーバーが192.168.0.2/24にします。

$ sudo ip address add dev wg0 192.168.0.1/24

$ ip addr show wg0
3: wg0: <POINTOPOINT,NOARP> mtu 1420 qdisc noop state DOWN group default qlen 1000
    link/none
    inet 192.168.0.1/24 scope global wg0
       valid_lft forever preferred_lft forever

秘密鍵を登録します。

$ sudo wg set wg0 private-key ./private.key

ネットワークインターフェースの状態をUPにします。

$ sudo ip link set wg0 up

$ ip addr show wg0
3: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 192.168.0.1/24 scope global wg0
       valid_lft forever preferred_lft forever

peerの公開鍵と、内部IPアドレス、外部公開されている固定IPアドレスをそれぞれ登録します。

  • allowed-ips: peerの内部IPアドレス
  • endpoint: 外部公開されている方(今回だとEC2)の固定IPアドレスとWireGuardが待ち受けるUDPのport
    • お家サーバーは固定IPアドレスを持たないので、EC2側ではendpointの指定をする必要はありません

WireGuardが待ち受けるportは、wgコマンドで確認することができます。
(※ セキュリティグループで穴を開けておく必要があります。)

$ sudo wg
interface: wg0
  public key: **********
  private key: **********
  listening port: 42706
  • お家サーバー
$ sudo wg set wg0 peer <公開鍵> allowed-ips 192.168.0.1 endpoint <EC2の固定IPアドレス:port>
  • EC2
$ sudo wg set wg0 peer <公開鍵> allowed-ips 192.168.0.2

これで、EC2 <-> お家サーバー間でVPN通信ができるようになります。

  • お家サーバー
$ ping -c 3 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=15.2 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=15.4 ms
64 bytes from 192.168.0.1: icmp_seq=3 ttl=64 time=15.3 ms
  • EC2
$ sudo tcpdump -n -i wg0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
13:24:12.871292 IP 192.168.0.2 > 192.168.0.1: ICMP echo request, id 37664, seq 1, length 64
13:24:12.871306 IP 192.168.0.1 > 192.168.0.2: ICMP echo reply, id 37664, seq 1, length 64
13:24:13.871937 IP 192.168.0.2 > 192.168.0.1: ICMP echo request, id 37664, seq 2, length 64
13:24:13.871953 IP 192.168.0.1 > 192.168.0.2: ICMP echo reply, id 37664, seq 2, length 64
13:24:14.872844 IP 192.168.0.2 > 192.168.0.1: ICMP echo request, id 37664, seq 3, length 64
13:24:14.872864 IP 192.168.0.1 > 192.168.0.2: ICMP echo reply, id 37664, seq 3, length 64

公式ページ

WireGuard securely encapsulates IP packets over UDP.

とあるように、IPパケットをUDPでカプセル化して通信しているので、UDPで待ち受けても確認することができます。
なので、セキュリティグループでICMPの穴を開けておく必要がないです。

$ sudo tcpdump -n -i <固定IPが当たっているネットワークインターフェース> udp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on <固定IPが当たっているネットワークインターフェース>, link-type EN10MB (Ethernet), snapshot length 262144 bytes
13:32:33.256273 IP XXX.XXX.XXX.XXX > YYY.YYY.YYY.YYY: UDP, length 148
13:32:33.256522 IP YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX: UDP, length 92
13:32:33.272506 IP XXX.XXX.XXX.XXX > YYY.YYY.YYY.YYY: UDP, length 128
13:32:33.272634 IP YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX: UDP, length 128
13:32:34.258299 IP XXX.XXX.XXX.XXX > YYY.YYY.YYY.YYY: UDP, length 128
13:32:34.258444 IP YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX: UDP, length 128
13:32:35.259912 IP XXX.XXX.XXX.XXX > YYY.YYY.YYY.YYY: UDP, length 128
13:32:35.260043 IP YYY.YYY.YYY.YYY > XXX.XXX.XXX.XXX: UDP, length 128

wg-quickを使う

上記のようにcliで逐次的に実行することもできますが、
wg-quickを使うと設定ファイルで管理できる & ネットワークインターフェースの設定を省略することができます。
設定ファイルは、/etc/wireguard/INTERFACE.confに設定します。(wg0を使うのであれば/etc/wireguard/wg0.confです。)

上記と同じ設定であれば、以下のようになります。

  • お家サーバー
/etc/wireguard/wg0.conf
[Interface]
Address = 192.168.0.2/24
PrivateKey = <作成した秘密鍵>

[Peer]
PublicKey = <EC2側で作成した公開鍵>
Endpoint = <EC2の固定IPアドレス:ListenPort>
AllowedIPs = 192.168.0.1/24
  • EC2
/etc/wireguard/wg0.conf
[Interface]
Address = 192.168.0.1/24
PrivateKey = <作成した秘密鍵>
ListenPort = 42706

[Peer]
PublicKey = <お家サーバーで作成した公開鍵>
AllowedIPs = 192.168.0.2/24

それぞれ下記コマンドを実行すると設定されます。

$ sudo wg-quick up wg0

他にも設定できるオプションが複数あるので、詳細はman wg-quickで確認してください。

ポートフォワーディング

EC2 <-> お家サーバー間でVPN通信ができるようになったので、EC2で受けたHTTPリクエストをWireGuard経由でお家サーバーに転送できるようにします。
基本的に、iptables を用いてNATの設定をするだけです。

その前に、EC2は固定IPアドレスで受け取ったリクエストをお家サーバーへ転送する、サブネットを跨ぐルーターの役割をすることになるので、カーネルのパラメータを変更します。
再起動後もこの設定を引き継ぎたい場合は、/etc/sysctl.confを変更してください。
https://linuc.org/study/knowledge/422/

$ sudo sysctl -w net.ipv4.ip_forward=1

EC2のTCP80番で受け取ったリクエストをお家サーバーのTCP80番に流したいので、iptablesを用いて以下のように設定することができます。

$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.0.2:80

入ってくるパケットを転送する設定は完了したので、出ていくパケット(お家サーバー -> EC2 -> 外部クライアント)に対する設定もします。

$ sudo iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE

これで、お家サーバーでnginxを動かして、EC2越しに外部クライアントからのHTTPリクエストを受けられるようになります。

しばらく放置するとEC2とお家サーバー間の通信が途切れてしまいます。

NAT and Firewall Traversal Persistence

By default, WireGuard tries to be as silent as possible when not being used; it is not a chatty protocol. For the most part, it only transmits data when a peer wishes to send packets. When it's not being asked to send packets, it stops sending packets until it is asked again. In the majority of configurations, this works well. However, when a peer is behind NAT or a firewall, it might wish to be able to receive incoming packets even when it is not sending any packets. Because NAT and stateful firewalls keep track of "connections", if a peer behind NAT or a firewall wishes to receive incoming packets, he must keep the NAT/firewall mapping valid, by periodically sending keepalive packets. This is called persistent keepalives. When this option is enabled, a keepalive packet is sent to the server endpoint once every interval seconds. A sensible interval that works with a wide variety of firewalls is 25 seconds. Setting it to 0 turns the feature off, which is the default, since most users will not need this, and it makes WireGuard slightly more chatty. This feature may be specified by adding the PersistentKeepalive = field to a peer in the configuration file, or setting persistent-keepalive at the command line. If you don't need this feature, don't enable it. But if you're behind NAT or a firewall and you want to receive incoming connections long after network traffic has gone silent, this option will keep the "connection" open in the eyes of NAT.

とあるように、WireGuardでは必要な時以外にパケットを送信しないため、NAT(お家サーバー側)がコネクションを維持できないからです。
これを回避するために、PersistentKeepaliveオプションを用いて定期的にパケットを送信することで状態を維持することができます。

$ sudo wg set wg0 peer <公開鍵> allowed-ips 192.168.0.1 endpoint <EC2の固定IPアドレス:port> persistent-keepalive 10
/etc/wireguard/wg0.conf
[Interface]
Address = 192.168.0.2/24
PrivateKey = <作成した秘密鍵>

[Peer]
PublicKey = <EC2側で作成した公開鍵>
Endpoint = <EC2の固定IPアドレス:ListenPort>
AllowedIPs = 192.168.0.1/24
+ PersistentKeepalive = 10
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?