{ config, my, pkgs, secrets, ... }: let fqdn = "git.${my.domain}"; in { sops.secrets."forgejo/mail/host" = { sopsFile = ../secrets/sops/forgejo.yaml; restartUnits = [ "forgejo.service" ]; }; sops.secrets."forgejo/mail/password" = { sopsFile = ../secrets/sops/forgejo.yaml; restartUnits = [ "forgejo.service" ]; }; services.forgejo = { enable = true; lfs.enable = true; database = { type = "postgres"; createDatabase = false; socket = "/run/postgresql"; }; # https://forgejo.org/docs/latest/admin/config-cheat-sheet/ settings = { DEFAULT.APP_NAME = fqdn; api.ENABLE_SWAGGER = false; cron = { ENABLE = true; RUN_AT_START = true; }; "cron.repo_health_check".TIMEOUT = "600s"; # 10 min "cron.git_gc_repos" = { ENABLED = true; RUN_AT_START = true; SCHEDULE = "@every 48h"; TIMEOUT = "1h"; }; git.GC_ARGS = "--prune=1.week.ago"; cors = { ENABLED = true; ALLOW_DOMAIN = fqdn; }; mailer = { ENABLED = true; FROM = "noreply@${my.domain}"; PROTOCOL = "smtps"; SMTP_PORT = 465; USER = "noreply@${my.domain}"; }; service = { ENABLE_CAPTCHA = false; ENABLE_BASIC_AUTHENTICATION = false; ENABLE_NOTIFY_MAIL = true; DISABLE_REGISTRATION = true; DEFAULT_ALLOW_CREATE_ORGANIZATION = true; VALID_SITE_URL_SCHEMES = "https"; }; server = { PROTOCOL = "http"; DOMAIN = fqdn; ROOT_URL = "https://${fqdn}"; HTTP_ADDR = "::1"; HTTP_PORT = 3110; SSH_USER = "git"; }; repository = { ENABLE_PUSH_CREATE_USER = true; ENABLE_PUSH_CREATE_ORG = false; PREFERRED_LICENSES = "MIT,GPL-3.0,LGPL-3.0"; }; security.INSTALL_LOCK = true; indexer.REPO_INDEXER_ENABLED = true; session = { PROVIDER = "db"; COOKIE_SECURE = true; }; actions = { ENABLED = true; DEFAULT_ACTIONS_URL = "https://code.forgejo.org"; }; "repository.pull-request".DEFAULT_MERGE_STYLE = "rebase"; "ui.meta" = { AUTHOR = "Christoph Heiss"; DESCRIPTION = "Christoph Heiss' git forge, powered by Forgejo."; KEYWORDS = "git,forge,forgejo,c8h4,christoph,heiss"; }; other = { SHOW_FOOTER_VERSION = false; SHOW_FOOTER_TEMPLATE_LOAD_TIME = false; }; }; secrets = { mailer = { SMTP_ADDR = secrets."forgejo/mail/host".path; PASSWD = secrets."forgejo/mail/password".path; }; }; dump = { enable = true; backupDir = "/var/backup/forgejo"; interval = "04:15"; type = "tar.zst"; file = "forgejo-dump"; # by default, timestamp is included }; }; assertions = let cfg = config.services.forgejo; in [{ assertion = cfg.database.name == cfg.database.user; }]; services.postgresql = { ensureDatabases = [ config.services.forgejo.database.name ]; ensureUsers = [{ name = config.services.forgejo.database.user; ensureDBOwnership = true; ensureClauses.login = true; }]; }; services.nginx.virtualHosts.${fqdn} = let serverCfg = config.services.forgejo.settings.server; in { forceSSL = true; useACMEHost = my.domain; kTLS = true; locations."/" = { proxyPass = "http://[${serverCfg.HTTP_ADDR}]:${toString serverCfg.HTTP_PORT}"; proxyWebsockets = true; extraConfig = '' client_max_body_size 256M; ''; }; }; services.openssh.settings.AllowUsers = [ "forgejo" ]; users.users.forgejo = { packages = with pkgs; [ forgejo ]; extraGroups = [ "restic-backup" ]; openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINVZ8zYHz1pUFzM8AKwMTWTTTvQTw10RyZJUVwXMt0FS" ]; }; services.restic.backups.forgejo = { environmentFile = secrets."restic/rest-env".path; initialize = true; repository = "${my.homelab.services.restic.repositoryBase}/${config.networking.hostName}"; passwordFile = secrets."restic/repo-password".path; inherit (config.services.forgejo) user; paths = [ "/var/backup/forgejo" ]; timerConfig.OnCalendar = "*-*-* 5:30:00"; # daily at 05:30 backupCleanupCommand = my.mkResticBackupNotificationCmd { name = "forgejo"; inherit pkgs secrets; }; }; }