Distributions
This guide is tested for Debian 9 Stretch Linux, but it may work with other recent Debian versions.
Requirements
- This guide assumes that you’re running Debian on a VPS or a remote server, since that’s the most likely scenario for a VPN.
- A working install of Debian Stretch with root access
Difficulty
MEDIUM
Conventions
- # – requires given linux commands to be executed with root privileges either directly as a root user or by use of
sudo
command - $ – requires given linux commands to be executed as a regular non-privileged user
Configuring Iptables
Setting up your own VPN is no small task, but there are plenty of reasons that you’d want to do it. For one, when you run your own VPN, you have complete control of it and know exactly what it’s doing.
Security is an important factor for VPNs. It’s possible to set up a simple one in a few minutes, but it won’t be secure at all. You need to take the appropriate steps to ensure that both the server and your connections remain private and encrypted.
Before embarking down this road, you may want to consider encrypting your disks, beefing up kernel security with SELinux or PAX, and making sure everything else is locked down.
Iptables is a big part of server security. You need iptables to ensure that information doesn’t leak out of your VPN. Iptables also works to prevent unauthorized connections. So, the first step in setting up a VPN on Debian is setting up iptables.
Find Your WAN Interface
Before you can start writing your iptables rules, you need to know which interface you’re writing them for.
Use ifconfig
or ip a
to search for the interface that your server is connected to the Internet with.
The rest of this guide will refer to that interface as eth0
, but that probably won’t be yours. Make sure to swap in the name of your server’s network interface instead.
Creating The Iptables Rules
Every Linux user and admin loves writing iptables rules, right? It’s not going to be that bad. You’ll compose a file with all of the commands and just restore it into iptables.
Create your file. You can make it somewhere that you want to save or just dump it in /tmp
. Iptables will save your rules anyway, so /tmp
is fine.
$ vim /tmp/v4rules
Start the file off by adding *filter
to let iptables know that these are filter rules.
Yes, there will be an IPv6 one too, but it’ll be much shorter.
Loopback Rules
Start off with the simplest set of rules, the loopback interface ones. These just tell iptables to only accept looback traffic originating from localhost.
-A INPUT -i lo -j ACCEPT -A INPUT ! -i lo -s 127.0.0.0/8 -j REJECT -A OUTPUT -o lo -j ACCEPT
Allowing Ping
Next, you probably want to be able to ping your server. This group of rules allows ping through.
-A INPUT -p icmp -m state --state NEW --icmp-type 8 -j ACCEPT -A INPUT -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT -A OUTPUT -p icmp -j ACCEPT
SSH Setup
You should probably change SSH off of port 22, so let your rules reflect that.
-A INPUT -i eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 22 -j ACCEPT -A OUTPUT -o eth0 -p tcp -m state --state ESTABLISHED --sport 22 -j ACCEPT
Allow OpenVPN Through
Obviously, you’re going to want to allow OpenVPN traffic through. This guide is going to use UDP for OpenVPN. If you choose to go with TCP, let the rules reflect that.
-A INPUT -i eth0 -p udp -m state --state NEW,ESTABLISHED --dport 1194 -j ACCEPT -A OUTPUT -o eth0 -p udp -m state --state ESTABLISHED --sport 1194 -j ACCEPT
DNS
You’re also going to want to allow DNS traffic through your VPN server. This will be through both UDP and TCP.
-A INPUT -i eth0 -p udp -m state --state ESTABLISHED --sport 53 -j ACCEPT -A OUTPUT -o eth0 -p udp -m state --state NEW,ESTABLISHED --dport 53 -j ACCEPT -A INPUT -i eth0 -p tcp -m state --state ESTABLISHED --sport 53 -j ACCEPT -A OUTPUT -o eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 53 -j ACCEPT
HTTP/S For Updates
It might seem odd to allow HTTP/S traffic, but you do want Debian to be able to update itself, right? These rules allow Debian to initiate HTTP requests, but not receive them from the outside.
-A INPUT -i eth0 -p tcp -m state --state ESTABLISHED --sport 80 -j ACCEPT -A INPUT -i eth0 -p tcp -m state --state ESTABLISHED --sport 443 -j ACCEPT -A OUTPUT -o eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 80 -j ACCEPT -A OUTPUT -o eth0 -p tcp -m state --state NEW,ESTABLISHED --dport 443 -j ACCEPT
NTP To Sync Your Clock
Assuming that you’re not going to manually synchronize your server clock and the client clocks, you’re going to need NTP. Allow it too.
-A INPUT -i eth0 -p udp -m state --state ESTABLISHED --sport 123 -j ACCEPT -A OUTPUT -o eth0 -p udp -m state --state NEW,ESTABLISHED --dport 123 -j ACCEPT
TUN To Tunnel Through The VPN
This guide uses TUN to tunnel through the VPN, if you’re using TAP, adjust accordingly.
-A INPUT -i tun0 -j ACCEPT -A FORWARD -i tun0 -j ACCEPT -A OUTPUT -o tun0 -j ACCEPT
For the VPN to forward your traffic to the Internet, you need to enable forwarding from TUN to your physical network interface.
-A FORWARD -i tun0 -o eth0 -s 10.8.0.0/24 -j ACCEPT -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
Log Blocked Traffic
You should probably have iptables log the traffic that it blocks. This way, you are aware of any potential threats.
-A INPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 4 -A FORWARD -m limit --limit 3/min -j LOG --log-prefix "iptables_FORWARD_denied: " --log-level 4 -A OUTPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_OUTPUT_denied: " --log-level 4
Reject All Other Traffic
Now that you’re logging everything that doesn’t fit into the existing rules, reject it.
-A INPUT -j REJECT -A FORWARD -j REJECT -A OUTPUT -j REJECT
Don’t forget to close out your file with COMMIT
.
NAT
This next part requires a different table. You can’t add it to the same file, so you’ll just have to run the command manually.
Make traffic from the VPN masquerade as traffic from the physical network interface.
# iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
Block All IPv6 Traffic
Traffic can leak out over IPv6, and there really isn’t any need to use IPv6 right now. The easiest thing to do is to shut it down entirely.
Create another file and throw in the rules to reject all IPv6 traffic.
$vim /tmp/v6rules
*filter -A INPUT -j REJECT -A FORWARD -j REJECT -A OUTPUT -j REJECT COMMIT
Commit Everything
Start off by flushing out all existing iptables rules.
# iptables -F && iptables -X
Import each of the rules files that you created.
# iptables-restore < /tmp/v4rules # ip6tables-restore < /tmp/v6rules
Making It Stick
Debian has a package that will handle automatically loading your iptable rules, so you don't have to create a cron job or anything like that.
# apt install iptables-persistent
The installation process will ask you if you want to save your configurations. Answer, "Yes."
In the future, you can update your rules by running the following linux command.
# service netfilter-persistent save
Additional Configuration
There are a couple more things that you need to do in order to get all of your network interfaces working as needed.
First, open up /etc/hosts
and comment out all of the IPv6 lines.
Next, open /etc/sysctl.d/99-sysctl.conf
. Find and uncomment the following line.
net.ipv4.ip_forward=1
Add these next lines to disable IPv6 completely.
net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1 net.ipv6.conf.eth0.disable_ipv6 = 1
Finally, apply your changes.
# sysctl -p
What's Next
That's the first part down. Your server's firewall is now ready to run OpenVPN, and your networking is all aligned properly too.
The next step is to create a certificate authority to handle all of your encryption keys. It's not lengthy a process as this was, but it's just as important.
Certification Authority
Use Easy-RSA to establish the certificate authority that you'll use to create and the encryption keys for your OpenVPN server.
This is the second part in configuring an OpenVPN server on Debian Stretch.
VPNs rely on encryption. It's absolutely vital that they encrypt their connections with clients as well as the connection process itself.
In order to generate the keys necessary for encrypted communication, you need to establish a certificate authority. It's really not that difficult, and there are tools that simplify the process further.
Installing the Packages
Before you get started, install OpenVPN and Easy-RSA.
# apt install openvpn easy-rsa
Set Up The Directory
The OpenVPN package created a directory for itself at /etc/openvpn
. That's where you can set up the certificate authority.
Easy-RSA includes a script that automatically creates a directory with everything that you need. Use it to create your certificate authority directory.
# make-cadir /etc/openvpn/certs
Enter that directory and create a soft link between the latest OpenSSL config with openssl.cnf
.
# ln -s openssl-1.0.0.cnf openssl.cnf
Set The Variables
Inside the folder is a file called, vars
. That file contains the variables that Easy-RSA will use to generate your keys. Open it up. There are a few values that you need to change.
Start by finding the KEY_SIZE
variable and change it's value to 4096
.
export KEY_SIZE=4096
Next, find a block of information concerning the location and identity of your certificate authority.
export KEY_COUNTRY="US" export KEY_PROVINCE="CA" export KEY_CITY="SanFrancisco" export KEY_ORG="Fort-Funston" export KEY_EMAIL="me@myhost.mydomain" export KEY_OU="MyOrganizationalUnit"
Change the values to correspond to you.
The last variable that you need to find is the KEY_NAME
export KEY_NAME="VPNServer"
Name it something identifiable.
Create The Authority Keys
Easy-RSA includes scripts to generate the certificate authority.
Load the variables first.
# source ./vars
A warning message will pop up in the terminal telling you that clean-all
will erase your keys. You don't have any yet, so it's alright.
# ./clean-all
You can now run the script to actually generate your certificate authority. The script will ask you questions about the keys that you're generating. The default answers will be the variables that you already entered. You can safely smash "Enter." Just remember to enter a password if you want to and answer "Yes" to the last two questions.
# ./build-ca
Create A Server Key
Those keys that you made were for the certificate authority itself. You need a key for the server too. Yet again, there's a script for that.
# ./build-key-server server
Generate a Diffie-Hellman PEM
You need to generate a Diffie-Hellman PEM which OpenVPN will use to create secure client sessions keys. Easy-RSA provides a script for this too, but it's just easier to use plain OpenSSL.
Since the goal here is security, it's best to generate a 4096bit key. It's going to take some time to generate, and it might slow down the connection process a bit, but the encryption will be reasonably strong.
# openssl dhparam 4096 > /etc/openvpn/dh4096.pem
Generate An HMAC Key
Yeah, you need another encryption key. OpenVPN uses HMAC keys to sign the packets it uses in the TLS authentication process. By signing those packets, OpenVPN can guarantee that only packets originating from a machine with the key are accepted. It just adds another layer of security.
The utility for generating your HMAC key is actually built into OpenVPN itself. Run it.
# openvpn --genkey --secret /etc/openvpn/certs/keys/ta.key
What's Next
Creating strong encryption is easily one of the most important aspects of setting up an OpenVPN server. Without good encryption, the whole process is basically meaningless.
By this point, you're finally ready to configure the server itself. The server configuration is actually less complicated than what you've done so far, so congratulations.
OpenVPN Sever
Configure the OpenVPN server using the encryption keys that you generated in the previous section of the guide.
This is the third part in configuring an OpenVPN server on Debian Stretch.
Now, you've arrived at the main event. This is the actual OpenVPN server configuration. Everything that you've done so far was absolutely necessary, but none of it has touched OpenVPN itself, until now.
This section is entirely concerned with configuring and running the OpenVPN server, and it's actually less complicated than you're probably thinking.
Get The Base Config
OpenVPN has made this process very easy. The package that you installed came with sample configuration files for both clients and the server. You just need to unzip the server one into you /etc/openvpn
directory.
# gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz > /etc/openvpn/server.conf
Open it in your favorite text editor and get ready to start changing things.
Use Your Keys
Once you're inside the file, you'll see that everything is filled out with reasonable defaults, and there are loads of comments that provide excellent documentation of what everything does.
The first thing that you need to find is the section to add your certificate authority and server keys. The variables are ca
, cert
, and key
. Set them equal to the full path of each of those files. It should look like the example below.
ca /etc/openvpn/certs/keys/ca.crt cert /etc/openvpn/certs/keys/server.crt key /etc/openvpn/certs/keys/server.key # This file should be kept secret
The next part that you need to find is the Diffie-Hellman .pem
When you're done, it should look like this:
dh dh4096.pem
Finally, find tls-auth
for your HMAC key.
tls-auth /etc/openvpn/certs/keys/ta.key 0 # This file is secret
Yes, leave the 0
on there.
Beef Up Security
The encryption settings in the configuration file are alright, but they could be much better. It's time to enable better encryption settings.
Find the section that begins with, # Select a cryptographic cipher.
That's where you need to add the following line below he existing commented options.
cipher AES-256-CBC
It's not one of the listed options there, but it is supported by OpenVPN. That 256bit AES encryption is probably the best one offered by OpenVPN.
Scroll to the end of the file. The next two options aren't already in the configuration, so you need to add them.
First, you need to specify a strong authentication digest. This is the encryption that OpenVPN will use for user authentication. Choose SHA512.
# Auth Digest auth SHA512
Next, limit the ciphers that OpenVPN will use to stronger ones. It's best to limit it as far as reasonably possible.
# Limit Ciphers tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA
Direct Traffic
All of the encryption stuff is out of the way. It's time to do some routing. You need to tell OpenVPN to handle redirecting traffic and DNS.
Start by redirecting traffic. Find the line below and uncomment it.
push "redirect-gateway def1 bypass-dhcp"
In order to route DNS through OpenVPN, you need to give it DNS options. These lines are already there and commented too. Uncomment them. If you want to use a different DNS server, you can change the IP to that DNS too.
push "dhcp-option DNS 208.67.222.222" push "dhcp-option DNS 208.67.220.220"
Set Up An OpenVPN User
OpenVPN runs as root by default. That's a pretty terrible idea. If OpenVPN is compromised, the whole system's screwed. There are a couple of commented lines to run OpenVPN as "nobody," but "nobody" is usually running other services too. If you don't want OpenVPN to have access to anything but OpenVPN, you need to run it as its own unprivileged user.
Create a system user for OpenVPN to run as.
# adduser --system --shell /usr/sbin/nologin --no-create-home openvpn
Then, you can edit the configuration file by uncommenting the lines that run OpenVPN as "nobody," and replace it with the user name that you just made.
user openvpn group nogroup
Send Logs To Null
There are two options when it comes to logs, and they both have their merits. You can log everything as normal and have the logs to loop back on at a later date, or you can be paranoid and log to /dev/null
.
By logging to /dev/null
, you're erasing any record of the clients that connect to the VPN and where they go. Even though you control your VPN, you may want to go this route if you're trying to be more privacy-minded.
If you want to destroy your logs, find the status
, log
, and log-append
variables and point them all at /dev/null
. It should look similar to the example below.
status /dev/null … log /dev/null log-append /dev/null
That's the last part of the configuration. Save it, and get ready to run your server.
Run Your Server
There are actually two services that you need to start to spin up OpenVPN on Debian Stretch. Start them both up with systemd.
# systemctl start openvpn # systemctl start openvpn@server
Verify that they're running properly.
# systemctl status openvpn*.service
Enable them both to run at startup.
# systemctl enable openvpn # systemctl enable openvpn@server
You now have a running VPN server on Debian Stretch!
What's next
You're here. You've done it! Debian is now running OpenVPN behind a secure firewall, and it's ready for clients to connect.
In the next section, you'll set up your first client and connect it to your server.
OpenVPN Client
Configure and OpenVPN client to connect to the newly configured OpenVPN server.
This is the fourth and final part in configuring an OpenVPN server on Debian Stretch.
Now that your server is running, you can set up a client to connect to it. That client can be any device that supports OpenVPN, which is nearly anything.
There are somethings that you need to do on the server first to hand off to the client, but after that, it's all about setting up that connection.
Create Client Keys
Start off by making a set of client keys. The process is almost identical to the one you used to make the server keys.
cd
into the certificate authority directory, set the source from the variables file and build the keys.
# cd /etc/openvpn/certs # source ./vars # ./build-key firstclient
You can name the client key whatever you choose. Again, the script will ask you a series of questions. The defaults should be good for everything.
Client Configuration File
OpenVPN provides example client configurations in addition to the server ones. Crate a new directory for your client configuration and copy the example in.
# mkdir /etc/openvpn/clients # cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/clients/client.ovpn
Open the file in your text editor of choice.
Remote Host
Find the line with the remote
variable. Set it equal to your server's IP.
remote 192.168.1.5 1194
Become Nobody
There's no training with the Faceless Men required. Just find an uncomment the lines below.
user nobody group nogroup
Set Up Your Keys
You have to tell the client configuration where to find the keys that it needs too. Find the following lines and edit them to match what you've set up.
ca ca.crt cert firstclient.crt key firstclient.key
Make sure to use the actual names of the client cert and key. The path is fine. You'll be putting it all in the same directory.
Find and uncomment the line for HMAC.
tls-auth ta.key 1
Specify Encryption
The client needs to know what encryption the server is using. Just like the server, a couple of these lines need to be added in.
Find the cipher
variable. It's commented. Uncomment it and add in the cipher that you used on the server.
cipher AES-256-CBC
Add in the authentication digest and the cipher restrictions at the end of the client configuration.
# Authentication Digest auth SHA512 # Cipher Restrictions tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA
Save your configuration and exit.
Send The Client A Tarball
You have to pack up your client configuration and keys in a tarball and send them to the client. Load everything into one tarball to simplify things on the client end.
# tar cJf /etc/openvpn/clients/firstclient.tar.xz -C /etc/openvpn/certs/keys ca.crt firstclient.crt firstclient.key ta.key -C /etc/openvpn/clients/ client.ovpn
Now, you can transfer that tarball to your client however you choose.
Connect
Assuming that your client is a Debian distribution, the connection process is very simple. Install OpenVPN like you did on the server.
# apt install openvpn
Extract your tarball into the /etc/openvpn
directory that the installation created.
# cd /etc/openvpn # tar xJf /path/to/firstclient.tar.xz
You may need to rename client.ovpn
to openvpn.conf
. You'll get an error on startup if you do.
Start and enable OpenVPN with systemd.
# systemctl start openvpn # systemctl enable openvpn
Conclusion
You have a working VPN server and a connected client! You can follow the same procedure detailed in this guide for your other clients too. Make sure to create separate keys for each one. You can use the same config file, though.
You also might want to make sure that everything is working properly. Head over to DNS Leak Test to make sure that your IP patches the server, and you're not using your IPS's DNS.