Innernet on NixOS

So I managed to get Innernet working on NixOS (I highly recommend Innernet), but I fell back to an approach more familiar to me coming from Debian land.

I understand that I should explore something like sops (which is in nixpkgs), or sops-nix (which you need to manually specify as an input in your system flakes config), to store your secrets, but I don’t know the difference quite yet and I can investigate that I can investigate later. One thing at a time.

But I do have some questions:

  1. I don’t see the etc/hosts file containing the names of my innernet peers. I do see resolveconf on my system, but perhaps I have not properly enabled it.
  2. I don’t seem to have a systemd unit for my innernet . This was automatically created for me in Debian, though I did have to create the innernet binary from the cargo source, as there is not yet a package
  3. I wonder what the proper way to do this in a good simple nixos configuration for an innernet peer would be. I have looked at some documentation which points in a helpful direction. I can get more sophisticated later.
  4. This could probably be a different topic, but I strongly prefer a hand-crafted nftable config to using ufw or firewalld, and have not really explored that yet in nixos

I’d be happy to create a newbie guide to this once I have the jigsaw puzzle in place

Thank you for your thoughts!

1 Like

Disclaimer: I do not know what “innernet” is, and therefore the following reply will be a generic reply to similar questions, and I leave out things that seem to be specific to “innernet”.

So the best is to actually package it. For a cargo-crate using rustPlatform.buildRustPackage would be the most common way.

https://nixos.org/manual/nixpkgs/stable/#rust

I think that a nixpkgs PR would be appreciated.

For this we use modules, especially systemd.services.*.

innernet/server/innernet-server@.service at cd105cc7c1ee7a306febd3c47c7fa3b455ed8f0d · tonarino/innernet · GitHub seems to exist, when creating the package you might want to throw it into $out/share/systemd (IIRC), then your module can just add it to systemd.packages and use systemd.services.<name> with an appropriate name to instantiate the template.

1 Like

Seems to be an alternative wg-based network, but hasn’t been audited to my knowledge.

Yes, it is a nice opensource service/tool that uses wiregaurd to create a secure private “internet” that will work using host names regardless of whether you are working from an office or a coffeeshop.

There is already nix package in nixpgks, and I have seen some sophisticated nix configurations.

see innernet for a description

and this post by johnae on a possible way of configuration in nixos

#/etc/nixos/flake.nix
{
  description = “NixOS configruration”;

  inputs = {
    nixpkgs.url = “github:NixOS/nixpkgs/nixos-unstable”;

    sops-nix = {                                                                  
      url = "github:mic92/sops-nix";                                              
      inputs.nixpkgs.follows = "nixpkgs";                                         
    };                                                                            

  };
  outputs = inputs@{ self, nixpkgs, sops-nix, … }:
    let
      lib = nixpkgs.lib;
    in {
    nixosConfigurations = {
      faline = lib.nixosSystem {
        system = “x86_64-linux”;
        modules = [
          ./configuration.nix
          sops-nix.nixosModules.sops
          # ./innernet.nix     # not enabled yet
        ];                                                                        
      };                                                                          
    };                                                                            
  };
}

the relevant lines from my configuration.nix:

#/etc/nixos/configuration.nix
{ config, lib, pkgs, … }:
{
  …
  boot.kernel.sysctl = {
    “net.ipv4.ip_forward” = 1;
    “net.ipv6.conf.all.forwarding” = 1;
  };
  …
  services = {
    …
    networking = {
      wireguard.enable = true;
      firewall.enable = false;     # to be revisited
    };
  };
  …
}


and a skeleton innernet.nix with bogus values:

#/etc/nixos/innernet.nix
{ pkgs, … }: {
  networking.wireguard.interfaces.wg0 = {
    ips = [ “10.80.0.2/24” ]; # Your innernet IP
    # Use a secret management tool for the privateKeyFile
    privateKeyFile = “/run/secrets/innernet-key”;

    peers = [                                                                     
      {                                                                           
        publicKey = "SERVER_PUBLIC_KEY";                                          
        allowedIPs = [ "10.80.0.0/24" ];                                          
        endpoint = "SERVER_IP:51820";                                             
        persistentKeepalive = 25;                                                 
      }                                                                           
    ];                                                                            
 };
}

I have good values for this from manually creating the innernet-server invite, and for now I will see if I can get this working with those, just creating a regular file for the private key.

And then look to see if I need to create a service for this, and the explore what’s the deal with the /etc/hosts file not including my peers

Anyway, thank you all for your kind advice. It is a very cool piece of software

1 Like

so this worked as far as getting a service working:

#/etc/nixos/configuration.nix
{ config, lib, pkgs, ... }:
{ ...
  networking.wireguard.enable = true;
  networking.firewall.enable = true;
  systemd.services."innernet-@<your name>" = {
    description = "innernet client for <your name>";
    wantedBy = [ "multi-user.target" ];
    after = [ "network-online.target" "nss-lookup.target" ];
    wants = [ "network-online.target" "nss-lookup.target" ];

    serviceConfig = {
      Type = "simple";
      Restart = "always";
      ExecStart = "${pkgs.innernet}/bin/innernet up <your-name>";
    };  
  ...
};

So that is working.

Now how to get it to update /etc/hosts and then flake or generalize and modularize this

1 Like

Ok. So /etc/hosts is unwriteable. Of course it is. However, I can redirect the generated host entries to a different file, and then use something like dnsmasq or unbound to pick up those extra entries.

The current roadblock I am running into is that while sudo innernet up pudu-collective --hosts-path /var/lib/innernet/hosts works perfectly, systemd is way too impatient, and I am not sure how to tell it to relax and wait a bit.

I have now:

#/etc/nixos/configuration.nix
{ config, lib, pkgs, ... }:
{ ...
  networking = {
    wireguard.enable = true;
    firewall.enable = true;
    firewall.allowedTCPPorts = [ 22 51820 ];
    firewall.allowedUDPPorts = [ 51820 ];
  };

  systemd.services."innernet-@pudu-collective" = {
    description = "innernet client for pudu-collective";
    wantedBy = [ "multi-user.target" ];
    after = [ "network-online.target" "nss-lookup.target" ];
    wants = [ "network-online.target" "nss-lookup.target" ];

    unitConfig = {
#      StartLimitInterval = "2m";
#      StartLimitBurst = 3;
    };

    serviceConfig = {
      Type = "simple";
      Restart = "always";
      ExecStart = "${pkgs.innernet}/bin/innernet up pudu-collective --hosts-path /var/lib/innernet/hosts";
    };

  };

But I am unsure how to instruct systemd to be more patient before killing the process and starting over

Thanks

Ok. This is better.

  systemd.services."innernet-@pudu-collective" = {
    description = "innernet client for pudu-collective";
    wantedBy = [ "multi-user.target" ];
    after = [ "network-online.target" "nss-lookup.target" ];
    wants = [ "network-online.target" "nss-lookup.target" ];

    unitConfig = {
      StartLimitInterval = 600;
      StartLimitBurst = 2;
    };

    serviceConfig = {
      Type = "simple";
      Restart = "on-failure";
#      TimeoutSec = 90000;
      ExecStart = "${pkgs.innernet}/bin/innernet up pudu-collective --hosts-path /var/lib/innernet/hosts";
    };

This actually works. Probably the values could be fine tuned, and certainly this could be refined and put into a flake or module. But simplicity and understanding take precedence at this point

1 Like

Ok. This is actually working now.

petrockette@faline:~$ ssh big-bambi.pudu-collective.wg
Linux big-bambi 6.19.14+deb14-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.19.14-1 (2026-04-25) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
You have new mail.
Last login: Mon Jun 22 18:34:34 2026 from 172.24.1.4
petrockette@big-bambi:~$ 

the key was adding:

    dnsmasq = {
      enable = true;
      alwaysKeepRunning = true;
      settings = {
        addn-hosts = "/var/lib/innernet/hosts";
      };
    };

and manually adjusting the permissions so /var/lib/innernet/hosts was readable

Next up: fail2ban, and the god-awful implicit nixos nftable rules

Better settings for the innernet systemd service:


  systemd.services."innernet@pudu-collective" = {
    description = "innernet client for pudu-collective";
    wantedBy = [ "multi-user.target" ];
    after = [ "network-online.target" "nss-lookup.target" ];
    wants = [ "network-online.target" "nss-lookup.target" ];

    unitConfig = {
#      StartLimitInterval = 600;
#      StartLimitBurst = 2;
    };

    serviceConfig = {
      Type = "simple";
      Restart = "always";
      # When the daemon exits, wait this amount of secs before restarting. Used to prevent StartLimitBurst
      # (5 by default) restarts happening within StartLimitIntervalSec (10 by default) after which systemd
      # would refrain from restarting innernet anymore.
      RestartSec = 10;
#      TimeoutSec = 90000;
      ExecStart = "${pkgs.innernet}/bin/innernet up pudu-collective --daemon --interval 60 --hosts-path /var/lib/innernet/hosts";
    };

  };
1 Like