sudo apt install easy-rsa
sudo cp /usr/share/easy-rsa /usr/local/
cd /usr/local/easy-rsa/
sudo cp vars.example vars
sudo editor vars

Edit in vars:

set_var EASYRSA_KEY_SIZE        4096
set_var EASYRSA_CERT_EXPIRE     <<time in days>>
set_var EASYRSA_CERT_RENEW      <<time in days>>
cd ..
chown <<user>> easy-rsa
./easy-rsa init-pki
./easyrsa build-ca

Password needed for new certs. Store well. Of course you can always install a new ca.crt on the openVPN server and sign all client certificates again.

In this example, all keys and signing requests are doene on the same system and then distributed to all servers and clients. Can only be done this way, if you have physical access to all systems and can use an usb-stick or similar to load keys on all machines.

./easyrsa build-server-full <keyname> nopass
./easyrsa build-client-full <keyname>
./easyrsa gen-dh

The last command will take quite a while. The build-client-full above generates client keys with password protection. If your client is unable to store that password (for example in the machines password storage), you may want to use the nopass option for client keys as well.

Certificates will be in ./pki/issued/
Private Keys will be in ./pki/private/
Each client will need the ca.crt, its own crt and its own key file.
The server will need the ca.crt, its own crt and key file and the dh.pem


(Text from community.openvpn.net/openvpn/wiki/Hardening) The --tls-auth option uses a static pre-shared key (PSK) that must be generated in advance and shared among all peers. Generate a PSK with:

openvpn --genkey --secret ta.key

And reference it in the configs as such. The 0/1 value is arbitrary and must be the opposite between peers (or omitted entirely.)

# server-example
--tls-auth ta.key 0
# client-example
--tls-auth ta.key 1


This is a bridge setup with tap device. Like this, clients will get an IP in the same range as other clients on the lan the server’s in. Works better with bonjour/zeroconf/mDNS clients on the network. Basically, the client will not see any difference whether it is connected over VPN or in the LAN.

Make sure that the local DHCP server’s IP address range and the VPN server’s IP address range don’t overlap.

The following config goes to openVPN’s config file. On debian this will be something like /etc/openvpn/server.conf. Start the server with systemctl start openvpn@<<config file name prefix>>. If the config is name server.conf, this will become systemctl start openvpn@server

 Sample OpenVPN 2.0 config file with tap interface
 needed for .local-domain names to work on vpn
 only non-default options are included
 of a many-clients <-> one-server
 Comments are preceded with '#' or ';'
port <<port vpn should be on>>
proto udp
dev tap0
ca <<location ca.crt>>
cert <<location server crt>>
key <<location server key>> # This file should be kept secret
dh .<<location diffie-hellman pem>>
tls-auth <<location tls-auth-key>> 0 # This file is secret
server # coming from tun-config
ifconfig-pool-persist ipp.txt
keepalive 10 120
compress lzo
user <<vpn user>>
group <<vpn group>>
status openvpn-status.log
verb 3

Network interfaces for bridging need to be set up in /etc/network/interfaces. The setup below is for a system with one ethernet card. Don’t use the start bridging or stop bridging scripts mentioned in many openvpn manuals.

# The loopback network interface
 auto lo
 iface lo inet loopback
# The primary network interface will be bridged 
# and so set to manually
 iface eth0 inet manual
 iface tap0 inet manual
# set bridge, auto brings it up at boot
 auto br0
 iface br0 inet dhcp
     bridge_ports eth0 tap0
 bridge_hw aa:38:d4:8b:12:5a 
# set a mac address for the bridge. 
# Needed to give the server a fixed IP 
# from a DHCP server in the network

Firewall setup

Use nftables on recent Debian. You don’t want all crap from your VPN going right into your LAN. So you should set up the firewall to only let packages pass that are needed for services you actually want to provide.