OpenVPN: Difference between revisions

From NixOS Wiki
imported>HLandau
Created page with " === 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..."
 
imported from old wiki
 
(8 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 
== VPN Client==
=== VPN Client ===
OpenVPN can be configured for automatic startup by enabling it in <tt>/etc/nixos/configuration.nix</tt>:
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.


<syntaxHighlight lang="nix">
<syntaxHighlight lang="nix">
services.openvpn.servers = {
{
  ...
  services.openvpn.servers = {
     officeVPN  = { config = '' config /root/nixos/openvpn/officeVPN.conf ''; };
     officeVPN  = { config = '' config /root/nixos/openvpn/officeVPN.conf ''; };
     homeVPN    = { config = '' config /root/nixos/openvpn/homeVPN.conf ''; };
     homeVPN    = { config = '' config /root/nixos/openvpn/homeVPN.conf ''; };
     serverVPN  = { config = '' config /root/nixos/openvpn/serverVPN.conf ''; };
     serverVPN  = { config = '' config /root/nixos/openvpn/serverVPN.conf ''; };
};
  };
  ...
}
</syntaxHighlight>
 
You will need to create the referenced configuration files. The above example will start three VPN instances; more can be added.
 
Ensure you use absolute paths for any files such as certificates and keys referenced from the configuration files.
 
Use <em>systemctl</em> to start/stop VPN service. Each generated service will have a prefix `openvpn-`:
<syntaxHighlight>
systemctl start openvpn-officeVPN.service
</syntaxHighlight>
</syntaxHighlight>


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.
Should you have trouble with DNS resolution for services that should be available via the VPN, try adding the following to the config:


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.
<syntaxHighlight lang="nix">
{
  ...
  services.openvpn.servers = {
    officeVPN  = {
      config = '' config /root/nixos/openvpn/officeVPN.conf '';
      updateResolvConf = true;
    };
  };
  ...
}
</syntaxHighlight>


Just enhance the options with the following option <code>"x-systemd.requires=openvpn-officeVPN.service"</code>.
=== Mounting filesystems via a VPN ===


This would then look like this:
If you mount filesystems through the VPN, the filesystem will not be unmounted properly because the VPN connection will be shut down prior to unmounting the filesystem. However, newer systemd versions allow you to set mount options to unmount the mount before closing the VPN connection via the mount option <tt>x-systemd.requires=openvpn-<em>vpnname</em>.service</tt>.


Example mount configurations:
<syntaxHighlight lang="nix">
<syntaxHighlight lang="nix">
fileSystems."/mnt/office" = {
{
  ...
  fileSystems."/mnt/office" = {
     device = "//10.8.0.x/Share";
     device = "//10.8.0.x/Share";
     fsType = "cifs";
     fsType = "cifs";
     options = [ "noauto" "user" "uid=1000" "gid=100" "username=xxx" "password=xxx" "iocharset=utf8" "x-systemd.requires=openvpn-officeVPN.service" ];
     options = [ "noauto" "user" "uid=1000" "gid=100" "username=xxx" "password=xxx" "iocharset=utf8"
};
      "x-systemd.requires=openvpn-officeVPN.service" ];
fileSystems."/mnt/home" = {
  };
  fileSystems."/mnt/home" = {
     device = "//10.9.0.x/Share";
     device = "//10.9.0.x/Share";
     fsType = "cifs";
     fsType = "cifs";
     options = [ "noauto" "user" "uid=1000" "gid=100" "username=xxx" "password=xxx" "iocharset=utf8" "x-systemd.requires=openvpn-homeVPN.service" ];
     options = [ "noauto" "user" "uid=1000" "gid=100" "username=xxx" "password=xxx" "iocharset=utf8"
};
      "x-systemd.requires=openvpn-homeVPN.service" ];
  };
  ...
}
</syntaxHighlight>
</syntaxHighlight>


So basically the value for the <code>x-systemd.requires</code> option is <code>openvpn-{name}.service</code>
If you want to run OpenVPN clients in NixOS declarative containers, you will need to set the {{nixos:option|enableTun}} container option.


If you want to run OpenVPN clients in nixos declarative containers, be sure to set [https://nixos.org/nixos/options.html#enabletun ''enableTun''] option.
=== Supporting legacy cipher providers ===
If you need to connect to servers with legacy ciphers (e.g. '''BF-CBC'''), one way is to override OpenVPN to use '''openssl_legacy''' package (which is [https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/development/libraries/openssl/3.0/legacy.cnf configured to enable legacy providers]), for example via an overlay:


=== VPN Server ===
<syntaxHighlight lang="nix">
final: prev: {
  openvpn = prev.openvpn.override {
    openssl = prev.openssl_legacy;
  };
}
</syntaxHighlight>


==== Simple one-client VPN Gateway server ====
== VPN 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 [https://openvpn.net/index.php/open-source/documentation/miscellaneous/78-static-key-mini-howto.html OpenVPN Static Key Mini How-To]. The Pro is that only a single static key is required.
=== Simple one-client VPN gateway server ===
The following is an example of a VPN server configuration which supports a single known client.


<syntaxHighlight lang="nix">
<syntaxHighlight lang="nix">
let
let
   # generate via openvpn --genkey --secret static.key
   # generate via openvpn --genkey --secret openvpn-laptop.key
   client-key = "/root/openvpn-laptop.key";
   client-key = "/root/openvpn-laptop.key";
   domain = "vpn.localhost.localdomain";
   domain = "vpn.localhost.localdomain";
Line 50: Line 87:
   port = 1194;
   port = 1194;
in {
in {
   boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
   # sudo systemctl start nat
   networking.nat = {
   networking.nat = {
     enable = true;
     enable = true;
     externalInterface = <your-server-out-itf>;
     externalInterface = <your-server-out-if>;
     internalInterfaces  = [ vpn-dev ];
     internalInterfaces  = [ vpn-dev ];
   };
   };
Line 65: Line 102:
     secret ${client-key}
     secret ${client-key}
     port ${toString port}
     port ${toString port}
     cipher AES-256-CBC
     cipher AES-256-CBC
    auth-nocache
     comp-lzo
     comp-lzo
     keepalive 10 60
     keepalive 10 60
     ping-timer-rem
     ping-timer-rem
Line 76: Line 115:
   environment.etc."openvpn/smartphone-client.ovpn" = {
   environment.etc."openvpn/smartphone-client.ovpn" = {
     text = ''
     text = ''
      client
       dev tun
       dev tun
       remote "${domain}"
       remote "${domain}"
       ifconfig 10.8.0.1 10.8.0.2
       ifconfig 10.8.0.2 10.8.0.1
       port ${toString port}
       port ${toString port}
      redirect-gateway def1


       cipher AES-256-CBC
       cipher AES-256-CBC
      auth-nocache
       comp-lzo
       comp-lzo
       keepalive 10 60
       keepalive 10 60
Line 92: Line 133:


     '';
     '';
     mode = "700";
     mode = "600";
   };
   };
   system.activationScripts.openvpn-addkey = ''
   system.activationScripts.openvpn-addkey = ''
Line 105: Line 146:
}
}
</syntaxHighlight>
</syntaxHighlight>
[[Category:Networking]]
[[Category:Applications]]

Latest revision as of 13:49, 7 June 2024

VPN Client

OpenVPN can be configured for automatic startup by enabling it in /etc/nixos/configuration.nix:

{
  ...
  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 ''; };
  };
  ...
}

You will need to create the referenced configuration files. The above example will start three VPN instances; more can be added.

Ensure you use absolute paths for any files such as certificates and keys referenced from the configuration files.

Use systemctl to start/stop VPN service. Each generated service will have a prefix `openvpn-`:

systemctl start openvpn-officeVPN.service

Should you have trouble with DNS resolution for services that should be available via the VPN, try adding the following to the config:

{
  ...
  services.openvpn.servers = {
    officeVPN  = {
      config = '' config /root/nixos/openvpn/officeVPN.conf '';
      updateResolvConf = true;
    };
  };
  ...
}

Mounting filesystems via a VPN

If you mount filesystems through the VPN, the filesystem will not be unmounted properly because the VPN connection will be shut down prior to unmounting the filesystem. However, newer systemd versions allow you to set mount options to unmount the mount before closing the VPN connection via the mount option x-systemd.requires=openvpn-vpnname.service.

Example mount configurations:

{
  ...
  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" ];
  };
  ...
}

If you want to run OpenVPN clients in NixOS declarative containers, you will need to set the enableTun container option.

Supporting legacy cipher providers

If you need to connect to servers with legacy ciphers (e.g. BF-CBC), one way is to override OpenVPN to use openssl_legacy package (which is configured to enable legacy providers), for example via an overlay:

final: prev: {
  openvpn = prev.openvpn.override {
    openssl = prev.openssl_legacy;
  };
}

VPN Server

Simple one-client VPN gateway server

The following is an example of a VPN server configuration which supports a single known client.

let
  # generate via openvpn --genkey --secret openvpn-laptop.key
  client-key = "/root/openvpn-laptop.key";
  domain = "vpn.localhost.localdomain";
  vpn-dev = "tun0";
  port = 1194;
in {
  # sudo systemctl start nat
  networking.nat = {
    enable = true;
    externalInterface = <your-server-out-if>;
    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
    auth-nocache

    comp-lzo
    keepalive 10 60
    ping-timer-rem
    persist-tun
    persist-key
  '';

  environment.etc."openvpn/smartphone-client.ovpn" = {
    text = ''
      dev tun
      remote "${domain}"
      ifconfig 10.8.0.2 10.8.0.1
      port ${toString port}
      redirect-gateway def1

      cipher AES-256-CBC
      auth-nocache

      comp-lzo
      keepalive 10 60
      resolv-retry infinite
      nobind
      persist-key
      persist-tun
      secret [inline]

    '';
    mode = "600";
  };
  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
  '';
}