From 7efb7a97614cb6d0f0a5a05cbe8d8abd068372bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Gro=C3=9Fmann?= Date: Fri, 12 Jan 2024 15:47:43 +0100 Subject: [PATCH] feat: gitea config --- hosts/elisabeth/guests.nix | 30 +++++- .../elisabeth/secrets/gitea/gitea-passwd.age | 16 ++++ hosts/elisabeth/secrets/gitea/secrets.nix.age | Bin 0 -> 795 bytes lib/containers.nix | 49 ---------- modules/config/users.nix | 1 + modules/services/adguardhome.nix | 14 ++- modules/services/gitea.nix | 90 ++++++++++++++++++ modules/services/nextcloud.nix | 19 +--- secrets/secrets.nix.age | Bin 4551 -> 4635 bytes 9 files changed, 145 insertions(+), 74 deletions(-) create mode 100644 hosts/elisabeth/secrets/gitea/gitea-passwd.age create mode 100644 hosts/elisabeth/secrets/gitea/secrets.nix.age delete mode 100644 lib/containers.nix create mode 100644 modules/services/gitea.nix diff --git a/hosts/elisabeth/guests.nix b/hosts/elisabeth/guests.nix index 2832a13..febc144 100644 --- a/hosts/elisabeth/guests.nix +++ b/hosts/elisabeth/guests.nix @@ -9,12 +9,33 @@ }: let adguardhomedomain = "adguardhome.${config.secrets.secrets.global.domains.web}"; nextclouddomain = "nc.${config.secrets.secrets.global.domains.web}"; + giteadomain = "git.${config.secrets.secrets.global.domains.web}"; + ipOf = hostName: lib.net.cidr.host config.secrets.secrets.global.net.ips."${config.guests.${hostName}.nodeName}" config.secrets.secrets.global.net.privateSubnet; in { services.nginx = { enable = true; recommendedSetup = true; + upstreams.gitea = { + servers."${ipOf "gitea"}:3000" = {}; + + extraConfig = '' + zone gitea 64k ; + keepalive 5 ; + ''; + }; + virtualHosts.${giteadomain} = { + forceSSL = true; + useACMEHost = "web"; + locations."/" = { + proxyPass = "http://gitea"; + proxyWebsockets = true; + }; + extraConfig = '' + client_max_body_size 1G ; + ''; + }; upstreams.adguardhome = { - servers."TODO:3000" = {}; + servers."${ipOf "adguardhome"}:3000" = {}; extraConfig = '' zone adguardhome 64k ; @@ -34,7 +55,7 @@ in { ''; }; upstreams.nextcloud = { - servers."TODO:80" = {}; + servers."${ipOf "nextcloud"}:3000" = {}; extraConfig = '' zone nextcloud 64k ; @@ -80,7 +101,7 @@ in { node.secretsDir = ./secrets/${guestName}; systemd.network.networks."10-${config.guests.${guestName}.networking.mainLinkName}" = { DHCP = lib.mkForce "no"; - address = [(lib.net.cidr.host config.secrets.secrets.global.net.ips.${config.guests.${guestName}.nodeName} config.secrets.secrets.global.net.privateSubnet)]; + address = [(ipOf guestName)]; gateway = [(lib.net.cidr.host 1 config.secrets.secrets.global.net.privateSubnet)]; }; } @@ -123,6 +144,9 @@ in { // mkContainer "nextcloud" { enablePanzer = true; } + // mkContainer "gitea" { + enablePanzer = true; + } // mkContainer "samba" { enablePanzer = true; enableRenaultFT = true; diff --git a/hosts/elisabeth/secrets/gitea/gitea-passwd.age b/hosts/elisabeth/secrets/gitea/gitea-passwd.age new file mode 100644 index 0000000..fad522e --- /dev/null +++ b/hosts/elisabeth/secrets/gitea/gitea-passwd.age @@ -0,0 +1,16 @@ +age-encryption.org/v1 +-> X25519 CMoCS3EqmXVkwSVuMB51DnV80S/H5zk8IcQeJxEqO0w +En/MAzeFWfcLrcUO4Ukt1zNBf5uVq+v0pBjz6+Um91U +-> piv-p256 XTQkUA A/AOwf+EXSep90xsABet03k1M+qNfxtRpRGR98Los0z0 +qid6WZum67EFiXR1hKjHrBIAnXfTqLipUpBhOAjWci4 +-> piv-p256 ZFgiIw A2QJdu+pkCF+oKjdRK6bZxESjy//RquUc8+mDoDj5fQ2 +0WqGNebppaN+RmIiDTh2j0SvmqakOt/qUhEc3mODXpU +-> piv-p256 5vmPtQ Ahcpp40amXecurWAP9dfZ1h7v49HPj0Bz9dvt8Cj9tB+ +kA/6aHJw5/GyqUXb8t15TPYxu8ZpNzGCD6/XRCPijPk +-> piv-p256 ZFgiIw ArryoUHlGkAM2e1BP1wfYeGceai5nKtvza3atjIxhh8B +bUKrpqhGst+Az60k7wy5hZMUsXq7f+VTcwuce0M/7pM +-> m\)y8qgO-grease ~N/[^ p8q(OzUj ztrT +0aZbW62GiFb8D7hcs4NT/OwKjpBpOYNslzhZRanUZpLr9t6+E4qXjCpAMTkg8UQe +SWw3pFmGBmaQh6rGJy1/J3VdLI0 +--- 9muabfoma9i62RxKgrGcp9bPYAjjDH3dLB3DJyjR58A +]׊6,^=夬O.:X7I@[0L ">w \ No newline at end of file diff --git a/hosts/elisabeth/secrets/gitea/secrets.nix.age b/hosts/elisabeth/secrets/gitea/secrets.nix.age new file mode 100644 index 0000000000000000000000000000000000000000..6ba5f85a4730315932664a9417937c04cd67a6c0 GIT binary patch literal 795 zcmY+y#S_1 z86k=^FhxLDgZ;n!a7AH_i;QDO}rTm_dV`G-f>%49O za-jOYE7y9M-easB?pYnLP^Do8b|n|dkwRGGVUWwJZ7_()`C_J3wj^5+U}L0DhW;>A zhCu0-Vz|swW}sP)P->nebh*^F*g-+Ih7}k9*)-*nfe~?ma)LHtTec*Nd14$Pl2pYY z1Q>uVx!Q4JX&iPHhf=E2G}9<-*};sF0!C(L$h=5XO$1T188!wyzZc zU22G$YL62$UvEs=<5^zQWfer3x|65=S=;+57#M13pwkBqwO9geVXlib4ToUeJd#SK z(4(JDfoXpiZ#CHyTe|O$^3G~-{zT8=N z@57p-Kc=^xyLx+~@>bQ4?R?MQ0zWtDpCV$%ZTib6SFA!p> zxRP9(-FoHz#NpjbA6I{^-aonN_xAPlY4XYWRqCDR7Y_fb%-+59Y4O@Na%uOe>kE@> yHcV_>@i1wqCOBTqh!0k}JC2;Wd2sEG6xj%O^fm&i(=G>lM@h literal 0 HcmV?d00001 diff --git a/lib/containers.nix b/lib/containers.nix deleted file mode 100644 index 1e98391..0000000 --- a/lib/containers.nix +++ /dev/null @@ -1,49 +0,0 @@ -inputs: _self: super: { - lib = - super.lib - // { - containers.mkConfig = name: attrs: config: - super.lib.mkMerge [ - { - config = { - imports = [ - ../modules/config - ]; - node.name = name; - node.secretsDir = attrs.config.node.secretsDir + "/guests/${name}"; - nixpkgs = { - inherit (attrs.pkgs) overlays config; - inherit (attrs.config.nixpkgs) hostPlatform; - }; - boot.initrd.systemd.enable = super.lib.mkForce false; - }; - specialArgs = { - inherit (attrs) lib inputs minimal stateVersion; - }; - extraFlags = [ - "--uuid=${builtins.substring 0 32 (builtins.hashString "sha256" name)}" - ]; - - autoStart = true; - macvlans = [ - "lan01:lan01-${name}" - ]; - ephemeral = true; - bindMounts = { - "state" = { - mountPoint = "/state"; - hostPath = "/state/containers/${name}"; - isReadOnly = false; - }; - "persist" = { - mountPoint = "/persist"; - hostPath = "/containers/${name}"; - isReadOnly = false; - }; - }; - zfs.mountpoint = super.lib.mkDefault "/containers/${name}"; - } - config - ]; - }; -} diff --git a/modules/config/users.nix b/modules/config/users.nix index 5f386b5..44af1ce 100644 --- a/modules/config/users.nix +++ b/modules/config/users.nix @@ -21,6 +21,7 @@ nextcloud = uidGid 213; redis-nextcloud = uidGid 214; radicale = uidGid 215; + gitea = uidGid 215; systemd-oom = uidGid 300; systemd-coredump = uidGid 301; patrick = uidGid 1000; diff --git a/modules/services/adguardhome.nix b/modules/services/adguardhome.nix index 484f09c..5b2587e 100644 --- a/modules/services/adguardhome.nix +++ b/modules/services/adguardhome.nix @@ -1,4 +1,8 @@ -{config, ...}: { +{ + config, + lib, + ... +}: { services.adguardhome = { enable = true; mutableSettings = false; @@ -7,7 +11,7 @@ bind_port = 3000; bind_host = "0.0.0.0"; dns = { - bind_hosts = ["TODO"]; + bind_hosts = ["0.0.0.0"]; anonymize_client_ip = true; upstream_dns = [ "1.0.0.1" @@ -22,9 +26,9 @@ "2001:4860:4860::8844" ]; }; - user_rules = '' - ||${config.secrets.secrets.global.domains.web}^$dnsrewrite=TODO - ''; + user_rules = [ + "||${config.secrets.secrets.global.domains.web}^$dnsrewrite=${lib.net.cidr.host config.secrets.secrets.global.net.ips.elisabeth config.secrets.secrets.global.net.privateSubnet}" + ]; dhcp.enabled = false; ratelimit = 60; users = [ diff --git a/modules/services/gitea.nix b/modules/services/gitea.nix new file mode 100644 index 0000000..e7dfa12 --- /dev/null +++ b/modules/services/gitea.nix @@ -0,0 +1,90 @@ +{ + config, + pkgs, + ... +}: let + giteaDomain = "git.${config.secrets.secrets.global.domains.web}"; +in { + # Recommended by forgejo: https://forgejo.org/docs/latest/admin/recommendations/#git-over-ssh + services.openssh.settings.AcceptEnv = "GIT_PROTOCOL"; + + environment.persistence."/panzer".directories = [ + { + directory = config.services.gitea.stateDir; + user = "gitea"; + group = "gitea"; + mode = "0700"; + } + ]; + age.secrets.gitea-mailer-passwd = { + rekeyFile = config.node.secretsDir + "/gitea-passwd.age"; + owner = "gitea"; + group = "gitea"; + mode = "0700"; + }; + + services.gitea = { + enable = true; + package = pkgs.forgejo; + appName = "Patricks tolles git"; # tungsten inert gas? + stateDir = "/var/lib/forgejo"; + # TODO db backups + # dump.enable = true; + lfs.enable = true; + mailerPasswordFile = config.age.secrets.gitea-mailer-passwd.path; + settings = { + actions = { + ENABLED = true; + DEFAULT_ACTIONS_URL = "github"; + }; + database = { + SQLITE_JOURNAL_MODE = "WAL"; + LOG_SQL = false; # Leaks secrets + }; + # federation.ENABLED = true; + mailer = { + ENABLED = true; + HOST = config.secrets.secrets.local.gitea.mail.host; + FROM = config.secrets.secrets.local.gitea.mail.from; + USER = config.secrets.secrets.local.gitea.mail.user; + SEND_AS_PLAIN_TEXT = true; + }; + # packages.ENABLED = true; + repository = { + DEFAULT_PRIVATE = "private"; + ENABLE_PUSH_CREATE_USER = true; + ENABLE_PUSH_CREATE_ORG = true; + }; + server = { + HTTP_ADDR = "0.0.0.0"; + HTTP_PORT = 3000; + DOMAIN = giteaDomain; + ROOT_URL = "https://${giteaDomain}/"; + LANDING_PAGE = "login"; + SSH_PORT = 9922; + # TODO + # port forwarding in fritz box + # port forwarding in elisabeth + }; + service = { + DISABLE_REGISTRATION = true; + ALLOW_ONLY_INTERNAL_REGISTRATION = true; + ALLOW_ONLY_EXTERNAL_REGISTRATION = false; + SHOW_REGISTRATION_BUTTON = false; + REGISTER_EMAIL_CONFIRM = false; + ENABLE_NOTIFY_MAIL = true; + DEFAULT_KEEP_EMAIL_PRIVATE = true; + }; + session.COOKIE_SECURE = true; + ui.DEFAULT_THEME = "forgejo-auto"; + "ui.meta" = { + AUTHOR = "Patrick"; + DESCRIPTION = "Tollstes Forgejo EU-West"; + }; + }; + }; + + systemd.services.gitea = { + serviceConfig.RestartSec = "600"; # Retry every 10 minutes + }; +} diff --git a/modules/services/nextcloud.nix b/modules/services/nextcloud.nix index badf481..df3c80a 100644 --- a/modules/services/nextcloud.nix +++ b/modules/services/nextcloud.nix @@ -6,18 +6,7 @@ }: let hostName = "nc.${config.secrets.secrets.global.domains.web}"; in { - systemd.network.networks = { - "TODO" = { - address = ["192.168.178.33/24"]; - gateway = ["192.168.178.1"]; - matchConfig.Name = "lan01*"; - dns = ["192.168.178.2"]; - networkConfig = { - IPv6PrivacyExtensions = "yes"; - MulticastDNS = true; - }; - }; - }; + # TODO mailer environment.persistence."/persist".directories = [ { directory = "/var/lib/postgresql/"; @@ -40,10 +29,6 @@ in { owner = "nextcloud"; }; services.postgresql.package = pkgs.postgresql_16; - services.nginx.virtualHosts.${hostName}.extraConfig = '' - allow TODO; - deny all; - ''; services.nextcloud = { inherit hostName; @@ -61,7 +46,7 @@ in { phpOptions."opcache.interned_strings_buffer" = "32"; extraOptions = { default_phone_region = "DE"; - trusted_proxies = ["TODO"]; + trusted_proxies = [(lib.net.cidr.host config.secrets.secrets.global.net.ips.elisabeth config.secrets.secrets.global.net.privateSubnet)]; overwriteprotocol = "https"; enabledPreviewProviders = [ "OC\\Preview\\BMP" diff --git a/secrets/secrets.nix.age b/secrets/secrets.nix.age index 0d5bdad23571ddbabf3de9a9318886fb09a3963c..36fc00b21dfda744ddeb2307b439930d6cbbc2fa 100644 GIT binary patch delta 4629 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 L|HV7v=`Hht8_th? delta 4545 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