For private use I only want to use a simple peer-to-peer openVPN connection without maintaining a complete Public Key Infrastructure. I have heard it can be simplified by using static keys, but how can I set this up using Raspberry Pi?
2 Answers
You can generate static secret keys and just preshare them to the devices using openVPN. Then this keys are used for authentication. There is no need to generate private/public keys and maintain them in an infrastructure with a certification authority.
For reference I use Raspbian Stretch Lite 2019-04-08 updated with sudo update && sudo full-upgrade && sudo reboot
on 2019-05-01.
Example for this setup:
10.8.0.1 10.8.0.2
/ vpn tunnel ┌──────────┐ \
peer1 ╔════════════════╗ ╔=═══════════════════════════════════ peer2
RPi(eth0) <-----------> router <-------------> │ INTERNET │
\ wired / \ wan │ │
192.168.50.2 192.168.50.1 172.217.18.174 └──────────┘
(public ip)
I assume you have a working internet connection.
On the openvpn peer1 install openvpn:
rpi ~$ sudo -Es
rpi ~# apt update
rpi ~# apt full-upgrade
rpi ~# apt install openvpn
rpi ~# systemctl disable --now openvpn.service
If you use systemd-networkd then install also
rpi ~# apt install openvpn-systemd-resolved
Then generate a static secret key:
rpi ~# openvpn --genkey --secret /etc/openvpn/static.key
Create a peer1 config file:
rpi ~# cat > /etc/openvpn/peer1.conf <<EOF
dev tun
ifconfig 10.8.0.1 10.8.0.2
secret static.key
cipher AES-256-CBC
EOF
Start the openvpn peer1:
rpi ~# systemctl enable --now openvpn@peer1.service
rpi ~# exit
rpi ~$
On the openvpn peer2 also install openvpn as shown above with that 5 or 6 commands. Don't generate a new static key, instead copy that one you have made on the openvpn peer1 to /etc/openvpn/
with same permission (sudo chmod 600 /etc/openvpn/static.key
). Create a peer2 config file:
mngmt ~# cat > /etc/openvpn/peer2.conf <<EOF
remote 192.168.50.3
dev tun
ifconfig 10.8.0.2 10.8.0.1
secret static.key
cipher AES-256-CBC
EOF
This config file is made to test the vpn tunnel on your local network first. Now start the peer2 with:
mngmt ~# exit
mngmt ~$ sudo systemctl start openvpn@peer2.service
Now you should be able to ping the peer1:
mngmt ~$ ping 10.8.0.1
If it works we can test to connect from the internet. To be sure not conflicting with local setup we have to use a complete different path to connect to the internet. For this I use my android cell phone with USB tethering to the management computer where I have disabled wifi on the phone to be sure only using 4G data uplink. I also disabled wifi on the management computer and pulled out its ethernet cord. The default port of openvpn is 1194
so you have to forward this port on your router to the local openvpn peer1 192.168.50.2 port 1194 (192.168.50.2:1194). It is important to use protocol udp not tcp. Look at the router what it's current public ip address is, in my example 172.217.18.174. Then change the line remote 192.168.50.3
in /etc/openvpn/peer2.conf
to remote 172.217.18.174
and
reboot.
Then enable USB tethering on your mobile phone and start peer2. You can check if port forwarding is set on the remote router with:
mngmt ~$ sudo nmap -Pn -sU -p1194 172.217.18.174
Starting Nmap 7.70 ( https://nmap.org ) at 2019-08-03 16:20 BST
Nmap scan report for p57A8602E.dip0.t-ipconnect.de (172.217.18.174)
Host is up.
PORT STATE SERVICE
1194/udp open|filtered openvpn
Nmap done: 1 IP address (1 host up) scanned in 2.31 seconds
This only checks if the port forwarding is active on the router. It does not check if the openvpn peer behind is active. This you can finally check with ping:
mngmt ~$ sudo systemctl start openvpn@peer2.service
mngmt ~$ ping 10.8.0.1
PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
64 bytes from 10.8.0.1: icmp_seq=1 ttl=64 time=743 ms
64 bytes from 10.8.0.1: icmp_seq=2 ttl=64 time=504 ms
64 bytes from 10.8.0.1: icmp_seq=3 ttl=64 time=403 ms
If this works then you have a running vpn tunnel through the internet to your local RasPi. If you want to connect in the other direction then just comment remote <ip address>
in /etc/openvpn/peer2.conf
and set it in /etc/openvpn/peer1.conf
.
With this simple setup with a pre shared secret key you can ensure that the environment is working (port forwarding, routing etc.). Now you can improve the setup of openvpn step by step with all its nice features like TLS public key authentication, connecting whole subnets, not only one RasPi, using tap interfaces instead of tun interfaces to remotely play games that need broadcasts and so on. But this isn't subject of this site.
References:
[1] openvpn - Static Key Mini-HOWTO
[2] man openvpn

- 42,107
- 20
- 85
- 197
For peer-to-peer with static keys I would use tinc-vpn available as the apt package tinc
.
It is simpler to manage than OVPN and much lighter, It is peer-to-peer with automatic routing and network forwarding and highly configurable.
It is flexible enough to be run out of a docker image for containerized VPN configurations (just mount the private key!)
apt-get install tinc
- Follow the instructions to generate and share the keys
There are many tutorials on-line for this, and tinc supports many systems with the same configuration, for the official examples/tutorials that demonstrate the flexibility look at https://www.tinc-vpn.org/examples/
Mesh VPN topologies are also supported.
Setup
You need to create
- config file
- network up/down script
- host configuration
- Generate host keys
There are optional scripts that do thinks like host/segment available/unavailable (for logging or emailing for example if partner is offline)
Create the network config
myvpn is the name of the network and can be anything you like (it will become the name of the tunnel interface)
as root:
# Create the config directory
cd /etc/tinc && mkdir myvpn && cd myvpn `
# Create a config file (https://www.tinc-vpn.org/documentation/tinc.conf.5)
cat > tinc.conf <<-EOF
Name = host1
AddressFamily = ipv4
Interface = myvpn
ConnectTo = host2
EOF
# create a network up script
cat > tinc-up <<-EOF
#!/bin/sh
ifconfig $INTERFACE 192.168.240.10 netmask 255.255.255.0
EOF &&
chmod u+x tinc-up;
# create a network down script
cat > tinc-down <<-EOF
#!/bin/sh
ifconfig $INTERFACE down
EOF
chmod u+x tinc-down
# create the host config
mkdir hosts
cat > hosts/host1 <<-EOF
# External Address
Address = my.external.ip
# VPN Network segment served
Subnet = 192.168.240.10/32
EOF
# Generate the public/private key pair
tincd -n myvpn -K
# this creates a private key and places the public key into hosts/host1
cat hosts/host1
Repeat the process on host 2 and exchange the host configuration file myvpn/hosts/host1
and myvpn/hosts/host2
Note: Only 1 host needs to be publically routable
afterwards start the network on each one tincd -n myvpn
you can enable automatic start at boot by adding echo myvpn >> /etc/tinc/nets.boot

- 2,993
- 1
- 10
- 20
-
How is that easier to manage than openvpn? Seems like same amount of configuration and having to know things. Openvpn static key is a very simple config as well. – Cray Mar 08 '21 at 08:28
-
@Cray, I agree, OpenVPN config is not difficult. But, the implementation is defined by a large config set, most of which is never touched by a user. In my experience, this tends to make "infrastructure as code" approach to system engineering more difficult than tools which leave fewer "black boxes". Contrast, a tinc deployment is defined by the configs in this answer, which are also scripted as heredocs. This approach, in my experience, improves the scalability of a system, and is more appropriate for applications requiring no configuration, like distributed pi clusters. – crasic Mar 09 '21 at 01:48