let hostIp = "192.168.1.10"; in { config, ... }: { networking = { # Label lan and wan interfaces _interfaceLabels = { enable = true; interfaces.lan0 = "50:9a:4c:5d:c3:7a"; interfaces.lan1 = "50:9a:4c:5d:c3:7a"; interfaces.lan2 = "50:9a:4c:5d:c3:7a"; interfaces.wan0 = "50:9a:4c:5d:c3:7b"; }; # Create bridged lan interface for all containers bridges.br-lan0.interfaces = [ "lan0" ]; # Disable dhcp on router interfaces interfaces = { veth-router-lan.useDHCP = false; vb-router-lan0.useDHCP = false; }; # Configure network defaultGateway = "10.255.255.1"; # Read explaination for veth-router-lan below nameservers = [ "192.168.1.1" ]; # DNS will only be available from this ip address THROUGH the default gateway # br-lan0 will be the interface used for networking on poweredge host interfaces.br-lan0.ipv4.addresses = [{ address = hostIp; prefixLength = 24; }]; }; # Router container containers.router = { autoStart = true; ephemeral = true; privateNetwork = true; # Pass wan0 directly into container since it isn't needed elsewhere interfaces = [ "wan0" ]; # Setup router lan0 # NOTE: Host/container communication is not possible through a hostBridge interface extraVeths.vb-router-lan0.hostBridge = "br-lan0"; # Setup virtual host-router bridge interface. # This is the default gateway for host/container communication since # communication isn't possible through hostBridge interfaces. # This is essentially equivalent to connecting the host to the # container with a virtual ethernet cable on a separate interface. extraVeths.veth-router-lan = { hostAddress = "10.255.255.2"; localAddress = "10.255.255.1"; }; # Bind wg0-router secret to container bindMounts."/run/secrets/wg0" = { hostPath = config.sops.secrets.wg0-router.path; isReadOnly = true; }; config = { lib, config, ... }: { imports = [ ../../nixos/services/router ./router-hosts.nix # Contains dhcp config + static leases + overrides ]; networking = { # Set ip addresses enableIPv6 = false; interfaces = { vb-router-lan0.ipv4.addresses = [{ address = "192.168.1.1"; prefixLength = 24; }]; wan0.ipv4.addresses = [ # .163 address reserved for remote backup access { address = "46.110.173.161"; prefixLength = 29; } # Gateway { address = "46.110.173.162"; prefixLength = 29; } # Mail { address = "46.110.173.164"; prefixLength = 29; } # Web { address = "46.110.173.165"; prefixLength = 29; } # Wg { address = "46.110.173.166"; prefixLength = 29; } # Spare ]; }; defaultGateway = { address = "46.110.173.161"; interface = "wan0"; }; # NAT (port-forwarding) rules nat.forwardPorts =[ #{ # Filebrowser # sourcePort = 19045; # proto = "tcp"; # destination = "192.168.1.45:9000"; #} ]; }; # Setup router services._router = { dnsDhcpConfig.enable = true; routing = { enable = true; interfaces = { lan = [ "vb-router-lan0" "veth-router-lan" ]; wan = "wan0"; }; }; }; services.unbound._blocklists = { enable = true; hageziBlocklists = [ "pro" "nsfw" ]; }; system.stateVersion = "26.05"; }; }; # FIXME the following snippet will cause the router container to fail to start: # networking.defaultGateway = { # address = "10.255.255.1"; # interface = "veth-router-lan"; # }; # Journalctl will report: # poweredge container router: Bring veth-router-lan up # poweredge container router: RTNETLINK answers: File exists # poweredge systemd: container@router.service: Control process exited, code=exited, status=2/INVALIDARGUMENT # So the issue nixos is creating an interface with that same name. # As a temporary workaround, the following service is deployed (after the container starts): systemd.services.router-default-route = { after = [ "container@router.service" ]; wants = [ "container@router.service" ]; serviceConfig.Type = "oneshot"; script = '' /run/current-system/sw/bin/ip route replace default via 10.255.255.1 dev veth-router-lan ''; wantedBy = [ "multi-user.target" ]; }; }