Blame
| d74dc5 | Wiki Migration | 2026-05-25 16:19:25 | 1 | # WireGuard Hub-and-Spoke VPN Setup Guide |
| 2 | ||||
| 3 | A step-by-step guide to creating a secure VPN with a central hub and multiple spokes. | |||
| 4 | ||||
| 5 |  | |||
| 6 | ||||
| 7 | --- | |||
| 8 | ||||
| 9 | ## Prerequisites | |||
| 10 | ||||
| 11 | Before you start, gather the public IP addresses of all three virtual machines: | |||
| 12 | - **VM A Public IP:** `VM_A_PUBLIC_IP` | |||
| 13 | - **VM B Public IP:** `VM_B_PUBLIC_IP` | |||
| 14 | - **VM C Public IP:** `VM_C_PUBLIC_IP` | |||
| 15 | ||||
| 16 | --- | |||
| 17 | ||||
| 18 | ## Step 1: Install WireGuard on All Three VMs | |||
| 19 | ||||
| 20 | **On Ubuntu / Debian:** | |||
| 21 | ```bash | |||
| 22 | sudo apt update | |||
| 23 | sudo apt install wireguard -y | |||
| 24 | ``` | |||
| 25 | ||||
| 26 | **On AlmaLinux / Rocky Linux / RHEL:** | |||
| 27 | ```bash | |||
| 28 | # Enable the EPEL repository | |||
| 29 | sudo dnf install epel-release -y | |||
| 30 | ||||
| 31 | # Install WireGuard tools | |||
| 32 | sudo dnf install wireguard-tools -y | |||
| 33 | ``` | |||
| 34 | ||||
| 35 | --- | |||
| 36 | ||||
| 37 | ## Step 2: Generate Keys on All Three VMs | |||
| 38 | ||||
| 39 | Each VM needs its own unique pair of cryptographic keys. **Perform these commands on VM A, VM B, and VM C.** | |||
| 40 | ||||
| 41 | ```bash | |||
| 42 | # Create a directory for the keys | |||
| 43 | mkdir -p ~/.wireguard | |||
| 44 | cd ~/.wireguard | |||
| 45 | ||||
| 46 | # Generate the keys | |||
| 47 | wg genkey | tee privatekey | wg pubkey > publickey | |||
| 48 | ||||
| 49 | # Secure the private key file | |||
| 50 | chmod 600 privatekey | |||
| 51 | ||||
| 52 | # View the keys so you can copy them | |||
| 53 | echo "--- PUBLIC KEY (Share this) ---" | |||
| 54 | cat publickey | |||
| 55 | echo "--- PRIVATE KEY (Keep this secret) ---" | |||
| 56 | cat privatekey | |||
| 57 | ``` | |||
| 58 | ||||
| 59 | > **Important:** Copy and paste each VM's public and private key into a text editor. Label them clearly (e.g., "VM A Public Key," "VM B Private Key") so you don't mix them up. | |||
| 60 | ||||
| 61 | --- | |||
| 62 | ||||
| 63 | ## Step 3: Configure the Hub (VM B) | |||
| 64 | ||||
| 65 | This is the central server. It will listen for connections from VM A and VM C and forward their traffic. | |||
| 66 | ||||
| 67 | **1. Enable IP Forwarding** | |||
| 68 | ```bash | |||
| 69 | # Enable forwarding now | |||
| 70 | sudo sysctl -w net.ipv4.ip_forward=1 | |||
| 71 | ||||
| 72 | # Make it permanent across reboots | |||
| 73 | echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf | |||
| 74 | ``` | |||
| 75 | ||||
| 76 | **2. Create `/etc/wireguard/wg0.conf` on VM B** | |||
| 77 | ||||
| 78 | > Replace `eth0` in the `PostUp`/`PostDown` lines with your VM's actual public network interface (find it with `ip a`). | |||
| 79 | ||||
| 80 | ```ini | |||
| 81 | # /etc/wireguard/wg0.conf on VM B (The Hub) | |||
| 82 | [Interface] | |||
| 83 | # VM B's private key and tunnel IP | |||
| 84 | PrivateKey = <PASTE_VM_B_PRIVATE_KEY_HERE> | |||
| 85 | Address = 10.10.0.1/24 | |||
| 86 | ListenPort = 51820 | |||
| 87 | ||||
| 88 | # Firewall rules to NAT traffic from peers to the internet | |||
| 89 | PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE | |||
| 90 | PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE | |||
| 91 | ||||
| 92 | # --- Peer 1: VM A --- | |||
| 93 | [Peer] | |||
| 94 | # VM A's public key and assigned tunnel IP | |||
| 95 | PublicKey = <PASTE_VM_A_PUBLIC_KEY_HERE> | |||
| 96 | AllowedIPs = 10.10.0.2/32 | |||
| 97 | ||||
| 98 | # --- Peer 2: VM C --- | |||
| 99 | [Peer] | |||
| 100 | # VM C's public key and assigned tunnel IP | |||
| 101 | PublicKey = <PASTE_VM_C_PUBLIC_KEY_HERE> | |||
| 102 | AllowedIPs = 10.10.0.3/32 | |||
| 103 | ``` | |||
| 104 | ||||
| 105 | --- | |||
| 106 | ||||
| 107 | ## Step 4: Configure the Spokes (VM A & VM C) | |||
| 108 | ||||
| 109 | **On VM A** — create `/etc/wireguard/wg0.conf`: | |||
| 110 | ```ini | |||
| 111 | # /etc/wireguard/wg0.conf on VM A (Spoke 1) | |||
| 112 | [Interface] | |||
| 113 | PrivateKey = <PASTE_VM_A_PRIVATE_KEY_HERE> | |||
| 114 | Address = 10.10.0.2/24 | |||
| 115 | ||||
| 116 | [Peer] | |||
| 117 | PublicKey = <PASTE_VM_B_PUBLIC_KEY_HERE> | |||
| 118 | Endpoint = <VM_B_PUBLIC_IP>:51820 | |||
| 119 | AllowedIPs = 10.10.0.0/24, 93.184.216.34/32 | |||
| 120 | PersistentKeepalive = 25 | |||
| 121 | ``` | |||
| 122 | ||||
| 123 | **On VM C** — create `/etc/wireguard/wg0.conf`: | |||
| 124 | ```ini | |||
| 125 | # /etc/wireguard/wg0.conf on VM C (Spoke 2) | |||
| 126 | [Interface] | |||
| 127 | PrivateKey = <PASTE_VM_C_PRIVATE_KEY_HERE> | |||
| 128 | Address = 10.10.0.3/24 | |||
| 129 | ||||
| 130 | [Peer] | |||
| 131 | PublicKey = <PASTE_VM_B_PUBLIC_KEY_HERE> | |||
| 132 | Endpoint = <VM_B_PUBLIC_IP>:51820 | |||
| 133 | AllowedIPs = 10.10.0.0/24, 93.184.216.34/32 | |||
| 134 | PersistentKeepalive = 25 | |||
| 135 | ``` | |||
| 136 | ||||
| 137 | --- | |||
| 138 | ||||
| 139 | ## Step 5: Start the Tunnels | |||
| 140 | ||||
| 141 | Bring the `wg0` interface up on all three machines: | |||
| 142 | ```bash | |||
| 143 | sudo wg-quick up wg0 | |||
| 144 | ``` | |||
| 145 | ||||
| 146 | To make WireGuard start automatically on boot: | |||
| 147 | ```bash | |||
| 148 | sudo systemctl enable wg-quick@wg0 | |||
| 149 | ``` | |||
| 150 | ||||
| 151 | --- | |||
| 152 | ||||
| 153 | ## Step 6: Verification | |||
| 154 | ||||
| 155 | **1. Check Tunnel Status** | |||
| 156 | ||||
| 157 | On any VM, run `sudo wg`. You should see your interface details and the latest handshake information for your peers. | |||
| 158 | ||||
| 159 | **2. Ping Across the Tunnel** | |||
| 160 | - From VM A, ping the hub: `ping 10.10.0.1` | |||
| 161 | - From VM A, ping VM C: `ping 10.10.0.3` | |||
| 162 | - From VM C, ping VM A: `ping 10.10.0.2` | |||
| 163 | ||||
| 164 | **3. Test the Specific Route** | |||
| 165 | ||||
| 166 | On VM A or VM C, use `traceroute` to see the path your traffic takes: | |||
| 167 | ```bash | |||
| 168 | # Install if needed: sudo apt install traceroute | |||
| 169 | traceroute example.com | |||
| 170 | ``` | |||
| 171 | ||||
| 172 | The **first hop** should be the hub's tunnel IP (`10.10.0.1`). This confirms traffic is correctly going through the VPN. |
