nixos/netbox: add opt-in nginx support
This is part of making way for simpler onboarding, because it stops requiring users to guess where to point the static directory to.
This commit is contained in:
@@ -10,6 +10,7 @@ let
|
||||
any
|
||||
attrValues
|
||||
mkChangedOptionModule
|
||||
mkEnableOption
|
||||
mkOption
|
||||
mkRemovedOptionModule
|
||||
mkRenamedOptionModule
|
||||
@@ -132,8 +133,9 @@ in
|
||||
description = ''
|
||||
Whether to enable Netbox, a DCIM and IPAM source of truth.
|
||||
|
||||
This module requires setting up a reverse proxy. The NetBox project has
|
||||
example configurations for [nginx] and the [Apache httpd] server.
|
||||
This module requires setting up a reverse proxy and has native support
|
||||
for nginx. Additionally, the NetBox project has example configurations
|
||||
for [nginx] and the [Apache httpd] server.
|
||||
|
||||
The important change to make is to serve `/static` from
|
||||
`''${config.services.netbox.settings.STATIC_ROOT}`.
|
||||
@@ -392,6 +394,23 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
nginx = {
|
||||
enable = mkEnableOption "nginx and configure a virtual host";
|
||||
|
||||
hostname = mkOption {
|
||||
type = types.str;
|
||||
example = "netbox.example.com";
|
||||
description = ''
|
||||
The hostname for which an nginx virtual host should be created.
|
||||
|
||||
::: {.tip}
|
||||
Customize the virtual host through
|
||||
`services.nginx.virtualHosts.''${config.services.netbox.nginx.hostname}`.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
redis.createLocally = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@@ -539,139 +558,164 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.netbox.plugins = lib.mkIf enableLDAP (ps: [ ps.django-auth-ldap ]);
|
||||
|
||||
services.redis.servers.netbox.enable = cfg.redis.createLocally;
|
||||
|
||||
services.postgresql = lib.mkIf cfg.postgresql.createLocally {
|
||||
enable = true;
|
||||
ensureDatabases = [ "netbox" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "netbox";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
environment.systemPackages = [ netboxManageScript ];
|
||||
|
||||
systemd.slices.system-netbox = {
|
||||
description = "Netbox DCIM/IPAM";
|
||||
};
|
||||
|
||||
systemd.targets.netbox = {
|
||||
description = "Target for all NetBox services";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
"redis-netbox.service"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services =
|
||||
let
|
||||
defaultUnitConfig = {
|
||||
documentation = [ "https://netboxlabs.com/docs/netbox/" ];
|
||||
environment.PYTHONPATH = finalPackage.pythonPath;
|
||||
};
|
||||
defaultServiceConfig = {
|
||||
WorkingDirectory = "${cfg.dataDir}";
|
||||
User = "netbox";
|
||||
Group = "netbox";
|
||||
StateDirectory = "netbox";
|
||||
StateDirectoryMode = "0750";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 30;
|
||||
Slice = "system-netbox.slice";
|
||||
EnvironmentFile = cfg.environmentFiles;
|
||||
};
|
||||
in
|
||||
config = lib.mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
netbox = defaultUnitConfig // {
|
||||
description = "NetBox WSGI Service";
|
||||
services.netbox.plugins = lib.mkIf enableLDAP (ps: [ ps.django-auth-ldap ]);
|
||||
|
||||
wantedBy = [ "netbox.target" ];
|
||||
services.redis.servers.netbox.enable = cfg.redis.createLocally;
|
||||
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
|
||||
preStart = ''
|
||||
# Generate random default secrets, if the user didn't supply any.
|
||||
${optionalString (cfg.secretKeyFile == null) ''
|
||||
if [ ! -e "${secretKeyFile}" ]; then
|
||||
${finalPackage}/opt/netbox/netbox/generate_secret_key.py > "${secretKeyFile}"
|
||||
fi
|
||||
''}
|
||||
${optionalString
|
||||
(any (path: path == "${cfg.dataDir}/pepper.1") (attrValues cfg.apiTokenPepperFiles))
|
||||
''
|
||||
if [ ! -e "${cfg.dataDir}/pepper.1" ]; then
|
||||
${finalPackage}/opt/netbox/netbox/generate_secret_key.py > "${cfg.dataDir}/pepper.1"
|
||||
fi
|
||||
''
|
||||
services.postgresql = lib.mkIf cfg.postgresql.createLocally {
|
||||
enable = true;
|
||||
ensureDatabases = [ "netbox" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "netbox";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# On the first run, or on upgrade / downgrade, run migrations and related.
|
||||
# This mostly correspond to upstream NetBox's 'upgrade.sh' script.
|
||||
versionFile="${cfg.dataDir}/version"
|
||||
environment.systemPackages = [ netboxManageScript ];
|
||||
|
||||
if [[ -h "$versionFile" && "$(readlink -- "$versionFile")" == "${cfg.package}" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
systemd.slices.system-netbox = {
|
||||
description = "Netbox DCIM/IPAM";
|
||||
};
|
||||
|
||||
${lib.getExe finalPackage} migrate
|
||||
${lib.getExe finalPackage} trace_paths --no-input
|
||||
${lib.getExe finalPackage} collectstatic --clear --no-input
|
||||
${lib.getExe finalPackage} remove_stale_contenttypes --no-input
|
||||
${lib.getExe finalPackage} reindex --lazy
|
||||
${lib.getExe finalPackage} clearsessions
|
||||
systemd.targets.netbox = {
|
||||
description = "Target for all NetBox services";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [
|
||||
"network-online.target"
|
||||
"redis-netbox.service"
|
||||
];
|
||||
};
|
||||
|
||||
ln -sfn "${cfg.package}" "$versionFile"
|
||||
'';
|
||||
systemd.services =
|
||||
let
|
||||
defaultUnitConfig = {
|
||||
documentation = [ "https://netboxlabs.com/docs/netbox/" ];
|
||||
environment.PYTHONPATH = finalPackage.pythonPath;
|
||||
};
|
||||
defaultServiceConfig = {
|
||||
WorkingDirectory = "${cfg.dataDir}";
|
||||
User = "netbox";
|
||||
Group = "netbox";
|
||||
StateDirectory = "netbox";
|
||||
StateDirectoryMode = "0750";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 30;
|
||||
Slice = "system-netbox.slice";
|
||||
EnvironmentFile = cfg.environmentFiles;
|
||||
};
|
||||
in
|
||||
{
|
||||
netbox = defaultUnitConfig // {
|
||||
description = "NetBox WSGI Service";
|
||||
|
||||
serviceConfig = defaultServiceConfig // {
|
||||
ExecStart = toString (
|
||||
[
|
||||
(lib.getExe finalPackage.gunicorn)
|
||||
"netbox.wsgi"
|
||||
]
|
||||
++ lib.cli.toCommandLineGNU { } (
|
||||
{
|
||||
inherit (cfg) bind;
|
||||
pythonpath = "${finalPackage}/opt/netbox/netbox";
|
||||
wantedBy = [ "netbox.target" ];
|
||||
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
|
||||
preStart = ''
|
||||
# Generate random default secrets, if the user didn't supply any.
|
||||
${optionalString (cfg.secretKeyFile == null) ''
|
||||
if [ ! -e "${secretKeyFile}" ]; then
|
||||
${finalPackage}/opt/netbox/netbox/generate_secret_key.py > "${secretKeyFile}"
|
||||
fi
|
||||
''}
|
||||
${optionalString
|
||||
(any (path: path == "${cfg.dataDir}/pepper.1") (attrValues cfg.apiTokenPepperFiles))
|
||||
''
|
||||
if [ ! -e "${cfg.dataDir}/pepper.1" ]; then
|
||||
${finalPackage}/opt/netbox/netbox/generate_secret_key.py > "${cfg.dataDir}/pepper.1"
|
||||
fi
|
||||
''
|
||||
}
|
||||
// cfg.gunicorn.extraArgs
|
||||
)
|
||||
);
|
||||
PrivateTmp = true;
|
||||
RuntimeDirectory = "netbox";
|
||||
TimeoutStartSec = lib.mkDefault "10min";
|
||||
|
||||
# On the first run, or on upgrade / downgrade, run migrations and related.
|
||||
# This mostly correspond to upstream NetBox's 'upgrade.sh' script.
|
||||
versionFile="${cfg.dataDir}/version"
|
||||
|
||||
if [[ -h "$versionFile" && "$(readlink -- "$versionFile")" == "${cfg.package}" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
${lib.getExe finalPackage} migrate
|
||||
${lib.getExe finalPackage} trace_paths --no-input
|
||||
${lib.getExe finalPackage} collectstatic --clear --no-input
|
||||
${lib.getExe finalPackage} remove_stale_contenttypes --no-input
|
||||
${lib.getExe finalPackage} reindex --lazy
|
||||
${lib.getExe finalPackage} clearsessions
|
||||
|
||||
ln -sfn "${cfg.package}" "$versionFile"
|
||||
'';
|
||||
|
||||
serviceConfig = defaultServiceConfig // {
|
||||
ExecStart = toString (
|
||||
[
|
||||
(lib.getExe finalPackage.gunicorn)
|
||||
"netbox.wsgi"
|
||||
]
|
||||
++ lib.cli.toCommandLineGNU { } (
|
||||
{
|
||||
inherit (cfg) bind;
|
||||
pythonpath = "${finalPackage}/opt/netbox/netbox";
|
||||
}
|
||||
// cfg.gunicorn.extraArgs
|
||||
)
|
||||
);
|
||||
PrivateTmp = true;
|
||||
RuntimeDirectory = "netbox";
|
||||
RuntimeDirectoryMode = "0750";
|
||||
TimeoutStartSec = lib.mkDefault "10min";
|
||||
};
|
||||
};
|
||||
|
||||
netbox-rq = defaultUnitConfig // {
|
||||
description = "NetBox Request Queue Worker";
|
||||
|
||||
wantedBy = [ "netbox.target" ];
|
||||
after = [ "netbox.service" ];
|
||||
|
||||
serviceConfig = defaultServiceConfig // {
|
||||
ExecStart = toString [
|
||||
(lib.getExe finalPackage)
|
||||
"rqworker"
|
||||
"high"
|
||||
"default"
|
||||
"low"
|
||||
];
|
||||
PrivateTmp = true;
|
||||
};
|
||||
};
|
||||
|
||||
netbox-housekeeping = defaultUnitConfig // {
|
||||
description = "NetBox housekeeping job";
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
after = [
|
||||
"network-online.target"
|
||||
"netbox.service"
|
||||
];
|
||||
wants = [ "network-online.target" ];
|
||||
|
||||
serviceConfig = defaultServiceConfig // {
|
||||
Type = "oneshot";
|
||||
ExecStart = toString [
|
||||
(lib.getExe finalPackage)
|
||||
"housekeeping"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
netbox-rq = defaultUnitConfig // {
|
||||
description = "NetBox Request Queue Worker";
|
||||
|
||||
wantedBy = [ "netbox.target" ];
|
||||
after = [ "netbox.service" ];
|
||||
|
||||
serviceConfig = defaultServiceConfig // {
|
||||
ExecStart = toString [
|
||||
(lib.getExe finalPackage)
|
||||
"rqworker"
|
||||
"high"
|
||||
"default"
|
||||
"low"
|
||||
];
|
||||
PrivateTmp = true;
|
||||
};
|
||||
};
|
||||
|
||||
netbox-housekeeping = defaultUnitConfig // {
|
||||
description = "NetBox housekeeping job";
|
||||
systemd.timers.netbox-housekeeping = {
|
||||
description = "Run NetBox housekeeping job";
|
||||
documentation = [ "https://netboxlabs.com/docs/netbox/" ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
@@ -681,41 +725,36 @@ in
|
||||
];
|
||||
wants = [ "network-online.target" ];
|
||||
|
||||
serviceConfig = defaultServiceConfig // {
|
||||
Type = "oneshot";
|
||||
ExecStart = toString [
|
||||
(lib.getExe finalPackage)
|
||||
"housekeeping"
|
||||
];
|
||||
timerConfig = {
|
||||
OnCalendar = "daily";
|
||||
AccuracySec = "1h";
|
||||
Persistent = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.timers.netbox-housekeeping = {
|
||||
description = "Run NetBox housekeeping job";
|
||||
documentation = [ "https://netboxlabs.com/docs/netbox/" ];
|
||||
users.users.netbox = {
|
||||
home = "${cfg.dataDir}";
|
||||
isSystemUser = true;
|
||||
group = "netbox";
|
||||
};
|
||||
users.groups.netbox = { };
|
||||
users.groups."${config.services.redis.servers.netbox.user}".members = [ "netbox" ];
|
||||
}
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
(lib.mkIf cfg.nginx.enable {
|
||||
# Access to STATIC_ROOT and the UNIX domain socket
|
||||
systemd.services.nginx.serviceConfig.SupplementaryGroups = [ "netbox" ];
|
||||
|
||||
after = [
|
||||
"network-online.target"
|
||||
"netbox.service"
|
||||
];
|
||||
wants = [ "network-online.target" ];
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedProxySettings = true;
|
||||
|
||||
timerConfig = {
|
||||
OnCalendar = "daily";
|
||||
AccuracySec = "1h";
|
||||
Persistent = true;
|
||||
};
|
||||
};
|
||||
|
||||
users.users.netbox = {
|
||||
home = "${cfg.dataDir}";
|
||||
isSystemUser = true;
|
||||
group = "netbox";
|
||||
};
|
||||
users.groups.netbox = { };
|
||||
users.groups."${config.services.redis.servers.netbox.user}".members = [ "netbox" ];
|
||||
};
|
||||
virtualHosts.${cfg.nginx.hostname} = {
|
||||
locations."/".proxyPass = "http://${toString config.services.netbox.bind}";
|
||||
locations."/static/".alias = cfg.settings.STATIC_ROOT;
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,17 +34,10 @@ in
|
||||
# Pick the NetBox package from this config's "pkgs" argument,
|
||||
# so that `nixpkgs.config.permittedInsecurePackages` works
|
||||
package = pkgs.${oldNetbox};
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
recommendedProxySettings = true;
|
||||
|
||||
virtualHosts.netbox = {
|
||||
default = true;
|
||||
locations."/".proxyPass = "http://${config.services.netbox.bind}";
|
||||
locations."/static/".alias = "/var/lib/netbox/static/";
|
||||
nginx = {
|
||||
enable = true;
|
||||
hostname = "localhost";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -34,6 +34,11 @@ import ../../make-test-python.nix (
|
||||
enable = true;
|
||||
package = netbox;
|
||||
|
||||
nginx = {
|
||||
enable = true;
|
||||
hostname = "localhost";
|
||||
};
|
||||
|
||||
ldapConfigFile = pkgs.writeText "ldap_config.py" ''
|
||||
import ldap
|
||||
from django_auth_ldap.config import LDAPSearch, PosixGroupType
|
||||
@@ -61,18 +66,6 @@ import ../../make-test-python.nix (
|
||||
'';
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
recommendedProxySettings = true;
|
||||
|
||||
virtualHosts.netbox = {
|
||||
default = true;
|
||||
locations."/".proxyPass = "http://${toString config.services.netbox.bind}";
|
||||
locations."/static/".alias = "/var/lib/netbox/static/";
|
||||
};
|
||||
};
|
||||
|
||||
# Adapted from the sssd-ldap NixOS test
|
||||
services.openldap = {
|
||||
enable = true;
|
||||
|
||||
Reference in New Issue
Block a user