WireGuard Over WebRTC With Weron

Weron is a cool project that makes it easy to set up a peer-to-peer mesh network through WebRTC. One of its built-in features is the ability to punch holes through NAT on both sides of a peer-to-peer connection, using STUN or TURN.

Similarly to WireGuard, Weron allows you to access its network of peers through a virtual network interface on each peer. But unlike WireGuard, it doesn’t allow connections to be forwarded through peers to other hosts (such as other computers on the same LAN as the peer, or to remote servers on the Internet). However, you can work around this — by running a WireGuard tunnel through Weron.

For example, say you have an internal site that has outbound Internet access, but no easy way to open up a port on a static public IP address for inbound WireGuard access; and you want to allow remote access to this internal network. You can run Weron on one of the hosts at that site, and use the NAT hole-punching capabilities of Weron to enable that host to communicate with other remote endpoints:

Point-to-point WebRTC connections
Figure 1. Weron mesh network

Inside this Weron network, you can tunnel a WireGuard network, allowing you to forward connections from remote endpoints to other hosts inside the internal network:

Point-to-site WireGuard connections
Figure 2. WireGuard tunneled through Weron

We’ll go through the following steps to enable this access:

Install Weron & WireGuard on Each Host

The first step is to download and install the Weron executable on each host. Follow the Weron installation instructions for your platform. On Linux hosts, you can download and install Weron like this:

$ curl -L -o /tmp/weron "https://github.com/pojntfx/weron/releases/latest/download/weron.linux-$(uname -m)"
$ sudo install /tmp/weron /usr/local/bin
$ sudo setcap cap_net_admin+ep /usr/local/bin/weron
Tip

For Windows hosts, you’ll also need to have a TAP-Windows adapter installed. You can download the installer for this adapter from the OpenVPN downloads page (scroll to the bottom for the tap-windows-* releases).

Also install WireGuard on each host. WireGuard has been built into the Linux since kernel version 5.6, so on most Linux boxes you just need to install the wireguard-tools package.

Start Weron on the Site

Next, generate a unique community name (ie network name), community password, and community encryption key that all the Weron peers will share; plus decide on a network address block for the Weron network. For this example, we’ll use the following:

  • Community name: wgtest123

  • Community password: password123

  • Community key: cipherkey123

  • Community address block: 10.123.123.0/24

Start up Weron on the site host using these parameters (and leave it running):

$ weron vpn ip --community wgtest123 --password password123 --key cipherkey123 --ips 10.123.123.1/24 --static
{"level":"info","addr":"wss://weron.up.railway.app/","time":"2024-04-14T22:51:13Z","message":"Connecting to signaler"}
{"level":"info","id":"[\"10.123.123.1/24\"]","time":"2024-04-14T22:51:18Z","message":"Connected to signaler"}

This will create an ephemeral community on the default Weron signaling server (wss://weron.up.railway.app/), and direct the site host to grab the private 10.123.123.1 address in that community’s Layer 3 network. The site host will set up a new virtual network interface (tun0 by default) with this address.

Start Weron on the Points

Next, start up Weron on each remote point with the following command (and leave it running):

$ weron vpn ip --community wgtest123 --password password123 --key cipherkey123 --ips 10.123.123.0/24
{"level":"info","addr":"wss://weron.up.railway.app/","time":"2024-04-14T23:00:06Z","message":"Connecting to signaler"}
{"level":"info","id":"[\"10.123.123.113/24\"]","time":"2024-04-14T23:00:12Z","message":"Connected to signaler"}
{"level":"info","id":"[\"10.123.123.1/24\"]","time":"2024-04-14T23:00:12Z","message":"Connected to peer"}
{"level":"info","id":"[\"10.123.123.63/24\"]","time":"2024-04-14T23:00:46Z","message":"Connected to peer"}

Each point will join the same community, and grab an unused IP address in the 10.123.123.0/24 block; with that address it will set up its own virtual network interface to the community network. In our example, Endpoint A has grabbed IP address 10.123.123.113, and Endpoint B has grabbed IP address 10.123.123.63.

To allow it to send traffic to other peers, each peer will use the default STUN server (stun:stun.l.google.com:19302) to create a WebRTC data channel between itself and other peers through whatever NAT firewall exists at its own site.

Tip

If STUN is not sufficient to allow all of your Weron peers to connect to one another, you may need a TURN server to relay traffic between them. The Open Relay Project provides free TURN server access; or you may find other TURN servers available by paid subscription; or you may host your own TURN server (for example, with Coturn or other FOSS TURN servers).

To use a TURN server (or STUN servers other than the default), add the --ice flag to your weron commands:

--ice stun:stun.l.google.com:19302,username:password@turn:global.relay.metered.ca:443?transport=udp

Start WireGuard on the Site

Now we’ll start setting up a new WireGuard network within the Weron network. On the site host, set up a WireGuard configuration file like the following:

# /etc/wireguard/wg0.conf

# local settings for Site Host
[Interface]
PrivateKey = 0F11111111111111111111111111111111111111110=
Address = 10.1.1.1/24
ListenPort = 51820

# IP forwarding
PreUp = sysctl -w net.ipv4.conf.all.forwarding=1
# IP masquerading
PreUp = iptables -t mangle -A PREROUTING -i wg0 -j MARK --set-mark 1
PreUp = iptables -t nat -A POSTROUTING ! -o wg0 -m mark --mark 1 -j MASQUERADE
PostDown = iptables -t mangle -D PREROUTING -i wg0 -j MARK --set-mark 1
PostDown = iptables -t nat -D POSTROUTING ! -o wg0 -m mark --mark 1 -j MASQUERADE

# remote settings for Endpoint A
[Peer]
PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
AllowedIPs = 10.1.1.65/32

# remote settings for Endpoint B
[Peer]
PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
AllowedIPs = 10.1.1.66/32

This configuration will work just like Host β from the WireGuard Point to Site Configuration guide, allowing the host to forward connections from remote endpoints to other hosts at the site. For our WireGuard network, we’ll use the 10.1.1.0/24 IP address block.

Start up the WireGuard tunnel on the site host:

$ sudo wg-quick up wg0

Start WireGuard on the Points

Finally, we’ll set up WireGuard on each point. On Endpoint A, set up a WireGuard configuration file like the following:

# /etc/wireguard/wg0.conf

# local settings for Endpoint A
[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
Address = 10.1.1.65/32

# remote settings for Site Host
[Peer]
PublicKey = hN+4fjPihcKbEDFQhqrMmW8oPqqaT4CUQYtyg3FUx3k=
Endpoint = 10.123.123.1:51820
AllowedIPs = 192.168.200.0/24, 10.1.1.1/32

This configuration will work similarly to Endpoint A from the WireGuard Point to Site Configuration guide, to allow the endpoint to access other hosts at the site through its WireGuard connection to the site host.

The special trick in this configuration, however, is to manipulate WireGuard’s Endpoint setting to run the WireGuard tunnel through the Weron tunnel — configuring it to use the private IP address of the site host within the Weron network (10.123.123.1):

Endpoint = 10.123.123.1:51820

With this configuration in place, start up the WireGuard interface on Endpoint A:

$ sudo wg-quick up wg0

Do the same for Endpoint B (or any other remote endpoints you want to add to the network), matching the unique key pair and IP address for the endpoint defined in the site host’s WireGuard configuration:

# /etc/wireguard/wg0.conf

# local settings for Endpoint B
[Interface]
PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA=
Address = 10.1.1.66/32

# remote settings for Site Host
[Peer]
PublicKey = hN+4fjPihcKbEDFQhqrMmW8oPqqaT4CUQYtyg3FUx3k=
Endpoint = 10.123.123.1:51820
AllowedIPs = 192.168.200.0/24, 10.1.1.1/32

Test It Out

On Endpoint A, with both Weron and the WireGuard tunnel up on all hosts, you should be able to connect to the other hosts at the internal site — for example, to run a command like the following on Endpoint A to access a web server running on some other host at 192.168.200.22 in the site:

$ curl 192.168.200.22
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
...
Note

The WireGuard tunnel will only be available when the Weron tunnel itself is available. If you stop running Weron on a peer — or if the Weron peer gets disconnected from its community — the WireGuard tunnel to that peer will stop being available.

In particular, if you see a message like the following in the Weron output on one of the endpoints, indicating that it has disconnected from the site host, you’ll need to restart Weron on that endpoint to try to reconnect it:

{"level":"info","id":"[\"10.123.123.1/24\"]","time":"2024-04-14T23:05:44Z","message":"Disconnected from peer"}