# Reverse proxy = the canonical Co-op Cloud `traefik` recipe, deployed via abra in # wildcard / file-provider mode (wildcard cert as ssl_cert/ssl_key swarm secrets, # LETS_ENCRYPT_ENV empty => NO ACME, no DNS token). See DECISIONS.md "Proxy: real coop-cloud/traefik". # Phase-1c: the cert at CERT_DIR is sops-decrypted from git (cc-ci-secrets) at activation # (modules/secrets.nix wildcard_cert/wildcard_key), NOT an out-of-band operator file drop. # # Declared as an idempotent-RECONCILE systemd oneshot (like swarm-init): it inspects current # state and converges every activation/boot, self-healing drift (redeploys if the stack is gone, # re-inserts secrets if missing). No run-once sentinel. So a from-scratch install is just # `nixos-rebuild switch` + operator preconditions (D8) — no manual post-steps. { pkgs, ... }: let reconcile = pkgs.writeShellApplication { name = "cc-ci-reconcile-proxy"; runtimeInputs = with pkgs; [ abra docker jq gnused gnugrep coreutils git ]; text = '' PROXY_DOMAIN="traefik.ci.commoninternet.net" CERT_DIR="/var/lib/ci-certs/live" ENV_FILE="$HOME/.abra/servers/default/$PROXY_DOMAIN.env" # Fail visibly (failed unit) if the cert is missing — do NOT silently skip. It is # sops-decrypted from git (cc-ci-secrets) at activation; a miss here means the sops decrypt # path is broken (e.g. age identity not present), which must surface, not be papered over. if [ ! -r "$CERT_DIR/fullchain.pem" ] || [ ! -r "$CERT_DIR/privkey.pem" ]; then echo "FATAL: wildcard cert missing at $CERT_DIR (sops decrypt from cc-ci-secrets failed?)" >&2 exit 1 fi abra server ls -m -n >/dev/null 2>&1 || abra server add --local -n || true abra recipe fetch traefik -n >/dev/null [ -f "$ENV_FILE" ] || abra app new traefik -s default -D "$PROXY_DOMAIN" -n set_env() { sed -i -E "/^[[:space:]]*#?[[:space:]]*$1=/d" "$ENV_FILE" printf '%s=%s\n' "$1" "$2" >> "$ENV_FILE" } set_env LETS_ENCRYPT_ENV "" set_env WILDCARDS_ENABLED "1" set_env SECRET_WILDCARD_CERT_VERSION "v1" set_env SECRET_WILDCARD_KEY_VERSION "v1" set_env COMPOSE_FILE '"compose.yml:compose.wildcard.yml"' have_secret() { docker secret ls --format '{{.Name}}' | grep -q "_$1_v1$"; } have_secret ssl_cert || abra app secret insert "$PROXY_DOMAIN" ssl_cert v1 "$CERT_DIR/fullchain.pem" -f -n have_secret ssl_key || abra app secret insert "$PROXY_DOMAIN" ssl_key v1 "$CERT_DIR/privkey.pem" -f -n # Converge the stack (idempotent: no-op if already at desired state). abra app deploy "$PROXY_DOMAIN" -n -C ''; }; in { systemd.services.deploy-proxy = { description = "Reconcile the Co-op Cloud traefik proxy (wildcard/no-ACME) via abra"; after = [ "swarm-init.service" "docker.service" "network-online.target" ]; requires = [ "swarm-init.service" "docker.service" ]; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; environment.HOME = "/root"; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStart = "${reconcile}/bin/cc-ci-reconcile-proxy"; }; }; }