Wireguard Networking

Last updated: June 26, 2026

The best way to understand WireGuard and WG-CP is to build a network from scratch. In this tutorial, we will manually connect a cloud server and a laptop, and then see how WG-CP automates this process as your network grows.

Why build a virtual network (VPN)?

Before we start, why do this at all? A virtual private network connects devices securely over the public internet as if they were plugged into the same local switch. This solves several common infrastructure problems:

  • Access Anywhere: Securely reach your Raspberry Pi, home server, or private projects from anywhere, even if they are stuck behind strict home routers or firewalls, without exposing them to the open internet.
  • Unified Infrastructure: Link servers across different cloud providers (e.g., AWS, DigitalOcean) and your local hardware into one cohesive, private network, seamlessly bridging isolated environments without complex firewall rules.
  • Exit Nodes (Web Anonymity): Route all your internet traffic through a remote server to hide your public IP address or secure your browsing on untrusted Wi-Fi. (This is how commercial services like NordVPN work, though this tutorial focuses on private infrastructure).

Why WireGuard? Unlike older, heavy VPN protocols, WireGuard is the modern industry standard with universal platform support. It is incredibly simple to configure, uses state-of-the-art cryptography, handles seamless roaming without dropping connections, and delivers blazing-fast performance — especially on Linux, where it runs directly in the kernel.

Step 1: Installation & Identity

First, install WireGuard on both your cloud server and your laptop. For your cloud server (Ubuntu/Debian):

sudo apt update && sudo apt install wireguard -y

For your laptop, if you are using Windows, macOS, or mobile, download the official GUI client from wireguard.com/install.

Next, generate a keypair on both machines. On your Linux server, run this command:

wg genkey | tee privatekey | wg pubkey > publickey

Note: If you are using a GUI client on your laptop, it will typically generate a keypair automatically for you when you click "Add empty tunnel".

💡 Concept: Cryptokey Routing
WireGuard doesn't use usernames or passwords. Your privatekey is your secret identity (never share it!). Your publickey is how others identify you on the network.

Step 2: The Gateway Server (Endpoints)

On your cloud server, create a file at /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = <SERVER_PRIVATE_KEY>
Address = 10.0.0.1/32
ListenPort = 51820

Start the interface with: sudo wg-quick up wg0

💡 Concept: Endpoints & Listen Ports
Because the server is in the cloud, it acts as our anchor. By setting ListenPort = 51820, we tell WireGuard to listen for incoming UDP packets on that specific port. The laptop will use the server's public IP and this port as its Endpoint to find it on the internet.

Step 3: Connecting the Laptop (AllowedIPs)

Now, on your laptop, configure the connection to the server. If using Linux, create /etc/wireguard/wg0.conf. If using a GUI client, click "Add empty tunnel" and paste this configuration:

[Interface]
PrivateKey = <LAPTOP_PRIVATE_KEY>
Address = 10.0.0.2/32

[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <SERVER_PUBLIC_IP>:51820
AllowedIPs = 10.0.0.1/32

Important: For the ping to succeed, the server needs to know how to reply. Go back to your server's /etc/wireguard/wg0.conf and add the laptop as a peer:

[Peer]
PublicKey = <LAPTOP_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32

Restart the interface on the server (sudo wg-quick down wg0 && sudo wg-quick up wg0) and start the interface on your laptop (use wg-quick on Linux, or click "Activate" in the GUI client).

Now try pinging the server from your laptop: ping 10.0.0.1

💡 Concept: AllowedIPs (The Magic of WireGuard)
This is the most important concept. AllowedIPs = 10.0.0.1/32 tells your laptop two things:
  1. Routing: "If an app tries to send traffic to 10.0.0.1, encrypt it and send it to this Peer's Endpoint."
  2. Security: "If I receive a decrypted packet from this Peer, only accept it if its source IP is 10.0.0.1."

Exposing a Subnet

WireGuard also allows you to route traffic to networks behind your peers. For example, if you want your laptop to securely access a Docker network or LAN hosted on your server:

First, ensure your server's OS allows packet routing by enabling IP forwarding. Run this on the server:

sudo sysctl -w net.ipv4.ip_forward=1

Then, simply update the laptop's config to include that subnet. For example, to access a 172.17.0.0/16 network:

[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <SERVER_PUBLIC_IP>:51820
AllowedIPs = 10.0.0.1/32, 172.17.0.0/16

Restart the laptop's interface (sudo wg-quick down wg0 && sudo wg-quick up wg0 on Linux, or toggle the connection off and on in the GUI client). Your laptop will now securely route all 172.17.x.x traffic through the server!

💡 Note on Docker & Internal Networks
  • Published Ports: The simplest way to securely expose a Docker service is to bind its published port directly to the VPN IP: docker run -p 10.0.0.1:8080:80. This guarantees only VPN users can access it without exposing it to the public internet.
  • Full Access: If you want full direct access to unpublished containers, modern Docker's strict firewall drops routed traffic by default. The easiest fix is to add "allow-direct-routing": true to your /etc/docker/daemon.json and run sudo systemctl reload docker. (Alternatively, on a per-network basis, you can use the com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected option).

The N-to-N Problem

While point-to-point configuration is simple, scaling it introduces significant overhead. Adding multiple users or servers requires updating configuration across many devices:

  • Adding a client: Requires logging into the server to add a new [Peer] block for the new device.
  • Adding a server: Requires updating the [Peer] blocks on all existing clients to route traffic to the new server.

Managing raw wg0.conf files manually across multiple machines becomes difficult to maintain as the network grows.

Centralized Configuration

WG-CP addresses this by acting as a centralized compiler for WireGuard configurations. Here is the complete API lifecycle:

1. Create the Network

First, initialize a new network namespace on the Control Plane to receive a unique Network ID.

curl -X POST https://w1.wgcp.dev/api/v1/networks

The API will respond with your new ID, for example: {"id": "abc123def456"}

2. Define and Push Configuration

Define your entire topology in a single network.yml file and push it to the API:

network.yml
version: 2
contact_email: "admin@example.com"

wireguard_networks:
  - network: "vpn"

nodes:
  - name: "server"
    public_key: "<SERVER_PUBLIC_KEY>"
    subnets: ["172.17.0.0/16"] # Automatically adds this to everyone's AllowedIPs
    physical:
      - network: "wan"
        address: "<SERVER_PUBLIC_IP>"
    wireguard:
      - network: "vpn"
        address: "10.0.0.1"

  - name: "laptop"
    public_key: "<LAPTOP_PUBLIC_KEY>"
    wireguard:
      - network: "vpn"
        address: "10.0.0.2"
curl -X POST https://w1.wgcp.dev/api/v1/networks/abc123def456/yaml \
  -H "Content-Type: text/plain" \
  --data-binary @network.yml

3. Node Retrieval

Nodes no longer need to know the topology. They simply ask the API for their specific configuration based on their public key:

curl https://w1.wgcp.dev/api/v1/networks/abc123def456/config/<LAPTOP_PUBLIC_KEY>

The API calculates the required [Peer] blocks, Endpoints, and AllowedIPs dynamically and returns a complete WireGuard configuration.

Dynamic State Sync
The WG-CP agent automates this retrieval by maintaining an open HTTP stream. When the central YAML configuration is updated, the API pushes the new configuration to connected agents. The agents apply these changes using wg syncconf, updating routing rules without terminating active connections.

Using the Control Plane UI

While the API is powerful, this Control Plane provides a complete web interface to simplify managing your network. Now that you understand the underlying concepts, explore the other tabs to see how it all ties together:

  • Editor: A live editor for your network.yml with real-time validation.
  • Inspect: Preview the generated WireGuard configurations and global hosts file for all your nodes before you deploy.
  • Agent Guide: Generates the bash scripts and installation commands for your specific network and nodes.

Head over to the Editor tab to start building your own topology!