nixpkgs/nixos/modules/services/web-servers/traefik.nix
Jade Lovelace 6c5ab28fce nixos: fix a bunch of services missing dep on network-online.target
This was done by generating a truly hilarious configuration:

rg 'services\.[^.]+\.enable\t' opts-tags | cut -f1 > allonconfig.nix

The following were not tested due to other evaluation errors. They
should probably be manually audited.
services.amule
services.castopod
services.ceph
services.chatgpt-retrieval-plugin
services.clamsmtp
services.clight
services.dante
services.dex
services.discourse
services.dwm-status
services.engelsystem
services.foundationdb
services.frigate
services.frp
services.grocy
services.guacamole-client
services.hedgedoc
services.home-assistant
services.honk
services.imaginary
services.jitsi-meet
services.kerberos_server
services.limesurvey
services.mastodon
services.mediawiki
services.mobilizon
services.moodle
services.mosquitto
services.nextcloud
services.nullmailer
services.patroni
services.pfix-srsd
services.pgpkeyserver-lite
services.postfixadmin
services.roundcube
services.schleuder
services.self-deploy
services.slskd
services.spacecookie
services.statsd
services.step-ca
services.sympa
services.tsmBackup
services.vdirsyncer
services.vikunja
services.yandex-disk
services.zabbixWeb
2024-01-19 00:11:34 -08:00

187 lines
5.1 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.traefik;
jsonValue = with types;
let
valueType = nullOr (oneOf [
bool
int
float
str
(lazyAttrsOf valueType)
(listOf valueType)
]) // {
description = "JSON value";
emptyValue.value = { };
};
in valueType;
dynamicConfigFile = if cfg.dynamicConfigFile == null then
pkgs.runCommand "config.toml" {
buildInputs = [ pkgs.remarshal ];
preferLocalBuild = true;
} ''
remarshal -if json -of toml \
< ${
pkgs.writeText "dynamic_config.json"
(builtins.toJSON cfg.dynamicConfigOptions)
} \
> $out
''
else
cfg.dynamicConfigFile;
staticConfigFile = if cfg.staticConfigFile == null then
pkgs.runCommand "config.toml" {
buildInputs = [ pkgs.yj ];
preferLocalBuild = true;
} ''
yj -jt -i \
< ${
pkgs.writeText "static_config.json" (builtins.toJSON
(recursiveUpdate cfg.staticConfigOptions {
providers.file.filename = "${dynamicConfigFile}";
}))
} \
> $out
''
else
cfg.staticConfigFile;
finalStaticConfigFile =
if cfg.environmentFiles == []
then staticConfigFile
else "/run/traefik/config.toml";
in {
options.services.traefik = {
enable = mkEnableOption (lib.mdDoc "Traefik web server");
staticConfigFile = mkOption {
default = null;
example = literalExpression "/path/to/static_config.toml";
type = types.nullOr types.path;
description = lib.mdDoc ''
Path to traefik's static configuration to use.
(Using that option has precedence over `staticConfigOptions` and `dynamicConfigOptions`)
'';
};
staticConfigOptions = mkOption {
description = lib.mdDoc ''
Static configuration for Traefik.
'';
type = jsonValue;
default = { entryPoints.http.address = ":80"; };
example = {
entryPoints.web.address = ":8080";
entryPoints.http.address = ":80";
api = { };
};
};
dynamicConfigFile = mkOption {
default = null;
example = literalExpression "/path/to/dynamic_config.toml";
type = types.nullOr types.path;
description = lib.mdDoc ''
Path to traefik's dynamic configuration to use.
(Using that option has precedence over `dynamicConfigOptions`)
'';
};
dynamicConfigOptions = mkOption {
description = lib.mdDoc ''
Dynamic configuration for Traefik.
'';
type = jsonValue;
default = { };
example = {
http.routers.router1 = {
rule = "Host(`localhost`)";
service = "service1";
};
http.services.service1.loadBalancer.servers =
[{ url = "http://localhost:8080"; }];
};
};
dataDir = mkOption {
default = "/var/lib/traefik";
type = types.path;
description = lib.mdDoc ''
Location for any persistent data traefik creates, ie. acme
'';
};
group = mkOption {
default = "traefik";
type = types.str;
example = "docker";
description = lib.mdDoc ''
Set the group that traefik runs under.
For the docker backend this needs to be set to `docker` instead.
'';
};
package = mkPackageOption pkgs "traefik" { };
environmentFiles = mkOption {
default = [];
type = types.listOf types.path;
example = [ "/run/secrets/traefik.env" ];
description = lib.mdDoc ''
Files to load as environment file. Environment variables from this file
will be substituted into the static configuration file using envsubst.
'';
};
};
config = mkIf cfg.enable {
systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0700 traefik traefik - -" ];
systemd.services.traefik = {
description = "Traefik web server";
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
startLimitIntervalSec = 86400;
startLimitBurst = 5;
serviceConfig = {
EnvironmentFile = cfg.environmentFiles;
ExecStartPre = lib.optional (cfg.environmentFiles != [])
(pkgs.writeShellScript "pre-start" ''
umask 077
${pkgs.envsubst}/bin/envsubst -i "${staticConfigFile}" > "${finalStaticConfigFile}"
'');
ExecStart = "${cfg.package}/bin/traefik --configfile=${finalStaticConfigFile}";
Type = "simple";
User = "traefik";
Group = cfg.group;
Restart = "on-failure";
AmbientCapabilities = "cap_net_bind_service";
CapabilityBoundingSet = "cap_net_bind_service";
NoNewPrivileges = true;
LimitNPROC = 64;
LimitNOFILE = 1048576;
PrivateTmp = true;
PrivateDevices = true;
ProtectHome = true;
ProtectSystem = "full";
ReadWriteDirectories = cfg.dataDir;
RuntimeDirectory = "traefik";
};
};
users.users.traefik = {
group = "traefik";
home = cfg.dataDir;
createHome = true;
isSystemUser = true;
};
users.groups.traefik = { };
};
}