{"id":13814685,"url":"https://github.com/chayleaf/nixos-router","last_synced_at":"2025-04-07T10:26:17.034Z","repository":{"id":177093375,"uuid":"657812840","full_name":"chayleaf/nixos-router","owner":"chayleaf","description":"A NixOS router framework","archived":false,"fork":false,"pushed_at":"2024-07-17T04:21:18.000Z","size":117,"stargazers_count":286,"open_issues_count":1,"forks_count":6,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-31T09:08:58.844Z","etag":null,"topics":["networking","nix","nixos","nixos-module","router"],"latest_commit_sha":null,"homepage":"","language":"Nix","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chayleaf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-23T23:17:14.000Z","updated_at":"2025-03-28T08:29:42.000Z","dependencies_parsed_at":"2023-10-01T17:14:18.102Z","dependency_job_id":"eb30de11-a814-4212-afc9-c8ff9d64aa32","html_url":"https://github.com/chayleaf/nixos-router","commit_stats":null,"previous_names":["chayleaf/nixos-router"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chayleaf%2Fnixos-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chayleaf%2Fnixos-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chayleaf%2Fnixos-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chayleaf%2Fnixos-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chayleaf","download_url":"https://codeload.github.com/chayleaf/nixos-router/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247634104,"owners_count":20970458,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["networking","nix","nixos","nixos-module","router"],"created_at":"2024-08-04T04:02:28.641Z","updated_at":"2025-04-07T10:26:17.002Z","avatar_url":"https://github.com/chayleaf.png","language":"Nix","funding_links":[],"categories":["Nix","NixOS Modules"],"sub_categories":[],"readme":"# nixos-router\n\nThis project has an ambitious goal of creating a framework for writing\nNixOS router configurations - in other words, being the\n[simple-nixos-mailserver](https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/)\nof the networking world, but without the \"simple\" part, because\nnetworking is hard. This may include complex features like running\nmultiple DHCP servers, using network namespaces, having interfaces turn\non and off while the rest of the system keeps working, etc.\n\nSadly, NixOS is written without such requirements in mind. That means\nthis project has to create the code from scratch. This is both a\nblessing and a curse - we can't reuse the existing code, but we can\nwrite new, better code that is more flexible.\n\nThat said, I'm not using this at an enterprise or an ISP, this is simply\nfor my home router config (yes, overkill, I know). So this is bound to\nnot fit everybody's needs right now. Obviously, I'm willing to add more\nfeatures even at the cost of breaking existing configs if necessary\n(after all, this project is in its infancy).\n\nI'll try to keep breaking changes to a minimum, but as I said, I can't\nguarantee they won't happen (even NixOS has them).\n\nThere are separate branches for stable NixOS versions (like the 24.05\nbranch for NixOS 24.05), each branch will only be supported until the\nnext stable NixOS release. Support entails non-breaking bugfixes and\ncertain backports. For nixos-unstable, use the master branch.\n\nI doubt it would be easy to upstream these changes to nixpkgs, as it\nwould introduce many breaking changes on top of breaking changes, so I\nam not willing to work on it. Some parts are more upstreamable, such as\nallowing JSON nftables rulesets, while other are less upstreamable,\nlike... most parts of this repo, which are a reimplementation of\nscripted networking, which some nixpkgs members want to get rid of in\ngeneral (in favor of systemd-networkd).\n\nWhen [this](https://github.com/systemd/systemd/issues/11103) gets\nclosed, I might be able to migrate to systemd-networkd. This may be the\ntime when `networking.interfaces` and this repo become compatible again.\n\nThis module expects you to use nftables, so it modifies NixOS's default\nsettings to use nftables. Firewall is still set to use iptables, but if\nyou set `networking.nftables.enable` to `true`, it should use nftables.\n\n## Roadmap\n\nI think the next logical step for this project is adding nftables\noptions for common scenarios like NAT, so this is what I want to do\nnext. Right now you're expected to create the nftables rules from\nscratch, but something like `networking.nat` (but with more\ncustomizability) could be nice. Another potential way to improve this is\nadding the missing virtual device types (currently only bridges and veth\npairs are supported; `networking` has bridge, bond, MacVLAN, 6-to-4,\nVLAN, Open vSwitch device support).\n\n## See also\n\n- [notnft](https://github.com/chayleaf/notnft) - a Nix DSL for writing\n  JSON nftables rules. If you use the included NixOS module, it is\n  automatically used for type checking JSON nftables rules.\n- [My router\n  config](https://github.com/chayleaf/dotfiles/blob/master/system/hosts/router/default.nix)\n  using this framework.\n\n## Options\n\nSee [the wiki](https://github.com/chayleaf/nixos-router/wiki/Options)\nfor an automatically built option list. This is a manually condensed\nversion of the option list.\n\n- `router.enable` - whether to do anything at all\n- `router.networkNamespaces` - per-network namespace config.\n  - A special namespace `default` is available for configuring the\n    default namespace.\n  - `\u003cnamespace\u003e.extraStartCommands` - extra commands to execute at\n    network namespace start\n  - `\u003cnamespace\u003e.extraStopCommands` - extra commands to execute at\n    network namespace stop\n  - `\u003cnamespace\u003e.rules` - IP routing rules to add for this namespace via\n    `ip rule`\n      - `\u003croute\u003e.ipv6` - whether this rule is an IPv6 rule\n      - `\u003croute\u003e.extraArgs` - arguments to pass to the `ip rule`\n        command. May be a list or a string.\n  - `\u003cnamespace\u003e.sysctl` - per-netns sysctl config\n    - This is useful because with separate network namespaces, sysctl\n      config is separate to some extent as well (e.g. forwarding rules)\n  - `\u003cnamespace\u003e.nftables` - nftables config to run in this namespace\n    (see `router.nftables` for options)\n    - Difference from `networking.nftables` - this supports JSON\n      rulesets, and lets you specify custom stop/reload rules, while\n      `networking.nftables` always flushes the ruleset on stop. Also, it\n      supports loading static rules and file-based rules at the same\n      time. One-way `networking.nftables` operability is supported.\n    - `\u003cnamespace\u003e.nftables.textFile` - `.nft` file to load\n    - `\u003cnamespace\u003e.nftables.textRules` - nft rules to load\n    - `\u003cnamespace\u003e.nftables.jsonFile` - `.json` file to load\n    - `\u003cnamespace\u003e.nftables.jsonRules` - JSON rules to load\n    - `\u003cnamespace\u003e.nftables.{stopTextFile,stopTextRules,stopJsonFile,stopJsonRules}` -\n      same as above, but get executed *before first start* and at\n      stop/reload time. Basically, they are supposed to undo the changes\n      this ruleset applies, or do nothing if it's not applied anyway.\n      They default to `flush ruleset` if no stop rules are set.\n- `router.tunnels.\u003cname\u003e` - IP tunnels\n  - `\u003ctunnel\u003e.mode` - tunnel mode (`gre | ipip | isatap | sit | vti`)\n  - `\u003ctunnel\u003e.remote` - remote address\n  - `\u003ctunnel\u003e.local` - local address\n  - `\u003ctunnel\u003e.ttl` - time to live\n- `router.veths.\u003cname\u003e` - veth pairs\n  - `\u003cveth\u003e.peerName` - peer name (second device to be created at the\n    same time)\n- `router.interfaces.\u003cname\u003e` - per-interface config\n  - Difference from `networking.interfaces` - it's just subtly\n    different... Many features were added that `networking.interfaces`\n    is incompatible with. This means you can't use it together with\n    `networking.interfaces`, as both `router.interfaces` and\n    `networking.interfaces` expect having to set the interfaces up.\n  - `\u003ciface\u003e.bridge` - bridge name to enslave this device to\n  - `\u003ciface\u003e.vlans.*` - VLAN filtering configuration\n    - `\u003cvlan\u003e.vid` - VLAN id filter\n    - `\u003cvlan\u003e.untagged` - whether this should match untagged traffic\n      (defaults to false)\n  - `\u003ciface\u003e.extraInitCommands` - extra commands to execute before\n    bridge/address configuration\n  - `\u003ciface\u003e.networkNamespace` - the network namespace where this device\n    and all dependent services will run\n  - `\u003ciface\u003e.dependentServices` - services that should depend on this\n    interface\n    - each is either a string (service name) or an attrset with the key\n      `service` and the rest being attrs to to pass to\n      `router-lib.mkServiceForIf'`, for example, you can set `inNetns`\n      to false to not use this interface's network namespace.\n  - `\u003ciface\u003e.systemdLink.linkConfig` - values to add to\n    [systemd.link(5)](https://www.freedesktop.org/software/systemd/man/systemd.link.html)\n    `[Link]` config for this interface\n  - `\u003ciface\u003e.systemdLink.matchConfig` - values to add to\n    [systemd.link(5)](https://www.freedesktop.org/software/systemd/man/systemd.link.html)\n    `[Match]` config for this interface. Defaults to `{ OriginalName =\n    \"\u003cinterface name\u003e\"; }`\n  - `\u003ciface\u003e.hostapd` - run hostapd to turn this device into a wireless\n    access point\n    - `\u003ciface\u003e.hostapd.enable` - enable hostapd\n    - `\u003ciface\u003e.hostapd.settings` - hostapd settings (attrset). See\n      example\n      [hostapd.conf](https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf)\n      for a list of options. Personally, I copied OpenWRT configs for\n      my router.\n    - There's a way to host multiple ssids on a single interface in\n      hostapd (on supported interfaces), this module doesn't currently\n      support it\n  - `\u003ciface\u003e.dhcpcd` - run `dhcpcd` on this interface.\n    - The reasons for adding it here:\n      - `dhcpcd` may fail in rare cases when not specifing the interface\n        list in the command line, which I do here.\n      - Strong caution is needed when running a single `dhcpcd` on many\n        interfaces, as settings may \"leak\" into other interfaces.\n        Example of an option you need to be careful with is IPv6 router\n        solicitation (ipv6rs).\n    - `\u003ciface\u003e.dhcpcd.enable` - enable dhcpcd on this interface\n    - `\u003ciface\u003e.dhcpcd.extraConfig` - extra text config for dhcpcd\n  - `\u003ciface\u003e.ipv4` - IPv4-specific config:\n    - `\u003ciface\u003e.ipv4.enableForwarding` - sets `forwarding` sysctl for\n      this device so it can forward packets it receives.\n    - `\u003ciface\u003e.ipv4.rpFilter` - set `rp_filter` value for this device to\n      check reverse path and block non-existent IPs (value 2) or IPs\n      coming from the wrong interfaces (value 1). Alternatively, you can\n      ignore this and query fib in nftables.\n    - `\u003ciface\u003e.ipv4.addresses` - IPv4 addresses of this device\n      - `\u003caddr\u003e.address` - the address\n      - `\u003caddr\u003e.prefixLength` - network prefix length\n      - `\u003caddr\u003e.assign` - whether to actually assign the address to this\n        device (defaults to `false` if the first octet is zero and\n        `true` otherwise). If not, it will simply be used as default\n        value for service config.\n      - `\u003caddr\u003e.gateways` - for DHCP servers - the IPv4 gateways for\n        this network. If not set, `address` is used as the sole gateway.\n      - `\u003caddr\u003e.dns` - for DHCP servers - IPv4 DNS servers for this\n        network.\n      - `\u003caddr\u003e.keaSettings` - prefix-specific Kea settings (only used\n        if Kea is enabled). `pools` has sane defaults (reserve 16\n        addresses before and after the interface address and\n        before and after prefix start/end, make the rest available\n        for DHCP clients), `option-data` defaults to whatever you\n        set in `gateways` and `dns`. If you want to unset those\n        settings, overwrite `pools` and `option-data` with empty\n        (or non-empty) lists.\n    - `\u003ciface\u003e.ipv4.routes` - List of IPv4 route to add when this device\n      is online.\n      - `\u003croute\u003e.extraArgs` - arguments to pass to the `ip -4 add`\n        command. May be a list or a string.\n      - There is no other options for `routes`, that's it.\n    - `\u003ciface\u003e.ipv4.kea` - Kea settings (maintained replacement for\n      dhcpd)\n      - `\u003ciface\u003e.ipv4.kea.enable` - enable Kea\n      - `\u003ciface\u003e.ipv4.kea.extraArgs` - extra args to pass to Kea\n      - `\u003ciface\u003e.ipv4.kea.configFile` - Kea config file (if this is set,\n        all other Kea settings are ignored)\n      - `\u003ciface\u003e.ipv4.kea.settings` - Kea settings. Defaults to one\n        `subnet4` (see `addresses.keaSettings` for a way to configure\n        it), `valid-lifetime = 4000`, `lease-database` set to a file at\n        `/var/lib/kea/dhcp4-${interface}.leases`, and obviously\n        `interfaces-config` set. You may overwrite any of it.\n  - `\u003ciface\u003e.ipv6` - IPv6-specific config:\n    - `\u003ciface\u003e.ipv6.enableForwarding` - sets `forwarding` sysctl for\n      this device so it can forward packets it receives. Obviously,\n      you better setup a firewall if you do this.\n    - `\u003ciface\u003e.ipv6.addresses` - List of IPv6 addresses of this device\n      - `\u003caddr\u003e.address` - the address\n      - `\u003caddr\u003e.prefixLength` - network prefix length\n      - `\u003caddr\u003e.assign` - whether to actually assign the address to this\n        device (defaults to `false` if the first octet is zero and\n        `true` otherwise). Otherwise, it will simply be used as\n        default value for service config.\n      - `\u003caddr\u003e.gateways` - for DHCP servers - the IPv6 gateways for\n        this network. If empty, I don't know what happens, you guess.\n        - Each gateway may be a string in the CIDR notation.\n          Alternatively, it may be an attrset with the following\n          attrs:\n        - `\u003cgateway\u003e.address` - the address\n        - `\u003cgateway\u003e.prefixLength` - network prefix length\n        - `\u003cgateway\u003e.radvdSettings` - radvd `route` settings for this\n          gateway (attrset)\n        - `\u003cgateway\u003e.coreradSettings` - CoreRAD `route` settings for\n          this gateway (attrset)\n      - `\u003caddr\u003e.dns` - for DHCP servers - IPv6 DNS servers for this\n        network.\n        - Each DNS server may be a string (the DNS address).\n          Alternatively, if may be an attrset with the following attrs:\n          - `address` - the DNS server address\n          - `radvdSettings` - radvd `RDNSS` settings for this\n            DNS server (attrset)\n          - `coreradSettings` - CoreRAD `rdnss` settings for this\n            DNS server (attrset)\n      - `\u003caddr\u003e.keaSettings` - prefix-specific Kea settings (only used\n        if Kea is enabled). `pools` has sane defaults (reserve 16\n        addresses before and after the interface address and\n        before and after prefix start/end, make the rest available\n        for DHCP clients), `option-data` defaults to whatever you\n        set in `dns`. If you want to unset it settings, overwrite\n        `pools` and `option-data` with empty (or non-empty) lists.\n      - `\u003caddr\u003e.radvdSettings` - radvd per-prefix settings (attrset).\n        `AdvAutonomous` defaults to `true` if `AdvManagedFlag` is set to\n        true in per-interface radvd settings.\n      - `\u003caddr\u003e.coreradSettings` - CoreRAD per-prefix settings\n        (attrset). `autonomous` defaults to `true` if `managed` is set\n        to true in per-interface CoreRAD settings.\n    - `\u003ciface\u003e.ipv6.routes` - List of IPv6 routes to add when this\n      device is online.\n      - `\u003croute\u003e.extraArgs` - arguments to pass to the `ip -6 add`\n        command. May be a list or a string.\n      - There is no other options for `routes`, that's it.\n    - `\u003ciface\u003e.ipv6.kea` - Kea settings (maintained replacement for\n      dhcpd)\n      - `\u003ciface\u003e.ipv6.kea.enable` - enable Kea\n      - `\u003ciface\u003e.ipv6.kea.extraArgs` - extra args to pass to Kea\n      - `\u003ciface\u003e.ipv6.kea.configFile` - Kea config file (if this is set,\n        all other Kea settings are ignored)\n      - `\u003ciface\u003e.ipv6.kea.settings` - Kea settings. Defaults to one\n        `subnet6` (see `addresses.*.keaSettings` for a way to configure\n        it), `valid-lifetime = 4000`, `preferred-lifetime = 3000`\n        `lease-database` set to a file at\n        `/var/lib/kea/dhcp6-${interface}.leases`, and obviously\n        `interfaces-config` set. You may overwrite any of it.\n    - `\u003ciface\u003e.ipv6.radvd` - radvd settings (IPv6 router advertisement\n      daemon)\n      - `\u003ciface\u003e.ipv6.radvd.enable` - enable radvd\n      - `\u003ciface\u003e.ipv6.radvd.interfaceSettings` - per-interface settings\n        (attrs). Defaults to `AdvSendAdvert = true`, if any DHCP server\n        (e.g. Kea) is enabled then `AdvManagedFlag` and\n        `AdvOtherConfigFlag` default to true as well.\n    - `\u003ciface\u003e.ipv6.corerad` - CoreRAD settings (IPv6 router\n      advertisement daemon)\n      - `\u003ciface\u003e.ipv6.corerad.enable` - enable radvd\n      - `\u003ciface\u003e.ipv6.corerad.interfaceSettings` - per-interface\n        settings (attrs). Defaults to `advertise = true`, if any DHCP\n        server (e.g. Kea) is enabled then `managed` and `other_config`\n        default to true as well.\n      - `\u003ciface\u003e.ipv6.corerad.settings` - general CoreRAD settings\n        (useful for setting `debug` options)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchayleaf%2Fnixos-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchayleaf%2Fnixos-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchayleaf%2Fnixos-router/lists"}