Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

1-4: LAB | A Simple Wireguard Network

Our first lab!

Make sure you have everything installed from Setup. Then, with your terminal in the repository directory, run:

just up 1-4

Whoah! What just happened?

zellij grid

Zellij has taken a single terminal window and split into four. In the top left quadrant is your OS shell. Bottom left is peer-1; top right is peer-2; and bottom right is peer-3. These are the machines we want to connect together in our Wireguard network. But each one needs some help.

Configuring the Peers

In any of the three Peer terminal windows, run the following Bash command:

cat /etc/wireguard/lab_1-4.conf

You’ll get something back that looks like:

# Peer 1
[Interface]
#PublicKey = <<PUBLIC_KEY>>
PrivateKey = <<PRIVATE_KEY>>
Address = <<WG_ADDRESS>>
ListenPort = 51820

About like what we discussed in the last section, right? But there’s some information missing from each config file. Pay attention to the comments for each [Peer] entry across the configs. Each node needs each other node’s information, and it’s easy to get mixed up as you fill these in.

How do you fill these in, anyhow?

The Wireguard Command Line

The wg command is used to manage Wireguard connections. It also has utilities for generating private a public keys for use in configs.

wg genkey creates a new private key, represented in base64 encoding. wg pubkey takes such a key from stdin and outputs the associated public key in the same format. That’s not the most ergonomic, but it allows us to easily create a keypair on the command line. Goes like this:

privkey=$(wg genkey)
pubkey=$(echo $privkey | wg pubkey)
echo $privkey
echo $pubkey

Interface Keys

Each container has both Nano and Helix editors installed, so you can manually fill in these values. The <<PUBLIC_KEY>> and <<PRIVATE_KEY>> placeholder values are there for a reason, though! We can use the sed command line tool to surgically replace those values.

sed -i "s#<<PUBLIC_KEY>>#$pubkey#" /etc/wireguard/lab_1-4.conf
sed -i "s#<<PRIVATE_KEY>>#$privkey#" /etc/wireguard/lab_1-4.conf

"s#<<PUBLIC_KEY>>#pubkey" instructs sed to replace the <<PUBLIC_KEY>> pattern with value in $pubkey.

The tee command outputs the result of sed to the command line as well as writing the result back to the named file. That way you can review the changes.

Note

Advanced command line users may notice something weird about our sed invocations. The # delimiter is used instead of the more common / between command components because base64 strings can themselves contain /. Since sed doesn’t care what we use as a separator, we choose an alternative.

On each of your three Peer shells, run the commands to generate the keys and add them to the respective configs.

Now, what about that Address field?

Interface Address

We need to decide on an address space to use. I didn’t hardcode this because I don’t know what your network environment is like. Choose a subnet that is different from your normal network. If your primary IP address is something like 192.168.1.10, maybe consider an address space like 172.16.100.0/24. We’ll use that in these examples.

Note

By default, Podman uses the 10.88.0.0/16 subnet for its own networking. If you run ip address show (or ip a s) in one of your lab containers, you’ll see such an address assigned to the container.

All the Peers in our Wireguard network will have an address in the same subnet. Wireguard does not supply addresses for you, so you will need to keep straight what Peer is assigned to what address. I like to keep it simple, so Peer 1 will get 172.16.100.1/24, Peer 2 will get 172.16.100.2/24, and Peer 3 will get 172.16.100.3/24.

Since there’s a <<WG_ADDRESS>> placeholder in the config, we can repeat our sed trick for each Peer with these addresses.

# On Peer 1
sed -i "s#<<WG_ADDRESS>>#172.16.100.1/24#" /etc/wireguard/lab_1-4.conf
# On Peer 2
sed -i "s#<<WG_ADDRESS>>#172.16.100.2/24#" /etc/wireguard/lab_1-4.conf
# On Peer 3
sed -i "s#<<WG_ADDRESS>>#172.16.100.3/24#" /etc/wireguard/lab_1-4.conf

Peer Data

Now comes the finicky part. You’ll likely want to have a text editor open on each terminal pane with the configurations open.

With the keys and addresses filled in for each Peer, we need to fill in the respective addresses across the configs. Here’s the breakdown of what keys and addresses need to go where.

  • Peer 1: Peer 2 and 3
  • Peer 2: Peer 1 and 3
  • Peer 3: Peer 1 and 2

Fill in the public keys from each to each. Now let’s talk about AllowedIPs.

Note

Zellij will try its best to copy highlighted text in any pane to your system clipboard. See if it works!

AllowedIPs

This is the most misunderstood entry in the config file. That’s because it means something slightly different depending on whether you are sending Wireguard data or receiving it. For senders, AllowedIPs serves as a routing rule: any address that matches the subnet listed there will be sent over that Wireguard tunnel. But for receivers, it means that only traffic from the subnets/addresses listed will be accepted.

In this case, that’s a distinction without a difference because we’re making point-to-point connections between Peers. But in networks where a single Peer handles incoming traffic for multiple other Peers, this difference matters greatly, and can lead to confusion.

Anyway, taking our addresses above as an example, here is how the AllowedIPs settings should look on each Peer:

  • Peer 1:
    • Peer 2: 172.16.100.2/32
    • Peer 3: 172.16.100.3/32
  • Peer 2:
    • Peer 1: 172.16.100.1/32
    • Peer 3: 172.16.100.3/32
  • Peer 3:
    • Peer 1: 172.16.100.1/32
    • Peer 2: 172.16.100.2/32

Get those set up and we’re nearly finished.

Endpoint

Endpoint defines the non-Wireguard address at which to attempt to contact a given Peer. We’ve predetermined the listening port to be 51820, but we still need to know the IP address (or the hostname) for each Peer.

We can of course run ip address show on each Peer to get their current network IP address, and use those in our configs, but Podman offers another option. Because each Peer can resolve the hostnames of other containers in the ad-hoc network for the deployment, we can use the hostname alone for this trick.

Prove for yourself that hostnames resolve. From Peer 1, run:

ping -c 4 lab_1-4_peer-2

See replies? Et voilà, we have hostname resolution! So for each Peer entry, the Endpoint should be like: lab_1-4-peer-N, where N is the peer number.

Putting it all together, here’s what a complete config would look like for Peer 1. Keep in mind the keys for your configuration will be completely different.

# Our Interface
[Interface]
#PublicKey = SU5dSM/fPQFirdIkGr9CfTwY/6Il9o3rLoblhuZzQ1U=
PrivateKey = EAMBHm/P48+4EDsQ8d4YnOJarNFFxthagDqc/y2I2Fs=
Address = 172.16.100.1/24
ListenPort = 51820

# Fill these in with detail from the other two peers!

[Peer]
PublicKey = mpl+K0M9U04nlrlVNAPeiggVPi19PZaG6A47KhKHckw=
AllowedIPs = 172.16.100.2/32
Endpoint = lab_1-4_peer-2:51820
PersistentKeepalive = 25

[Peer]
PublicKey = +4h5gepZN/o+N6BNrcKcTUHNvi9U21IJUDYgAvl++R8=
AllowedIPs = 172.16.100.3/32
Endpoint = lab_1-4_peer-3:51820
PersistentKeepalive = 25

Save your configs on each Peer. Now we’re ready to bring the Wireguard network up!

Launching the Network

The wg-quick command allows us to quickly spin Wireguard interfaces up and down on a system. It takes two arguments: an interface action (up, down), and the name of either an existing Wireguard interface, or the name of a config file in the config folder—in our case, /etc/wireguard.

On each Peer, run:

wg-quick up lab_1-4

The output should look like:

[#] ip link add dev lab_1-4 type wireguard
[#] wg setconf lab_1-4 /dev/fd/63
[#] ip -4 address add 172.16.100.1/24 dev lab_1-4
[#] ip link set mtu 65440 up dev lab_1-4 

If you receive an error and an ip link delete command, check your config files for mistakes.

If the network came up, you can run wg show on any Peer and you should see the status of the Wireguard connection, including data sent between nodes. Which probably won’t look like much yet. That’s okay though; we’re just confirming the network functions. To send some data over the Wireguard tunnel, try this from Peer 1:

ping -c 4 172.16.100.2
ping -c 4 172.16.100.3

When you’re ready, run this to bring the lab down:

just down 1-4

Congratulations! You’ve made your first Wireguard network! We did everything the hard way in this lab to get familiar with the basic components of a Wireguard config. Some of this will be automated as we move forward.