Running local servers behind a droplet using IPSec
I have a bit of an unorthodox setup with my FreeBSD 12.0 digitalocean droplet and a server hosted at home. The home server does not have a public IP, which is a problem since I use it to host this website. Instead I use the public-facing droplet to redirect traffic to the server over a VPN connection.
Below are the relevant portions of my configurations. Obviously I am not responsible for any damage caused if you use them. Let me know if you have any fixes or improvements.
How does it work?
Here's a quick rundown on all of the major components and what they do. I'm going to assume you have at least a base knowledge of FreeBSD and VPNs.
ipsec.ko
- This is the kernel module provided by the base system which implements the ipsec protocols. Ipsec is a set of protocols which provide security and authentication services.Strongswan
- a VPN based on ipsec and Internet Key Exchange (IKE) protocols. It agrees on keys and sets up the VPN connection.rinetd
- A redirection server which will forward connections from the public droplet to the VPN client (the home server).
Disclaimer
This isn't a "copy directly into your config" tutorial. My configuration was edited for simplicity for this post and isn't guaranteed to work.
This post is designed to show the concepts I use to create a unique setup. Having one droplet and being able to expose ports on a physical machine you own is really useful, and this post tries to show the general organization.
Installation
Here's a quick one liner for installing everything. This needs to be done on both the client and the server:
$ pkg install strongswan rinetd
Server
These are the configs on the public facing droplet which is the VPN server:
/usr/local/etc/ipsec.conf
# basic configuration
config setup
uniqueids = no
# Connection defaults
conn %default
keyexchange=ikev2
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
keyexchange=ikev2
authby=secret
# This is a designated connection for the client
conn punk
left=<public_ip>
leftid="punk"
leftsourceip=10.3.0.1
right=%any
rightsourceip=10.3.0.2
auto=add
# ... add more connections
/usr/local/etc/ipsec.secrets
The easiest way (which I don't actually use but is the simplest to configure) is to just use a Pre Shared Key for authentication:
# ipsec.secrets - strongSwan IPsec secrets file
: RSA /usr/local/etc/ipsec.d/private/vpn-server-key.pem
<public_ip> : PSK "passphrase"
punk : PSK "passphrase"
/usr/local/etc/rinetd.conf
The following is just a simple entry to map the public server's port
2222
to the client's ssh port. Add additional rules here for other
ports you need.
# rinetd.conf
<public_ip> 2222 10.3.0.2 22
Starting the services
sysrc strongswan_enable=YES rinetd_enable=YES
service strongswan start
service rinetd start
Client
/usr/local/etc/ipsec.conf
# ipsec.conf - strongSwan IPsec configuration file
# basic configuration
config setup
conn %default
ikelifetime=60m
keylife=20m
rekeymargin=3m
keyingtries=1
keyexchange=ikev2
authby=secret # psk or secret
conn home # name used in ipsec(1) commands
leftsourceip=%config
right=<public_ip>
rightid="punk"
auto=start # Add routing entries?
/usr/local/etc/ipsec.secrets
# ipsec.secrets - strongSwan IPsec secrets file
<public_ip> : PSK "passphrase"
punk : PSK "passphrase"
Starting the services
sysrc strongswan_enable=YES rinetd_enable=YES
service strongswan start
service rinetd start
Connecting
To manually initiate a VPN connection from the client, use the
following. ipsec up
starts up a connection of the given name.
$ ipsec up home
Reaching the client
At this point you should be able to ping the client from the server by
using its virtual IP. I use 10.3.0.3
for the client, and hence I can
ping and forward any packets to it.
The strange thing (which I can't seem to explain) is that strongswan doesn't add the proper routing rules to have a two-way tunnel between the client and server. Normally this would be a problem, but my use case only requires that the server can reach the client. If you get this working in a better way please let me know!
Miscellaneous
One thing to watch out for is that the normal ipsec_enable
rc variable is
not compatible with strongswan. Ipsec is also shipped in the base system,
and this rcvar will do the setup for those tools.
I really, really hate writing:
- Firewall rules
- vpn configurations
I can never get them right and it's miserable the entire time.