diff --git a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
index 6c8d881b15fc..797cb1f16939 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
@@ -229,6 +229,13 @@
services.prometheus.exporters.pve.
+
+
+ netbox,
+ infrastructure resource modeling (IRM) tool. Available as
+ services.netbox.
+
+
tetrd, share your
diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md
index 9aba688cb9b1..351ef6448289 100644
--- a/nixos/doc/manual/release-notes/rl-2205.section.md
+++ b/nixos/doc/manual/release-notes/rl-2205.section.md
@@ -67,6 +67,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- [prometheus-pve-exporter](https://github.com/prometheus-pve/prometheus-pve-exporter), a tool that exposes information from the Proxmox VE API for use by Prometheus. Available as [services.prometheus.exporters.pve](options.html#opt-services.prometheus.exporters.pve).
+- [netbox](https://github.com/netbox-community/netbox), infrastructure resource modeling (IRM) tool. Available as [services.netbox](options.html#opt-services.netbox.enable).
+
- [tetrd](https://tetrd.app), share your internet connection from your device to your PC and vice versa through a USB cable. Available at [services.tetrd](#opt-services.tetrd.enable).
- [agate](https://github.com/mbrubeck/agate), a very simple server for the Gemini hypertext protocol. Available as [services.agate](options.html#opt-services.agate.enable).
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index adeddbf139a3..a9ed8f251283 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -1048,6 +1048,7 @@
./services/web-apps/mediawiki.nix
./services/web-apps/miniflux.nix
./services/web-apps/moodle.nix
+ ./services/web-apps/netbox.nix
./services/web-apps/nextcloud.nix
./services/web-apps/nexus.nix
./services/web-apps/node-red.nix
diff --git a/nixos/modules/services/web-apps/netbox.nix b/nixos/modules/services/web-apps/netbox.nix
new file mode 100644
index 000000000000..a7d8bede74b4
--- /dev/null
+++ b/nixos/modules/services/web-apps/netbox.nix
@@ -0,0 +1,265 @@
+{ config, lib, pkgs, buildEnv, ... }:
+
+with lib;
+
+let
+ cfg = config.services.netbox;
+ staticDir = cfg.dataDir + "/static";
+ configFile = pkgs.writeTextFile {
+ name = "configuration.py";
+ text = ''
+ STATIC_ROOT = '${staticDir}'
+ ALLOWED_HOSTS = ['*']
+ DATABASE = {
+ 'NAME': 'netbox',
+ 'USER': 'netbox',
+ 'HOST': '/run/postgresql',
+ }
+
+ # Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate
+ # configuration exists for each. Full connection details are required in both sections, and it is strongly recommended
+ # to use two separate database IDs.
+ REDIS = {
+ 'tasks': {
+ 'URL': 'unix://${config.services.redis.servers.netbox.unixSocket}?db=0',
+ 'SSL': False,
+ },
+ 'caching': {
+ 'URL': 'unix://${config.services.redis.servers.netbox.unixSocket}?db=1',
+ 'SSL': False,
+ }
+ }
+
+ with open("${cfg.secretKeyFile}", "r") as file:
+ SECRET_KEY = file.readline()
+
+ ${optionalString cfg.enableLdap "REMOTE_AUTH_BACKEND = 'netbox.authentication.LDAPBackend'"}
+
+ ${cfg.extraConfig}
+ '';
+ };
+ pkg = (pkgs.netbox.overrideAttrs (old: {
+ installPhase = old.installPhase + ''
+ ln -s ${configFile} $out/opt/netbox/netbox/netbox/configuration.py
+ '' + optionalString cfg.enableLdap ''
+ ln -s ${ldapConfigPath} $out/opt/netbox/netbox/netbox/ldap_config.py
+ '';
+ })).override {
+ plugins = ps: ((cfg.plugins ps)
+ ++ optional cfg.enableLdap [ ps.django-auth-ldap ]);
+ };
+ netboxManageScript = with pkgs; (writeScriptBin "netbox-manage" ''
+ #!${stdenv.shell}
+ export PYTHONPATH=${pkg.pythonPath}
+ sudo -u netbox ${pkg}/bin/netbox "$@"
+ '');
+
+in {
+ options.services.netbox = {
+ enable = mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Enable Netbox.
+
+ This module requires a reverse proxy that serves /static separately.
+ See this example on how to configure this.
+ '';
+ };
+
+ listenAddress = mkOption {
+ type = types.str;
+ default = "[::1]";
+ description = ''
+ Address the server will listen on.
+ '';
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 8001;
+ description = ''
+ Port the server will listen on.
+ '';
+ };
+
+ plugins = mkOption {
+ type = types.functionTo (types.listOf types.package);
+ default = _: [];
+ defaultText = literalExpression ''
+ python3Packages: with python3Packages; [];
+ '';
+ description = ''
+ List of plugin packages to install.
+ '';
+ };
+
+ dataDir = mkOption {
+ type = types.str;
+ default = "/var/lib/netbox";
+ description = ''
+ Storage path of netbox.
+ '';
+ };
+
+ secretKeyFile = mkOption {
+ type = types.path;
+ description = ''
+ Path to a file containing the secret key.
+ '';
+ };
+
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ description = ''
+ Additional lines of configuration appended to the configuration.py.
+ See the documentation for more possible options.
+ '';
+ };
+
+ enableLdap = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Enable LDAP-Authentication for Netbox.
+
+ This requires a configuration file being pass through ldapConfigPath.
+ '';
+ };
+
+ ldapConfigPath = mkOption {
+ type = types.path;
+ default = "";
+ description = ''
+ Path to the Configuration-File for LDAP-Authentification, will be loaded as ldap_config.py.
+ See the documentation for possible options.
+ '';
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services.redis.servers.netbox.enable = true;
+
+ services.postgresql = {
+ enable = true;
+ ensureDatabases = [ "netbox" ];
+ ensureUsers = [
+ {
+ name = "netbox";
+ ensurePermissions = {
+ "DATABASE netbox" = "ALL PRIVILEGES";
+ };
+ }
+ ];
+ };
+
+ environment.systemPackages = [ netboxManageScript ];
+
+ systemd.targets.netbox = {
+ description = "Target for all NetBox services";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network-online.target" "redis-netbox.service" ];
+ };
+
+ systemd.services = let
+ defaultServiceConfig = {
+ WorkingDirectory = "${cfg.dataDir}";
+ User = "netbox";
+ Group = "netbox";
+ StateDirectory = "netbox";
+ StateDirectoryMode = "0750";
+ Restart = "on-failure";
+ };
+ in {
+ netbox-migration = {
+ description = "NetBox migrations";
+ wantedBy = [ "netbox.target" ];
+
+ environment = {
+ PYTHONPATH = pkg.pythonPath;
+ };
+
+ serviceConfig = defaultServiceConfig // {
+ Type = "oneshot";
+ ExecStart = ''
+ ${pkg}/bin/netbox migrate
+ '';
+ };
+ };
+
+ netbox = {
+ description = "NetBox WSGI Service";
+ wantedBy = [ "netbox.target" ];
+ after = [ "netbox-migration.service" ];
+
+ preStart = ''
+ ${pkg}/bin/netbox trace_paths --no-input
+ ${pkg}/bin/netbox collectstatic --no-input
+ ${pkg}/bin/netbox remove_stale_contenttypes --no-input
+ '';
+
+ environment = {
+ PYTHONPATH = pkg.pythonPath;
+ };
+
+ serviceConfig = defaultServiceConfig // {
+ ExecStart = ''
+ ${pkgs.python3Packages.gunicorn}/bin/gunicorn netbox.wsgi \
+ --bind ${cfg.listenAddress}:${toString cfg.port} \
+ --pythonpath ${pkg}/opt/netbox/netbox
+ '';
+ };
+ };
+
+ netbox-rq = {
+ description = "NetBox Request Queue Worker";
+ wantedBy = [ "netbox.target" ];
+ after = [ "netbox.service" ];
+
+ environment = {
+ PYTHONPATH = pkg.pythonPath;
+ };
+
+ serviceConfig = defaultServiceConfig // {
+ ExecStart = ''
+ ${pkg}/bin/netbox rqworker high default low
+ '';
+ };
+ };
+
+ netbox-housekeeping = {
+ description = "NetBox housekeeping job";
+ after = [ "netbox.service" ];
+
+ environment = {
+ PYTHONPATH = pkg.pythonPath;
+ };
+
+ serviceConfig = defaultServiceConfig // {
+ Type = "oneshot";
+ ExecStart = ''
+ ${pkg}/bin/netbox housekeeping
+ '';
+ };
+ };
+ };
+
+ systemd.timers.netbox-housekeeping = {
+ description = "Run NetBox housekeeping job";
+ wantedBy = [ "timers.target" ];
+
+ timerConfig = {
+ OnCalendar = "daily";
+ };
+ };
+
+ users.users.netbox = {
+ home = "${cfg.dataDir}";
+ isSystemUser = true;
+ group = "netbox";
+ };
+ users.groups.netbox = {};
+ users.groups."${config.services.redis.servers.netbox.user}".members = [ "netbox" ];
+ };
+}