How To set up OpenVPN on Debian 11 Bullseye

OpenVPN Logo

Here's a how to about setting up a OpenVPN server under Debian 11 Bullseye.

The goal is to make our debian server a VPN gateway allowing our Windows remote clients to join our entire network.

Network diagram

OpenVPN windows client/debian server architecture
  • OpenVPN Server :
    • OS : Debian GNU/Linux 11 (Bullseye)
    • Role : OpenVPN Server + Gateway
    • IP : 192.168.0.254

Server (Debian)

Debian Logo

Installation

  • Install openvpn package :
root@host:~# apt install openvpn
  • Make OpenVPN start at boot
root@host:~# sed -i 's/#AUTOSTART="all"/AUTOSTART="all"/' /etc/default/openvpn ; systemctl daemon-reload

PKI

  • Go to /etc/openvpn/ directory :
root@host:~# cd /etc/openvpn/
  • Initialize the pki
root@host:~# /usr/share/easy-rsa/easyrsa clean-all
root@host:~# /usr/share/easy-rsa/easyrsa init-pki
  • Type yes to initialize :
WARNING!!!

You are about to remove the EASYRSA_PKI at: /etc/openvpn/pki
and initialize a fresh PKI here.

Type the word 'yes' to continue, or any other input to abort.
  Confirm removal: yes
  • Build the certificate authority in /etc/openvpn/pki/ca.crt :
root@host:~# /usr/share/easy-rsa/easyrsa build-ca nopass
  • Give a Common Name :
Using SSL: openssl OpenSSL 1.1.1k  25 Mar 2021
Generating RSA private key, 2048 bit long modulus (2 primes)
.........+++++
............................+++++
e is 65537 (0x010001)
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:openvpn-host

CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/etc/openvpn/pki/ca.crt

Server certificates

  • Generate certificate and key for server :
root@host:~# /usr/share/easy-rsa/easyrsa build-server-full server nopass
  • Generate Diffie Hellman parameters in /etc/openvpn/pki/dh.pem :
root@host:~# /usr/share/easy-rsa/easyrsa gen-dh

Client certificates

  • Create client01 certificate :

Client certificates are inside /etc/openvpn/pki/private/ and /etc/openvpn/pki/issued/ directories.

root@host:~# /usr/share/easy-rsa/easyrsa build-client-full client01 nopass
  • Create 10 clients certificates with one command :
root@host:~# for i in $(seq -w 1 10);do /usr/share/easy-rsa/easyrsa build-client-full client"$i" nopass; done

/etc/openvpn/server.conf

  • Edit /etc/openvpn/server.conf configuration file :
port 1194
proto udp
dev tun

ca /etc/openvpn/pki/ca.crt # generated keys
cert /etc/openvpn/pki/issued/server.crt
key /etc/openvpn/pki/private/server.key # keep secret
dh /etc/openvpn/pki/dh.pem

server 10.50.8.0 255.255.255.0 # internal tun0 connection IP
ifconfig-pool-persist ipp.txt

keepalive 10 120

comp-lzo # Compression - must be turned on at both end
persist-key
persist-tun

push "dhcp-option DNS 192.168.0.200"
push "dhcp-option DOMAIN std.local"
push "route 192.168.0.0 255.255.255.0"

status /var/log/openvpn-status.log

verb 3 # verbose mode

Systemd

  • Enable OpenVPN Server service :
root@host:~# systemctl enable openvpn-server@.service
  • Start OpenVPN Server service :
root@host:~# systemctl start openvpn@server.service

Router mode

Router mode will allow us to make the 192.168.0.0/24 network reachable from the client side.

nftables

A simple netfilter rule to allow vpn clients to access to the entire network.

Identify network interfaces

  • List network interfaces
root@host:~# ip addr sh
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 01:02:a0:21:fd:54 brd ff:ff:ff:ff:ff:ff
    inet OPENVPN_IP brd X.X.X.X scope global wan
       valid_lft forever preferred_lft forever
    inet6 fe80::ff:fe5d:f333/64 scope link 
       valid_lft forever preferred_lft forever
3: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 11:a2:a9:21:fd:54 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.254 brd X.X.X.X scope global wan
       valid_lft forever preferred_lft forever
    inet6 fe80::6a05:caff:fe39:c153/64 scope link 
       valid_lft forever preferred_lft forever
4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 500
    link/none 
    inet 10.50.8.1 peer 10.50.8.2/32 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::7ea2:577f:e834:7a20/64 scope link stable-privacy 
       valid_lft forever preferred_lft forever

Temporary rules

  • Enter the masquerade rules to make your internal network reachable from Windows :
root@host:~# nft add table ip NAT
root@host:~# nft add chain ip NAT my_masquerade '{ type nat hook postrouting priority 100; }'
root@host:~# nft add rule NAT my_masquerade ip saddr { 10.50.8.0/24 } oifname enp2s0 masquerade

Persistant rules

  • To make our nat persistent, edit /etc/nftables.conf file :
#!/usr/sbin/nft -f

flush ruleset

table inet filter {
        chain input {
                type filter hook input priority 0;
        }
        chain forward {
                type filter hook forward priority 0;
        }
        chain output {
                type filter hook output priority 0;
        }
}
table ip NAT {
        chain my_masquerade {
                type nat hook postrouting priority 100; policy accept;
                ip saddr { 10.50.8.0/24 } oifname "enp2s0" masquerade comment "outgoing NAT"
        }
}
  • Enable nftables service with systemctl :
root@host:~# root@host:~# systemctl enable nftables.service

Gateway mode

  • Edit /etc/sysctl.conf file and add :
net.ipv4.ip_forward=1
  • And Run this command to take this into account :
root@host:~# sysctl -p /etc/sysctl.conf

What if my OpenVPN server has one network interface and it is not my default gateway?

OpenVPN VM server architecture

Of course we can be in a situation where we cannot install OpenVPN on our router. In this case we can for example install our OpenVPN server as a Virtual Machine.

We need obviously to create a port redirection on our wan router to redirect OpenVPN traffic (step 1 on the diagram) to our OpenVPN server (step 2).

And that's it, it won't change much in terms of configuration because we still have to enable gateway mode and create a NAT rule.

In fact we just need to apply the exact same rules as above and this is it.

Windows client configuration

Microsoft Logo
  • Files to get :
    • ca.crt : /etc/openvpn/pki/ca.crt
    • client01.crt : /etc/openvpn/pki/issued/client01.crt
    • client01.key : /etc/openvpn/pki/private/client01.key
  • You should see this client files :
openvpn files on a windows host
  • Edit C:\Program Files\OpenVPN\config\client.ovpn file :
client

dev tun

proto udp

remote OPENVPN_IP 1194

resolv-retry infinite
nobind
persist-key
persist-tun

ca ca.crt
cert client01.crt
key client01.key

comp-lzo

verb 3
  • Open OpenVPN with administrator rights (otherwise routes rules won't work) and connect :
Start openvpn from a windows host
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Contact :