Massive nixfmt reformatting
This commit is contained in:
parent
fe4492f004
commit
b29ddd5e65
109 changed files with 4323 additions and 2368 deletions
|
@ -1,11 +1,15 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
let
|
||||
cfg = config.cloud.authentik;
|
||||
|
||||
mkImage =
|
||||
{ imageName, imageDigest, ... }: "${imageName}@${imageDigest}";
|
||||
mkImage = { imageName, imageDigest, ... }: "${imageName}@${imageDigest}";
|
||||
# If we can pullImage we can just do
|
||||
# mkImage = pkgs.dockerTools.pullImage;
|
||||
|
||||
|
@ -62,7 +66,10 @@ in
|
|||
image = images.postgresql;
|
||||
restart = "unless-stopped";
|
||||
healthcheck = {
|
||||
test = [ "CMD-SHELL" "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}" ];
|
||||
test = [
|
||||
"CMD-SHELL"
|
||||
"pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"
|
||||
];
|
||||
start_period = "20s";
|
||||
interval = "30s";
|
||||
retries = 5;
|
||||
|
@ -73,14 +80,20 @@ in
|
|||
POSTGRES_USER = "authentik";
|
||||
POSTGRES_DB = "authentik";
|
||||
};
|
||||
env_file = [ cfg.envFile "${postgresEnv}" ];
|
||||
env_file = [
|
||||
cfg.envFile
|
||||
"${postgresEnv}"
|
||||
];
|
||||
};
|
||||
services.redis.service = {
|
||||
image = images.redis;
|
||||
command = "--save 60 1 --loglevel warning";
|
||||
restart = "unless-stopped";
|
||||
healthcheck = {
|
||||
test = [ "CMD-SHELL" "redis-cli ping | grep PONG" ];
|
||||
test = [
|
||||
"CMD-SHELL"
|
||||
"redis-cli ping | grep PONG"
|
||||
];
|
||||
start_period = "20s";
|
||||
interval = "30s";
|
||||
retries = 5;
|
||||
|
@ -102,7 +115,10 @@ in
|
|||
AUTHENTIK_POSTGRESQL__USER = "authentik";
|
||||
AUTHENTIK_POSTGRESQL__NAME = "authentik";
|
||||
};
|
||||
env_file = [ cfg.envFile "${authentikEnv}" ];
|
||||
env_file = [
|
||||
cfg.envFile
|
||||
"${authentikEnv}"
|
||||
];
|
||||
ports = [
|
||||
"127.0.0.1:${toString cfg.port}:9000"
|
||||
];
|
||||
|
@ -124,7 +140,10 @@ in
|
|||
AUTHENTIK_POSTGRESQL__USER = "authentik";
|
||||
AUTHENTIK_POSTGRESQL__NAME = "authentik";
|
||||
};
|
||||
env_file = [ cfg.envFile "${authentikEnv}" ];
|
||||
env_file = [
|
||||
cfg.envFile
|
||||
"${authentikEnv}"
|
||||
];
|
||||
user = "root";
|
||||
};
|
||||
docker-compose.volumes = {
|
||||
|
@ -134,4 +153,3 @@ in
|
|||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ pkgs, lib, config, ... }:
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
let
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.cloud.conduit;
|
||||
|
@ -33,95 +38,105 @@ with lib;
|
|||
};
|
||||
|
||||
instances = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
server_name = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
noCloudflare = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
allow_registration = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
well-known_port = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
};
|
||||
server_name = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
noCloudflare = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
allow_registration = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
well-known_port = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
config.systemd.services = mkIf cfg.enable
|
||||
(lib.attrsets.mapAttrs'
|
||||
(name: instance: lib.attrsets.nameValuePair "matrix-conduit-${name}"
|
||||
(
|
||||
let
|
||||
srvName = "matrix-conduit-${name}";
|
||||
format = pkgs.formats.toml { };
|
||||
server_name = if instance.server_name == "" then instance.host else instance.server_name;
|
||||
configFile = format.generate "conduit.toml" (lib.attrsets.recursiveUpdate defaultConfig {
|
||||
config.systemd.services = mkIf cfg.enable (
|
||||
lib.attrsets.mapAttrs' (
|
||||
name: instance:
|
||||
lib.attrsets.nameValuePair "matrix-conduit-${name}" (
|
||||
let
|
||||
srvName = "matrix-conduit-${name}";
|
||||
format = pkgs.formats.toml { };
|
||||
server_name = if instance.server_name == "" then instance.host else instance.server_name;
|
||||
configFile = format.generate "conduit.toml" (
|
||||
lib.attrsets.recursiveUpdate defaultConfig {
|
||||
global.server_name = server_name;
|
||||
global.port = instance.port;
|
||||
global.allow_registration = instance.allow_registration;
|
||||
global.database_path = "/mnt/data/${srvName}/";
|
||||
global.well_known_client = "https://${instance.host}";
|
||||
global.well_known_server = "${instance.host}:443";
|
||||
});
|
||||
in
|
||||
{
|
||||
description = "Conduit Matrix Server (for ${server_name})";
|
||||
documentation = [ "https://gitlab.com/famedly/conduit/" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
environment = { CONDUIT_CONFIG = configFile; };
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
User = "${srvName}";
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
PrivateDevices = true;
|
||||
PrivateMounts = true;
|
||||
PrivateUsers = true;
|
||||
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
];
|
||||
# StateDirectory = "/mnt/data/${srvName}";
|
||||
BindPaths = [ "/mnt/data/${srvName}" ];
|
||||
ExecStart = "${cfg.package}/bin/conduit";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 10;
|
||||
StartLimitBurst = 5;
|
||||
};
|
||||
}
|
||||
))
|
||||
cfg.instances);
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
description = "Conduit Matrix Server (for ${server_name})";
|
||||
documentation = [ "https://gitlab.com/famedly/conduit/" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
environment = {
|
||||
CONDUIT_CONFIG = configFile;
|
||||
};
|
||||
serviceConfig = {
|
||||
DynamicUser = true;
|
||||
User = "${srvName}";
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
PrivateDevices = true;
|
||||
PrivateMounts = true;
|
||||
PrivateUsers = true;
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
];
|
||||
# StateDirectory = "/mnt/data/${srvName}";
|
||||
BindPaths = [ "/mnt/data/${srvName}" ];
|
||||
ExecStart = "${cfg.package}/bin/conduit";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 10;
|
||||
StartLimitBurst = 5;
|
||||
};
|
||||
}
|
||||
)
|
||||
) cfg.instances
|
||||
);
|
||||
|
||||
config.cloud.traefik.hosts = mkIf cfg.enable (
|
||||
(lib.attrsets.mapAttrs'
|
||||
(name: instance: lib.attrsets.nameValuePair "conduit-${name}" ({
|
||||
(lib.attrsets.mapAttrs' (
|
||||
name: instance:
|
||||
lib.attrsets.nameValuePair "conduit-${name}" ({
|
||||
inherit (instance) host port noCloudflare;
|
||||
}))
|
||||
cfg.instances)
|
||||
})
|
||||
) cfg.instances)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
{ pkgs, lib, config, ... }:
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.cloud.conduit.heisenbridge;
|
||||
cfgConduit = config.cloud.conduit;
|
||||
in
|
||||
with lib; {
|
||||
with lib;
|
||||
{
|
||||
options.cloud.conduit.heisenbridge = {
|
||||
enable = mkEnableOption "Enable heisenbridge for conduit";
|
||||
package = mkPackageOption pkgs "heisenbridge" { };
|
||||
|
@ -23,17 +29,26 @@ with lib; {
|
|||
};
|
||||
config = mkIf cfg.enable (
|
||||
let
|
||||
cfgFile = if cfg.port == null then cfg.appserviceFile else
|
||||
pkgs.runCommand "heisenbridge-config" { } ''
|
||||
cp ${cfg.appserviceFile} $out
|
||||
${pkgs.sd}/bin/sd '^url: .*$' "url: http://127.0.0.1:${cfg.port}"
|
||||
'';
|
||||
listenArgs = lists.optionals (cfg.port != null) [ "--listen-port" (toString cfg.port) ];
|
||||
cfgFile =
|
||||
if cfg.port == null then
|
||||
cfg.appserviceFile
|
||||
else
|
||||
pkgs.runCommand "heisenbridge-config" { } ''
|
||||
cp ${cfg.appserviceFile} $out
|
||||
${pkgs.sd}/bin/sd '^url: .*$' "url: http://127.0.0.1:${cfg.port}"
|
||||
'';
|
||||
listenArgs = lists.optionals (cfg.port != null) [
|
||||
"--listen-port"
|
||||
(toString cfg.port)
|
||||
];
|
||||
in
|
||||
{
|
||||
systemd.services.heisenbridge = {
|
||||
description = "Matrix<->IRC bridge";
|
||||
requires = [ "matrix-conduit-nkagami.service" "matrix-synapse.service" ]; # So the registration file can be used by Synapse
|
||||
requires = [
|
||||
"matrix-conduit-nkagami.service"
|
||||
"matrix-synapse.service"
|
||||
]; # So the registration file can be used by Synapse
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig = rec {
|
||||
|
@ -77,12 +92,18 @@ with lib; {
|
|||
RemoveIPC = true;
|
||||
UMask = "0077";
|
||||
|
||||
CapabilityBoundingSet = [ "CAP_CHOWN" ] ++ optional (cfg.port != null && cfg.port < 1024) "CAP_NET_BIND_SERVICE";
|
||||
CapabilityBoundingSet = [
|
||||
"CAP_CHOWN"
|
||||
] ++ optional (cfg.port != null && cfg.port < 1024) "CAP_NET_BIND_SERVICE";
|
||||
AmbientCapabilities = CapabilityBoundingSet;
|
||||
NoNewPrivileges = true;
|
||||
LockPersonality = true;
|
||||
RestrictRealtime = true;
|
||||
SystemCallFilter = [ "@system-service" "~@privileged" "@chown" ];
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
"@chown"
|
||||
];
|
||||
SystemCallArchitectures = "native";
|
||||
RestrictAddressFamilies = "AF_INET AF_INET6";
|
||||
};
|
||||
|
@ -97,4 +118,3 @@ with lib; {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
let
|
||||
cfg = config.cloud.firezone;
|
||||
|
||||
mkImage =
|
||||
{ imageName, imageDigest, ... }: "${imageName}@${imageDigest}";
|
||||
mkImage = { imageName, imageDigest, ... }: "${imageName}@${imageDigest}";
|
||||
# If we can pullImage we can just do
|
||||
# mkImage = pkgs.dockerTools.pullImage;
|
||||
|
||||
|
@ -48,7 +52,10 @@ in
|
|||
image = images.postgresql;
|
||||
restart = "unless-stopped";
|
||||
healthcheck = {
|
||||
test = [ "CMD-SHELL" "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}" ];
|
||||
test = [
|
||||
"CMD-SHELL"
|
||||
"pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"
|
||||
];
|
||||
start_period = "20s";
|
||||
interval = "30s";
|
||||
retries = 5;
|
||||
|
@ -89,7 +96,10 @@ in
|
|||
driver = "bridge";
|
||||
ipam.config = [
|
||||
{ subnet = "172.25.0.0/16"; }
|
||||
{ subnet = "2001:3990:3990::/64"; gateway = "2001:3990:3990::1"; }
|
||||
{
|
||||
subnet = "2001:3990:3990::/64";
|
||||
gateway = "2001:3990:3990::1";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.cloud.gotosocial;
|
||||
|
@ -41,13 +46,21 @@ in
|
|||
# Postgres
|
||||
cloud.postgresql.databases = [ dbUser ];
|
||||
# Traefik
|
||||
cloud.traefik.hosts = { gotosocial = { inherit (cfg) host port; }; } //
|
||||
(if cfg.accountDomain != cfg.host && cfg.accountDomain != "" then {
|
||||
gotosocial-wellknown = {
|
||||
inherit (cfg) port;
|
||||
filter = "Host(`${cfg.accountDomain}`) && (PathPrefix(`/.well-known/webfinger`) || PathPrefix(`/.well-known/nodeinfo`) || PathPrefix(`/.well-known/host-meta`))";
|
||||
};
|
||||
} else { });
|
||||
cloud.traefik.hosts =
|
||||
{
|
||||
gotosocial = { inherit (cfg) host port; };
|
||||
}
|
||||
// (
|
||||
if cfg.accountDomain != cfg.host && cfg.accountDomain != "" then
|
||||
{
|
||||
gotosocial-wellknown = {
|
||||
inherit (cfg) port;
|
||||
filter = "Host(`${cfg.accountDomain}`) && (PathPrefix(`/.well-known/webfinger`) || PathPrefix(`/.well-known/nodeinfo`) || PathPrefix(`/.well-known/host-meta`))";
|
||||
};
|
||||
}
|
||||
else
|
||||
{ }
|
||||
);
|
||||
# The service itself
|
||||
services.gotosocial = {
|
||||
enable = true;
|
||||
|
@ -60,7 +73,10 @@ in
|
|||
bind-address = "localhost";
|
||||
port = cfg.port;
|
||||
# Instance
|
||||
instance-languages = [ "en-ca" "vi" ];
|
||||
instance-languages = [
|
||||
"en-ca"
|
||||
"vi"
|
||||
];
|
||||
# Accounts
|
||||
accounts-registration-open = false;
|
||||
accounts-allow-custom-css = true;
|
||||
|
@ -73,15 +89,23 @@ in
|
|||
web-template-base-dir = "${cfg.package}/share/gotosocial/web/template";
|
||||
web-asset-base-dir = "${cfg.package}/share/gotosocial/web/assets";
|
||||
# Media
|
||||
media-emoji-remote-max-size = 256 * 1024 /* bytes */;
|
||||
media-emoji-local-max-size = 256 * 1024 /* bytes */;
|
||||
media-emoji-remote-max-size =
|
||||
256 * 1024 # bytes
|
||||
;
|
||||
media-emoji-local-max-size =
|
||||
256 * 1024 # bytes
|
||||
;
|
||||
media-remote-cache-days = 7;
|
||||
media-cleanup-from = "00:00";
|
||||
media-cleanup-every = "24h";
|
||||
# OIDC
|
||||
oidc-enabled = true;
|
||||
oidc-idp-name = "DTTH";
|
||||
oidc-scopes = [ "openid" "email" "profile" ];
|
||||
oidc-scopes = [
|
||||
"openid"
|
||||
"email"
|
||||
"profile"
|
||||
];
|
||||
# HTTP Client
|
||||
http-client.block-ips = [ "11.0.0.0/24" ];
|
||||
# Advanced
|
||||
|
@ -92,8 +116,14 @@ in
|
|||
# instance-inject-mastodon-version = true;
|
||||
};
|
||||
};
|
||||
systemd.services.gotosocial.requires = mkAfter [ "postgresql.service" "arion-authentik.service" ];
|
||||
systemd.services.gotosocial.after = mkAfter [ "postgresql.service" "arion-authentik.service" ];
|
||||
systemd.services.gotosocial.requires = mkAfter [
|
||||
"postgresql.service"
|
||||
"arion-authentik.service"
|
||||
];
|
||||
systemd.services.gotosocial.after = mkAfter [
|
||||
"postgresql.service"
|
||||
"arion-authentik.service"
|
||||
];
|
||||
systemd.services.gotosocial.unitConfig = {
|
||||
RequiresMountsFor = [ storageLocation ];
|
||||
ReadWritePaths = [ storageLocation ];
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
let
|
||||
|
@ -238,7 +243,12 @@ in
|
|||
# MTA-STS server
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts.maddy-mta-sts = {
|
||||
listen = [{ addr = "127.0.0.1"; port = mtaStsPort; }];
|
||||
listen = [
|
||||
{
|
||||
addr = "127.0.0.1";
|
||||
port = mtaStsPort;
|
||||
}
|
||||
];
|
||||
root = mtaStsDir;
|
||||
};
|
||||
|
||||
|
@ -273,7 +283,10 @@ in
|
|||
|
||||
# maddy itself
|
||||
systemd.services."${name}" = {
|
||||
after = [ "network.target" "traefik-certs-dumper.service" ];
|
||||
after = [
|
||||
"network.target"
|
||||
"traefik-certs-dumper.service"
|
||||
];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
requires = [ "postgresql.service" ];
|
||||
|
||||
|
@ -327,7 +340,6 @@ in
|
|||
KillMode = "mixed";
|
||||
KillSignal = "SIGTERM";
|
||||
|
||||
|
||||
# Required to bind on ports lower than 1024.
|
||||
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
|
||||
CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
let
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
let
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ pkgs, lib, config, ... }:
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
let
|
||||
|
@ -9,126 +14,169 @@ let
|
|||
};
|
||||
|
||||
# Copied from traefik.nix
|
||||
jsonValue = with types;
|
||||
jsonValue =
|
||||
with types;
|
||||
let
|
||||
valueType = nullOr
|
||||
(oneOf [
|
||||
valueType =
|
||||
nullOr (oneOf [
|
||||
bool
|
||||
int
|
||||
float
|
||||
str
|
||||
(lazyAttrsOf valueType)
|
||||
(listOf valueType)
|
||||
]) // {
|
||||
description = "JSON value";
|
||||
emptyValue.value = { };
|
||||
};
|
||||
])
|
||||
// {
|
||||
description = "JSON value";
|
||||
emptyValue.value = { };
|
||||
};
|
||||
in
|
||||
valueType;
|
||||
|
||||
hostType = with types; submodule {
|
||||
options = {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
description = "The host for the router filter";
|
||||
};
|
||||
path = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = "The path for the router filter (exact path is matched)";
|
||||
};
|
||||
filter = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = "The filter syntax for the router. Overrides `host` and `path` if provided";
|
||||
};
|
||||
localHost = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = "The local host of the service. Must be an IP if protocol is TCP. Default to localhost/127.0.0.1";
|
||||
default = null;
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
description = "The port that the service is listening on";
|
||||
};
|
||||
entrypoints = mkOption {
|
||||
type = listOf (enum [ "http" "https" "smtp-submission" "smtp-submission-ssl" "imap" "wireguard" ]);
|
||||
default = [ "https" ];
|
||||
description = "The entrypoints that will serve the host";
|
||||
};
|
||||
middlewares = mkOption {
|
||||
type = listOf jsonValue;
|
||||
default = [ ];
|
||||
description = "The middlewares to be used with the host.";
|
||||
};
|
||||
protocol = mkOption {
|
||||
type = enum [ "http" "tcp" "udp" ];
|
||||
default = "http";
|
||||
description = "The protocol of the router and service";
|
||||
};
|
||||
tlsPassthrough = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Sets the TCP passthrough value. Defaults to `true` if the connection is tcp";
|
||||
};
|
||||
noCloudflare = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Bypasses the client cert requirement, enable if you don't route things through cloudflare";
|
||||
hostType =
|
||||
with types;
|
||||
submodule {
|
||||
options = {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
description = "The host for the router filter";
|
||||
};
|
||||
path = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = "The path for the router filter (exact path is matched)";
|
||||
};
|
||||
filter = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = "The filter syntax for the router. Overrides `host` and `path` if provided";
|
||||
};
|
||||
localHost = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = "The local host of the service. Must be an IP if protocol is TCP. Default to localhost/127.0.0.1";
|
||||
default = null;
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
description = "The port that the service is listening on";
|
||||
};
|
||||
entrypoints = mkOption {
|
||||
type = listOf (enum [
|
||||
"http"
|
||||
"https"
|
||||
"smtp-submission"
|
||||
"smtp-submission-ssl"
|
||||
"imap"
|
||||
"wireguard"
|
||||
]);
|
||||
default = [ "https" ];
|
||||
description = "The entrypoints that will serve the host";
|
||||
};
|
||||
middlewares = mkOption {
|
||||
type = listOf jsonValue;
|
||||
default = [ ];
|
||||
description = "The middlewares to be used with the host.";
|
||||
};
|
||||
protocol = mkOption {
|
||||
type = enum [
|
||||
"http"
|
||||
"tcp"
|
||||
"udp"
|
||||
];
|
||||
default = "http";
|
||||
description = "The protocol of the router and service";
|
||||
};
|
||||
tlsPassthrough = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Sets the TCP passthrough value. Defaults to `true` if the connection is tcp";
|
||||
};
|
||||
noCloudflare = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Bypasses the client cert requirement, enable if you don't route things through cloudflare";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Returns the filter given a host configuration
|
||||
filterOfHost = host:
|
||||
filterOfHost =
|
||||
host:
|
||||
let
|
||||
hostFilter = if host.protocol == "http" then "Host" else "HostSNI";
|
||||
in
|
||||
if host.filter != null then host.filter
|
||||
else if host.path == null then "${hostFilter}(`${host.host}`)"
|
||||
else "${hostFilter}(`${host.host}`) && Path(`${host.path}`)";
|
||||
if host.filter != null then
|
||||
host.filter
|
||||
else if host.path == null then
|
||||
"${hostFilter}(`${host.host}`)"
|
||||
else
|
||||
"${hostFilter}(`${host.host}`) && Path(`${host.path}`)";
|
||||
|
||||
# Turns a host configuration into dynamic traefik configuration
|
||||
hostToConfig = name: host: {
|
||||
"${host.protocol}" = {
|
||||
routers."${name}-router" = (if (host.protocol != "udp") then {
|
||||
rule = filterOfHost host;
|
||||
tls = { certResolver = "le"; }
|
||||
// (if host.protocol == "tcp" then { passthrough = if (host ? tlsPassthrough) then host.tlsPassthrough else true; } else { })
|
||||
// (if host.noCloudflare then tlsNoCloudflare else { });
|
||||
} else { }) // {
|
||||
entryPoints = host.entrypoints;
|
||||
service = "${name}-service";
|
||||
} // (
|
||||
if host.protocol == "http" then
|
||||
{ middlewares = lists.imap0 (id: m: "${name}-middleware-${toString id}") host.middlewares; }
|
||||
else if host.middlewares == [ ] then
|
||||
"${host.protocol}" =
|
||||
{
|
||||
routers."${name}-router" =
|
||||
(
|
||||
if (host.protocol != "udp") then
|
||||
{
|
||||
rule = filterOfHost host;
|
||||
tls =
|
||||
{
|
||||
certResolver = "le";
|
||||
}
|
||||
// (
|
||||
if host.protocol == "tcp" then
|
||||
{ passthrough = if (host ? tlsPassthrough) then host.tlsPassthrough else true; }
|
||||
else
|
||||
{ }
|
||||
)
|
||||
// (if host.noCloudflare then tlsNoCloudflare else { });
|
||||
}
|
||||
else
|
||||
{ }
|
||||
)
|
||||
// {
|
||||
entryPoints = host.entrypoints;
|
||||
service = "${name}-service";
|
||||
}
|
||||
// (
|
||||
if host.protocol == "http" then
|
||||
{ middlewares = lists.imap0 (id: m: "${name}-middleware-${toString id}") host.middlewares; }
|
||||
else if host.middlewares == [ ] then
|
||||
{ }
|
||||
else
|
||||
abort "Cannot have middlewares on non-http routers"
|
||||
);
|
||||
services."${name}-service".loadBalancer.servers = [
|
||||
(
|
||||
let
|
||||
localhost =
|
||||
if isNull host.localHost then
|
||||
(if host.protocol == "http" then "localhost" else "127.0.0.1")
|
||||
else
|
||||
host.localHost;
|
||||
in
|
||||
if host.protocol == "http" then
|
||||
{ url = "http://${localhost}:${toString host.port}"; }
|
||||
else
|
||||
{ address = "${localhost}:${toString host.port}"; }
|
||||
)
|
||||
];
|
||||
}
|
||||
// (
|
||||
if (host.middlewares != [ ]) then
|
||||
{
|
||||
middlewares = builtins.listToAttrs (
|
||||
lists.imap0 (id: v: {
|
||||
name = "${name}-middleware-${toString id}";
|
||||
value = v;
|
||||
}) host.middlewares
|
||||
);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
else abort "Cannot have middlewares on non-http routers"
|
||||
);
|
||||
services."${name}-service".loadBalancer.servers = [
|
||||
(
|
||||
let
|
||||
localhost =
|
||||
if isNull host.localHost then
|
||||
(
|
||||
if host.protocol == "http" then "localhost"
|
||||
else "127.0.0.1"
|
||||
) else host.localHost;
|
||||
in
|
||||
if host.protocol == "http" then
|
||||
{ url = "http://${localhost}:${toString host.port}"; }
|
||||
else { address = "${localhost}:${toString host.port}"; }
|
||||
)
|
||||
];
|
||||
} // (if (host.middlewares != [ ]) then {
|
||||
middlewares = builtins.listToAttrs (lists.imap0
|
||||
(id: v: {
|
||||
name = "${name}-middleware-${toString id}";
|
||||
value = v;
|
||||
})
|
||||
host.middlewares);
|
||||
} else { });
|
||||
};
|
||||
|
||||
tlsConfig = {
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
let
|
||||
|
@ -28,7 +33,8 @@ in
|
|||
# Dynamic configuration
|
||||
# ---------------------
|
||||
## Middleware
|
||||
services.traefik.dynamicConfigOptions.http.middlewares.dashboard-auth.basicAuth.usersFile = cfg.usersFile;
|
||||
services.traefik.dynamicConfigOptions.http.middlewares.dashboard-auth.basicAuth.usersFile =
|
||||
cfg.usersFile;
|
||||
## Router
|
||||
services.traefik.dynamicConfigOptions.http.routers.dashboard = {
|
||||
rule = "Host(`${cfg.host}`)";
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
{ pkgs, config, lib, ... }:
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
with lib;
|
||||
let
|
||||
# Copied from traefik.nix
|
||||
jsonValue = with types;
|
||||
jsonValue =
|
||||
with types;
|
||||
let
|
||||
valueType = nullOr
|
||||
(oneOf [
|
||||
valueType =
|
||||
nullOr (oneOf [
|
||||
bool
|
||||
int
|
||||
float
|
||||
str
|
||||
(lazyAttrsOf valueType)
|
||||
(listOf valueType)
|
||||
]) // {
|
||||
description = "JSON value";
|
||||
emptyValue.value = { };
|
||||
};
|
||||
])
|
||||
// {
|
||||
description = "JSON value";
|
||||
emptyValue.value = { };
|
||||
};
|
||||
in
|
||||
valueType;
|
||||
|
||||
|
@ -41,7 +48,11 @@ let
|
|||
cfg = config.cloud.traefik;
|
||||
in
|
||||
{
|
||||
imports = [ ./config.nix ./dashboard.nix ./certs-dumper.nix ];
|
||||
imports = [
|
||||
./config.nix
|
||||
./dashboard.nix
|
||||
./certs-dumper.nix
|
||||
];
|
||||
options.cloud.traefik = {
|
||||
cloudflareKeyFile = mkOption {
|
||||
type = types.path;
|
||||
|
@ -104,7 +115,12 @@ in
|
|||
config.systemd.services.traefik.environment.CF_DNS_API_TOKEN_FILE = cfg.cloudflareKeyFile;
|
||||
|
||||
# Set up firewall to allow traefik traffic.
|
||||
config.networking.firewall.allowedTCPPorts = [ 443 993 587 465 ];
|
||||
config.networking.firewall.allowedTCPPorts = [
|
||||
443
|
||||
993
|
||||
587
|
||||
465
|
||||
];
|
||||
config.networking.firewall.allowedUDPPorts = [
|
||||
443 # QUIC
|
||||
51820 # Wireguard
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.cloud.writefreely;
|
||||
|
@ -62,4 +67,3 @@ in
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue