{ pkgs, lib, config, ... }: with lib; let cfg = config.fudo.git; databaseOpts = { ... }: { options = { name = mkOption { type = types.str; description = "Database name."; }; hostname = mkOption { type = types.str; description = "Hostname of the database server."; }; user = mkOption { type = types.str; description = "Database username."; }; password-file = mkOption { type = types.path; description = "File containing the database user's password."; }; }; }; sshOpts = { ... }: with types; { options = { listen-ip = mkOption { type = str; description = "IP on which to listen for SSH connections."; }; listen-port = mkOption { type = port; description = "Port on which to listen for SSH connections, on ."; default = 22; }; }; }; in { options.fudo.git = with types; { enable = mkEnableOption "Enable Fudo git web server."; hostname = mkOption { type = str; description = "Hostname at which this git server is accessible."; example = "git.fudo.org"; }; site-name = mkOption { type = str; description = "Name to use for the git server."; default = "Fudo Git"; }; database = mkOption { type = (submodule databaseOpts); description = "Gitea database options."; }; repository-dir = mkOption { type = path; description = "Path at which to store repositories."; example = /srv/git/repo; }; state-dir = mkOption { type = path; description = "Path at which to store server state."; example = /srv/git/state; }; user = mkOption { type = with types; nullOr str; description = "System user as which to run."; default = "git"; }; local-port = mkOption { type = port; description = "Local port to which the Gitea server will bind. Not globally accessible."; default = 3543; }; ssh = mkOption { type = nullOr (submodule sshOpts); description = "SSH listen configuration."; default = null; }; }; config = mkIf cfg.enable { security.acme.certs.${cfg.hostname}.email = let domain-name = config.fudo.hosts.${config.instance.hostname}.domain; in config.fudo.domains.${domain-name}.admin-email; networking.firewall.allowedTCPPorts = mkIf (cfg.ssh != null) [ cfg.ssh.listen-port ]; services = { gitea = { enable = true; appName = cfg.site-name; database = { createDatabase = true; host = cfg.database.hostname; name = cfg.database.name; user = cfg.database.user; passwordFile = cfg.database.password-file; type = "postgres"; }; domain = cfg.hostname; httpAddress = "127.0.0.1"; httpPort = cfg.local-port; repositoryRoot = toString cfg.repository-dir; stateDir = toString cfg.state-dir; rootUrl = "https://${cfg.hostname}/"; user = mkIf (cfg.user != null) cfg.user; ssh = { enable = true; clonePort = cfg.ssh.listen-port; }; settings = mkIf (cfg.ssh != null) { server = { SSH_DOMAIN = cfg.hostname; SSH_LISTEN_PORT = cfg.ssh.listen-port; SSH_LISTEN_HOST = cfg.ssh.listen-ip; }; }; }; nginx = { enable = true; virtualHosts = { "${cfg.hostname}" = { enableACME = true; forceSSL = true; locations."/" = { proxyPass = "http://127.0.0.1:${toString cfg.local-port}"; extraConfig = '' proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-By $server_addr:$server_port; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; ''; }; }; }; }; }; }; }