Running an OpenVPN Server on the Raspberry Pi

Time for a nice little Raspberry Pi project again, this time an OpenVPN Server! 🙂 My router at home is a bit oldish and can’t handle custom firmwares like DD-WRT or OpenWrt. It most certainly can’t handle VPN connections either. With these facts in mind, I thought I’d build my own vpn server with a Raspberry Pi. It was a little bit more complex than I thought, but I actually got it up ‘n running in a few days. It’s better to be safe than sorry, so please do some reading before you build. Here are a couple of good starting points which helped me in the right direction:

http://readwrite.com/2014/04/10/raspberry-pi-vpn-tutorial-server-secure-web-browsing (Mine is a modified version of this guide using server-bridge from the next link)
http://www.emaculation.com/doku.php/bridged_openvpn_server_setup
http://readwrite.com/2014/04/11/building-a-raspberry-pi-vpn-part-two-creating-an-encrypted-client-side#awesm=~oB89WBfWrt21bV
https://community.openvpn.net/openvpn/wiki/323-i-want-to-set-up-an-ethernet-bridge-on-the-1921681024-subnet-existing-dhcp
https://openvpn.net/index.php/open-source/documentation/miscellaneous/76-ethernet-bridging.html
https://openvpn.net/index.php/open-source/documentation/howto.html#config

My goals: Build a VPN Server using an existing DHCP server (router) on my internal LAN. (This is done by bridging btw). Port forwarding is used on the router so the vpn server is exposed to the Internet/WAN. Other goals was to keep the server rather secure. I built the server on top of Raspbian, which I’ll assume you can install by now. So here goes – the steps for building an OpenVPN server on a Raspberry Pi. Note: This is a VERY short guide, there are urls to longer explanations in my text. (I don’t feel like re-writing existing information).

  • Update the Pi to the newest version;
    • sudo apt-get update && sudo apt-get upgrade –y (for software)
    • sudo rpi-update (for kernel and firmware)
  • Install OpenVPN and bridge utils; sudo apt-get install openvpn bridge-utils –y
  • Become root: sudo –s
  • Generate keys:
  • Copy openvpn examples from /usr/share/doc/openvpn/examples/easy-rsa/2.0 to /etc/openvpn/easy-rsa
    • cp –r /usr/share/doc/openvpn/examples/easy-rsa/2.0 /etc/openvpn/easy-rsa
    • edit /etc/openvpn/easy-rsa/vars file
      • find and change EASY_RSA variable to export EASY_RSA=”/etc/openvpn/easy-rsa
  • Build CA Certificate and Root CA Certificate:
    • change dir to /etc/openvpn/easy-rsa
    • source ./vars –file: source ./vars
    • remove previous keys if necessary; ./clean-all
    • build your CA: ./build-ca
    • Create server credentials: ./build-key-server server
  • Create Diffie-Hellman key exchange: ./build-dh
  • Use OpenVPN’s built in DoS attack protection (generate a static HMAC key): openvpn –-genkey –-secret keys/ta.key
  • That’s it for the server, now we will create keys for the clients:
    • ./build-key jocke (leave challenge password blank and sign the certificate)
    • go to the keys directory: cd /etc/openvpn/easy-rsa/keys
    • (optional) use des3 encryption on the key: openssl rsa -in jocke.key -des3 -out jocke.3des.key

Until now, I’ve been following the guide from http://readwrite.com/2014/04/10/raspberry-pi-vpn-tutorial-server-secure-web-browsing. I’m going to use bridging however, so step 9 and forward aren’t suitable for me. Instead I followed the guide from http://www.emaculation.com/doku.php/bridged_openvpn_server_setup , and the “VPN Setup” –part. It worked really well, I just changed the IP’s to match my own network configuration/subnet. Also remember to change the settings mentioned in the “Final Settings in the VM” –part. My server.conf is a mix of both guides. Here it is:

port 1194
proto udp
dev tap0
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/xxxx.crt # SWAP WITH YOUR CRT NAME
key /etc/openvpn/easy-rsa/keys/xxxx.key # SWAP WITH YOUR KEY NAME
dh /etc/openvpn/easy-rsa/keys/dh1024.pem # If you changed to 2048, change that here!
remote-cert-tls client
ifconfig-pool-persist ipp.txt
server-bridge 192.168.11.1 255.255.255.0 192.168.11.201 192.168.11.254
client-to-client
keepalive 10 120
tls-auth /etc/openvpn/easy-rsa/keys/ta.key 0
cipher AES-128-CBC
comp-lzo
persist-key
persist-tun
status /var/log/openvpn-status.log 20
log /var/log/openvpn.log
verb 3

You should now have created the user keys following the above commands/guides. Instead of copying multiple key files to the clients, I prefer using the script from http://readwrite.com/2014/04/11/building-a-raspberry-pi-vpn-part-two-creating-an-encrypted-client-side#awesm=~oB89WBfWrt21bV. It’s very convenient and produces an .ovpn file which you can import in different OpenVPN clients. I’m too lazy to copy/paste, all I can say is that the default.txt –file should match the server.conf (use the same options).

Also remember to set up the Linux firewall to permit packets to flow freely over the newly created tap0 and br0 interfaces:

iptables -A INPUT -i tap0 -j ACCEPT
iptables -A INPUT -i br0 -j ACCEPT
iptables -A FORWARD -i br0 -j ACCEPT

and to make this information persistent/permanent:

  • sudo bash -c ‘iptables-save > /etc/network/iptables’
    • add a line to /etc/network/interfaces so the changes will become persistent;
      • pre-up iptables-restore < /etc/network/iptables (add it after the line iface eth0 inet dhcp)

 

The configuration part is now done. It’s always a good idea to look at the log files for better understanding and to check that everything is working. In my case everything looks (almost) fine:

cat /var/log/openvpn.log

Looking at the log when VPN-server starts (Nevermind the dates. Username and IPs also censored):

Tue Dec  2 12:21:02 2014 OpenVPN 2.2.1 arm-linux-gnueabihf [SSL] [LZO2] [EPOLL] [PKCS11] [eurephia] [MH] [PF_INET6] [IPv6 payload 20110424-2 (2.2RC2)] built on Oct 12 2013
Tue Dec  2 12:21:02 2014 NOTE: when bridging your LAN adapter with the TAP adapter, note that the new bridge adapter will often take on its own IP address that is different from what the LAN adapter was previously set to
Tue Dec  2 12:21:02 2014 NOTE: OpenVPN 2.1 requires ‘–script-security 2’ or higher to call user-defined scripts or executables
Tue Dec  2 12:21:02 2014 Diffie-Hellman initialized with 1024 bit key
Tue Dec  2 12:21:02 2014 Control Channel Authentication: using ‘/etc/openvpn/easy-rsa/keys/ta.key’ as a OpenVPN static key file
Tue Dec  2 12:21:02 2014 Outgoing Control Channel Authentication: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Tue Dec  2 12:21:02 2014 Incoming Control Channel Authentication: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Tue Dec  2 12:21:02 2014 TLS-Auth MTU parms [ L:1590 D:166 EF:66 EB:0 ET:0 EL:0 ]
Tue Dec  2 12:21:02 2014 Socket Buffers: R=[163840->131072] S=[163840->131072]
Tue Dec  2 12:21:02 2014 TUN/TAP device tap0 opened
Tue Dec  2 12:21:02 2014 TUN/TAP TX queue length set to 100
Tue Dec  2 12:21:02 2014 Data Channel MTU parms [ L:1590 D:1450 EF:58 EB:135 ET:32 EL:0 AF:3/1 ]
Tue Dec  2 12:21:02 2014 UDPv4 link local (bound): [undef]
Tue Dec  2 12:21:02 2014 UDPv4 link remote: [undef]
Tue Dec  2 12:21:02 2014 MULTI: multi_init called, r=256 v=256
Tue Dec  2 12:21:02 2014 IFCONFIG POOL: base=192.168.11.201 size=54, ipv6=0
Tue Dec  2 12:21:02 2014 ifconfig_pool_read(), in=’xxxxx,192.168.11.201′, TODO: IPv6
Tue Dec  2 12:21:02 2014 succeeded -> ifconfig_pool_set()
Tue Dec  2 12:21:02 2014 IFCONFIG POOL LIST
Tue Dec  2 12:21:02 2014 xxxxx,192.168.11.201
Tue Dec  2 12:21:02 2014 Initialization Sequence Completed

Looking at the (same) log when a client connects:

Mon Dec  1 15:52:13 2014 MULTI: multi_create_instance called
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Re-using SSL/TLS context
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 LZO compression initialized
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Control Channel MTU parms [ L:1590 D:166 EF:66 EB:0 ET:0 EL:0 ]
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Data Channel MTU parms [ L:1590 D:1450 EF:58 EB:135 ET:32 EL:0 AF:3/1 ]
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Local Options hash (VER=V4): ‘xxxxxx’
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Expected Remote Options hash (VER=V4): ‘xxxxxx’
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 TLS: Initial packet from [AF_INET]x.x.x.x:51208, sid=40186f54 2801328f
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 VERIFY OK: depth=1, /C=XX/ST=XX/L=XXX/O=XXXXXXXXX/OU=xxx/CN=xxxxx/name=XX/emailAddress=mail@host.domain
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Validating certificate key usage
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 ++ Certificate has key usage  0080, expects 0080
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 VERIFY KU OK
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Validating certificate extended key usage
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 ++ Certificate has EKU (str) TLS Web Client Authentication, expects TLS Web Client Authentication
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 VERIFY EKU OK
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 VERIFY OK: depth=0, /C=XX/ST=XX/L=XXX/O=XXXXXXXXX/OU=xxx/CN=xxxxx/name=XX/emailAddress=mail@host.domain
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Data Channel Encrypt: Cipher ‘AES-128-CBC’ initialized with 128 bit key
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Data Channel Encrypt: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Data Channel Decrypt: Cipher ‘AES-128-CBC’ initialized with 128 bit key
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Data Channel Decrypt: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Control Channel: TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 1024 bit RSA
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 [xxxxx] Peer Connection Initiated with [AF_INET]x.x.x.x:51208
Mon Dec  1 15:52:13 2014 xxxxx/x.x.x.x:51208 MULTI_sva: pool returned IPv4=192.168.11.201, IPv6=bccd:800:8ced:200:14c2:700:8427:5201
Mon Dec  1 15:52:16 2014 xxxxx/x.x.x.x:51208 PUSH: Received control message: ‘PUSH_REQUEST’
Mon Dec  1 15:52:16 2014 xxxxx/x.x.x.x:51208 send_push_reply(): safe_cap=960
Mon Dec  1 15:52:16 2014 xxxxx/x.x.x.x:51208 SENT CONTROL [xxxxx]: ‘PUSH_REPLY,route-gateway 192.168.11.1,ping 10,ping-restart 120,ifconfig 192.168.11.201 255.255.255.0’ (status=1)
Mon Dec  1 15:52:16 2014 xxxxx/x.x.x.x:51208 MULTI: Learn: 7e:0a:47:c6:2a:76 -> xxxxx/x.x.x.x:51208
Mon Dec  1 15:52:29 2014 read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
Mon Dec  1 15:52:39 2014 read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
Mon Dec  1 15:52:49 2014 read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
Mon Dec  1 15:53:20 2014 read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
Mon Dec  1 15:53:30 2014 read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
Mon Dec  1 15:56:16 2014 read UDPv4 [EHOSTUNREACH]: No route to host (code=113)

I was wondering what the ECONNREFUSED was all about. A little bit of googling got me on the right track. The solution was to add the line

push “explicit-exit-notify 3” to the server.conf.

After this trick the errors went away.

Source: https://forums.openvpn.net/topic10674.html

 

Finally I thought I’d read about server hardening so I won’t leave any holes open for hackers:

https://community.openvpn.net/openvpn/wiki/Hardening
https://openvpn.net/index.php/open-source/documentation/howto.html#security
http://darizotas.blogspot.fi/2014/04/openvpn-hardening-cheat-sheet.html

Most of these options are already in use so I’m feeling safe enough. This is after all only a little hobby server and not a big company server. I’ve learned tons and tons of stuff and I now have a working OpenVPN server at home 🙂

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s