A NixOS module that lets you route traffic from systemd services through a VPN while preventing DNS leaks.
Important
To "prevent" DNS leaks, this module simply makes the NSCD socket inaccessible to a systemd service. This might cause other problems, and leaks have only been tested when resolving DNS over UDP. Other ways of resolving DNS like DoT and DoH have not been tested, and DNS can leak in other ways, so you are always advised to monitor and test for DNS leaks yourself.
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
vpn-confinement.url = "github:Maroka-chan/VPN-Confinement";
};
outputs = { self, nixpkgs, vpn-confinement, ... }:
{
# Change hostname, system, etc. as needed
nixosConfigurations.hostname = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
vpn-confinement.nixosModules.default
];
};
};
}vpnNamespaces.<name> = { # The name is limited to 7 characters
enable = true;
wireguardConfigFile = <path to secret wireguard config file>;
accessibleFrom = [
"<ip or subnet>"
];
portMappings = [{
from = <port on host>;
to = <port in VPN network namespace>;
protocol = "<transport protocol>"; # protocol = "tcp"(default), "udp", or "both"
}];
openVPNPorts = [{
port = <port to access through VPN interface>;
protocol = "<transport protocol>"; # protocol = "tcp"(default), "udp", or "both"
}];
};systemd.services.<name>.vpnConfinement = {
enable = true;
vpnNamespace = "<network namespace name>";
};# configuration.nix
{ pkgs, lib, config, ... }:
{
# Define VPN network namespace
vpnNamespaces.wg = {
enable = true;
wireguardConfigFile = /. + "/secrets/wg0.conf";
accessibleFrom = [
"192.168.0.0/24"
];
portMappings = [
{ from = 9091; to = 9091; }
];
openVPNPorts = [{
port = 60729;
protocol = "both";
}];
};
# Add systemd service to VPN network namespace
systemd.services.transmission.vpnConfinement = {
enable = true;
vpnNamespace = "wg";
};
services.transmission = {
enable = true;
settings = {
"rpc-bind-address" = "192.168.15.1"; # Bind RPC/WebUI to VPN network namespace address
# RPC-whitelist examples
"rpc-whitelist" = "192.168.15.5"; # Access from default network namespace
"rpc-whitelist" = "192.168.1.*"; # Access from other machines on specific subnet
"rpc-whitelist" = "127.0.0.1"; # Access through loopback within VPN network namespace
};
};
}Note
Access from the default network namespace is done using the VPN network namespace address.
curl 192.168.15.1:9091
See all options and their descriptions in the module file.