{ config, pkgs, ...}: let forgejoBackgroundCss = pkgs.runCommand "forgejo-0ff-space-background.css" { } '' cat ${../../globalServices/branding/0ff-space-background.css} \ ${./branding/forgejo-theme-override.css} \ > "$out" ''; in { # Der known-hosts-Pin fuer Forgejos eingebetteten SSH-Server (Port 2222) # steht jetzt in hosts/globalServices/forgejo-known-host.nix: ihn braucht # jeder Host, der das Repo klont, nicht nur der, der den Dienst betreibt. services.forgejo= { enable = true; lfs.enable = true; dump.enable = true; settings = { service = { ENABLE_INTERNAL_SIGNIN = true; DISABLE_REGISTRATION = false; ALLOW_ONLY_INTERNAL_REGISTRATION = false; ENABLE_REGISTRATION = true; ALLOW_ONLY_EXTERNAL_REGISTRATION = true; #ENABLE_AUTO_REGISTRATION=true; # Reduce platform-y surface area: this instance is a personal code # showcase today, maybe a handful of collaborators later, not a # forge for teams/CI. Issues, pull requests, and wiki stay on. DISABLE_ORGANIZATION_CREATION = true; }; log.level = "Debug"; # Instance-wide kill switch for mirror sync: the only mirror that # exists today (nixos-config -> Codeberg push mirror) fails on every # run ("branch master is the default branch and cannot be deleted", # see docs/research/full-system-aufit.md, Executive Summary point 3 # -- not docs/review/reviewer-systemaudit-2026-09-01.md, an unrelated # earlier audit a prior commit here mistakenly cited). # This is a deliberate "disable, don't repair" -- it would also stop # any future pull/push mirror on this instance, acceptable since none # else exists yet. mirror.DISABLED = true; repository = { ENABLE_PUSH_CREATE_USER = true; DISABLED_REPO_UNITS = "repo.projects,repo.packages,repo.actions"; }; pwa = { ENABLE_STANDALONE = true; }; server = { START_SSH_SERVER = true; SSH_PORT = 2222; # Bind only the Tailnet interface -- no public exposure, and no # Traefik TCP passthrough needed since Forgejo now runs on the same # host as Traefik (unlike the old pinix setup, which needed a # passthrough to reach across the Tailnet). SSH_LISTEN_HOST = config.tailnetIPs.blunix; HTTP_ADDR = "127.0.0.1"; HTTP_PORT = 3000; DOMAIN = "git.${config.domain}"; ROOT_URL = "https://git.${config.domain}/"; TRUSTED_PROXIES = "127.0.0.1"; LANDING_PAGE = "login"; # Forgejo's default (6h) made the robots.txt fix (see this file's # tmpfiles.rules) invisible to an external reader's own cache for up # to 6h after deploy -- verified live 2026-09-11, "private" cache # semantics meant it wasn't even a shared/CDN caching problem to fix # server-side, just this TTL being longer than useful whenever a # static override here actually changes. STATIC_CACHE_TIME = "5m"; }; session = { PROVIDER = "file"; COOKIE_SECURE = true; }; security = { LOGIN_REMEMBER_DAYS = 10; REVERSE_PROXY_TRUSTED_PROXIES = "127.0.0.1"; }; # Forgejo calls out to webhook receivers on both blunix itself # (website/launcher/tasks auto-pull, co-located now) and pinix # (wiki-update, gitpull-calendar-web -- receiver stays on pinix). # "external" alone does NOT cover Tailnet (100.64.0.0/10) addresses -- # found the hard way: the tasks auto-pull hook was silently denied # ("webhook can only call allowed HTTP servers") until both Tailnet # IPs were listed explicitly. webhook.ALLOWED_HOST_LIST = "external,127.0.0.1,${config.tailnetIPs.blunix},${config.tailnetIPs.pinix}"; oauth2_client = { # Never use auto account linking with this, otherwise users cannot change # their new user name and they could potentially overtake other users accounts # by setting their email address to an existing account. # With "login" linking the user must choose a non-existing username first or login # with the existing account to link. ACCOUNT_LINKING = "login"; USERNAME = "nickname"; # This does not mean that you cannot register via oauth, but just that there should # be a confirmation dialog shown to the user before the account is actually created. # This dialog allows changing user name and email address before creating the account. ENABLE_AUTO_REGISTRATION = false; REGISTER_EMAIL_CONFIRM = false; UPDATE_AVATAR = true; }; }; }; systemd.tmpfiles.rules = [ "d /var/lib/forgejo/custom/public 0750 forgejo forgejo -" "d /var/lib/forgejo/custom/public/assets 0755 forgejo forgejo -" "d /var/lib/forgejo/custom/public/assets/img 0755 forgejo forgejo -" # L+ (symlink, unconditionally relinked), not C+ (copy): C+ only forces # an overwrite when the source is a directory -- for a single regular # file it silently degrades to "copy only if the destination doesn't # already exist yet", so a changed source would stop reaching disk # after the very first deploy. Found the hard way on pinix: the # background CSS below kept serving stale content across two redeploys # with different store paths until the destination was deleted by hand. "L+ /var/lib/forgejo/custom/public/assets/img/logo.svg - forgejo forgejo - ${./branding/spiral-v2.svg}" "L+ /var/lib/forgejo/custom/public/assets/img/logo.png - forgejo forgejo - ${./branding/spiral-v2-512.png}" "L+ /var/lib/forgejo/custom/public/assets/img/apple-touch-icon.png - forgejo forgejo - ${./branding/spiral-v2-192.png}" "L+ /var/lib/forgejo/custom/public/assets/img/favicon.svg - forgejo forgejo - ${./branding/spiral-v2.svg}" "L+ /var/lib/forgejo/custom/public/assets/img/favicon.png - forgejo forgejo - ${./branding/spiral-v2-192.png}" "d /var/lib/forgejo/custom/public/assets/css 0755 forgejo forgejo -" "L+ /var/lib/forgejo/custom/public/assets/css/0ff-space-background.css - forgejo forgejo - ${forgejoBackgroundCss}" # Overrides Forgejo's built-in default robots.txt -- see the file's own # header comment for why (/*/*/src/ and /*/*/raw/ were blocking an # external reader from actually reading any file content, verified # live 2026-09-11, once git.0ff.space went external). "L+ /var/lib/forgejo/custom/public/robots.txt - forgejo forgejo - ${./branding/forgejo-robots.txt}" "d /var/lib/forgejo/custom/templates 0750 forgejo forgejo -" "d /var/lib/forgejo/custom/templates/custom 0750 forgejo forgejo -" # header.tmpl is Forgejo's documented extension point -- included # verbatim on every page, which is how the background stylesheet above # actually gets linked in (the public/assets tree above is only served # statically, nothing references it on its own). "L+ /var/lib/forgejo/custom/templates/custom/header.tmpl - forgejo forgejo - ${./branding/forgejo-header.tmpl}" ]; systemd.services.forgejo.restartTriggers = [ ./branding/spiral-v2.svg ./branding/spiral-v2-192.png ./branding/spiral-v2-512.png forgejoBackgroundCss ./branding/forgejo-header.tmpl ./branding/forgejo-robots.txt ]; }