2017-09-27 16:30:49 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.services.traefik;
|
2020-02-08 11:38:38 +00:00
|
|
|
jsonValue = with types;
|
|
|
|
let
|
|
|
|
valueType = nullOr (oneOf [
|
|
|
|
bool
|
|
|
|
int
|
|
|
|
float
|
|
|
|
str
|
|
|
|
(lazyAttrsOf valueType)
|
|
|
|
(listOf valueType)
|
|
|
|
]) // {
|
|
|
|
description = "JSON value";
|
|
|
|
emptyValue.value = { };
|
|
|
|
};
|
|
|
|
in valueType;
|
2019-12-31 00:41:18 +00:00
|
|
|
dynamicConfigFile = if cfg.dynamicConfigFile == null then
|
|
|
|
pkgs.runCommand "config.toml" {
|
2020-06-29 07:34:41 +00:00
|
|
|
buildInputs = [ pkgs.remarshal ];
|
2019-12-31 00:41:18 +00:00
|
|
|
preferLocalBuild = true;
|
|
|
|
} ''
|
2020-06-29 07:34:41 +00:00
|
|
|
remarshal -if json -of toml \
|
2019-12-31 00:41:18 +00:00
|
|
|
< ${
|
|
|
|
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;
|
2023-03-04 23:12:06 +00:00
|
|
|
|
|
|
|
finalStaticConfigFile =
|
|
|
|
if cfg.environmentFiles == []
|
|
|
|
then staticConfigFile
|
|
|
|
else "/run/traefik/config.toml";
|
2017-09-27 16:30:49 +00:00
|
|
|
in {
|
|
|
|
options.services.traefik = {
|
|
|
|
enable = mkEnableOption (lib.mdDoc "Traefik web server");
|
|
|
|
|
2019-12-31 00:41:18 +00:00
|
|
|
staticConfigFile = mkOption {
|
2017-09-27 16:30:49 +00:00
|
|
|
default = null;
|
2021-10-03 16:06:03 +00:00
|
|
|
example = literalExpression "/path/to/static_config.toml";
|
2017-09-27 16:30:49 +00:00
|
|
|
type = types.nullOr types.path;
|
2017-10-04 10:47:34 +00:00
|
|
|
description = lib.mdDoc ''
|
2019-12-31 00:41:18 +00:00
|
|
|
Path to traefik's static configuration to use.
|
|
|
|
(Using that option has precedence over `staticConfigOptions` and `dynamicConfigOptions`)
|
2017-10-04 10:47:34 +00:00
|
|
|
'';
|
2017-09-27 16:30:49 +00:00
|
|
|
};
|
2017-10-04 10:47:34 +00:00
|
|
|
|
2019-12-31 00:41:18 +00:00
|
|
|
staticConfigOptions = mkOption {
|
2017-09-27 16:30:49 +00:00
|
|
|
description = lib.mdDoc ''
|
2019-12-31 00:41:18 +00:00
|
|
|
Static configuration for Traefik.
|
2017-09-27 16:30:49 +00:00
|
|
|
'';
|
2020-02-08 11:38:38 +00:00
|
|
|
type = jsonValue;
|
2019-12-31 00:41:18 +00:00
|
|
|
default = { entryPoints.http.address = ":80"; };
|
2017-09-27 16:30:49 +00:00
|
|
|
example = {
|
2019-12-31 00:41:18 +00:00
|
|
|
entryPoints.web.address = ":8080";
|
2017-10-04 10:47:34 +00:00
|
|
|
entryPoints.http.address = ":80";
|
|
|
|
|
2019-12-31 00:41:18 +00:00
|
|
|
api = { };
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
dynamicConfigFile = mkOption {
|
|
|
|
default = null;
|
2021-10-03 16:06:03 +00:00
|
|
|
example = literalExpression "/path/to/dynamic_config.toml";
|
2019-12-31 00:41:18 +00:00
|
|
|
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.
|
|
|
|
'';
|
2020-02-08 11:38:38 +00:00
|
|
|
type = jsonValue;
|
2019-12-31 00:41:18 +00:00
|
|
|
default = { };
|
|
|
|
example = {
|
|
|
|
http.routers.router1 = {
|
|
|
|
rule = "Host(`localhost`)";
|
|
|
|
service = "service1";
|
2017-09-27 16:30:49 +00:00
|
|
|
};
|
2019-12-31 00:41:18 +00:00
|
|
|
|
|
|
|
http.services.service1.loadBalancer.servers =
|
|
|
|
[{ url = "http://localhost:8080"; }];
|
2017-09-27 16:30:49 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
dataDir = mkOption {
|
|
|
|
default = "/var/lib/traefik";
|
|
|
|
type = types.path;
|
|
|
|
description = lib.mdDoc ''
|
2019-12-31 00:41:18 +00:00
|
|
|
Location for any persistent data traefik creates, ie. acme
|
2017-09-27 16:30:49 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2018-02-09 09:37:29 +00:00
|
|
|
group = mkOption {
|
|
|
|
default = "traefik";
|
2019-08-08 20:48:27 +00:00
|
|
|
type = types.str;
|
2018-02-09 09:37:29 +00:00
|
|
|
example = "docker";
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
Set the group that traefik runs under.
|
|
|
|
For the docker backend this needs to be set to `docker` instead.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2017-09-27 16:30:49 +00:00
|
|
|
package = mkOption {
|
|
|
|
default = pkgs.traefik;
|
2021-10-03 16:06:03 +00:00
|
|
|
defaultText = literalExpression "pkgs.traefik";
|
2017-09-27 16:30:49 +00:00
|
|
|
type = types.package;
|
|
|
|
description = lib.mdDoc "Traefik package to use.";
|
|
|
|
};
|
2023-03-04 23:12:06 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
'';
|
|
|
|
};
|
2017-09-27 16:30:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
2019-12-31 00:41:18 +00:00
|
|
|
systemd.tmpfiles.rules = [ "d '${cfg.dataDir}' 0700 traefik traefik - -" ];
|
2019-02-24 13:04:49 +00:00
|
|
|
|
2017-09-27 16:30:49 +00:00
|
|
|
systemd.services.traefik = {
|
|
|
|
description = "Traefik web server";
|
|
|
|
after = [ "network-online.target" ];
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
2020-09-09 07:31:27 +00:00
|
|
|
startLimitIntervalSec = 86400;
|
|
|
|
startLimitBurst = 5;
|
2017-09-27 16:30:49 +00:00
|
|
|
serviceConfig = {
|
2023-03-04 23:12:06 +00:00
|
|
|
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}";
|
2017-09-27 16:30:49 +00:00
|
|
|
Type = "simple";
|
|
|
|
User = "traefik";
|
2018-02-09 09:37:29 +00:00
|
|
|
Group = cfg.group;
|
2017-09-27 16:30:49 +00:00
|
|
|
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;
|
2023-03-04 23:12:06 +00:00
|
|
|
RuntimeDirectory = "traefik";
|
2017-09-27 16:30:49 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2018-06-29 23:58:35 +00:00
|
|
|
users.users.traefik = {
|
2017-09-27 16:30:49 +00:00
|
|
|
group = "traefik";
|
|
|
|
home = cfg.dataDir;
|
|
|
|
createHome = true;
|
2019-10-12 20:25:28 +00:00
|
|
|
isSystemUser = true;
|
2017-09-27 16:30:49 +00:00
|
|
|
};
|
|
|
|
|
2019-12-31 00:41:18 +00:00
|
|
|
users.groups.traefik = { };
|
2017-09-27 16:30:49 +00:00
|
|
|
};
|
|
|
|
}
|