Files
cc-ci/modules/traefik.nix
2026-05-26 21:55:08 +01:00

97 lines
2.8 KiB
Nix

# Traefik for the test swarm (M1). Runs as a swarm service on the `proxy` overlay so it can
# reach recipe service VIPs (a host process couldn't). TLS terminates here using the operator's
# pre-issued wildcard cert via the file provider — NO ACME for commoninternet.net (§4.0).
# Recipe routers only need `traefik.enable=true` + a Host(...) rule + tls=true; the default
# certificate (the wildcard) is served for every *.ci.commoninternet.net host.
{ pkgs, ... }:
let
# Static config. Docker *Swarm* provider (v3) + file provider for the cert.
staticCfg = pkgs.writeText "traefik.yml" ''
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
swarm:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: proxy
file:
directory: /etc/traefik/dynamic
watch: true
log:
level: INFO
accessLog: {}
api:
dashboard: false
ping: {}
'';
# Dynamic config: serve the pre-issued wildcard as the DEFAULT certificate, so any
# *.ci.commoninternet.net router with tls=true is covered without a cert resolver.
certsCfg = pkgs.writeText "certs.yml" ''
tls:
stores:
default:
defaultCertificate:
certFile: /var/lib/ci-certs/live/fullchain.pem
keyFile: /var/lib/ci-certs/live/privkey.pem
certificates:
- certFile: /var/lib/ci-certs/live/fullchain.pem
keyFile: /var/lib/ci-certs/live/privkey.pem
'';
stack = pkgs.writeText "traefik-stack.yml" ''
version: "3.8"
services:
traefik:
image: traefik:v3.3
ports:
- target: 80
published: 80
mode: host
- target: 443
published: 443
mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /var/lib/ci-certs/live:/var/lib/ci-certs/live:ro
- ${staticCfg}:/etc/traefik/traefik.yml:ro
- ${certsCfg}:/etc/traefik/dynamic/certs.yml:ro
networks:
- proxy
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
restart_policy:
condition: any
networks:
proxy:
external: true
'';
in
{
# Gateway forwards 80/443 to cc-ci over the public interface (enp5s0), so open them.
networking.firewall.allowedTCPPorts = [ 80 443 ];
systemd.services.traefik-deploy = {
description = "Deploy the Traefik swarm stack";
after = [ "swarm-init.service" ];
requires = [ "swarm-init.service" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
set -eu
docker stack deploy --detach=true -c ${stack} traefik
'';
};
}