Skip to content

Instantly share code, notes, and snippets.

@mikoim
Last active November 27, 2023 09:22
Show Gist options
  • Save mikoim/e75846a0d07db04906e27c54f97e7e5d to your computer and use it in GitHub Desktop.
Save mikoim/e75846a0d07db04906e27c54f97e7e5d to your computer and use it in GitHub Desktop.
WireGuard example configuration for VPN

Server

iptables -A FORWARD -i wg0 -o YOUR_INTERFACE -s 10.200.200.0/24 -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -o YOUR_INTERFACE -s 10.200.200.0/24 -j MASQUERADE

systemd-networkd

see vpn.netdev and vpn.network.

Client

wg-quick

wg-quick up `pwd`/client.conf
wg-quick down `pwd`/client.conf

systemd-networkd

see vpn-client.netdev and vpn-client.network.

Issues

  • can't read wg-quick's resolve.conf due to insufficient permissions

Changelog

  • June 25, 2019: added client side configuration files for systemd-networkd
  • Aug 30, 2019: added WireGuard Mesh Network builder for systemd-networkd

Tips

wg0: Could not set route: Network is unreachable

To fix this issue, add GatewayOnlink=true to [Route] section in .network file. https://www.freedesktop.org/software/systemd/man/systemd.network.html#GatewayOnLink=

[Interface]
Address = 10.200.200.2/24
PrivateKey = CLIENT_PRIVATE_KEY
#DNS = 1.1.1.1
[Peer]
PublicKey = SERVER_PUBLIC_KEY
PresharedKey = PRESHARED_KEY
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = 123.123.123.123:51820
import subprocess
def generate_private_key() -> str:
proc = subprocess.run(["wg", "genkey"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return proc.stdout.decode("utf8").strip()
def generate_public_key(private_key: str) -> str:
s = subprocess.Popen(['wg', 'pubkey'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, errs = s.communicate(private_key.encode())
output = output.decode()
return output.strip()
def generate_preshared_key() -> str:
proc = subprocess.run(["wg", "genpsk"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return proc.stdout.decode("utf8").strip()
def main():
for x in range(3, 255):
private_key = generate_private_key()
public_key = generate_public_key(private_key)
preshared_key = generate_preshared_key()
with open(f'vpn-192.168.99.{x}.conf', mode='w') as c:
client = f"""
[Interface]
PrivateKey = {private_key}
Address = 192.168.99.{x}/24
DNS = 8.8.8.8
[Peer]
PublicKey = FOOOOOOOOOOO
PresharedKey = {preshared_key}
AllowedIPs = 0.0.0.0/0
Endpoint = BAARRRRRRRRRRRR
"""
c.write(client)
with open(f'server', mode='a') as s:
server = f"""
[WireGuardPeer]
PublicKey = {public_key}
PresharedKey = {preshared_key}
AllowedIPs = 192.168.99.{x}/32
"""
s.write(server)
if __name__ == '__main__':
main()
# use this file on client
[NetDev]
Name = wg0
Kind = wireguard
[WireGuard]
PrivateKey = CLIENT_PRIVATE_KEY
[WireGuardPeer]
PublicKey = SERVER_PUBLIC_KEY
PresharedKey = PRESHARED_KEY
AllowedIPs = 10.200.200.0/24
Endpoint = SERVER_IP:SERVER_PORT
# PersistentKeepalive = 30 # uncomment this if you're inside NAPT
# use this file on client
[Match]
Name = wg0
[Network]
Address = 10.200.200.2/32
[Route]
Gateway = 10.200.200.1
Destination = 10.200.200.0/24
GatewayOnlink=true
# use this file on server
[NetDev]
Name = wg0
Kind = wireguard
[WireGuard]
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY
[WireGuardPeer]
PublicKey = CLIENT_PUBLIC_KEY
PresharedKey = YOUR_PRESHARED_KEY
AllowedIPs = 10.200.200.2/32
# use this file on server
[Match]
Name = wg0
[Network]
Address = 10.200.200.1/32
[Route]
Gateway = 10.200.200.1
Destination = 10.200.200.0/24
#!/bin/env python3
"""
WireGuard Mesh Network builder for systemd-networkd
10.0.123.1
alpha --- bravo 10.0.123.2
|- charlie 10.0.123.3
10.1.123.1
bravo --- alpha 10.1.123.2
|- charlie 10.1.123.3
10.2.123.1
charlie --- alpha 10.2.123.2
|- bravo 10.2.123.3
How to use?
1. fill your host info. ``HOSTS``
2. run this script
3. copy generated .netdev, .network files to your hosts (e.g. /etc/systemd/network/)
4. enjoy mesh network
"""
import subprocess
import os
HOSTS = [
{
'hostname': 'alpha',
'external_ip': '198.51.100.1',
'external_port': '11111',
'private_key': None, # DON'T FILL
'public_key': None, # DON'T FILL
'preshared_key': None # DON'T FILL
},
{
'hostname': 'bravo',
'external_ip': '198.51.100.2',
'external_port': '22222',
'private_key': None, # DON'T FILL
'public_key': None, # DON'T FILL
'preshared_key': None # DON'T FILL
},
{
'hostname': 'charlie',
'external_ip': '198.51.100.3',
'external_port': '33333',
'private_key': None, # DON'T FILL
'public_key': None, # DON'T FILL
'preshared_key': None # DON'T FILL
}
]
def generate_private_key() -> str:
proc = subprocess.run(["wg", "genkey"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return proc.stdout.decode("utf8").strip()
def generate_public_key(private_key: str) -> str:
s = subprocess.Popen(['wg', 'pubkey'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, errs = s.communicate(private_key.encode())
output = output.decode()
return output.strip()
def generate_preshared_key() -> str:
proc = subprocess.run(["wg", "genpsk"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return proc.stdout.decode("utf8").strip()
def generate_config(index, router_hostname, peers):
root_peer = [x for x in peers if x['hostname'] == router_hostname][0]
non_router_peers = [x for x in peers if x['hostname'] != router_hostname]
router_netdev = f"""[NetDev]
Name = wg{index}
Description = WireGuard mesh .netdev "{router_hostname}" [router]
Kind = wireguard
[WireGuard]
ListenPort = {root_peer['external_port']}
PrivateKey = {root_peer['private_key']}
# PublicKey = {root_peer['public_key']}
"""
for peer_index, peer in enumerate(non_router_peers):
router_netdev += f"""
# {peer['hostname']}
[WireGuardPeer]
PublicKey = {peer['public_key']}
PresharedKey = {peer['preshared_key']}
AllowedIPs = 10.{index}.123.{peer_index + 2}/32
"""
router_network = f"""[Match]
Name = wg{index}
[Network]
Description = WireGuard mesh .network "{router_hostname}" [router]
Address = 10.{index}.123.1/32
[Route]
Gateway = 10.{index}.123.1
Destination = 10.{index}.123.0/24
"""
os.makedirs(f'mesh/{router_hostname}', exist_ok=True)
with open(f'mesh/{router_hostname}/wg{index}.netdev', mode='w+') as netdev:
netdev.write(router_netdev)
with open(f'mesh/{router_hostname}/wg{index}.network', mode='w+') as network:
network.write(router_network)
for peer_index, peer in enumerate(non_router_peers):
peer_netdev = f"""[NetDev]
Name = wg{index}
Description = WireGuard mesh .netdev "{peer['hostname']}" to "{router_hostname}" [non-router]
Kind = wireguard
[WireGuard]
PrivateKey = {peer['private_key']}
# PublicKey = {peer['public_key']}
[WireGuardPeer]
PublicKey = {root_peer['public_key']}
PresharedKey = {peer['preshared_key']}
AllowedIPs = 10.{index}.123.0/24
Endpoint = {root_peer['external_ip']}:{root_peer['external_port']}
PersistentKeepalive = 60
"""
peer_network = f"""[Match]
Name = wg{index}
[Network]
Description = WireGuard mesh .network "{peer['hostname']}" to "{router_hostname}" [non-router]
Address = 10.{index}.123.{peer_index + 2}/32
[Route]
Gateway = 10.{index}.123.1
Destination = 10.{index}.123.0/24
GatewayOnlink=true
"""
with open(f"mesh/{peer['hostname']}/wg{index}.netdev", mode='w+') as netdev:
netdev.write(peer_netdev)
with open(f"mesh/{peer['hostname']}/wg{index}.network", mode='w+') as network:
network.write(peer_network)
def update_peer_keys(peers):
for peer in peers:
private_key = generate_private_key()
public_key = generate_public_key(private_key)
preshared_key = generate_preshared_key()
peer['private_key'] = private_key
peer['public_key'] = public_key
peer['preshared_key'] = preshared_key
if __name__ == '__main__':
for mesh_index, router_peer in enumerate(HOSTS):
update_peer_keys(HOSTS)
generate_config(mesh_index, router_peer['hostname'], HOSTS)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment