{ pkgs, lib, config, ... }: let cfg = config.bagel.services.forgejo; inherit (lib) mkIf mkEnableOption mkOption types; domain = "git.forkos.org"; in { options.bagel.services.forgejo = { enable = mkEnableOption "Forgejo"; sshBindAddr = mkOption { type = types.str; }; }; config = mkIf cfg.enable { services.forgejo = { enable = true; package = pkgs.callPackage ../../pkgs/forgejo { }; database = { type = "postgres"; createDatabase = true; }; lfs.enable = true; settings = { DEFAULT = { APP_NAME = "ForkOS"; }; server = { PROTOCOL = "http+unix"; ROOT_URL = "https://${domain}/"; DOMAIN = "${domain}"; BUILTIN_SSH_SERVER_USER = "git"; SSH_PORT = 22; SSH_LISTEN_HOST = cfg.sshBindAddr; START_SSH_SERVER = true; }; session = { PROVIDER = "db"; COOKIE_NAME = "session"; }; service = { DISABLE_REGISTRATION = true; DEFAULT_KEEP_EMAIL_PRIVATE = true; }; oauth2_client = { REGISTER_EMAIL_CONFIRM = false; ENABLE_AUTO_REGISTRATION = true; }; # TODO: transactional mails # TODO: redis cache instead of default in-memory ui = { SHOW_USER_EMAIL = false; }; repository = { # Forks in forgejo are suprisingly expensive because they are full git clones. # If we do want to enable forks, we can write a small patch that disables # only for repositories that are as large as nixpkgs. DISABLE_FORKS = true; }; packages = { # Forgejo's various package registries can easily take up a lot of space. # We could either store the blobs on some slower disks but larger, or even # better, use an s3 bucket for it. But until we actually have a use-case for # this feature, we will simply keep it disabled for now. ENABLED = false; }; indexer = { REPO_INDEXER_REPO_TYPES = "sources,mirrors,templates"; # skip forks REPO_INDEXER_ENABLED = true; ISSUE_INDEXER_TYPE = "bleve"; }; "git.timeout" = { MIGRATE = 3600; # increase from default 600 (seconds) for something as large as nixpkgs on a slow uplink }; log = { LEVEL = "Warn"; }; }; }; systemd.services.forgejo = { serviceConfig = lib.optionalAttrs (config.services.forgejo.settings.server.SSH_PORT < 1024) { AmbientCapabilities = lib.mkForce "CAP_NET_BIND_SERVICE"; CapabilityBoundingSet = lib.mkForce "CAP_NET_BIND_SERVICE"; PrivateUsers = lib.mkForce false; }; # start Forgejo *after* sshd.service, so in case Forgejo tries to wildcard bind :22 due to # a bug or whatever, we don't lose OpenSSH in a race. wants = [ "sshd.service" ]; requires = [ "sshd.service" ]; }; services.nginx = { enable = true; virtualHosts.${domain} = { enableACME = true; forceSSL = true; locations."/".proxyPass = "http://unix:${config.services.forgejo.settings.server.HTTP_ADDR}"; }; }; networking.firewall.allowedTCPPorts = [ 80 443 config.services.forgejo.settings.server.SSH_PORT ]; }; }