OpenVPN
VPN Client
Auto-starting openvpn on Nixos can easily be done by enabling it in the configuration nix. Just place the configs where you want them to have and set it up like below.
services.openvpn.servers = {
officeVPN = { config = '' config /root/nixos/openvpn/officeVPN.conf ''; };
homeVPN = { config = '' config /root/nixos/openvpn/homeVPN.conf ''; };
serverVPN = { config = '' config /root/nixos/openvpn/serverVPN.conf ''; };
};
This will start three vpn instances; more can be added. Also make sure that you use absolute path for certs and keys if you don't have integreated in the config files.
In case you want to mount filesystems through the vpn, then on shutdown there will be a 90 second timeout. However, newer systemd you can set mount options that will require systemd to first umount the mount before closing the vpn connection.
Just enhance the options with the following option "x-systemd.requires=openvpn-officeVPN.service"
.
This would then look like this:
fileSystems."/mnt/office" = {
device = "//10.8.0.x/Share";
fsType = "cifs";
options = [ "noauto" "user" "uid=1000" "gid=100" "username=xxx" "password=xxx" "iocharset=utf8" "x-systemd.requires=openvpn-officeVPN.service" ];
};
fileSystems."/mnt/home" = {
device = "//10.9.0.x/Share";
fsType = "cifs";
options = [ "noauto" "user" "uid=1000" "gid=100" "username=xxx" "password=xxx" "iocharset=utf8" "x-systemd.requires=openvpn-homeVPN.service" ];
};
So basically the value for the x-systemd.requires
option is openvpn-{name}.service
If you want to run OpenVPN clients in nixos declarative containers, be sure to set enableTun option.
VPN Server
Simple one-client VPN Gateway server
One of the main use cases to run a VPN server is to provide a secure gateway to the internet for the connecting clients. This example builds a one-client VPN gateway in line with the OpenVPN Static Key Mini How-To. The Pro is that only a single static key is required.
let
# generate via openvpn --genkey --secret static.key
client-key = "/root/openvpn-laptop.key";
domain = "vpn.localhost.localdomain";
vpn-dev = "tun0";
port = 1194;
in {
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
networking.nat = {
enable = true;
externalInterface = <your-server-out-itf>;
internalInterfaces = [ vpn-dev ];
};
networking.firewall.trustedInterfaces = [ vpn-dev ];
networking.firewall.allowedUDPPorts = [ port ];
environment.systemPackages = [ pkgs.openvpn ]; # for key generation
services.openvpn.servers.smartphone.config = ''
dev ${vpn-dev}
proto udp
ifconfig 10.8.0.1 10.8.0.2
secret ${client-key}
port ${toString port}
cipher AES-256-CBC
comp-lzo
keepalive 10 60
ping-timer-rem
persist-tun
persist-key
'';
environment.etc."openvpn/smartphone-client.ovpn" = {
text = ''
client
dev tun
remote "${domain}"
ifconfig 10.8.0.1 10.8.0.2
port ${toString port}
cipher AES-256-CBC
comp-lzo
keepalive 10 60
resolv-retry infinite
nobind
persist-key
persist-tun
secret [inline]
'';
mode = "700";
};
system.activationScripts.openvpn-addkey = ''
f="/etc/openvpn/smartphone-client.ovpn"
if ! grep -q '<secret>' $f; then
echo "appending secret key"
echo "<secret>" >> $f
cat ${client-key} >> $f
echo "</secret>" >> $f
fi
'';
}