Aug 192022
 

For years I’ve run the dev, test, and stage nodes for FreshPorts off servers in my basement. This meant that those hostnames have always pointed at my home IP address. I’d like to change that.

I first started this using interactive commands (e.g. wg set) but found that approach unsatisfactory. I think directly editing the configuration file to be more intuitive and easily followed. I left my first approach up because it had been written.

Why? Nobody needs to know my home IP address. It’s a static IP, and keeping a dynamic DNS hostname pointed there is not difficult, but sometimes it does mess up, if only briefly.

What will I do instead?

I will use a server in a colo. The hostnames will point at that server. Let’s call it my portal. I will configure Nginx on the portal to relay to my home servers. The connection between the portal and my basement will be maintained by the server at home and Wireguard will be involved.

The link between the client and server is referred to as the tunnel. The tunnel has IP addresses associated with each end of the tunnel. These ends are known as endpoints.

In this post:

  • FreeBSD 13.1-RELEASE
  • net/wireguard-go: 0.0.20220316_4,1
  • wireguard-tools: 1.0.20210914_1
  • I consider the server side to be the one with the static IP – that’s my server in the datacenter or colo
  • What I’m doing is rather unusual: One endpoint is not my gateway; instead, it’s on a host inside my gateway/router/firewall.
  • The server has a subnet of 10.200.0.0/24
  • The home network has a subnet of 10.55.0.0/24
  • I’m not actually using the network values shown here. Some might be taken from IP ranges used for documentation. Others might be changed from the actual subnets to others in the 10.0.0.0/8 range.

Background

Wireguard encryption (as does many encryption approaches) involves a private key and a public key. You should be familiar with this, perhaps from ssh keys.

  • The server needs to know the public key of the client.
  • The client needs to know the public key of the server.
  • This is known as pre-shared Keys (PSK).
  • Only the host knows its private key.

The configuration show later will demonstrate how this is done.

That should get you started.

The install

The install is the same on both hosts:

Install:

% sudo pkg install wireguard-go wireguard-tools

Why two packages?

wireguard-go installs only the binary file /usr/local/bin/wireguard-go.

wireguard-tools installs other tools, including the rc.d script, and creates the configuration directory /usr/local/etc/wireguard.

Creating the keys

Keys must be created on each of the server and the client. It is traditional to do this on the host which will use the key, as opposed to doing it on another host and copying the file over. Following this tradition means less chance of the file being accidentally exposed.

Creating the server key

This is tricky to do with only sudo, so let’s assume you are already root. The file can be named anything you want. It does not have to be server.key.

# cd /usr/local/etc/wireguard
# (umask 0077; wg genkey > server.key)
# ls -l
total 1
-rw-------  1 root  wheel  45 Aug 15 16:41 server.key
# wg pubkey < server.key
10A3[this is the server public key]nA8=

The umask is a way to avoid a later chmod 0600 on the file. wireguard is very picky about file permissions, and rightly so.

The wg pubkey command extracts the public key from server.key.

Creating the client key

This is the same set of commands, only with a different file name.

# cd /usr/local/etc/wireguard
# (umask 0077; wg genkey > client.key)
# ls -l
total 1
-rw-------  1 root  wheel  45 Aug 15 16:41 client.key
# wg pubkey < client.key
dW86s[this is the client public key]cnimI=

The configuration files

The configuration files are next. In my case, these live in /usr/local/etc/wireguard/wg0.conf -I keep these files chown root:wheel and chmod 0600:

% sudo ls -l /usr/local/etc/wireguard/wg0.conf
-rw-------  1 root  wheel  277 Aug 17 22:07 /usr/local/etc/wireguard/wg0.conf

The tunnel

Subnets and netmasks are involved in this topic, and they are beyond scope for this post. If you don't know, just use a /30.

I have chosen 10.9.1.144/30 as my tunnel. Using a subnet calculator, I found that I have two usable IP addresses in that /30:

  • 10.9.1.145
  • 10.9.1.146

Those IP addresses will be my tunnel endpoints. They will be used to configure the wg0 interfaces on each host. For no particular reason, I have decided to use the 146 address on the server. The other will be on the client.

Server configuration

The server has a static IP address of 203.0.113.1 (see RFC 5737) and will listen on port 12738)
This is the server configuration. The keys shown are the keys I used for this blog post. Those keys are no longer in use. Private keys should never be shown. Don't use these keys. They won't work for you. I've slightly changed them.

This is the contents of /usr/local/etc/wireguard/wg0.conf on the server:

[Interface]
Address = 10.9.1.146/30
ListenPort = 12738
PrivateKey = 2GvL[this is the server private key]fGLFE=

[Peer]
PublicKey = dW86s[this is the client public key]cnimI=
AllowedIPs = 10.55.0.0/24
PersistentKeepalive = 30

The following should explain the above:

1 - this section defines where and how we listen2 - the server endpoint and netmask used (see The tunnel, above)
3 - the port the server should listen on for the connections coming from the client
4 - the private key created for this server - to see it: sudo cat /usr/local/etc/wireguard/server.key - then copy/paste it into this file
5 - peers are who are allowed to connect to us
6 - the public key of the client
7 - the IP addresses which the server will be able to access at the other end of the tunnel
8 - Wireguard operates over UDP - some devices along the network might want to tear down the connection if nothing is received recently - this sends a packet every 30 seconds to keep that connection open

Client configuration

This is the client configuration:

This is the contents of /usr/local/etc/wireguard/wg0.conf on the client:

[Interface]
Address = 10.9.1.145/30
PrivateKey = OOf6u[this is the client private key]JlHwVM=

[Peer]
PublicKey = 10A3[this is the server public key]nA8=
AllowedIPs = 10.9.1.146/32,10.200.0.0/24
Endpoint = 203.0.113.1:12738
PersistentKeepalive = 30

1 - this section defines where and how we listen
2 - the server client and netmask used (see The tunnel, above)
3 - the private key created for this client - to see it: sudo cat /usr/local/etc/wireguard/client.key - then copy/paste it into this file
5 - peers are who are allowed to connect to us
6 - the public key of the server
7 - the IP address of the other end of the tunnel and the network this client can reach at the other end of this tunnel
8 - The IP address and port where we find the server
9 - Wireguard operates over UDP - some devices along the network might want to tear down the connection if nothing is received recently - this sends a packet every 30 seconds to keep that connection open

Getting it started

With configuration behind us, let's get wireguard up and running.

These commands enable wireguard and tell it to use the interface wg0, which matches the configuration filename we have been using.

Run these commands on both hosts.

% sudo sysrc wireguard_interfaces="wg0"
wireguard_interfaces:  -> wg0
% sysrc wireguard_enable="YES"
wireguard_enable:  -> YES

You only need to do that once. It gets the values into /etc/rc.conf.

This starts wireguard on my server:

[r720-02 dan ~] % sudo service wireguard start
[#] ifconfig wg create name wg0
[!] Missing WireGuard kernel support (ifconfig: SIOCIFCREATE2: Invalid argument). Falling back to slow userspace implementation.
[#] wireguard-go wg0
????????????????????????????????????????????????????????
?                                                      ?
?   Running wireguard-go is not required because this  ?
?   kernel has first class support for WireGuard. For  ?
?   information on installing the kernel module,       ?
?   please visit:                                      ?
?         https://www.wireguard.com/install/           ?
?                                                      ?
????????????????????????????????????????????????????????
[#] wg setconf wg0 /dev/stdin
[#] ifconfig wg0 inet 10.9.1.146/30 alias
[#] ifconfig wg0 mtu 1420
[#] ifconfig wg0 up
[#] route -q -n add -inet 10.55.0.0/24 -interface wg0
[+] Backgrounding route monitor

This starts it on the client:

[r720-01 dan ~] % sudo service wireguard start
[#] rm -f /var/run/wireguard/wg0.sock
[#] ifconfig wg create name wg0
[!] Missing WireGuard kernel support (ifconfig: SIOCIFCREATE2: Invalid argument). Falling back to slow userspace implementation.
[#] wireguard-go wg0
????????????????????????????????????????????????????????
?                                                      ?
?   Running wireguard-go is not required because this  ?
?   kernel has first class support for WireGuard. For  ?
?   information on installing the kernel module,       ?
?   please visit:                                      ?
?         https://www.wireguard.com/install/           ?
?                                                      ?
????????????????????????????????????????????????????????
[#] wg setconf wg0 /dev/stdin
[#] ifconfig wg0 inet 10.9.1.145/30 alias
[#] ifconfig wg0 mtu 1420
[#] ifconfig wg0 up
[#] route -q -n add -inet 10.9.1.146/32 -interface wg0
[#] route -q -n add -inet 10.200.0.0/24 -interface wg0
[+] Backgrounding route monitor

Status

This shows the status of server. service wireguard status also works.

[r720-02 dan ~] % sudo wg show
interface: wg0
  public key: 10A3[this is the server public key]nA8=
  private key: (hidden)
  listening port: 37284

peer: dW86s[this is the client public key]cnimI=
  endpoint: 108.36.xx.yyy:20691
  allowed ips: 10.55.0.0/24
  latest handshake: 34 seconds ago
  transfer: 424 B received, 280 B sent
  persistent keepalive: every 30 seconds

And of the client:

[r720-01 dan ~] % sudo wg show
interface: wg0
  public key: dW86s[this is the client public key]cnimI=
  private key: (hidden)
  listening port: 57835

peer: 10A3[this is the server public key]nA8=
  endpoint: 203.0.113.1: 12738
  allowed ips: 10.9.1.146/32, 10.200.0.0/24
  latest handshake: 10 seconds ago
  transfer: 312 B received, 488 B sent
  persistent keepalive: every 30 seconds

That should help you get started.

Testing the ping

Here is a ping on the server hitting a host in my basement:

[r720-01 dan ~] % ping 10.55.0.24                                                                              15:55:38
PING 10.55.0.24 (10.55.0.24): 56 data bytes
64 bytes from 10.55.0.24: icmp_seq=0 ttl=64 time=0.316 ms
64 bytes from 10.55.0.24: icmp_seq=1 ttl=64 time=0.135 ms
64 bytes from 10.55.0.24: icmp_seq=2 ttl=64 time=0.135 ms
64 bytes from 10.55.0.24: icmp_seq=3 ttl=64 time=0.142 ms
64 bytes from 10.55.0.24: icmp_seq=4 ttl=64 time=0.108 ms
64 bytes from 10.55.0.24: icmp_seq=5 ttl=64 time=0.137 ms
64 bytes from 10.55.0.24: icmp_seq=6 ttl=64 time=0.165 ms
^C
--- 10.55.0.24 ping statistics ---
7 packets transmitted, 7 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.108/0.162/0.316/0.064 ms
[r720-01 dan ~] %                                                                                              16:04:03

Routing

I implemented the endpoint in my basement on a host which was not the gateway. None of the hosts know about the 10.200.0.0/24 subnet. They don't know how to get there.

To fix that, I added this static route to my gateway:

# route add 10.200.0.0/25 10.55.0.59

Where 10.55.0.59 is an IP address, any IP address, on the host with the wireguard tunnel.

This route could also be added to every host so that it goes direct to the wireguard host instead of taking the default route to the gateway.

Additional information about what I did

The server network (10.200.0.0/24) is the subnet I assigned to a jail on the server. It's not actually the whole server. It's just one part of the server. This jail will be the public proxy into which incoming public connections arrive. They will then be relayed/proxied through the tunnel to the websites in my basement.

Website Pin Facebook Twitter Myspace Friendfeed Technorati del.icio.us Digg Google StumbleUpon Premium Responsive