Fail-closed WireGuard confinement for selected NixOS systemd services.
Give each service group a network namespace with WireGuard, default-drop
nftables, and its own DNS policy. Other host services keep their normal routes.
The project targets NixOS unstable and the networking.wireguard.interfaces
backend.
Follow the complete Transmission recipe
for a working application with persistent downloads, persistent secrets, and an
authenticated local Web UI. The actual configuration is in
examples/transmission.nix and is covered by a VM test.
For an existing service, add the flake input:
inputs.vpn-confinement.url = "github:nix-forge/vpn-confinement";
inputs.vpn-confinement.inputs.nixpkgs.follows = "nixpkgs";Import inputs.vpn-confinement.nixosModules.default, configure the namespace and
WireGuard interface using your provider's values, and select the service:
systemd.services.your-service.vpn = {
enable = true;
namespace = "downloads";
};A service or socket declaring vpn.enable = true requires the global module to
be enabled. Contradictory settings fail evaluation instead of dropping confinement.
Inspect your deployment without sending external requests or exposing keys:
sudo vpn-confinement-doctor
sudo vpn-confinement-doctor downloads --jsonNamespace routing and nftables prevent ordinary clearnet fallback. Strict DNS and IPv6 disable are defaults. Inline and store-backed WireGuard keys are rejected by default. Keep file-based secrets outside the world-readable Nix store.
An ISP still sees the VPN connection and traffic patterns. This is protection against direct traffic leakage, not a promise of anonymity. Host sockets, privileged helpers, application tracking, and the VPN operator require separate consideration. Read the threat model.
A remote VPN outage can leave an application running with traffic stalled. Stopping a managed WireGuard unit stops dependent services; restarting it restarts previously active consumers. See the architecture for exact lifecycle behavior.
Use balanced for services such as torrents that need changing destinations.
Service hardening can independently be set to strict. Use highAssurance for
narrow destination allowlists and stronger assertions.
publishToHost.tcp permits host ingress over a veth. It does not create a localhost
listener, reverse proxy, or VPN-provider port forward. The Transmission example
provides the local proxy explicitly.
- Setup and Transmission
- Diagnostics
- Common deployments
- Generated options
- Performance measurements
- Documentation site
- Format:
nix fmt - Check:
nix flake check --show-trace --system x86_64-linux - Regenerate options:
bash scripts/generate-options-doc.sh x86_64-linux - Build docs:
bun install --cwd site --frozen-lockfile && bun run --cwd site build - Run the optional local benchmark:
nix build .#vpn-benchmark
Runtime VM checks run on x86_64 Linux. ARM checks currently evaluate configuration;
they do not provide equivalent VM coverage. The benchmark's raw results are in
result/benchmark.json and describe a synthetic local tunnel.
See CONTRIBUTING.md and SECURITY.md. Licensed under MIT.
