Configuring WireGuard

WireGuard is a novel VPN that runs inside the Linux Kernel and uses state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPSec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. It runs over UDP.

You might also want to read the Conceptual Overview, the Quickstart and the Whitepaper.

Fedora CoreOS has full support for WireGuard out of the box. This page shows how to set up a single connection between a Fedora CoreOS server and another computer. It goes over the basic client configuration, but it does not cover installing WireGuard on your client.

There are two options to set up WireGuard on Fedora CoreOS:

  • Importing the WireGuard configuration in NetworkManager

  • Using wg-quick

Generating Keys

You will need to generate keys to configure WireGuard. You can generate the keys on your workstation or a running Fedora CoreOS system.

First, let’s create the WireGuard keys for the Fedora CoreOS system:

Generate WireGuard keys for the Fedora CoreOS system
umask 077
wg genkey | tee fcos_private_key | wg pubkey > fcos_public_key

Now let’s generate the WireGuard keys for the client:

Generate WireGuard keys for the client
umask 077
wg genkey | tee client_private_key | wg pubkey > client_public_key

You can optionnaly generate a pre-shared key to increase security:

Generate a preshared key for this peer pair
wg genpsk > fcos_client_psk

You should generate a pre-shared key for each peer pair.

Configuring WireGuard on Fedora CoreOS

You can now modify your Butane config to create the wg0 configuration file:

Example Butane config with a WireGuard configuration file
variant: fcos
version: 1.6.0
storage:
  files:
    - path: /etc/wireguard/wg0.conf
      mode: 0600
      contents:
        inline: |
          [Interface]
          Address = 192.168.71.1/24,fdc9:3c6b:21c7:e6bd::1/64
          PrivateKey = 
          ListenPort = 51820

          [Peer]
          PublicKey = 
          PresharedKey = 
          AllowedIPs = 192.168.71.2/32,fdc9:3c6b:21c7:e6bd::2/128

Using NetworkManager

If you want to use the support in NetworkManager, you can import the WireGuard configuration with a oneshot unit:

Example systemd service unit to import the WireGuard configuration
systemd:
  units:
    - name: import-wireguard-config.service
      enabled: true
      contents: |
        [Unit]
        ConditionPathExists=!/etc/NetworkManager/system-connections/wg0.nmconnection
        Description=Import wireguard configuration to NetworkManager
        [Service]
        Type=oneshot
        RemainAfterExit=yes
        ExecStart=nmcli connection import type wireguard file /etc/wireguard/wg0.conf
        [Install]
        WantedBy=multi-user.target

NetworkManager will ignGre PostUp and PostDown directives in the WireGuard config. If you have firewall configuration to apply, make sure to apply it with a separate unit, or manually.

If you need to make further changes to update WireGuard’s configuration, delete the connection and re-import it from the updated configuration file.

Re-import updated WireGuard configuration
$ sudo nmcli con delete wg0 && sudo nmcli con import type wireguard file /etc/wireguard/wg0.conf
Connection 'wg0' (1e4f869e-f95c-4221-b2b9-99726ffde92b) successfully deleted.
Connection 'wg0' (18cd8e61-1cc2-43a2-9f2e-467b75cd99da) successfully added.

Using wg-quick

If you want to use wg-quick instead of the support in NetworkManager, you can add the following to your Butane config:

systemd:
  units:
    - name: wg-quick@wg0.service
      enabled: true

If you need to make further changes to WireGuard’s configuration, reload the service with:

systemctl reload wg-quick@wg0.conf

Verifying the configuration on the Fedora CoreOS system

Boot Fedora CoreOS and log in. When you run sudo wg show you should see this:

Check WireGuard configuration
[core@server ~]$ sudo wg show
interface: wg0
  public key: <fcos_public_key>
  private key: (hidden)
  listening port: 51820

peer: <client_one_public_key>
  preshared key: (hidden)
  endpoint: <Client IP Address>:51821
  allowed ips: 192.168.71.0/24, fdc9:3c6b:21c7:e6bd::/64

[core@server ~]$ sudo ip addr show wg0
12: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 192.168.71.1/24 scope global wg0
       valid_lft forever preferred_lft forever
    inet6 fdc9:3c6b:21c7:e6bd::1/64 scope global
       valid_lft forever preferred_lft forever

<Client IP address> above is the IP or FQDN of the Client computer.

Configuring WireGuard on a client

You will now have to configure WireGuard on your client computer with the following configuration:

Client WireGuard configuration
[Interface]
Address = 192.168.71.2/24,fdc9:3c6b:21c7:e6bd::2/64
PrivateKey = <client_private_key>
ListenPort = 51821

[Peer]
PublicKey = <fcos_public_key>
PresharedKey = <fcos_client_psk>
Endpoint = <FCOS IP address>:51820
AllowedIPs = 192.168.71.0/24,fdc9:3c6b:21c7:e6bd::/64

<FCOS IP address> is the IP or FQDN of the FCOS server.

Write the above config to /etc/wireguard/wg0.conf, set the access mode on the configuration file and then import the configuration on your client:

Import the WireGuard configuration on the client
[core@client ~]$ sudo chmod 0600 /etc/wireguard/wg0.conf
[core@client ~]$ sudo nmcli con import type wireguard file /etc/wireguard/wg0.conf

Then check your configuration:

Check WireGuard configuration on the client
[core@client ~]$ sudo wg show
interface: wg0
  public key: <client_one_public_key>
  private key: (hidden)
  listening port: 51821

peer: <fcos_public_key>
  preshared key: (hidden)
  endpoint: <FCOS IP address>:51820
  allowed ips: 192.168.71.0/24, fdc9:3c6b:21c7:e6bd::/64

[core@client ~]$ sudo ip addr show wg0
21: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 192.168.71.2/24 scope global wg0
       valid_lft forever preferred_lft forever
    inet6 fdc9:3c6b:21c7:e6bd::2/64 scope global
       valid_lft forever preferred_lft forever

Testing the WireGuard connection

You can now ping the Fedora CoreOS server’s WireGuard IP address:

Ping the Fedora CoreOS server over WireGuard from the client
[core@client ~]$ ping 192.168.71.1
PING 192.168.71.1 (192.168.71.1) 56(84) bytes of data.
64 bytes from 192.168.71.1: icmp_seq=1 ttl=64 time=0.439 ms
64 bytes from 192.168.71.1: icmp_seq=2 ttl=64 time=0.422 ms
64 bytes from 192.168.71.1: icmp_seq=3 ttl=64 time=0.383 ms
^C
--- 192.168.71.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2027ms
rtt min/avg/max/mdev = 0.383/0.414/0.439/0.023 ms

[core@client ~]$ ping6 fdc9:3c6b:21c7:e6bd::1
PING fdc9:3c6b:21c7:e6bd::1(fdc9:3c6b:21c7:e6bd::1) 56 data bytes
64 bytes from fdc9:3c6b:21c7:e6bd::1: icmp_seq=1 ttl=64 time=1.55 ms
64 bytes from fdc9:3c6b:21c7:e6bd::1: icmp_seq=2 ttl=64 time=0.454 ms
64 bytes from fdc9:3c6b:21c7:e6bd::1: icmp_seq=3 ttl=64 time=0.424 ms
64 bytes from fdc9:3c6b:21c7:e6bd::1: icmp_seq=4 ttl=64 time=0.424 ms
^C
--- fdc9:3c6b:21c7:e6bd::1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3054ms
rtt min/avg/max/mdev = 0.424/0.712/1.546/0.481 ms

When you run sudo wg show on your client you should see a recent handshake and a transfer sections with sent and received:

Verify handshake and transfer metrics
[core@client ~]$ sudo wg show
interface: wg0
  public key: <client_one_public_key>
  private key: (hidden)
  listening port: 51821

peer: <fcos_public_key>
  preshared key: (hidden)
  endpoint: <Client IP address>:51820
  allowed ips: 192.168.71.0/24, fdc9:3c6b:21c7:e6bd::/64
  latest handshake: 9 seconds ago
  transfer: 22.02 KiB received, 22.28 KiB sent

Routing all traffic over WireGuard

If you plan on forwarding all of your client’s traffic through the Fedora CoreOS instance, you will need to enable IP Forwarding and set some PostUp and PostDown directives:

Example Fedora CoreOS WireGuard configuration with IP forwarding
variant: fcos
version: 1.6.0
storage:
  files:
    - path: /etc/sysctl.d/90-ipv4-ip-forward.conf
      mode: 0644
      contents:
        inline: |
          net.ipv4.ip_forward = 1

    - path: /etc/sysctl.d/90-ipv6-ip-forwarding.conf
      mode: 0644
      contents:
        inline: |
          net.ipv6.conf.all.forwarding = 1

    - path: /etc/wireguard/wg0.conf
      mode: 0600
      contents:
        inline: |
          [Interface]
          Address = 192.168.71.1/24,fdc9:3c6b:21c7:e6bd::1/64
          PrivateKey = 
          ListenPort = 51820

          PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE
          PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o enp1s0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o enp1s0 -j MASQUERADE

          [Peer]
          PublicKey = 
          PresharedKey = 
          AllowedIPs = 192.168.71.0/24,fdc9:3c6b:21c7:e6bd::/64

systemd:
  units:
    - name: wg-quick@wg0.service
      enabled: true

Fedora CoreOS uses predictable interface names by default. Make sure to use the correct interface name for your hardware in the above PostUp and PostDown commands.

Then set AllowedIPs = 0.0.0.0/0,::/0 in /etc/wireguard/wg0.conf in the client configuration to route all IPv4 and IPv6 traffic on the client computer over the WireGuard interface:

A configuration for routing all traffic on the client over WireGuard:
[Interface]
Address = 192.168.71.1/24,fdc9:3c6b:21c7:e6bd::2/64
PrivateKey = <client_private_key>
ListenPort = 51821

[Peer]
PublicKey = <fcos_public_key>
PresharedKey = <fcos_client_psk>
Endpoint = <FCOS IP Address>:51820
AllowedIPs = 0.0.0.0/0,::/0