Files
Numbus/modules/backup/services/applications/traefik.nix
T
2026-05-02 12:52:08 +02:00

178 lines
4.9 KiB
Nix

{ config, pkgs, lib, ... }:
with lib;
let
# Container config
name = "traefik";
# Version tagging
traefikVersion = "v3.6.8";
# Helper
helper = import ../service-helper.nix { inherit config pkgs lib; };
cfg = config.numbus-server.services.traefik;
in
helper.mkPodmanService {
inherit name;
description = "Traefik reverse proxy, one to rule them all";
defaultPort = "7780";
pod = "false";
startDelay = 10;
dataDirEnabled = false;
middlewares = [
"secureHeaders"
];
dependencies = [
"sops-install-secrets.service"
"network-online.target"
];
dirPermissions = [
"100999:100 ${cfg.configDir}"
"100999:100 ${cfg.configDir}/certs"
];
# Compose file good
composeText = ''
services:
traefik:
image: docker.io/library/traefik:${traefikVersion}
container_name: traefik
hostname: traefik
user: '1000:1000'
network_mode: pasta
ports:
- "${cfg.port}:8080/tcp"
- "443:443/tcp"
volumes:
- ${config.sops.templates."traefik/config".path}:/etc/traefik/traefik.yaml:ro
- ${cfg.configDir}/certs:/var/traefik/certs
- /etc/traefik/rules:/etc/traefik/rules:ro
environment:
- CF_DNS_API_TOKEN=${config.sops.placeholder."traefik/cloudflare_api_token"}
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
restart: unless-stopped
'';
extraConfig = {
sops.secrets."traefik/cloudflare_api_token" = {
sopsFile = /etc/nixos/secrets/podman/traefik.yaml;
gid = "100";
uid = "1000";
mode = "0400";
};
sops.templates."traefik/config"= {
gid = "100";
uid = "100999";
mode = "0400";
content = ''
global:
checkNewVersion: false
sendAnonymousUsage: false
log:
level: ${cfg.logLevel}
accesslog: {}
api:
dashboard: true
insecure: false
entryPoints:
web:
address: :80
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: :443
forwardedHeaders:
trustedIPs:
- "127.0.0.1/32"
- "10.0.0.0/8"
- "192.168.0.0/16"
- "172.16.0.0/12"
certificatesResolvers:
cloudflare:
acme:
email: ${config.numbus-server.mail.adminAddress}
storage: /var/traefik/certs/cloudflare-acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "9.9.9.9:53"
serversTransport:
insecureSkipVerify: true
providers:
file:
directory: "/etc/traefik/rules"
watch: true
'';
path = "/etc/traefik/traefik.yaml";
};
sops.templates."traefik/rules/secureHeaders" = {
gid = "100";
uid = "100999";
mode = "0400";
content = ''
http:
middlewares:
secureHeaders:
headers:
FrameDeny: true
AccessControlAllowMethods: 'GET,OPTIONS,PUT'
AccessControlAllowOriginList:
- origin-list-or-null
AccessControlMaxAge: 100
AddVaryHeader: true
BrowserXssFilter: true
ContentTypeNosniff: true
ForceSTSHeader: true
STSIncludeSubdomains: true
STSPreload: true
ContentSecurityPolicy: default-src 'self' 'unsafe-inline'
CustomFrameOptionsValue: SAMEORIGIN
ReferrerPolicy: same-origin
PermissionsPolicy: vibrate 'self'
STSSeconds: 315360000
'';
path = "/etc/traefik/rules/secureHeaders.yaml";
};
sops.templates."traefik/rules/secureTLS" = {
gid = "100";
uid = "100999";
mode = "0400";
content = ''
tls:
options:
secureTLS:
minVersion: VersionTLS12
sniStrict: true
curvePreferences:
- CurveP521
- CurveP384
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
'';
path = "/etc/traefik/rules/secureTLS.yaml";
};
};
extraOptions = {
enable.default = true;
logLevel = mkOption {
type = types.enum [ "TRACE" "DEBUG" "INFO" "WARN" "ERROR" "FATAL" ];
default = "ERROR";
example = "ERROR";
description = "The level of detail Traefik should print in the logs.";
};
};
}