Documentation

Server 4.x

⚠️ Version 4.x of eduVPN is currently under development. Switch to "Server 3.x" Documentation for the production release!

Deploy a Node#

If you want to run on >1 server, for example to allow for more connections, or to have nodes in multiple locations, you can deploy additional nodes.

Running a node requires to run wg-daemon, and optionally proxyguard-server. You probably want to configure TLS as well, for which we recommend certbot so the TLS certificate management can be handled automatically.

The software can be installed from the repository using apt or dnf. We assume below that you installed the software packages and enabled them.

On Debian / Ubuntu:

$ sudo apt install wg-daemon proxyguard-server certbot
$ sudo systemctl enable --now wg-daemon
$ sudo systemctl enable --now proxyguard-server

On Fedora / Enterprise Linux:

$ sudo dnf install wg-daemon proxyguard-server certbot
$ sudo systemctl enable --now wg-daemon
$ sudo systemctl enable --now proxyguard-server

NOTE: on Enterprise Linux you need to install the epel-release package first to have access to EPEL packages which includes certbot.

TLS#

It probably makes sense to first get a TLS key and certificate for your node, the easiest way is certonly using the “standalone” web server embedded in certbot:

$ sudo certbot certonly --standalone -d node.vpn.example.org

We’ll use the certificate later on to configure wg-daemon and proxyguard-server.

wg-daemon#

In order to allow connecting to the wg-daemon service from your portal, you need to change the configuration. This can be done using systemctl.

$ sudo systemctl edit wg-daemon

Add the following top the top of the file as instructed:

[Service]
Environment=LISTEN=:51194
LoadCredential=fullchain.pem:/etc/letsencrypt/live/node.vpn.example.org/fullchain.pem
LoadCredential=privkey.pem:/etc/letsencrypt/live/node.vpn.example.org/privkey.pem

You SHOULD restrict access to tcp/51194 to only allow connections from your portal. This can be done by modifying the firewall.

When wg-daemon starts it generates an API key and stores it in /var/lib/wg-daemon/auth.key. It is a 256 bit Base64 encoded random string. Use the exact value as the --key parameter in the add-node command below.

proxyguard-server#

$ sudo systemctl edit proxyguard-server

Add the following top the top of the file as instructed:

[Service]
Environment=LISTEN=:443
LoadCredential=fullchain.pem:/etc/letsencrypt/live/node.vpn.example.org/fullchain.pem
LoadCredential=privkey.pem:/etc/letsencrypt/live/node.vpn.example.org/privkey.pem

Portal#

NOTE: make sure you get the trailing / correct for the URLs!

$ sudo /usr/libexec/vpn-mini-portal/add-node \
    --name "My Node" \
    --url https://node.vpn.example.org:51194/ \
    --host node.vpn.example.org \
    --proxy-url https://node.vpn.example.org/ \
    --key 5BnH5QrzRGxpqrva5oILg12k+9pD9IRjhRRK7rvchFQ=

After running this command, the node should be visible on the “Nodes” pages in the portal admin. Viewing the node details should not show any errors.

TLS Renewal Hook#

If you use certbot, you can install the following hook that gets run after certificate renewal. It will restart the processes so they’ll use the updated certificates. This way, you SHOULD not need to ever do something regarding TLS.

$ cat << EOF | sudo tee /etc/letsencrypt/renewal-hooks/post/restart_services.sh
#!/bin/sh
systemctl restart wg-daemon
systemctl restart proxyguard-server
EOF
$ sudo chmod +x /etc/letsencrypt/renewal-hooks/post/restart_services.sh

To enable the timer to automatically renew certificates, only needed on Fedora / Enterprise Linux, run this:

$ sudo systemctl enable --now certbot-renew.timer

Firewall#

Below you’ll find a pretty minimal firewall for running on a node using nftables. On Debian / Ubuntu you put this file in /etc/nftables.conf. On Fedora and Enterprise Linux in /etc/sysconfig/nftables.conf. Make sure you first remove firewalld on Fedora and Enterprise Linux before installing nftables. Replace ens18 with the external “default gateway” interface of your VPN server.

#!/usr/sbin/nft -f

flush ruleset

define EXTERNAL_IF = ens18

table inet filter {
    chain input {
        type filter hook input priority filter; policy drop;
        ct state vmap { invalid : drop, established : accept, related : accept }
        iif "lo" accept
        # we do not use tcp/80, except for certbot DV, but it does not really
        # hurt to leave it open
        tcp dport { 22, 80, 443 } accept
        udp dport { 51820 } accept

        # IPs of your portal that need access to wg-daemon
        ip saddr 192.0.2.10/32 tcp dport 51194 accept
        ip6 saddr 2001:db8::10/128 tcp dport 51194 accept

        meta l4proto ipv6-icmp accept
        meta l4proto icmp accept
    }

    chain forward {
        type filter hook forward priority filter; policy drop;
        tcp flags syn tcp option maxseg size set rt mtu
        ct state vmap { invalid : drop, established : accept, related : accept }
        iifname { "vpn0" } oifname $EXTERNAL_IF accept
    }

    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;
        ip saddr { 10.0.0.0/8 } oifname $EXTERNAL_IF masquerade
        ip6 saddr fd00::/8 oifname $EXTERNAL_IF masquerade
    }
}

To permanently start/enable nftables:

$ sudo systemctl enable nftables
$ sudo systemctl restart nftables

Now enable IP forwarding for both IPv4 and IPv6. For IPv6 we need to keep allowing receiving router advertisements (RAs) if that’s how we receive the IPv6 address on the server from the router. Replace ens18 with the external “default gateway” interface of your VPN server.

$ cat << EOF | sudo tee /etc/sysctl.d/70-vpn.conf
net.ipv6.conf.ens18.accept_ra = 2
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
EOF
$ sudo sysctl --system