<p>
OpenVPN is an open-source virtual private network (VPN).
</p>
<p>
This tutorial was written for Debian 10 (buster) in March, 2020.
</p>

<h3>Contents</h3>
<ul>
<li><a href="#server">Server</a>
<ul>
  <li><a href="#easy-rsa">Easy RSA</a></li>
  <li><a href="#server.conf">Server Config</a></li>
  <li><a href="#start_server">Start Server</a></li>
</ul>
</li>
<li><a href="#client">Client</a>
<ul>
  <li><a href="#client_certs">Client Certificates</a></li>
  <li><a href="#client.conf">Client Config</a></li>
  <li><a href="#start_client">Start Client</a></li>
  <li><a href="#gui">GUI</a></li>
</ul>
<li><a href="#internet">Internet Access</a>
<ul>
  <li><a href="#internet_server">Server</a></li>
  <li><a href="#internet_client">Client</a></li>
</ul>
</li>
<li><a href="#external_links">External Links</a></li>
</ul>

<h3 id="server">Server</h3>
<p>
The official Debian 10 repository contains a package for OpenVPN 2.4.<br />
The following command installs this package:
</p>
<pre><code class="language-bash">apt install openvpn</code></pre>

<h4 id="easy-rsa">Easy RSA</h4>
<p>
OpenVPN utilizes SSL/TLS security mechanisms.<br />
Therefore, certificates (and keys) need to be generated and signed<br />
by a certificate authority (CA). Easy RSA is helpful in that regard.
</p>
<p>
Use the following command to initialize a directory <code>easy-rsa</code> with files<br />
that help creating the required certificates:
</p>
<pre><code class="language-bash">cd /etc/openvpn
make-cadir easy-rsa
</code></pre>
<p>
Default values for certificates can be specified by uncommenting corresponding<br />
fields in the following file:
</p>
<dl class="file">
<dt><code class="filename">/etc/openvpn/easy-rsa/vars</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">#...

# Organizational fields (used with 'org' mode and ignored in 'cn_only' mode.)
# These are the default values for fields which will be placed in the
# certificate.  Don't leave any of these fields blank, although interactively
# you may omit any specific field by typing the "." symbol (not valid for
# email.)

#set_var EASYRSA_REQ_COUNTRY    "US"
#set_var EASYRSA_REQ_PROVINCE   "California"
#set_var EASYRSA_REQ_CITY       "San Francisco"
#set_var EASYRSA_REQ_ORG        "Copyleft Certificate Co"
#set_var EASYRSA_REQ_EMAIL      "me@example.net"
#set_var EASYRSA_REQ_OU         "My Organizational Unit"

#...
</code></pre>
</dd>
</dl>

<p>
The following commands generate the certificate authority (CA),<br />
a certificate/key pair for the server and a certificate/key pair for<br />
a client named <code>client1</code>:
</p>
<pre><code class="language-bash">cd /etc/openvpn/easy-rsa
./easyrsa init-pki
./easyrsa build-ca
./easyrsa build-server-full server
./easyrsa gen-dh
./easyrsa build-client-full client1
</code></pre>
<p>
If the OpenVPN server is started on boot, removing the passphrase<br />
prevents being prompted for a password:
</p>
<pre><code class="language-bash">./easyrsa set-rsa-pass server nopass</code></pre>
<p>
To change the passphrase:
</p>
<pre><code class="language-bash">./easyrsa set-rsa-pass server</code></pre>
<p>
Create an archive for the client:
</p>
<pre><code class="language-bash">cd /etc/openvpn
tar czvf client1_ovpn.tar.gz easy-rsa/pki/ca.crt easy-rsa/pki/issued/client1.crt easy-rsa/pki/private/client1.key
</code></pre>

<h4 id="server.conf">Server Config</h4>
<p>
Copy the example config file for the server to the correct location:
</p>
<pre><code class="language-bash">zcat /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz &gt; /etc/openvpn/server/server.conf</code></pre>
<p>
Edit relevant parts in server config file:
</p>
<dl class="file">
<dt><code class="filename">/etc/openvpn/server/server.conf</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">#...

# SSL/TLS root certificate (ca), certificate
# (cert), and private key (key).  Each client
# and the server must have their own cert and
# key file.  The server and all clients will
# use the same ca file.
#
# See the "easy-rsa" directory for a series
# of scripts for generating RSA certificates
# and private keys.  Remember to use
# a unique Common Name for the server
# and each of the client certificates.
#
# Any X509 key management system can be used.
# OpenVPN can also use a PKCS #12 formatted key file
# (see "pkcs12" directive in man page).
ca /etc/openvpn/easy-rsa/pki/ca.crt
cert /etc/openvpn/easy-rsa/pki/issued/server.crt
key /etc/openvpn/easy-rsa/pki/private/server.key

# Diffie hellman parameters.
# Generate your own with:
#   openssl dhparam -out dh2048.pem 2048
dh /etc/openvpn/easy-rsa/pki/dh.pem

#...

# Uncomment this directive to allow different
# clients to be able to "see" each other.
# By default, clients will only see the server.
# To force clients to only see the server, you
# will also need to appropriately firewall the
# server's TUN/TAP interface.
client-to-client

#...

# For extra security beyond that provided
# by SSL/TLS, create an "HMAC firewall"
# to help block DoS attacks and UDP port flooding.
#
# Generate with:
#   openvpn --genkey --secret ta.key
#
# The server and each client must have
# a copy of this key.
# The second parameter should be '0'
# on the server and '1' on the clients.
;tls-auth ta.key 0 # This file is secret

#...
</code></pre>
</dd>
</dl>

<h4 id="start_server">Start Server</h4>
<p>
Start OpenVPN with the config <code>/etc/openvpn/server/server.conf</code>:
</p>
<pre><code class="language-bash">systemctl start openvpn-server@server</code></pre>
<p>
Start the given config on boot:
</p>
<pre><code class="language-bash">systemctl enable openvpn-server@server</code></pre>

<h3 id="client">Client</h3>
<p>
OpenVPN needs to be installed on the clients:
</p>
<pre><code class="language-bash">apt install openvpn</code></pre>

<h4 id="client_certs">Client Certificates</h4>
<p>
Copy the certificate/key pair from the server to a client:
</p>
<pre><code class="language-bash">cd /etc/openvpn
tar xvf client1_ovpn.tar.gz
</code></pre>

<p>
Each client should have its own certificate/key pair.
</p>

<h4 id="client.conf">Client Config</h4>
<p>
Copy the example config file for the client to the correct location:
</p>
<pre><code class="language-bash">cat /usr/share/doc/openvpn/examples/sample-config-files/client.conf &gt; /etc/openvpn/client/vpn.example.net.conf</code></pre>
<p>
Edit relevant parts in the client config file:
</p>

<dl class="file">
<dt><code class="filename">/etc/openvpn/client/vpn.example.net.conf</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">#...

# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
remote vpn.example.net 1194

#...

# SSL/TLS parms.
# See the server config file for more
# description.  It's best to use
# a separate .crt/.key file pair
# for each client.  A single ca
# file can be used for all clients.
ca /etc/openvpn/easy-rsa/pki/ca.crt
cert /etc/openvpn/easy-rsa/pki/issued/client1.crt
key /etc/openvpn/easy-rsa/pki/private/client1.key

#...

# If a tls-auth key is used on the server
# then every client must also have the key.
;tls-auth ta.key 1

#...
</code></pre>
</dd>
</dl>

<h4 id="start_client">Start Client</h4>
<p>
Start OpenVPN with the config <code>/etc/openvpn/client/vpn.example.net.conf</code>:
</p>
<pre><code class="language-bash">systemctl start openvpn-client@vpn.example.net</code></pre>

<h4 id="gui">GUI</h4>
<p>
A system tray icon for systemd services can be used as graphical user interface (GUI)<br />
for an OpenVPN client.
</p>
<ul>
<li><a href="http://gernot-walzl.at/Debian/Raspbian/servicetrayicon.py" download>
http://gernot-walzl.at/Debian/Raspbian/servicetrayicon.py</a></li>
</ul>

<h3 id="internet">Internet Access</h3>
<p>
This section describes how to route all client traffic (including web-traffic)<br />
through the VPN.
</p>

<h4 id="internet_server">Server</h4>
<p>
Enable IPv4 packet forwarding in the kernel:
</p>
<dl class="file">
<dt><code class="filename">/etc/sysctl.conf</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">#...

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

#...
</code></pre>
</dd>
</dl>
<p>
Forward traffic from the VPN over the interface <code>eth0</code>:
</p>
<pre><code class="language-bash">iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE</code></pre>

<h4 id="internet_client">Client</h4>
<dl class="file">
<dt><code class="filename">/etc/openvpn/client/vpn.example.net.conf</code></dt>
<dd>
<pre class="file"><code class="language-plaintext">#...

redirect-gateway autolocal
</code></pre>
</dd>
</dl>

<h3 id="external_links">External Links</h3>
<ul>
<li><a href="https://openvpn.net/" target="_blank">
https://openvpn.net/</a></li>
<li><a href="https://wiki.debian.org/OpenVPN" target="_blank">
https://wiki.debian.org/OpenVPN</a></li>
<li><a href="https://openvpn.net/community-resources/how-to/" target="_blank">
https://openvpn.net/community-resources/how-to/</a></li>
</ul>