Wireguard
Setup Wireguard on AWS
Tested Environment
- Debian 10.5 on AWS
- Ubuntu 20.04 on AWS
Install wireguard on server
$ sudo apt-get install wireguard-dkms wireguard-tools linux-headers-$(uname -r)
Note that the package "linux-headers-$(uname -r)" is necessary to run wireguard.
Next we need to enable IP Forwarding. Open "/etc/sysctl.conf" and search for the line "#net.ipv4.ip_forward". Uncomment this line by removing the # at the beginning. It should look like this:
net.ipv4.ip_forward=1
Generate server and client keys
You will need root privilege to manipuate the "/etc/wireguard" directory
$ sudo -i$ cd /etc/wireguard$ umask 077$ wg genkey | tee server_private_key | wg pubkey \> server_public_key
You will need to create a key pair for each client (more deails below, not needed for now)
$ wg genkey | tee <client_private_key_name\> | wg pubkey \> <client_public_key_name\>
Generate server and client keys
You will need root privilege to manipuate the "/etc/wireguard" directory
$ sudo -i$ cd /etc/wireguard$ umask 077$ wg genkey | tee server_private_key | wg pubkey \> server_public_key
You will need to create a key pair for each client (more deails below, not needed for now)
$ wg genkey | tee <client_private_key_name\> | wg pubkey \> <client_public_key_name\>
Create server configuration file
Create a file "/etc/wireguard/wg0.conf" with the following content
[Interface]Address = 10.200.200.1/24SaveConfig = truePostUp = /etc/wireguard/iptable-set.shPostDown = /etc/wireguard/iptable-reset.shListenPort = 51820PrivateKey = <insert server_private_key\>[Peer]PublicKey = <insert client_public_key\>AllowedIPs = 10.200.200.2/32
Note in the above example,
- "10.200.200.0" range is used for the VPN network. You can change it to other preferred ranges
- The ListenPort has to be accesible and you will need to add a rule in your Firewall to allow "UDP:<ListenPort>"
- Two scripts are used to set up or recover the routing table when you bring up or down the VPN network
The setup script:
#!/bin/bash# Reference:# [1] https://www.ckn.io/blog/2017/11/14/wireguard-vpn-typical-setup/# [2] https://www.cyberciti.biz/faq/how-to-set-up-wireguard-firewall-rules-in-linux/IN_FACE="eth0" # NIC connected to the internetWG_FACE="wg0" # WG NICSUB_NET="10.200.200.0/24" # WG IPv4 sub/net aka CIDRWG_PORT="51820" # WG udp port# track VPN connection/sbin/iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT/sbin/iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT# allow incoming VPN traffic on the listening port/sbin/iptables -A INPUT -p udp -m udp --dport $WG_PORT -m conntrack --ctstate NEW -j ACCEPT# allow both TCP and UDP recursive DNS traffic/sbin/iptables -A INPUT -s $SUB_NET -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -A INPUT -s $SUB_NET -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT# allow forwarding of packets between interfaces/sbin/iptables -A FORWARD -i $WG_FACE -o $WG_FACE -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -A FORWARD -i $IN_FACE -o $WG_FACE -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -A FORWARD -i $WG_FACE -o $IN_FACE -m conntrack --ctstate NEW -j ACCEPT# set up nat/sbin/iptables -t nat -A POSTROUTING -s $SUB_NET -o $IN_FACE -j MASQUERADE
The recovery script:
#!/bin/bashIN_FACE="eth0" # NIC connected to the internetWG_FACE="wg0" # WG NICSUB_NET="10.200.200.0/24" # WG IPv4 sub/net aka CIDRWG_PORT="51820" # WG udp port# allow incoming VPN traffic on the listening port/sbin/iptables -D INPUT -p udp -m udp --dport $WG_PORT -m conntrack --ctstate NEW -j ACCEPT# allow both TCP and UDP recursive DNS traffic/sbin/iptables -D INPUT -s $SUB_NET -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -D INPUT -s $SUB_NET -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT# allow forwarding of packets between interfaces/sbin/iptables -D FORWARD -i $WG_FACE -o $WG_FACE -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -D FORWARD -i $IN_FACE -o $WG_FACE -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -D FORWARD -i $WG_FACE -o $IN_FACE -m conntrack --ctstate NEW -j ACCEPT# set up nat/sbin/iptables -t nat -D POSTROUTING -s $SUB_NET -o $IN_FACE -j MASQUERADE
Configure DNS
Here "ubound" is used to provide DNS
$ apt-get install unbound unbound-host dnsutils
Download the list of root DNS servers
$ curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache$ chown -R unbound:unbound /var/lib/unbound$ cd /etc/unbound/unbound.conf.d$ nano unbound_srv.conf
Add the following content
server:num-threads: 4#Enable logsverbosity: 1#list of Root DNS Serverroot-hints: "/var/lib/unbound/root.hints"#Use the root servers key for DNSSEC#auto-trust-anchor-file: "/var/lib/unbound/root.key"#Respond to DNS requests on all interfacesinterface: 0.0.0.0max-udp-size: 3072#Authorized IPs to access the DNS Serveraccess-control: 0.0.0.0/0 refuseaccess-control: 127.0.0.1 allowaccess-control: 10.200.200.0/24 allow#not allowed to be returned for public internet namesprivate-address: 10.200.200.0/24# Hide DNS Server infohide-identity: yeshide-version: yes#Limit DNS Fraud and use DNSSECharden-glue: yesharden-dnssec-stripped: yesharden-referral-path: yes#Add an unwanted reply threshold to clean the cache and avoid when possible a DNS Poisoningunwanted-reply-threshold: 10000000#Have the validator print validation failures to the log.val-log-level: 1#Minimum lifetime of cache entries in secondscache-min-ttl: 1800#Maximum lifetime of cached entriescache-max-ttl: 14400prefetch: yesprefetch-key: yes
Now restart unbound service and enable it to autostart
$ systemctl restart unbound$ systemctl enable unbound
Create server configuration file
Create a file "/etc/wireguard/wg0.conf" with the following content
[Interface]Address = 10.200.200.1/24SaveConfig = truePostUp = /etc/wireguard/iptable-set.shPostDown = /etc/wireguard/iptable-reset.shListenPort = 51820PrivateKey = <insert server_private_key\>[Peer]PublicKey = <insert client_public_key\>AllowedIPs = 10.200.200.2/32
Note in the above example,
"10.200.200.0" range is used for the VPN network. You can change it to other preferred ranges
The ListenPort has to be accesible and you will need to add a rule in your Firewall to allow "UDP:<ListenPort>"
Two scripts are used to set up or recover the routing table when you bring up or down the VPN network
The setup script:
#!/bin/bash# Reference:# [1] https://www.ckn.io/blog/2017/11/14/wireguard-vpn-typical-setup/# [2] https://www.cyberciti.biz/faq/how-to-set-up-wireguard-firewall-rules-in-linux/IN_FACE="eth0" # NIC connected to the internetWG_FACE="wg0" # WG NICSUB_NET="10.200.200.0/24" # WG IPv4 sub/net aka CIDRWG_PORT="51820" # WG udp port# track VPN connection/sbin/iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT/sbin/iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT# allow incoming VPN traffic on the listening port/sbin/iptables -A INPUT -p udp -m udp --dport $WG_PORT -m conntrack --ctstate NEW -j ACCEPT# allow both TCP and UDP recursive DNS traffic/sbin/iptables -A INPUT -s $SUB_NET -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -A INPUT -s $SUB_NET -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT# allow forwarding of packets between interfaces/sbin/iptables -A FORWARD -i $WG_FACE -o $WG_FACE -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -A FORWARD -i $IN_FACE -o $WG_FACE -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -A FORWARD -i $WG_FACE -o $IN_FACE -m conntrack --ctstate NEW -j ACCEPT# set up nat/sbin/iptables -t nat -A POSTROUTING -s $SUB_NET -o $IN_FACE -j MASQUERADE
The recovery script:
#!/bin/bashIN_FACE="eth0" # NIC connected to the internetWG_FACE="wg0" # WG NICSUB_NET="10.200.200.0/24" # WG IPv4 sub/net aka CIDRWG_PORT="51820" # WG udp port# allow incoming VPN traffic on the listening port/sbin/iptables -D INPUT -p udp -m udp --dport $WG_PORT -m conntrack --ctstate NEW -j ACCEPT# allow both TCP and UDP recursive DNS traffic/sbin/iptables -D INPUT -s $SUB_NET -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -D INPUT -s $SUB_NET -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT# allow forwarding of packets between interfaces/sbin/iptables -D FORWARD -i $WG_FACE -o $WG_FACE -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -D FORWARD -i $IN_FACE -o $WG_FACE -m conntrack --ctstate NEW -j ACCEPT/sbin/iptables -D FORWARD -i $WG_FACE -o $IN_FACE -m conntrack --ctstate NEW -j ACCEPT# set up nat/sbin/iptables -t nat -D POSTROUTING -s $SUB_NET -o $IN_FACE -j MASQUERADE
Configure DNS
Here "ubound" is used to provide DNS
$ apt-get install unbound unbound-host dnsutils
Download the list of root DNS servers
$ curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache$ chown -R unbound:unbound /var/lib/unbound$ cd /etc/unbound/unbound.conf.d$ nano unbound_srv.conf
Add the following content
server:num-threads: 4#Enable logsverbosity: 1#list of Root DNS Serverroot-hints: "/var/lib/unbound/root.hints"#Use the root servers key for DNSSEC#auto-trust-anchor-file: "/var/lib/unbound/root.key"#Respond to DNS requests on all interfacesinterface: 0.0.0.0max-udp-size: 3072#Authorized IPs to access the DNS Serveraccess-control: 0.0.0.0/0 refuseaccess-control: 127.0.0.1 allowaccess-control: 10.200.200.0/24 allow#not allowed to be returned for public internet namesprivate-address: 10.200.200.0/24# Hide DNS Server infohide-identity: yeshide-version: yes#Limit DNS Fraud and use DNSSECharden-glue: yesharden-dnssec-stripped: yesharden-referral-path: yes#Add an unwanted reply threshold to clean the cache and avoid when possible a DNS Poisoningunwanted-reply-threshold: 10000000#Have the validator print validation failures to the log.val-log-level: 1#Minimum lifetime of cache entries in secondscache-min-ttl: 1800#Maximum lifetime of cached entriescache-max-ttl: 14400prefetch: yesprefetch-key: yes
Now restart unbound service and enable it to autostart
$ systemctl restart unbound$ systemctl enable unbound
You may need to disable the default DNS resolver if unbound fails to start with an error message saying port 53 has been binded to another process [8][9][10]
% use netstat to check whether port 53 has been binded$ netstat -lutnp% disable systemd-resolved$ sudo systemctl stop systemd-resolved$ sudo systemctl disable systemd-resolved
You can test your DNS setup with the following commands and you should expect to see similar results returned
$ nslookup www.google.com. 10.200.200.1Server: 10.8.6.1Address: 10.8.6.1#53Non-authoritative answer:Name: www.google.comAddress: 74.125.200.99Name: www.google.comAddress: 74.125.200.106Name: www.google.comAddress: 74.125.200.103Name: www.google.comAddress: 74.125.200.105Name: www.google.comAddress: 74.125.200.104Name: www.google.comAddress: 74.125.200.147Name: www.google.comAddress: 2404:6800:4003:c00::68Name: www.google.comAddress: 2404:6800:4003:c00::67Name: www.google.comAddress: 2404:6800:4003:c00::63Name: www.google.comAddress: 2404:6800:4003:c00::93$ unbound-host -C /etc/unbound/unbound.conf -v ietf.org[1599212188] libunbound[2097:0] notice: init module 0: validator[1599212188] libunbound[2097:0] notice: init module 1: iteratorietf.org has address 4.31.198.44 (secure)ietf.org has IPv6 address 2001:1900:3001:11::2c (secure)ietf.org mail is handled by 0 mail.ietf.org. (secure)
Additionally you can use http://dnsleak.com/ to test DNS leakage.
Start wireguard service on server
Now you're ready to start the wireguard service on your server
$ sudo wg-quick up wg0$ sudo systemctl enable wg-quick@wg0.service
Use the following command to bring down the service
$ sudo wg-quick down wg0
Setup clients
Server side
As mentioned above, you will have create a key pair for each client, for example:
$ wg genkey | tee rdu_acer_private.key | wg pubkey \> rdu_acer_public.key
Register the client on the server
$ wg set wg0 peer <new_client_public_key\> allowed-ips <new_client_vpn_IP\>/32
In the following client setup part, we will assume you've assigned 10.200.200.2/32 to the client rdu-acer.
You need to restart the "wg0" interface to make this change into effect.
Client side
You can either set up the VPN profile on your device manually or from a QR code
Manual setup on Linux
$ sudo apt-get install wireguard-dkms wireguard-tools linux-headers-$(uname -r)
Create the configuration file
$ sudo -i$ nano /etc/wireguard/wg0-acer.conf
[Interface]Address = 10.200.200.2/32PrivateKey = <insert client_private_key\>DNS = 10.200.200.1[Peer]PublicKey = <insert server_public_key\>Endpoint = <VPN-Server-Public-IP\>:<ListenPort\>AllowedIPs = 0.0.0.0/0PersistentKeepalive = 25
Now you can bring up the connection
$ sudo wg-quick up wg0-acer$ sudo systemctl enable wg-quick@wg0-acer.service
QR code setup on Android
Instead of manually typing in the VPN information on the phone, you can generate a QR code on the server and setup your phone with this QR code.
$ cd /etc/wireguard/$ nano rdu_acer_qr.conf
[Interface]Address = 10.200.200.2/32PrivateKey = client_private_keyDNS = 10.200.200.1[Peer]PublicKey = server_public_keyAllowedIPs = 0.0.0.0/0Endpoint = <VPN-Server-Public-IP\>:<ListenPort\>PersistentKeepalive = 25
Then generate the QR code:
$ apt install qrencode$ qrencode -t ansiutf8 < rdu_acer_qr.conf
Now you can scan the QR code on your phone to setup the VPN connection.
Reference:
- [1] https://golb.hplar.ch/2018/10/wireguard-on-amazon-lightsail.html
- [2] https://www.ckn.io/blog/2017/11/14/wireguard-vpn-typical-setup/
- [3] https://www.cyberciti.biz/faq/how-to-set-up-wireguard-firewall-rules-in-linux/
- [4] https://stackoverflow.com/questions/37570910/rtnetlink-answers-operation-not-supported
- [5] https://emanuelduss.ch/2018/09/wireguard-vpn-road-warrior-setup/
- [6] https://engineerworkshop.com/blog/how-to-set-up-a-wireguard-vpn-server-on-ubuntu-linux/
- [7] https://www.zahradnik.io/wireguard-a-vpn-with-real-world-usage-in-mind
- [8] https://askubuntu.com/questions/907246/how-to-disable-systemd-resolved-in-ubuntu
- [9] https://blobfolio.com/2017/05/fix-linux-dns-issues-caused-by-systemd-resolved/
- [10] https://askubuntu.com/questions/59458/error-message-sudo-unable-to-resolve-host-none
- [11] https://www.linuxbabe.com/ubuntu/set-up-local-dns-resolver-ubuntu-20-04-bind9
- [12] https://nlnetlabs.nl/documentation/unbound/howto-anchor/