Force all traffic through tun0 (OpenVPN)

I would like to force all outbound traffic through tun0 created by an OpenVPN systemd service. The usual considerations apply, such as immediately dropping all packages as soon as my VPN connection dies.

It seems that there are two approaches: iptables and the uncomplicated firewall (ufw). iptables seems scary and this really isn’t the topic where I’d like to make mistakes based on misunderstanding of iptables. Therefore, ufw sounds more appealing. But that seems to be a Ubuntu thing.

I looked around in the NixOS options but I couldn’t find anything that looks like a solution specifically to this problem. In addition, there’s a thread about a similar topic, but using Wireguard, Route all traffic through Wireguard interface - #18 by VulNix. It doesn’t look like people had much success.

The only thing I found is this custom module but it also looks complicated and who knows if it really works. Unfortunately this isn’t the kind of topic where “probably works but might have edge cases” is a viable approach.

Depending on your needs a NixOS container might be able to help you out. Are you running a systemd service which you want behind the VPN?

  ovpn = builtins.fetchurl {
    url = "";
    sha256 = "0z76s695lgd0v5ygs9wishmnmmilj4xhivzgfrn786lbdjdz2x7j";
  containers.slickvpn = {
    autoStart = true;
    enableTun = true;
    ephemeral = true;

    privateNetwork = true;
    hostAddress = "";
    localAddress = "";

    config =
      { config, pkgs, lib, ... }:
        environment.systemPackages = with pkgs; [ dnsutils ];

        services.openvpn.servers.SlickVPN.updateResolvConf = true;
        services.openvpn.servers.SlickVPN.authUserPass.username = "<username>";
        services.openvpn.servers.SlickVPN.authUserPass.password = "<password>";
        services.openvpn.servers.SlickVPN.config = "config ${ovpn}";

        # TODO: run some sort of daemon here

If this is your use case and you have any additional questions feel free to ping me on matrix.