baicai

白菜

一个勤奋的代码搬运工!

Set up VPN access to the home intranet via WireGuard

Since the home network does not have a public IP, a server with a public IP is needed as the "server" for the WireGuard network. There needs to be a device at home acting as a node in the WireGuard network. We will use a mobile phone to check if the VPN is successfully set up under the 4G network.

IP Segment Selection#

WireGuard networking requires the use of an IP address range that does not conflict with any of your devices' networks. Address ranges like 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24 are allocated for documentation and examples as "TEST-NET," and these ranges are typically not used by other networks you need to connect to.

In the configuration below, I will assign 192.0.2.1, 192.0.2.2, and 192.0.2.3 to the public server, the Mac at home, and the iPhone, respectively.

Configuring WireGuard on the Server#

To use WireGuard, you first need to ensure that the Linux kernel supports it. You can check if WireGuard is built-in using the command modinfo wireguard. You can also check if the kernel version is 5.6 or higher using uname -r.

Installing WireGuard#

Debian

apt install wireguard

Other systems reference: install

Completing Server-Side Configuration#

After WireGuard is correctly installed, you can quickly create a set of public and private keys with the following command.

$ wg genkey | tee peer_A.key | wg pubkey > peer_A.pub && cat peer_A.key && cat peer_A.pub

Create /etc/wireguard/wg0.conf and fill in the configuration

[Interface]
PrivateKey = (your server private key here)
Address = 192.0.2.1/24
ListenPort = 51820

[Peer]
# Mac at home
PublicKey = (Mac public key here)
AllowedIPs = 192.0.2.2/32, 192.168.1.0/24

[Peer]
# iPhone
PublicKey = (iPhone public key here)
AllowedIPs = 192.0.2.3/32

In WireGuard, you need to manually assign IPs to each device and ensure that each device has a unique IP. The Interface section contains the settings for the current device, and for the "server," the ListenPort is required. Each Peer section below represents another device that can connect to this device.

After saving the configuration file, we can use wg-quick up wg0 to enable the configuration file. wg-quick will automatically configure the routing table without requiring manual setup.

Remember to allow UDP port 51820.

Configuration on the Mac at Home#

Create /etc/wireguard/wg0.conf and fill in the configuration

[Interface]
PrivateKey = (private key of Mac)
Address = 192.0.2.2/24
DNS = 1.1.1.1

[Peer]
PublicKey = (public key of server)
AllowedIPs = 192.0.2.0/24
Endpoint = (server ip address):51820
PersistentKeepalive = 10

Here, we set the public server as the only Peer, using PersistentKeepalive to maintain the connection. The AllowedIPs here ensure that traffic from our WireGuard subnet can be processed by the local WireGuard virtual network card.

iPhone Configuration#

Install WireGuard  Download from App Store

This configuration can refer to screenshots from the app store.

Notes#

Reserved Address Ranges#

Reserved IP Addresses

Minor Issues#

When encountering the error message:

/usr/bin/wg-quick: line 31: resolvconf: command not found [WireGuard | Debian]

You can create a symbolic link to resolve it

ln -s /usr/bin/resolvectl /usr/local/bin/resolvconf

When encountering the error message:

[SELF-SOLVED] Unit dbus-org.freedesktop.resolve1.service not found

You can resolve it by starting the systemd-resolved service

systemctl start systemd-resolved.service
systemctl enable systemd-resolved.service

Configuration Details#

WireGuard uses INI syntax as its configuration file format. Configuration files can be placed in any path but must be referenced by absolute path. The default path is /etc/wireguard/wg0.conf.

The naming format for configuration files must be ${WireGuard interface name}.conf. Typically, WireGuard interface names start with the prefix wg and are numbered starting from 0, but you can use other names as long as they conform to the regular expression ^[a-zA-Z0-9_=+.-]{1,15}$.

You can choose to use the wg command to manually configure the VPN, but it is generally recommended to use wg-quick, which provides a more powerful and user-friendly configuration experience that can manage configurations through configuration files.

[Interface]#

Defines the local VPN configuration. For example:

  1. The local node is a client that only routes its own traffic, exposing only one IP.
[Interface]
# Name = phone.example-vpn.dev
Address = 192.0.2.5/32
PrivateKey = <private key for phone.example-vpn.dev>

The local node is a relay server that can forward traffic to other peers and expose the routing for the entire VPN subnet.

[Interface]
# Name = public-server1.example-vpn.tld
Address = 192.0.2.1/24
ListenPort = 51820
PrivateKey = <private key for public-server1.example-vpn.tld>
DNS = 1.1.1.1

# Name#

This is a standard comment in INI syntax used to indicate which node this configuration section belongs to. This part of the configuration will be completely ignored by WireGuard and has no effect on the behavior of the VPN.

Address#

Defines the address range that the local node should route. If it is a regular client, set it to the single IP of the node itself (using CIDR notation, e.g., 192.0.2.3/32); if it is a relay server, set it to a routable subnet range.
For example:

Regular client, routing only its own traffic:

Address = 192.0.2.3/32

Relay server, capable of forwarding traffic to other peers:

Address = 192.0.2.1/24

Multiple subnets or IPv6 subnets can also be specified:

Address = 192.0.2.1/24,2001:DB8::/64

ListenPort#

When the local node is a relay server, this parameter specifies the port to listen for incoming VPN connections, with the default port number being 51820. Regular clients do not need this option.

PrivateKey#

The private key of the local node, which must be set for all nodes (including relay servers). It cannot be shared with other servers.

The private key can be generated using the command wg genkey > example.key.

DNS#

Announces the DNS server to clients via DHCP. Clients will use the DNS server specified here to handle DNS requests within the VPN subnet, but this option can also be overridden in the system. For example:

# If not configured, the system default DNS will be used
# A single DNS can be specified:
DNS = 1.1.1.1
# Multiple DNS can also be specified:
DNS = 1.1.1.1,8.8.8.8

Table#

Defines the routing table used by the VPN subnet, which does not need to be set by default. There are two special values to note:

    Table = off : Prevents route creation
    Table = auto (default value) : Adds routes to the system's default table and enables special handling for the default route.

For example: Table = 1234

MTU#

Defines the MTU (Maximum Transmission Unit) for connections to peers, which does not need to be set by default and is generally determined automatically by the system.

PreUp#

Commands to run before starting the VPN interface. This option can be specified multiple times and will execute in order.

For example:
Adding a route:

    PreUp = ip rule add ipproto tcp dport 22 table 1234

PostUp#

Commands to run after starting the VPN interface. This option can be specified multiple times and will execute in order.

For example:

Reading configuration values from a file or the output of a command:
    PostUp = wg set %i private-key /etc/wireguard/wg0.key <(some command here)
Adding a line of log to a file:
    PostUp = echo "$(date +%s) WireGuard Started" >> /var/log/wireguard.log
Calling a WebHook:
    PostUp = curl https://events.example.dev/wireguard/started
Adding a route:
    PostUp = ip rule add ipproto tcp dport 22 table 1234
Adding iptables rules to enable packet forwarding:
    PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Forcing WireGuard to re-resolve the IP address of the peer domain:
    PostUp = resolvectl domain %i "~."; resolvectl dns %i 192.0.2.1; resolvectl dnssec %i yes

PreDown#

Commands to run before stopping the VPN interface. This option can be specified multiple times and will execute in order.
For example:

Adding a line of log to a file:
    PreDown = echo "$(date +%s) WireGuard Going Down" >> /var/log/wireguard.log

PostDown#

Commands to run after stopping the VPN interface. This option can be specified multiple times and will execute in order.
For example:

Adding a line of log to a file:
PostDown = echo "$(date +%s) WireGuard Down" >> /var/log/wireguard.log

[Peer]#

Defines the VPN settings for peers that can route traffic for one or more addresses. Peers can be relay servers that forward traffic to other peers or clients that connect directly via public or private networks.

Relay servers must define all clients as peers, and other clients cannot define nodes behind NAT as peers because routing is unreachable. For clients that only route traffic for themselves, simply define the relay server as a peer, along with any other nodes that need direct access.

Configuration examples:

A peer is a routable client that only routes its own traffic

[Peer]
# Name = public-server2.example-vpn.dev
Endpoint = public-server2.example-vpn.dev:51820
PublicKey = <public key for public-server2.example-vpn.dev>
AllowedIPs = 192.0.2.2/32

A peer is a client behind NAT that only routes its own traffic

[Peer]
# Name = home-server.example-vpn.dev
Endpoint = home-server.example-vpn.dev:51820
PublicKey = <public key for home-server.example-vpn.dev>
AllowedIPs = 192.0.2.3/32

A peer is a relay server that forwards traffic to other peers

[Peer]
# Name = public-server1.example-vpn.tld
Endpoint = public-server1.example-vpn.tld:51820
PublicKey = <public key for public-server1.example-vpn.tld>
# Routes all traffic for the entire VPN subnet
AllowedIPs = 192.0.2.1/24
PersistentKeepalive = 25

Endpoint#

Specifies the public address of the remote peer. If the peer is behind NAT or does not have a stable public access address, this field can be ignored. Typically, only the relay server's Endpoint needs to be specified, although nodes with stable public IPs can also specify it. For example:

Specifying by IP:

Endpoint = 123.124.125.126:51820

Specifying by domain name:

Endpoint = public-server1.example-vpn.tld:51820

AllowedIPs#

Specifies the range of source addresses in the VPN traffic that the peer is allowed to send. This field will also be used as the IP address range bound to wg0 in the local routing table. If the peer is a regular client, set it to the single IP of the node; if the peer is a relay server, set it to a routable subnet range. Multiple IPs or subnet ranges can be specified using a comma. This field can also be specified multiple times.

When determining how to route a packet, the system will first select the most specific route; if it does not match, it will select a broader route. For example, for a packet destined for 192.0.2.3, the system will first look for a peer with the address 192.0.2.3/32; if none is found, it will look for a peer with the address 192.0.2.1/24, and so on.

For example:

A peer is a regular client that only routes its own traffic:

AllowedIPs = 192.0.2.3/32

A peer is a relay server that can forward traffic to other peers:

AllowedIPs = 192.0.2.1/24

A peer is a relay server that can forward all traffic, including external and VPN traffic:

AllowedIPs = 0.0.0.0/0,::/0

A peer is a relay server that can route its own traffic and that of other peers:

AllowedIPs = 192.0.2.3/32,192.0.2.4/32

A peer is a relay server that can route its own traffic and that of the internal network it is in:

AllowedIPs = 192.0.2.3/32,192.168.1.1/24

PublicKey#

The public key of the peer, which must be set for all nodes (including relay servers). It can be shared with other peers.

The public key can be generated using the command wg pubkey < example.key > example.key.pub, where example.key is the private key generated above.

PersistentKeepalive#

If the connection is from a peer behind NAT to a publicly reachable peer, the peer behind NAT must periodically send an outbound ping to check connectivity; if the IP changes, the Endpoint will be automatically updated.

For example:

The local node can connect directly to the peer: this field does not need to be specified because connection checks are not required.

The peer is behind NAT: this field does not need to be specified because maintaining the connection is the responsibility of the client (the initiator of the connection).

The local node is behind NAT, and the peer is publicly reachable: this field needs to be specified as PersistentKeepalive = 25, indicating that a ping will be sent every 25 seconds to check the connection.

Sharing a peers.conf File#

If a peer's public key can pair with the local interface's private key, WireGuard will ignore that peer. Using this feature, we can share the same peer list across all nodes, with each node only needing to define a single [Interface], even if the list contains its own node, it will be ignored. The specific method is as follows:

Each peer has a separate /etc/wireguard/wg0.conf file that only contains the configuration for the [Interface] section.

Each peer shares the same /etc/wireguard/peers.conf file, which contains all the peers.

The wg0.conf file needs to configure a PostUp hook with the content

PostUp = wg addconf /etc/wireguard/peers.conf
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.