WireGuard VPN for Remote Access¶
Current versions of TNSR support using WireGuard as a means of providing a remote access VPN for clients. This can also be referred to as a “mobile VPN” or a “road warrior VPN”.
Though WireGuard is a true peer-to-peer VPN and has no internal concept of “client” or “server”, it can behave in ways similar to those roles, so for the sake of making this easy to follow, this document will still use those terms. See Design Style for details.
This is different from a site-to-site VPN in several ways, notably:
The remote peer endpoints are unknown and dynamic, because clients connect from any location with Internet access, such as mobile phones, hotels, coffee shops, libraries, and so on.
There are no networks behind the remote peers, the remote clients are all accessing resources on the server side or beyond (e.g. routed networks, Internet hosts)
This TNSR instance uses addresses inside the larger subnet
which makes it easier for clients to route traffic to any network located behind
the server. Thus, when a client wishes to only reach resources routed by the
server, they can use that network instead of listing server networks
A remote access WireGuard VPN requires a dedicated subnet used to communicate
between the peers inside the VPN. In this case, the server will use
Addresses inside this subnet must be allocated manually to peers as WireGuard does not have a mechanism by which it can allocate these addresses automatically.
In this example, the server will use the first address in the subnet,
10.31.111.1. As peers are added, they will receive the next available
address in the subnet.
Use IP address management software or a spreadsheet to track allocated addresses.
Before starting, generate a set of keys for the WireGuard server at a shell prompt:
$ wg genkey | tee ra.prv.key | wg pubkey > ra.pub.key $ cat ra.prv.key iK24AJ251et8cBe3+QsmE6BV0X8jRcf8Wzy5ukkEXFY= $ cat ra.pub.key LQZRVWTPMSNfB+T7OjgLmWwK8nE4kVw+Xme0gwinFXQ=
Each client should generate their own keys and give the public key to the TNSR administrator configuring the VPN. The server does not need to know the client private keys, only the public keys.
The table Example WireGuard Remote Access Configuration contains the required information and other settings which form the WireGuard Remote Access VPN for this example.
TNSR WG Private Key
TNSR WG Public Key
TNSR Local Network
TNSR Server Address
TNSR Local WG Port
TNSR WG Interface
Alice WG Interface
Alice WG Public Key
Bob WG Interface
Bob WG Public Key
For each peer, the remote access VPN server only requires its public key and an interface address the client will use to access the VPN.
Configure WireGuard Instance¶
The next step is to start configuring the WireGuard instance, filling in the values from the table above:
tnsr(config)# interface wireguard 1 tnsr(config-wireguard)# description WireGuard Remote Access VPN tnsr(config-wireguard)# source-address 203.0.113.31 tnsr(config-wireguard)# port 51820 tnsr(config-wireguard)# private-key base64 iK24AJ251et8cBe3+QsmE6BV0X8jRcf8Wzy5ukkEXFY=
Do not exit at the end, continue on to setup the peers.
Configure WireGuard Peers¶
Now enter the configuration for the two peers using the values from the table.
Set the peer
allowed-prefix to the single address in the client subnet
allocated to this client. Ensure this value uses a
/32 prefix length.
tnsr(config-wireguard)# peer 1 tnsr(config-wireguard-peer)# description Alice tnsr(config-wireguard-peer)# allowed-prefix 10.31.111.2/32 tnsr(config-wireguard-peer)# public-key base64 WTayq0ZP4pWUV4eAk3FnRAPskw+Qcvf86S3mCiH0rAA= tnsr(config-wireguard-peer)# exit tnsr(config-wireguard)# peer 2 tnsr(config-wireguard-peer)# description Bob tnsr(config-wireguard-peer)# allowed-prefix 10.31.111.3/32 tnsr(config-wireguard-peer)# public-key base64 FzyY/KFTL1FSz8jJJ7fyscIvGchqxSU5izxWWgD/SmA= tnsr(config-wireguard-peer)# exit
Repeat as needed for more peers, then exit the WireGuard instance configuration:
Configure WireGuard Interface¶
Next is the
wg1 interface which the server will use to communicate with
peers inside the tunnel. Use the chosen server address with a prefix length
reflective of the entire subnet here, in this case
tnsr(config)# interface wg1 tnsr(config-interface)# enable tnsr(config-interface)# description WireGuard Remote Access VPN tnsr(config-interface)# ip address 10.31.111.1/24 tnsr(config-interface)# exit tnsr(config)#
If the external-facing interface from which the WireGuard clients will connect has an input ACL limiting inbound traffic, then it must be adjusted to allow the incoming WireGuard clients.
If the external interface does not have an input ACL, this can be skipped.
For a brief look at a basic ACL configuration, see the ACL section of the ZTP guide.
The ACL must allow traffic to the IP address and port configured on the WireGuard instance. Since remote access client addresses are unknown, the ACL rule must allow WireGuard traffic from any source.
tnsr(config)# acl internet-in tnsr(config-acl)# rule 50 tnsr(config-acl-rule)# description Allow WireGuard tnsr(config-acl-rule)# action permit tnsr(config-acl-rule)# ip-version ipv4 tnsr(config-acl-rule)# source address 0.0.0.0/0 tnsr(config-acl-rule)# destination address 203.0.113.31/32 tnsr(config-acl-rule)# destination port 51820 51820 tnsr(config-acl-rule)# protocol udp tnsr(config-acl-rule)# exit tnsr(config-acl)# exit tnsr(config)#
If the same interface has a restrictive output ACL it may need a similar rule there but with the source and destination swapped.
Additionally, if there are ACLs on other internal interfaces, these may also require adjustment.
To restrict traffic to or from WireGuard clients, output and input ACLs can
be added to the
Configure Peer Routes¶
Each peer must have an entry in the routing table informing TNSR that the
individual address is reachable through the
This cannot be summarized by using a larger prefix route, each client address must be listed separately.
The routes in this case are added to the default route table:
tnsr(config)# route table ipv4-VRF:0
This example adds a separate route for each of the peers, Alice and Bob:
tnsr(config-route-table)# route 10.31.111.2/32 tnsr(config-rttbl4-next-hop)# description WG RA Peer Route for Alice tnsr(config-rttbl4-next-hop)# next-hop 0 via 0.0.0.0 wg1 tnsr(config-rttbl4-next-hop)# exit tnsr(config-route-table)# route 10.31.111.3/32 tnsr(config-rttbl4-next-hop)# description WG RA Peer Route for Bob tnsr(config-rttbl4-next-hop)# next-hop 0 via 0.0.0.0 wg1 tnsr(config-rttbl4-next-hop)# exit
Repeat for each additional peer, then exit the route table configuration:
That completes the server-side configuration on TNSR.
There are WireGuard clients for a variety of platforms. So many that it is difficult to list and describe them all and how they operate. There are clients for major desktop and mobile operating system and other less common devices as well. Some WireGuard clients have a graphical interface (GUI) and others use configuration files. Thankfully, in most cases these clients use identical, or at least similar, terminology.
This is the general form of a basic WireGuard client configuration:
[Interface] PrivateKey = < private to the client > Address = < allocated VPN interface address > [Peer] PublicKey = < server public key > Endpoint = < server address>:<server port > AllowedIPs = < server-side network(s) >
For clients with a GUI, it should be relatively intuitive to map those fields to similar fields in the GUI. Often clients have a means to import configuration files as well, which means a crafted configuration could be imported to bypass any differences in the GUI.
This example configuration is for the client peer Alice:
[Interface] PrivateKey = < not shown > Address = 10.31.111.2/24 [Peer] PublicKey = LQZRVWTPMSNfB+T7OjgLmWwK8nE4kVw+Xme0gwinFXQ= Endpoint = 203.0.113.31:51820 AllowedIPs = 10.31.0.0/16
This example configuration is for the client peer Bob:
[Interface] PrivateKey = < not shown > Address = 10.31.111.3/24 [Peer] PublicKey = LQZRVWTPMSNfB+T7OjgLmWwK8nE4kVw+Xme0gwinFXQ= Endpoint = 203.0.113.31:51820 AllowedIPs = 10.31.0.0/16
Note that in both cases the server side configuration in the
is identical. Only the private key and client address are different.
With a client configuration in place, a client should be able to activate the VPN and transmit traffic to hosts behind the server.
Allowing Internet Access¶
Another common use case for remote access VPNs is for the server to act as an Internet gateway for clients. This can be leveraged for private browsing across an untrusted local network, geographic relocation of traffic, or other uses where such traffic is centrally routed.
The configuration thus far is nearly complete to allow this except for a few simple items.
For clients on the WireGuard VPN to reach the Internet, TNSR must apply NAT to their traffic to mask the true source address. This example assumes NAT is already configured on TNSR for other local hosts.
For a brief look at a basic NAT configuration, see the NAT section of the ZTP guide.
To perform NAT on client traffic originating from the
wg1 interface, set it
inside NAT interface:
tnsr(config)# interface wg1 tnsr(config-interface)# ip nat inside tnsr(config-interface)# exit
Allowed IP Address Change¶
To make the client route all of its traffic through the WireGuard VPN, the client configuration must be changed to reflect this behavior.
Note that in the previous examples the
AllowedIPs entry in the
section were set to the subnet reachable through the VPN:
[Peer] AllowedIPs = 10.31.0.0/16
To route all traffic through, set this value to
[Peer] AllowedIPs = 0.0.0.0/0
Deactivate and activate the VPN client so it will use the new settings.
Part of private and/or secure browsing is controlling the DNS servers used by clients to resolve hostnames to IP addresses.
If clients send their DNS requests to a third party public DNS server on the Internet, such as CloudFlare or Google, this configuration may not be necessary.
For VPN clients to use the Unbound DNS resolver on TNSR for DNS, first allow the VPN client subnet to access the resolver:
tnsr(config)# unbound server tnsr(config-unbound)# access-control 10.31.111.0/24 allow tnsr(config-unbound)# exit
Next, set the VPN client to use an address on TNSR for DNS. The address to use
varies based on how Unbound was configured, but is likely the LAN interface
address, such as
10.31.0.1 in this example.
For a brief look at a basic Unbound configuration, see the DNS section of the ZTP guide.
Now add the DNS server to the
[Interface] section of the client
[Interface] DNS = 10.31.0.1
Deactivate and activate the VPN client so it will use the new settings.