Skip to main content
https://github.com/ianlini/wg-wizard/actions/workflows/main.yml/badge.svg https://github.com/ianlini/wg-wizard/actions/workflows/release.yml/badge.svg https://img.shields.io/pypi/v/wg-wizard.svg https://img.shields.io/pypi/l/wg-wizard.svg https://img.shields.io/github/stars/ianlini/wg-wizard.svg?style=social

wg-wizard can help you generate the configs for WireGuard interactively, and control all the server and client configs in a centralized way.

Why Do We Need wg-wizard

When I was trying to build my own VPN, although WireGuard is quite simple, it was still hard to make everything right at the first trial. The 2 most common issues are incorrect iptables and unmatched server/client configs. Therefore, I built this tool to make these steps less error-prone by centralizing all the configs as one simple wizard config and generating the configs required by WireGuard when needed. Besides, the tool also provides some simple interactive CLI tools to help you create the wizard config easily, and it can generate QR code for you to set up your smart phone easily.

Network Architecture

Our default network architecture is one relay server with multiple clients connecting to the VPN via the relay server.

We assume that most people need a network architecture like this. If you want another architecture, you can still achieve some of them using the advance configuration.

Prerequisite

  1. A server with Ubuntu, Debian or Raspberry Pi OS. You can still use other Linux distributions, but the following instructions might not be applicable.

  2. Install Docker on your relay server.

  3. Install Wireguard on your relay server.

Run the Docker Container

We use Docker to disable the network to make the whole process secure.

# go to the directory you want to put the configs
# assuming ~/wg-wizard here
export WG_WIZARD_CONFIG='~/wg-wizard'
cd "${WG_WIZARD_CONFIG}"
docker run -it --rm --network=none --volume="$PWD":/workdir ianlini/wg-wizard

Initialize the Configuration

# inside the Docker container
wg-wizard init

Follow the instruction to create the config. Example output:

Interface name for WireGuard [wg0]:
Interface.ListenPort of the relay server [51820]:
Interface.Address of the relay server [192.168.10.1/24]:
The default endpoint in clients' Peer.Endpoint configs (e.g., example.com:51820): example.com
If you want to allow the clients to access the internet via the relay server, you must provide the interface name you want to forward the internet traffic to. It's usually eth0 or wlan0. You can check it by executing `ip addr`. If you provide an interface name {interface}, the following rules will be added:
- iptables -A FORWARD -i %i -o {interface} -j ACCEPT
- iptables -A FORWARD -i {interface} -o %i -j ACCEPT
- iptables -t nat -A POSTROUTING -s {network} -o {interface} -j MASQUERADE
Interface name for connecting to the internet []: eth0
Do you want to allow the clients to connect with each other? If yes, a rule will be added: `iptables -A FORWARD -i %i -o %i -j ACCEPT` [Y/n]:
Do you want to allow the clients to connect to any IPs on the relay server? If no, only the IP of the WireGuard interface can be connected, that is, the following rules will be added:
- iptables -A INPUT -d {wg_server_interface_ip} -i %i -j ACCEPT
- iptables -A INPUT -i %i -j DROP
[y/N]:
[2022-10-12 18:41:34,190][INFO] wg_wizard.core: Writing config to /home/pi/pi-gateway/wireguard/wg0.yml
[2022-10-12 18:41:38,868][INFO] wg_wizard.core: Writing secret to /home/pi/pi-gateway/wireguard/wg0_secret.json

Normally, you can use the default values for almost all of the options.

If you allow the internet access or allow the clients to connect with each other, you also need to enable IP forwarding.

For convenience, in the following instructions, we assume that your WireGuard interface name is wg0:

export WG_INTERFACE=wg0

Add a Peer

# inside the Docker container
wg-wizard add-peer

Follow the instruction to create the peer config. Example output:

Interface name for WireGuard [wg0]:
Name of the client: phone1
Peer.PersistentKeepalive of the client [25]:
Interface.Address of the client [192.168.10.2/32]:
Peer.AllowedIPs of the client [0.0.0.0/0, ::/0]:
[2022-10-04 16:40:01,337][INFO] wg_wizard.core: Writing config to /workdir/wg0.yml
[2022-10-04 16:40:01,358][INFO] wg_wizard.core: Writing secret to /workdir/wg0_secret.json
[2022-10-04 16:40:01,362][INFO] wg_wizard.cli: Client's wg-quick config QR Code:
...

Normally, you can use the default values for almost all of the options. In the end, there will be a QR Code generated. You can now use your WireGuard app on your phone to scan the QR Code to import the config. If your client doesn’t support QR Code, you can use another command to generate the text:

wg-wizard export-client-config --interface "${WG_INTERFACE}" --name phone1 --no-qrcode

Set Up the WireGuard Server

Preparing:

# on your relay server (outside the Docker container)
cd "${WG_WIZARD_CONFIG}"
export WG_INTERFACE=wg0  # replace wg0 with your interface name
(umask 077; sudo mkdir /etc/wireguard/)

Exporting server config:

docker run --rm --network=none --volume="$PWD":/workdir ianlini/wg-wizard \
    wg-wizard export-server-config -i "${WG_INTERFACE}" \
    | sudo cp --backup /dev/stdin "/etc/wireguard/${WG_INTERFACE}.conf"

If you haven’t enabled the service:

# start the WireGuard server
sudo systemctl enable "wg-quick@${WG_INTERFACE}.service"
sudo systemctl start "wg-quick@${WG_INTERFACE}.service"

Now you can turn on the WireGuard tunnel on your client (phone1), and it should work.

If the service is already running, you can check the config diff first:

sudo diff "/etc/wireguard/${WG_INTERFACE}.conf~" "/etc/wireguard/${WG_INTERFACE}.conf"

After confirming the changes, there are 2 ways to apply them.

  1. If you are not changing the wg-quick specific interface configs (e.g., Address, DNS, MTU, Table, PreUp, PostUp, PreDown, PostDown and SaveConfig), you can reload the config without stopping the server:

    sudo systemctl reload "wg-quick@${WG_INTERFACE}.service"
  2. Otherwise, you should restart the server:

    sudo systemctl restart "wg-quick@${WG_INTERFACE}.service"

Troubleshooting

Read the service log:

journalctl -u "wg-quick@${WG_INTERFACE}.service" -f -n 1000

Enable the kernel log:

sudo modprobe wireguard
echo module wireguard +p | sudo tee /sys/kernel/debug/dynamic_debug/control

Read the kernel log:

journalctl -k -f -n 1000 | grep wireguard

Debug iptables:

# trace the ICMP packets from a WireGuard client
sudo iptables -t raw -A PREROUTING -i "${WG_INTERFACE}" -p icmp -j TRACE
# trace the incoming ICMP packets from the internet to a WireGuard client
sudo iptables -t mangle -A FORWARD -d 192.168.10.0/24 -p icmp -j TRACE

Build the Docker Image from Scratch

TODO

git clone ...
cd ...
docker build . -t ianlini/wg-wizard

References

Metadata

Release files for wg-wizard 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wg-wizard 0.3.0
File Size Uploaded
wg_wizard-0.3.0.tar.gz 16.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wg-wizard 0.3.0
File Interpreter ABI Platform
wg_wizard-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 30.4 kB

Release files / wg_wizard-0.3.0.tar.gz

Download URL wg_wizard-0.3.0.tar.gz
Size 16.0 kB
Tags Source
SHA-256 checksum
How to use checksums
912ecc180d74e82c021e4527c1f08885fb039da3995377f612b63cfe3adb5c04
BLAKE2b-256 checksum
How to use checksums
90b51991ee531fc26acd2d58bd69ed8cd7932c77aca682527a8588b9faef94e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.11.6 Linux/6.2.0-1016-azure

Release files / wg_wizard-0.3.0-py3-none-any.whl

Download URL wg_wizard-0.3.0-py3-none-any.whl
Size 14.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b0f6d7e72b93ff54f67e2b5d7b52d3ed2643b69f320d2d0805617c1f85c5e952
BLAKE2b-256 checksum
How to use checksums
084d37cf15ce15f9078a99acc38f4011ee9d47d6e38a94d264e3393464bb0736
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.3.2 CPython/3.11.6 Linux/6.2.0-1016-azure

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page