Two offices, one network. Staff at the branch open the file server at headquarters like it is down the hall, printers and internal apps work from both sides, and nothing is exposed to the internet. That is a site-to-site VPN, and WireGuard is the modern way to build one: it is built into the Linux kernel, the config for a whole tunnel fits on one screen, and it is fast enough that you will not notice it is there. By the end of this guide you will have an encrypted tunnel between two office networks with traffic routing both ways.
Prerequisites
- A Linux machine at each office to act as the VPN gateway. A small Ubuntu 22.04 or 24.04 box or VM works fine.
- Root or sudo access on both.
- At least one site with a public IP or DNS name reachable from the internet. (Only one side needs to be reachable; the other side dials out.)
- The two office LANs must use different subnets. We will use
192.168.1.0/24for Office A and192.168.2.0/24for Office B. If both offices are on 192.168.1.x, renumber one first or the routing cannot work. - Ability to open UDP port 51820 on the reachable site's firewall or router.
Install WireGuard on both gateways:
sudo apt update
sudo apt install wireguard
Step 1: Generate keys on both gateways
WireGuard identifies peers by key pairs, no usernames or certificates. On each gateway, generate a private and public key:
wg genkey | sudo tee /etc/wireguard/private.key
sudo chmod 600 /etc/wireguard/private.key
sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
Do this on Office A's gateway and again on Office B's. You will end up with four keys. Each side keeps its own private key secret and shares only its public key with the other side. The tunnel itself gets its own tiny subnet: we will give Office A's gateway 10.100.0.1 and Office B's 10.100.0.2.
Step 2: Configure Office A (the reachable site)
Create /etc/wireguard/wg0.conf on Office A's gateway:
[Interface]
Address = 10.100.0.1/24
ListenPort = 51820
PrivateKey = <OFFICE_A_PRIVATE_KEY>
[Peer]
# Office B
PublicKey = <OFFICE_B_PUBLIC_KEY>
AllowedIPs = 10.100.0.2/32, 192.168.2.0/24
AllowedIPs is the line people get wrong, because it does two jobs at once. It is both a routing table entry ("send traffic for these networks through this peer") and a filter ("accept traffic from this peer only if it comes from these networks"). Office A's config says: to reach Office B's tunnel address or anything on Office B's LAN, use this tunnel. It is not related to what traffic is allowed in the firewall sense of an allowlist of clients.
Step 3: Configure Office B
Create /etc/wireguard/wg0.conf on Office B's gateway:
[Interface]
Address = 10.100.0.2/24
PrivateKey = <OFFICE_B_PRIVATE_KEY>
[Peer]
# Office A
PublicKey = <OFFICE_A_PUBLIC_KEY>
Endpoint = vpn.example.com:51820
AllowedIPs = 10.100.0.1/32, 192.168.1.0/24
PersistentKeepalive = 25
Two things are different on this side. Endpoint is Office A's public IP or DNS name; Office B initiates the connection, which is why Office B does not need to be reachable from the internet. PersistentKeepalive = 25 sends a tiny packet every 25 seconds so the NAT router at Office B keeps the connection alive. Without it, the tunnel goes quiet, the router forgets the mapping, and Office A can no longer reach Office B until B sends traffic again. On a site-to-site link behind NAT, always set it.
Step 4: Enable IP forwarding
Each gateway needs to pass packets between its LAN and the tunnel, which Linux refuses to do by default. On both gateways:
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf
Skipping this is the classic "the gateways can ping each other but nothing else works" bug.
Step 5: Open the firewall and bring the tunnel up
On Office A (the listening side), allow WireGuard's port. With ufw:
sudo ufw allow 51820/udp
If Office A's gateway sits behind an office router, also forward UDP 51820 on that router to the gateway's LAN address. Then start the tunnel on both sides and set it to survive reboots:
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0
Step 6: Tell the LANs about each other
Machines at Office A need to know that 192.168.2.0/24 lives behind the gateway. The clean fix is one static route on each office's main router: at Office A, route 192.168.2.0/24 via the gateway's LAN IP; at Office B, route 192.168.1.0/24 via its gateway's LAN IP. Almost every business router has a static routes page. Without this step, only the gateways themselves can cross the tunnel.
Verify it
Check the tunnel is alive on either gateway:
sudo wg show
You want to see a latest handshake line with a recent time and the transfer counters climbing. Then prove the routing end to end:
# From Office A's gateway, ping B's tunnel address, then a LAN host at B
ping 10.100.0.2
ping 192.168.2.10
# From a regular desktop at Office A
ping 192.168.2.10
If the gateways ping but desktops do not, recheck Step 4 (forwarding) and Step 6 (static routes). If there is no handshake at all, it is almost always the endpoint address, the port forward, or a mixed-up key. Once the handshake shows and pings cross both LANs, you are done: reboot a gateway to confirm it comes back on its own, and the two offices are one network from then on. If you would rather have this built, tested, and documented for you, tunnel jobs like this are routine work for us.
Stuck on this, or want it done for you? That's the job.
Email us →