Self-host your own digital island
1{ pkgs, config, lib, ... }: 2 3with lib; 4let 5 cfg = config.eilean; 6 domain = config.networking.domain; 7 subdomain = "git.${domain}"; 8in { 9 options.eilean.gitea = { 10 enable = mkEnableOption "gitea"; 11 sshPort = mkOption { 12 type = types.int; 13 default = 3001; 14 }; 15 databasePasswordFile = mkOption { 16 type = types.nullOr types.path; 17 default = null; 18 }; 19 }; 20 21 config = mkIf cfg.gitea.enable { 22 security.acme-eon.nginxCerts = [ subdomain ]; 23 24 services.nginx = { 25 enable = true; 26 recommendedProxySettings = true; 27 virtualHosts."${subdomain}" = { 28 enableACME = lib.mkIf (!cfg.acme-eon) true; 29 forceSSL = true; 30 locations."/" = { 31 proxyPass = "http://localhost:${ 32 builtins.toString config.services.gitea.settings.server.HTTP_PORT 33 }/"; 34 }; 35 }; 36 }; 37 38 users.users.git = { 39 description = "Git Service"; 40 home = config.services.gitea.stateDir; 41 useDefaultShell = true; 42 group = "gitea"; 43 isSystemUser = true; 44 }; 45 46 services.gitea = { 47 enable = true; 48 user = "git"; 49 appName = "git | ${domain}"; 50 mailerPasswordFile = cfg.mailserver.systemAccountPasswordFile; 51 settings = { 52 server = { 53 ROOT_URL = "https://${subdomain}/"; 54 DOMAIN = subdomain; 55 }; 56 mailer = { 57 ENABLED = true; 58 FROM = "git@${domain}"; 59 MAILER_TYPE = "smtp"; 60 HOST = "mail.${domain}:465"; 61 USER = "system@${domain}"; 62 IS_TLS_ENABLED = true; 63 }; 64 repository.DEFAULT_BRANCH = "main"; 65 service.DISABLE_REGISTRATION = true; 66 #server.HTTP_PORT = 3000; 67 }; 68 database = { 69 type = "postgres"; 70 passwordFile = cfg.gitea.databasePasswordFile; 71 user = "git"; 72 name = "git"; 73 #createDatabase = true; 74 #socket = "/run/postgresql"; 75 }; 76 #stateDir = "/var/lib/gitea"; 77 }; 78 79 # https://github.com/NixOS/nixpkgs/issues/103446 80 systemd.services.gitea.serviceConfig = { 81 ReadWritePaths = [ "/var/lib/postfix/queue/maildrop" ]; 82 NoNewPrivileges = mkForce false; 83 PrivateDevices = mkForce false; 84 PrivateUsers = mkForce false; 85 ProtectHostname = mkForce false; 86 ProtectClock = mkForce false; 87 ProtectKernelTunables = mkForce false; 88 ProtectKernelModules = mkForce false; 89 ProtectKernelLogs = mkForce false; 90 RestrictAddressFamilies = mkForce [ ]; 91 LockPersonality = mkForce false; 92 MemoryDenyWriteExecute = mkForce false; 93 RestrictRealtime = mkForce false; 94 RestrictSUIDSGID = mkForce false; 95 SystemCallArchitectures = mkForce ""; 96 SystemCallFilter = mkForce [ ]; 97 }; 98 99 eilean.dns.enable = true; 100 eilean.services.dns.zones.${config.networking.domain}.records = [{ 101 name = "git"; 102 type = "CNAME"; 103 value = cfg.domainName; 104 }]; 105 106 # proxy port 22 on ethernet interface to internal gitea ssh server 107 # openssh server remains accessible on port 22 via vpn(s) 108 109 # allow forwarding 110 boot.kernel.sysctl = { 111 "net.ipv4.ip_forward" = 1; 112 "net.ipv6.conf.all.forwarding" = 1; 113 }; 114 115 networking.firewall = { 116 allowedTCPPorts = [ 22 cfg.gitea.sshPort ]; 117 extraCommands = '' 118 # proxy all traffic on public interface to the gitea SSH server 119 iptables -A PREROUTING -t nat -i ${config.eilean.publicInterface} -p tcp --dport 22 -j REDIRECT --to-port ${ 120 builtins.toString cfg.gitea.sshPort 121 } 122 ip6tables -A PREROUTING -t nat -i ${config.eilean.publicInterface} -p tcp --dport 22 -j REDIRECT --to-port ${ 123 builtins.toString cfg.gitea.sshPort 124 } 125 126 # proxy locally originating outgoing packets 127 iptables -A OUTPUT -d ${config.eilean.serverIpv4} -t nat -p tcp --dport 22 -j REDIRECT --to-port ${ 128 builtins.toString cfg.gitea.sshPort 129 } 130 ip6tables -A OUTPUT -d ${config.eilean.serverIpv6} -t nat -p tcp --dport 22 -j REDIRECT --to-port ${ 131 builtins.toString cfg.gitea.sshPort 132 } 133 ''; 134 }; 135 136 services.gitea.settings.server = { 137 START_SSH_SERVER = true; 138 SSH_LISTEN_PORT = cfg.gitea.sshPort; 139 }; 140 }; 141}