Home VPN with DNS server

you have some servers at home (e.g. a kubernetes cluster) but you want to work with them at Starbucks or out in the green? Here is how to setup a VPN server in your home network with a DNS server that would resolve anything you want.

The DNS Server

Even if you don't need the VPN, you can set up a DNS server, that would resolve any host you want. Of course you can just put the hosts in the /etc/hosts file on every device, but that could be tricky if you have a lot of devices/VMs and change/add hosts frequently, or if you need them on a tablet/smart phone.

The following shows how to install and configure the DNS server bind9 on a Ubuntu Server. It could be a standalone server or a VM or even a Raspberry Pi.

Install bind9

bind9 is the DNS server that I am going to use. Here is how to install it:

$ sudo apt update
$ sudo apt install bind9
$ sudo apt install dnsutils

Add Forwarders

Edit the file /etc/bind/named.conf.options and add:

forwarders {
    8.8.8.8;
};

You can use also your favourite DNS server, instead of Google. It will be used to resolve anything that your local DNS "does not know".

Test

You can now do a quick test to make sure it works.

$ sudo systemctl restart bind9
$ dig google.com

The expected output should looks like this:

; <<>> DiG 9.18.1-1ubuntu1.1-Ubuntu <<>> google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49030
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;google.com.			IN	A

;; ANSWER SECTION:
google.com.		193	IN	A	142.250.186.46

;; Query time: 15 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Fri Oct 14 19:20:42 UTC 2022
;; MSG SIZE  rcvd: 55

If you execute the dig command again, it should be much faster:

; <<>> DiG 9.18.1-1ubuntu1.1-Ubuntu <<>> google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59904
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;google.com.			IN	A

;; ANSWER SECTION:
google.com.		168	IN	A	142.250.186.46

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Fri Oct 14 19:21:07 UTC 2022
;; MSG SIZE  rcvd: 55

(0msec vs 15msec)

Configure named.conf

open /etc/bind/named.conf and make sure these lines are not commented out:

include “/etc/bind/named.conf.options”;
include “/etc/bind/named.conf.local”;
include “/etc/bind/named.conf.default-zones”;

Add a zone (and a reverse zone)

Now, we have to define our zones. Edit the file /etc/bind/named.conf.local and add:

zone "mydomain.com" {
  type master;
  file "/etc/bind/db.mydomain.com";
};
zone "192.168.0.in-addr.arpa" {
  type master;
  file "/etc/bind/db.192";
};

I am assuming here, that the home network has the standard subnet 192.168.0.0/24.

Configure the zone db file

Next, we must add the zones' DB files, defined above. Starting with the zone db file, you can copy the local db file and edit it:

$ sudo cp /etc/bind/db.local /etc/bind/db.mydomain.com

Example configuration:

$TTL    604800
@       IN      SOA     mydomain. root.mydomain.com. (
                              2         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
;
@       IN      NS      ns.mydomain.com.
@       IN      A       192.168.0.100 ; the IP of the Ubuntu Server, that's hosting the DNS server
@       IN      AAAA    ::1
ns      IN      A       192.168.0.100 ; ns.mydomain.com
test    IN      A       192.168.0.111 ; test.mydomain.com
test2   IN      A       192.168.0.122 ; test2.mydomain.com
real    IN      NS      8.8.8.8 ; real.mydomain.com


Above we configure the subdomains test.mydomain.com and test2.mydomain.com to local IPs and we let the real.mydomain.com be resolved by the Google's DNS server, so that the real IP of that domain is used. This is required, because when you define a zone in your DNS server, you take exclusive control over it. Anything that is not defined or forwarded would not be resolved, even if it is a real host, known by other DNS servers.

You can do much more in this configuration. If you need something specific, check the list of record types: https://en.wikipedia.org/wiki/List_of_DNS_record_types.

Configure the reverse db file

Similar to the zone db file, you can also copy the local reverse zone db file and edit it:

$ sudo cp /etc/bind/db.127 /etc/bind/db.192

Just set the NS to the local server:

$TTL    604800
@       IN      SOA     ns.mydomain.com. root.mydomain.com. (
                              1         ; Serial
                         604800         ; Refresh
                          86400         ; Retry
                        2419200         ; Expire
                         604800 )       ; Negative Cache TTL
;
@       IN      NS      ns.
1.0.0   IN      PTR     ns.mydomain.com.

Verify

You can execute the following commands to verify your configuration files. No errors should be reported.

$ named-checkzone mydomain.com /etc/bind/db.mydomain.com
$ named-checkzone 192.168.0.0/32 /etc/bind/db.192
$ named-checkconf  /etc/bind/named.conf.local 
$ named-checkconf  /etc/bind/named.conf

Final Test

At this point your DNS server is configured and ready to use. Let's do some tests.

Edit /etc/resolve.conf and set (temporary) the DNS server to your local DNS server:

nameserver 192.168.0.131

Then you can start "digging" the hosts defined above:

$ dig test.mydomain.com
...
$ dig test2.mydomain.com
...
$ dig real.mydomain.com
...


The VPN Server

There is a script that makes configuring OpenVPN very easy.

However, make sure the OS is up to date:

$ sudo apt update
$ sudo apt upgrade

Download the script and run it

$ wget https://git.io/vpn -O openvpn-install.sh
$ chmod +x openvpn-install.sh
$ sudo ./openvpn-install.sh

Here is an example how to configure it:

Welcome to this OpenVPN road warrior installer!

This server is behind NAT. What is the public IPv4 address or hostname?
Public IPv4 address / hostname [xxx.xxx.xxx.xxx]: vpn.myhost.com

Which protocol should OpenVPN use?
   1) UDP (recommended)
   2) TCP
Protocol [1]: 1

What port should OpenVPN listen to?
Port [1194]: 

Select a DNS server for the clients:
   1) Current system resolvers
   2) Google
   3) 1.1.1.1
   4) OpenDNS
   5) Quad9
   6) AdGuard
DNS server [1]: 2

Enter a name for the first client:
Name [client]: MyLaptop

OpenVPN installation is ready to begin.
Press any key to continue...

...

Using configuration from /etc/openvpn/server/easy-rsa/pki/52d1ba80/temp.e290b259
....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*......+............+..+.+..............+.+...+..+....+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+......+.....+...+.+............+..+...+............+.+.....+.+.....+.+..+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
...+.......+....................+...+.+......+...+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+.+.....+.+........+.......+.....+....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.......+..+....+.....+....+..+.......+...............+.....+................+..+.........+...............................+.....+.......+....................+..........+......+......+......+..+.+..+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
.+....+..+.......+...........+...................+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+..+............+...................+..+....+...+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+..+...+....+.....+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
..........+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..+...+.....+.......+.....+...+.+......+......+..+...+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..............+...+...+.........+.......................+....+......+............+..+.+.................+......+.+......+.........+......+........+....+...+..+...+.........+....+.........+........+....+.....+...+............+....+...........+..........+.........+.........+..+...+.+..+..................+.......+.....+..................+.+........+...+.......+..+.+.....+...+....+........+.........+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
Using configuration from /etc/openvpn/server/easy-rsa/pki/06983a57/temp.da1b8443
4057FD16457F0000:error:0700006C:configuration file routines:NCONF_get_string:no value:../crypto/conf/conf_lib.c:315:group=<NULL> name=unique_subject
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'server'
Certificate is to be certified until Nov  6 20:25:53 2032 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated
.........+......+.+.........+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+....+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+..........+..+...+......+.......+..+.......+......+........+.+.........+.....+......+.+............+...+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
...............+.........+.+..+............+.............+..+.+..+.+...........+....+..+..........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+..........+.....+.......+..+...+...+.+...+..+.........+....+...+...+.................+...+....+.................+.+..+.............+.........+...........+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+......+.........+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
Using configuration from /etc/openvpn/server/easy-rsa/pki/35d70dcf/temp.95880599
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'MyLaptop'
Certificate is to be certified until Nov  6 20:25:53 2032 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated
Using configuration from /etc/openvpn/server/easy-rsa/pki/dbda15cb/temp.c5eccaad
2022-11-09 20:25:53 WARNING: Using --genkey --secret filename is DEPRECATED.  Use --genkey secret filename instead.
Created symlink /etc/systemd/system/multi-user.target.wants/openvpn-iptables.service → /etc/systemd/system/openvpn-iptables.service.
Created symlink /etc/systemd/system/multi-user.target.wants/openvpn-server@server.service → /lib/systemd/system/openvpn-server@.service.

Finished!

The client configuration is available in: /root/MyLaptop.ovpn
New clients can be added by running this script again.

Notes:

  • "IPv4 address / hostname" should be the IP or hostname of your home network (here: vpn.myhostname.com). In case you don't have a static IP address you can use a DDNS like https://www.noip.com/ to get a hostname. Additionally, if you have a domain name of your own, you can configure it to resolve the subdomain, using the DDNS by CNAME.
  • You can use any DNS from the list. In the next step we will configure it to use the local one.
  • The client name should be something meaningful, e.g. "MyLaptop", "MyTablet", etc. In case you have many clients and you want to remove the access of one of them, it's easier to find out which one that is.
  • The file listed above, /root/MyLaptop.ovpn, must be copied to your device in order to connect.

Add the Local DNS Server

Edit the file /etc/openvpn/server/server.conf and add this line "before all other DNSes":

push "dhcp-option DNS 192.168.0.100"

where the IP is that of the local DNS server, configured above.

Run Again the Script to Create more Clients

$ sudo ./openvpn-install.sh

Example:

OpenVPN is already installed.

Select an option:
   1) Add a new client
   2) Revoke an existing client
   3) Remove OpenVPN
   4) Exit
Option: 1

Provide a name for the client:
Name: MyTablet
...........+.+.....+...+.+..+....+.....+..........+...+..+.+...+.....+.......+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+...+...........+.+.....+.+..+.......+......+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+...+......+.....+.+..............+......+.+.....+...+.+...........+.........+....+.................+.........+......+............+.+.....+.+...+...........+......+......+.......+...+.....+...+.......+..............+...+.+.........+..+.............+...+...+..+..........+.......................+............+.........+...............+....+..+....+...+..+...+..........+.....+.............+.........+......+..+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
....+.....+.+......+...+............+.........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*......+.+........+..........+.....+....+..+...+...+.........+...................+..+.......+..+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.....+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
Using configuration from /etc/openvpn/server/easy-rsa/pki/fc167864/temp.78d7fada
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'MyTablet'
Certificate is to be certified until Nov  6 20:35:20 2032 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated

MyTablet added. Configuration available in: /root/MyTablet.ovpn

As you might have noticed, you can also run the script to revoke clients.

Configure your Home Router

In order to be able to connect to the VPN server from the internet, you must configure your router to forward UDP requests on port 1194 to the Ubuntu Server, where you installed it.

Finally, restart the OpenVPN server:

$ sudo systemctl stop openvpn-server@server.service
$ sudo systemctl start openvpn-server@server.service

Connect to the VPN

You can either use the apps, provided by OpenVPN or use the built-in VPN functionality of the device's OS, in case OpenVPN is supported.

You can download the OpenVPN client apps for Windows, MacOS, Android and iOS from here: https://openvpn.net/vpn-client/ 

You just have to import the ovpn file, created above and connect.