Wireguard Setup on Azure

Installation on server

$ sudo apt-get install wireguard-dkms wireguard-tools
$ sudo nano /etc/sysctl.conf
  • uncomment the line

net.ipv4.ip_forward=1

Generation of keys for server and client

$ sudo -i
$ cd /etc/wireguard
$ wg genkey | tee server_private_key | wg pubkey > server_public.key

Configuration file for server

  • create /etc/wireguard/wg0.conf as following

  • for this example, the IP address of server used is 100.0.0.1

  • make sure the ip address is not having same subnet as the internet source of the server for example eth0.

  • DO NOT use IP 100.0.0.1 if you realize it is having same subnet as eth0 as shown below

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 100.0.0.4  netmask 255.255.255.0  broadcast 100.0.0.255
[Interface]
Address = 100.0.0.1/24
SaveConfig = true
PostUp = /etc/wireguard/iptable/rules.sh A
PostDown = /etc/wireguard/iptable/rules.sh D
ListenPort = 51820
PrivateKey = <server_private_key>

[Peer]
PublicKey = <client_public_key>
AllowedIPs = 100.0.0.2/32
  • the ListenPort depends on the your UDP port allowed at firewall.

  • example of firewall at Azure

  • create /etc/wireguard/iptable/rules.sh.

#!/bin/bash
IN_IFACE="eth0"                  # NIC connected to the internet
WG_IFACE="wg0"                   # WG NIC
SUB_NET="100.0.0.0/24"            # WG IPv4 sub/net aka CIDR
WG_PORT="51820"                  # WG udp port

# handle argument
ARG=$1
if [ "$ARG" = "A" ]
then
echo "Appending rules..."
elif [ "$ARG" = "D" ]
then
echo "Deleting rules..."
else
echo "Invalid operation!"
echo "Usage: ./rules.sh A or ./rules.sh D>"
exit 1
fi

# track VPN connection and allow related/established connections
/sbin/iptables -$ARG INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
/sbin/iptables -$ARG FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# allow incoming VPN traffic on the listening port
/sbin/iptables -$ARG INPUT -p udp -m udp --dport $WG_PORT -m conntrack --ctstate NEW -j ACCEPT

# allow both TCP and UDP recursive DNS traffic
/sbin/iptables -$ARG INPUT -s $SUB_NET -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
/sbin/iptables -$ARG INPUT -s $SUB_NET -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT

# allow forwarding of packets between interfaces
/sbin/iptables -$ARG FORWARD -i $WG_IFACE -o $WG_IFACE -m conntrack --ctstate NEW -j ACCEPT
/sbin/iptables -$ARG FORWARD -i $IN_IFACE -o $WG_IFACE -m conntrack --ctstate NEW -j ACCEPT
/sbin/iptables -$ARG FORWARD -i $WG_IFACE -o $IN_IFACE -m conntrack --ctstate NEW -j ACCEPT

######

# set up nat (if allowing clients to access Internet)
/sbin/iptables -t nat -$ARG POSTROUTING -s $SUB_NET -o $IN_IFACE -j MASQUERADE

######

# exit script
echo "Done"
exit 0

Configuration for DNS

  • Install unbound to provide DNS

$ apt-get install unbound unbound-host dnsutils
  • check number of threads by running

lscpu | egrep 'Model name|Socket|Thread|NUMA|CPU\(s\)'
  • You will need to fill in num-threads in the next configuration

$ 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
server:

  num-threads: 1

  #Enable logs
  verbosity: 1

  #list of Root DNS Server
  root-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 interfaces
  interface: 0.0.0.0
  max-udp-size: 3072

  #Authorized IPs to access the DNS Server
  access-control: 0.0.0.0/0                 refuse
  access-control: 127.0.0.1                 allow
  access-control: 100.0.0.0/24               allow

  #not allowed to be returned for public internet  names
  private-address: 100.0.0.0/24

  # Hide DNS Server info
  hide-identity: yes
  hide-version: yes

  #Limit DNS Fraud and use DNSSEC
  harden-glue: yes
  harden-dnssec-stripped: yes
  harden-referral-path: yes

  #Add an unwanted reply threshold to clean the cache and avoid when possible a DNS Poisoning
  unwanted-reply-threshold: 10000000

  #Have the validator print validation failures to the log.
  val-log-level: 1

  #Minimum lifetime of cache entries in seconds
  cache-min-ttl: 1800

  #Maximum lifetime of cached entries
  cache-max-ttl: 14400
  prefetch: yes
  prefetch-key: yes
  • Restart and enable unbound service

$ 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

% use netstat to check whether port 53 has been binded 
$ netstat -lutnp

% disable systemd-resolved
$ systemctl stop systemd-resolved.service
$ systemctl disable systemd-resolved.service

% fix hostname
% if you have seen error like "unable to resolve host <your_hostname>: Name or service not known"
$ nano /etc/hosts

% add your hostname
127.0.0.1 <your_hostname>

Wireguard service on server

$ wg-quick up wg0
$ systemctl enable wg-quick@wg0.service
  • You can test your DNS setup with the following commands and you should expect to see similar results returned

$ nslookup www.google.com 100.0.0.1

Server:		100.0.0.1
Address:	100.0.0.1#53

Non-authoritative answer:
Name:	www.google.com
Address: 74.125.24.103

Setting up clients

Server

$ wg genkey | tee client_private.key | wg pubkey > client_public.key
$ wg set wg0 peer <new_client_public_key> allowed-ips <new_client_vpn_IP>/32
$ wg addconf wg0 <(wg-quick strip wg0)
  • Set wg0 down then up again in order to take effect

Client

  • Install dependencies

$ sudo apt install wireguard resolvconf
  • Assuming the client vpn IP is 100.0.0.2

  • Create configuration file as below

$ sudo -i
$ nano /etc/wireguard/wg0.conf
[Interface]
Address = 100.0.0.2/32
PrivateKey = <client_private_key>
DNS = 100.0.0.1

[Peer]
PublicKey = <server_public_key>
Endpoint = <server_public_IP>:<ListenPort>
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
  • Bring up the connection

$ sudo wg-quick up wg0
$ sudo systemctl enable wg-quick@wg0.service

Last updated