My understanding of Wireguard is that the interface for the server and client (although seemingly indiscernible?) each have their own .conf
file. For example consider the following .conf
file.
[Interface]
PrivateKey = some_key_1
Address = 10.193.130.174/16
[Peer]
PublicKey = some_key_2
PresharedKey = some_key_3
AllowedIPs = 10.129.130.1/32
Endpoint = 54.91.5.130:1952
How can one tell if this is a client or server .conf
file (if at all possible)? This may be a really simple question but what is the difference between the Endpoint
and AllowedIPs
fields for the [Peer]
? I infer from the CryptoKey Routing that once the interface
receives a packet it decrypts it with the interface
private key and checks the sender IP against the AllowedIPs
of all peers
and if the credentials in fact match with the peer
it accepts it. On the other hand, if the interface
wants to send a packet it encrypts it with the peer
public key but does it send it to the Endpoint
or one of the AllowedIPs
?
EDIT 1: I did use man wg
and the definition of Endpoint
still seemed vague to me. Nevertheless, the AllowedIPs
field seems easier to grasp.
EDIT 2: After further research I think that AllowedIPs
field specifies the IP addresses the peer can use to either receive traffic from or send traffic to. I'll appreciate it if someone can confirm or correct this.
Endpoint ( [Peer] config section) is the remote peer's "real" IP address and port, outside of the WireGuard VPN. This setting tells the local host how to connect to the remote peer in order to set up a WireGuard tunnel.
The keyword allowed-ips is a list of addresses that will get routed to the peer. Make sure to specify at least one address range that contains the WireGuard connection's internal IP address(es).
The config files are generally stored in /etc/wireguard folder. Create a new configuration file called wg0. conf in that folder. The configuration below will make your WireGuard server accept connections to 51820 and allow a client with the public key corresponding to the private key we made above.
The Address setting is the virtual address of the local WireGuard peer. It's the IP address of the virtual network interface that WireGuard sets up for the peer; and as such you can set it to whatever you want (whatever makes sense for the virtual WireGuard network you're building).
Yes, each interface has its own config file. WireGuard doesn't have built-in "client" or "server" roles -- every node is considered a "peer".
If you have two peers, Peer A and Peer B, the config file for Peer A will have the settings for its own local interface in the [Interface]
section, and the settings for its remote connection with Peer B in a [Peer]
section. Similarly, the config file for Peer B will have the settings for its own local interface in the [Interface]
section, and the settings for its remote connection with Peer A in a [Peer]
section. So the [Interface]
section in Peer A's config corresponds to the [Peer]
section in Peer B's config; and the [Interface]
section in Peer B's config corresponds to the [Peer]
section of Peer A's config.
Endpoint ([Peer]
config section) is the remote peer's "real" IP address and port, outside of the WireGuard VPN. This setting tells the local host how to connect to the remote peer in order to set up a WireGuard tunnel.
In the example config, where Endpoint = 54.91.5.139:1952
for the remote peer, any packets routed through the virtual WireGuard tunnel for that peer will actually be encrypted, wrapped in a new set of UDP packets, and sent across the Internet (or some other "real" network, like your corporate network) to 54.91.5.139
UDP port 1952
.
Unless you're also doing some fancy routing on the local host outside of WireGuard, if you try to send ping packets from the local host to this endpoint (eg ping 54.91.5.139
), or if you try to access some other service of the remote peer from the local host via this endpoint address (eg navigate to http://54.91.5.139/
in a web browser), you will not be using the WireGuard tunnel -- you will be using your regular Internet (or other "real" network) connection.
AllowedIPs ([Peer]
config section) is the set of IP addresses the local host should route to the remote peer through the WireGuard tunnel. This setting tells the local host what goes in tunnel.
In the example config, where AllowedIPs = 10.129.130.1/32
for the remote peer, any packets on the local host destined for 10.129.130.1
will not be sent directly over your regular Internet (or other "real" network) connection, but instead first sent to the virtual WireGuard tunnel. WireGuard will encrypt them, wrap them in a new set of UDP packets, and send them across the Internet (or other "real" network) to the peer's endpoint, 54.91.5.139
. From there, the peer will unwrap and decrypt the packets, and try to forward them on to 10.129.130.1
.
So if you try to send ping packets from the local host to 10.129.130.1
(eg ping 10.129.130.1
), or try to access some other service of 10.129.130.1
(eg navigate to http://10.129.130.1
in a web browser), you will be using the WireGuard tunnel.
Conversely, like you mentioned, for packets that have come through the tunnel from this remote peer, if they, once unwrapped and decrypted, have a source IP outside of the block(s) specified by AllowedIPs
(eg the source IP is 10.1.1.1
instead of 10.129.130.1
), the local host will drop them.
Address ([Interface]
config section) is the virtual IP address of the local host, within the WireGuard VPN. This setting affects the routing of packets going in and out of the WireGuard tunnel, and therefore should not be a "real" IP address routeable outside of the VPN.
In the example config, where Address = 10.193.130.174/16
, the virtual IP address of the local host within the WireGuard VPN is 10.193.130.174
. Therefore any packets from local sockets that the local host sends through the WireGuard tunnel will have a source address of 10.193.130.174
, and any packets it receives from the tunnel with a destination address of 10.193.130.174
will be routed back to a local socket (unless you're doing some fancy routing outside of WireGuard).
Let's say the "real" network address of the host is 10.10.10.10
. If, from the host, you run ping 10.129.130.1
, the host will generate ping packets with a source address of 10.193.130.174
and a destination address of 10.129.130.1
, and send them through the WireGuard tunnel. WireGuard will encrypt these packets, and wrap them with UDP packets where the source address is 10.10.10.10
, the source port is 51820
(the WireGuard default, since no ListenPort
was specified in the config), the destination address is 54.91.5.139
, and the destination port is 1952
. It will then send these UDP packets out to the "real" network.
When the remote peer, listening on a "real" network interface at IP address 54.91.5.139
and UDP port 1952
, receives these packets, it will unwrap and decrypt them. It will then re-queue them on its own network stack in their original form, as ICMP packets with a source address of 10.193.130.174
and destination address of 10.129.130.1
.
And if the original host receives a reply back from this remote peer for the ping, it would be received initially from a "real" network interface as UDP packets, with a source address of 54.91.5.139
, a source port of 1952
, a destination address of 10.10.10.10
, and a destination port of 51820
. WireGuard would unwrap and decrypt these packets back to their original form as ICMP packets with a source address of 10.129.130.1
and destination address of 10.193.130.174
, and re-queue them. Since the IP address of the virtual WireGuard interface is 10.193.130.174
(as configured via the Address
setting), the local host will know to route these packets back to a local socket.
Note that specifying a netmask for the Address
setting (/16
in our example) affects the routing decisions made by the local host about what traffic should be sent into the tunnel (and what to do with traffic received by the tunnel), in a way that can be redundant to, or at cross purposes with, the AllowedIPs
setting. In our example, Address = 10.193.130.174/16
, which will normally result in all traffic destined for any address in the 10.193.x.x
range to be routed to this WireGuard interface on the local host (not including the interface's own address, 10.193.130.174
, which would be routed to the loopback interface).
However, the AllowedIPs
setting for the only peer in our example doesn't include anything in the 10.193.x.x
range. So if we ran ping 10.193.0.1
on the host, the host would generate ping packets with a source address of 10.193.130.174
and a destination address of 10.193.0.1
, and send them through the WireGuard tunnel. But since that destination address doesn't fit into the AllowedIPs
of any configured peers, WireGuard would drop those packets.
So usually it's simplest to omit the netmask in the Address
setting (for IPv4 addresses, or use /32
, which has the same effect), and use only the AllowedIPs
settings on each peer to control what is routed to it. Usually you'd specify a netmask only if you had a number of different peers using the same virtual subnet (or if you were doing some fancy routing outside of WireGuard).
One more thing to know about Endpoint
is that you only need to set it on one side of a WireGuard tunnel (but you can set it on both sides if both sides have a static IP). If you set an Endpoint
for Peer B in Peer A's config, but you omit it for Peer A in Peer B's config, Peer A will be able to initiate and set up the tunnel with Peer B, without Peer B having to know Peer A's endpoint ahead of time.
This is ideal if Peer A has a dynamically-assigned public IP address; but the drawback is that Peer B won't be able to initiate the tunnel -- it will have to wait for Peer A to connect to it. If you sometimes need for Peer B to initiate a connection to Peer A, you can mitigate this by including a PersistentKeepalive
setting for Peer B in Peer A's config -- this will direct Peer A to proactively reach out and connect to Peer B every N seconds (where N is the value you put in the PersistentKeepalive
setting).
There's really not much I can add on Mr. Ludwig's answer. WireGuard is kinda simple by design. Nonetheless, here is an example of my current setup, including nftables rules on the "server" side, allowing all "client" peers to ping machines on my LAN.
Server configuration (Ubuntu), stored in /etc/wireguard/wg0.conf
. Local LAN address 192.168.2.0/24
, and this particular server address is 192.168.2.1
on the LAN interface, and 192.168.3.1
on the VPN (WireGuard) interface (wg0
). The address assigned to the WireGuard VPN is 192.168.3.0/24
:
[Interface]
Address = 192.168.3.1/24
#SaveConfig = true
ListenPort = 51820
PrivateKey = +N3K<redacted>
# Peer configurations
[Peer]
PublicKey = h/tr<redacted>
AllowedIPs = 192.168.3.0/24
Client (or Peer) configuration (Windows), stored on the official WireGuard client for Windows (not sure where the file or registry is currently located). Local VPN address is 192.168.3.2
:
[Interface]
PrivateKey = gIIB<redacted>
Address = 192.168.3.2/24
[Peer]
PublicKey = od4j<redacted>
AllowedIPs = 192.168.3.0/24, 192.168.2.0/24
Endpoint = <MyFreeDdnsDomainOn>.duckdns.org:51820
PersistentKeepalive = 25
nftables rules on the Ubuntu (server) side, stored in /etc/nftables.conf
, including my firewall rules:
define wan = "eth0"
define lan = "br0"
define lo = "lo"
define vpn = "wg0"
table ip nat {
chain PREROUTING {
# priority dstnat = -100.
type nat hook prerouting priority dstnat; policy accept;
}
chain INPUT {
# priority srcnat = 100.
type nat hook input priority 100; policy accept;
}
chain OUTPUT {
# priority dstnat = -100.
type nat hook output priority -100; policy accept;
}
# For all packets to WAN (eth0), after routing, replace the source address
# with the primary IP of WAN interface (masquerade).
# Also necessary to enable masquerade on LAN for WireGuard (VPN).
chain POSTROUTING {
# priority srcnat = 100.
type nat hook postrouting priority srcnat; policy accept;
oifname $wan counter masquerade
oifname $lan counter masquerade
}
}
# Allow all outgoing, but drop incoming and forwarding packets by default:
table ip filter {
chain INPUT {
type filter hook input priority filter; policy drop;
# Boilerplate acceptance policy.
iifname $lo counter accept
iifname $lan counter accept
iifname $vpn counter accept
# Accept already established and related connections.
iifname $wan ct state established,related counter accept
# Drop invalid packets.
iifname $wan ct state invalid counter drop
# Pass traffic to protocol-specific chains:
# Only allow new connections (established and related should already be handled)
# For TCP, additionally only allow new SYN packets since that is the only valid
# method for establishing a new TCP connection.
iifname $wan ip protocol udp ct state new counter jump UDP
iifname $wan tcp flags & (fin | syn | rst | ack) == syn ct state new counter jump TCP
iifname $wan ip protocol icmp ct state new counter jump ICMP
# Drop anything that's fallen through to this point.
counter drop
}
chain FORWARD {
type filter hook forward priority filter; policy drop;
# Forward filtering boilerplate rules.
iifname $wan oifname $lan ct state established,related counter accept
iifname $vpn oifname $lan counter accept
iifname $lan oifname $vpn counter accept
iifname $lan oifname $wan counter accept
}
chain OUTPUT {
type filter hook output priority filter; policy accept;
}
# Custom per-protocol chains:
chain ICMP {
}
# Acceptable TCP traffic:
chain TCP {
# Example:
#iifname $wan tcp dport 51413 counter accept
}
# Acceptable UDP traffic:
chain UDP {
# Allow WireGuard
iifname $wan udp dport 51820 counter accept
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With