An experiment in making a wireguard VPN setup super easy (almost 0-conf). The only supported topology right now is the server-and-clients (a.k.a. root-and-leafs, hub-and-spokes) topology. This is mainly useful if you just need a VPN for your personal machines and you have a cheap server available on the internet (the smallest virtual private server (VPS) should be fine.) Since all your machines are under your control it is easy to have a shared secret on all of them. This shared secret is a private key from which all other privae and public keys are derived via mixing in names.
We give up security for convenience:
- There is a central "master" private key from which all other keys are derived mixing in the nodes' names. This master key can (optionally) be derived from a password/phrase using
0vpn-tool key-from-password > keyfile
, which reads the password fromstdin
. - Clients can dynamically announce the wish to partake in the VPN by sending their node name and their (derived) public key. The server listens on an extra UDP port for these announcements.
- The server can rederive the client's key and check for the correctness of the transmitted public key.
- If those check out the client's public key is added to the peers list.
- The VPN uses IPv6 exclusively.
- The network prefix is derived from the private key by hashing with
sha256sum
. - IP addresses are derived from the node's names via hashing with
sha256sum
as well. So the names must be unique. If - For non linux clients that only have a "vanilla" wireguard "app" we provide ready to use .cfg files (these are written to the TMPDIR path reported during startup of
0vpn-root
and can be used with the equivalents of wg-quick.) - We run an instance of dnsmasq on the server which resolves clients in the "internal" TLD (the TLD can be configured as well).
- netcat-openbsd (it won't work with the traditional netcat)
- dnsmasq
- wireguard-tools
- bash
- core utilities like cat, kill, mktemp, etc..
- wireguard-tools
- bash
- core utilities like cat, kill, mktemp, etc..
- systemd-resolved
- wireguard in some form or other (wireguard-android, wireguard-windows)
Build the helper tool on all machines that want to take part in dynamic client setup (this includes AT LEAST the server):
go build
This should have produced a binary called 0vpn-tool
Generate a master private key:
wg genkey > private
Guard this key carefully. It is used to derive all other private keys.
Alternatively derive the master private key from a password:
./0vpn-tool key-from-password > private
Enter the password.
In the simplest case, just run:
0vpn-server --keyfile [file] --server-name [name] --server-hostname [hostname] --static-clients "client_a client_b"
where:
Note that this requires privileges to create and configure the wireguard device.
The script will have created config files for every static leaf. In the case of the example config that would be client_a.cfg
and client_b.cfg
. You can generate a QR code and display it in the terminal with
0vpn-show-qr client_a.cfg
On android you can just create a new tunnel directly from this QR code and things should work.
Note that this requires privileges to configure the wireguard device. Note that for this to work you need the openbsd netcat version, as it's much less broken than the default debian installed netcat (PR's welcome to make this a proper daemon.)
0vpn-client --keyfile [file] --server-name [name] --server-hostname [hostname] --client-name [name]
Note that the value of the --server-name
option has to be identical to the one passed to the server.
Common available options: --server-hostname [hostname] (default: "localhost") --server-name [name] (default: "ogfx100") --wireguard-port [port] (default: "4242") --announce-port [port] (default: "4243") --dns-port [port] (default: "53") --keyfile [filename] (default: "key") --tld [domain-name] (default: "internal") --wireguard-device [device-name] (default: "wg0") Server-only options: --static-clients [list of names] (default: "") Client-only options: --client-name [name] (default: "ogfx100") --announce-interval [seconds] (default: "30")
Note that some options like --server-name
and --client-name
are set to $(hostname --short)
per default (in this case ogfx100
).