From 3c09cf9f69f4ccdc14b03bc8869776b43f7d20a3 Mon Sep 17 00:00:00 2001 From: Nikolaos Karaolidis Date: Fri, 16 May 2025 18:16:25 +0100 Subject: [PATCH] Add gitea Signed-off-by: Nikolaos Karaolidis --- .../nick/configs/console/podman/default.nix | 2 +- .../nikara/configs/console/podman/default.nix | 2 +- .../configs/podman/prometheus/default.nix | 4 +- .../nick/configs/console/podman/default.nix | 2 +- .../console/podman/authelia/default.nix | 58 ++-- .../podman/authelia/init-entrypoint.sh | 7 + .../storm/configs/console/podman/default.nix | 3 +- .../configs/console/podman/gitea/default.nix | 256 ++++++++++++++++++ .../console/podman/gitea/entrypoint.sh | 17 ++ .../podman/grafana/dashboards/system.json | 88 ++---- .../console/podman/grafana/default.nix | 10 +- .../configs/console/podman/ntfy/default.nix | 85 +++--- .../configs/console/podman/ntfy/entrypoint.sh | 20 ++ .../console/podman/prometheus/default.nix | 14 +- .../console/podman/traefik/default.nix | 10 +- hosts/jupiter/users/storm/default.nix | 36 +-- packages/default.nix | 1 + packages/docker/base/default.nix | 4 + packages/docker/gitea/default.nix | 36 +++ 19 files changed, 471 insertions(+), 184 deletions(-) create mode 100644 hosts/jupiter/users/storm/configs/console/podman/authelia/init-entrypoint.sh create mode 100644 hosts/jupiter/users/storm/configs/console/podman/gitea/default.nix create mode 100644 hosts/jupiter/users/storm/configs/console/podman/gitea/entrypoint.sh create mode 100644 hosts/jupiter/users/storm/configs/console/podman/ntfy/entrypoint.sh create mode 100644 packages/docker/gitea/default.nix diff --git a/hosts/eirene/users/nick/configs/console/podman/default.nix b/hosts/eirene/users/nick/configs/console/podman/default.nix index 099957b..605d8e7 100644 --- a/hosts/eirene/users/nick/configs/console/podman/default.nix +++ b/hosts/eirene/users/nick/configs/console/podman/default.nix @@ -13,7 +13,7 @@ in "registry/registry.karaolidis.com".sopsFile = ../../../../../../../secrets/personal/secrets.yaml; }; - templates."containers-auth.json" = { + templates.containers-auth = { content = builtins.readFile ( (pkgs.formats.json { }).generate "auth.json" { auths = { diff --git a/hosts/elara/users/nikara/configs/console/podman/default.nix b/hosts/elara/users/nikara/configs/console/podman/default.nix index 087ec0f..d9802be 100644 --- a/hosts/elara/users/nikara/configs/console/podman/default.nix +++ b/hosts/elara/users/nikara/configs/console/podman/default.nix @@ -30,7 +30,7 @@ in }; }; - templates."containers-auth.json" = { + templates.containers-auth = { content = builtins.readFile ( (pkgs.formats.json { }).generate "auth.json" { auths = { diff --git a/hosts/jupiter-vps/configs/podman/prometheus/default.nix b/hosts/jupiter-vps/configs/podman/prometheus/default.nix index 89e4869..45ee7aa 100644 --- a/hosts/jupiter-vps/configs/podman/prometheus/default.nix +++ b/hosts/jupiter-vps/configs/podman/prometheus/default.nix @@ -51,14 +51,14 @@ in prometheus-podman-exporter.containerConfig = { image = "docker-archive:${selfPkgs.docker-prometheus-podman-exporter}"; - publishPorts = [ "9882:9882" ]; + publishPorts = [ "9882:9882/tcp" ]; volumes = [ "/run/podman/podman.sock:/run/podman/podman.sock:ro" ]; exec = [ "--collector.enable-all" ]; }; prometheus-fail2ban-exporter.containerConfig = { image = "docker-archive:${selfPkgs.docker-prometheus-fail2ban-exporter}"; - publishPorts = [ "9191:9191" ]; + publishPorts = [ "9191:9191/tcp" ]; volumes = [ "/run/fail2ban/fail2ban.sock:/var/run/fail2ban/fail2ban.sock:ro" ]; }; }; diff --git a/hosts/jupiter/users/nick/configs/console/podman/default.nix b/hosts/jupiter/users/nick/configs/console/podman/default.nix index c8b51c9..0fb3755 100644 --- a/hosts/jupiter/users/nick/configs/console/podman/default.nix +++ b/hosts/jupiter/users/nick/configs/console/podman/default.nix @@ -10,7 +10,7 @@ in home-manager.users.${user}.sops = { secrets."registry/docker.io".sopsFile = ../../../../../../../secrets/personal/secrets.yaml; - templates."containers-auth.json" = { + templates.containers-auth = { content = builtins.readFile ( (pkgs.formats.json { }).generate "auth.json" { auths = { diff --git a/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix b/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix index 6315b1a..1f607e3 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/authelia/default.nix @@ -30,11 +30,11 @@ in }; templates = { - "authelia-postgresql.env".content = '' + authelia-postgresql-env.content = '' POSTGRES_PASSWORD=${hmConfig.sops.placeholder."authelia/postgresql"} ''; - "authelia-configuration.yaml".content = builtins.readFile ( + authelia.content = builtins.readFile ( (pkgs.formats.yaml { }).generate "configuration.yaml" { authentication_backend = { refresh_interval = "always"; @@ -120,13 +120,16 @@ in } ); - "authelia-users.yaml".content = builtins.readFile ( + authelia-users.content = builtins.readFile ( (pkgs.formats.yaml { }).generate "users.yaml" { users.karaolidis = { displayname = "Nick Karaolidis"; password = hmConfig.sops.placeholder."authelia/users/karaolidis"; email = "nick@karaolidis.com"; - groups = [ "admins" ]; + groups = [ + "admins" + "git" + ]; }; } ); @@ -144,20 +147,24 @@ in containers = { authelia-init = { - containerConfig = { - image = "docker-archive:${selfPkgs.docker-yq}"; - volumes = [ - "${volumes.authelia.ref}:/etc/authelia" - "${hmConfig.sops.templates."authelia-users.yaml".path}:/etc/authelia/users.yaml.default:ro" - ]; - exec = [ - "eval-all" - ". as $item ireduce ({}; . *+ $item)" - "/etc/authelia/users.yaml" - "/etc/authelia/users.yaml.default" - "-i" - ]; - }; + containerConfig = + let + entrypoint = pkgs.writeTextFile { + name = "entrypoint.sh"; + executable = true; + text = builtins.readFile ./init-entrypoint.sh; + }; + in + { + image = "docker-archive:${selfPkgs.docker-yq}"; + volumes = [ + "${volumes.authelia.ref}:/etc/authelia" + "${hmConfig.sops.templates.authelia-users.path}:/etc/authelia/users.yaml.default:ro" + "${hmConfig.sops.templates.authelia.path}:/etc/authelia/conf.d/authelia.yaml:ro" + "${entrypoint}:/entrypoint.sh:ro" + ]; + entrypoint = "/entrypoint.sh"; + }; serviceConfig = { Type = "oneshot"; @@ -170,12 +177,7 @@ in authelia = { containerConfig = { image = "docker-archive:${selfPkgs.docker-authelia}"; - volumes = [ - "${volumes.authelia.ref}:/etc/authelia" - "${ - hmConfig.sops.templates."authelia-configuration.yaml".path - }:/etc/authelia/conf.d/configuration.yaml:ro" - ]; + volumes = [ "${volumes.authelia.ref}:/etc/authelia" ]; networks = [ networks.authelia.ref networks.traefik.ref @@ -183,7 +185,7 @@ in ]; exec = [ "--config" - "/etc/authelia/conf.d/" + "/etc/authelia/configuration.yaml" ]; labels = [ "traefik.enable=true" @@ -212,7 +214,7 @@ in POSTGRES_DB = "authelia"; POSTGRES_USER = "authelia"; }; - environmentFiles = [ hmConfig.sops.templates."authelia-postgresql.env".path ]; + environmentFiles = [ hmConfig.sops.templates.authelia-postgresql-env.path ]; }; unitConfig.After = [ "sops-nix.service" ]; @@ -227,7 +229,7 @@ in prometheus-init.containerConfig.volumes = let - autheliaConfig = (pkgs.formats.yaml { }).generate "authelia.yml" { + autheliaConfig = (pkgs.formats.yaml { }).generate "authelia.yaml" { scrape_configs = let hostname = config.networking.hostName; @@ -248,7 +250,7 @@ in ]; }; in - [ "${autheliaConfig}:/etc/prometheus/conf.d/authelia.yml" ]; + [ "${autheliaConfig}:/etc/prometheus/conf.d/authelia.yaml" ]; }; }; diff --git a/hosts/jupiter/users/storm/configs/console/podman/authelia/init-entrypoint.sh b/hosts/jupiter/users/storm/configs/console/podman/authelia/init-entrypoint.sh new file mode 100644 index 0000000..a8798a3 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/authelia/init-entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +touch /etc/authelia/users.yaml +# shellcheck disable=SC2016 +yq eval-all '. as $item ireduce ({}; . * $item)' /etc/authelia/users.yaml /etc/authelia/users.yaml.default -i +# shellcheck disable=SC2016 +yq eval-all '. as $item ireduce ({}; . *+ $item)' /etc/authelia/conf.d/*.yaml > /etc/authelia/configuration.yaml diff --git a/hosts/jupiter/users/storm/configs/console/podman/default.nix b/hosts/jupiter/users/storm/configs/console/podman/default.nix index 798aaf4..b7b8e20 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/default.nix @@ -9,6 +9,7 @@ in { imports = [ (import ./authelia { inherit user home; }) + (import ./gitea { inherit user home; }) (import ./grafana { inherit user home; }) (import ./ntfy { inherit user home; }) (import ./prometheus { inherit user home; }) @@ -29,7 +30,7 @@ in sops = { secrets."registry/docker.io".sopsFile = ../../../../../../../secrets/personal/secrets.yaml; - templates."containers-auth.json" = { + templates.containers-auth = { content = builtins.readFile ( (pkgs.formats.json { }).generate "auth.json" { auths = { diff --git a/hosts/jupiter/users/storm/configs/console/podman/gitea/default.nix b/hosts/jupiter/users/storm/configs/console/podman/gitea/default.nix new file mode 100644 index 0000000..64e2ca1 --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/gitea/default.nix @@ -0,0 +1,256 @@ +{ + user ? throw "user argument is required", + home ? throw "home argument is required", +}: +{ + config, + inputs, + lib, + pkgs, + system, + ... +}: +let + selfPkgs = inputs.self.packages.${system}; + hmConfig = config.home-manager.users.${user}; + inherit (hmConfig.virtualisation.quadlet) volumes networks; + autheliaClientId = "I2ZYDFGWP1bzfiauXe94IaiReZF6SqoEskSp6phoL2L8l16Cq7YX3Vr4pkQOSYfNDOwuFjTRIpqQ8eAqK0M93NeEgpr8YoPhKHyR"; + podman = lib.meta.getExe pkgs.podman; + podmanAsUser = "${config.security.wrapperDir}/git-sudo -u ${user} ${podman}"; +in +{ + security = { + sudo.extraRules = [ + { + users = [ config.users.users.git.name ]; + runAs = user; + commands = [ + { + command = podman; + options = [ "NOPASSWD" ]; + } + ]; + } + ]; + + wrappers."git-sudo" = { + source = "${config.security.sudo.package}/bin/sudo"; + owner = "root"; + group = "root"; + setuid = true; + }; + }; + + users = { + users.git = { + isSystemUser = true; + description = "Git"; + uid = config.ids.uids.git; + group = "git"; + shell = pkgs.writeShellApplication { + name = "git-podman-shell"; + text = '' + ${podmanAsUser} exec -i -e SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@" + ''; + passthru.shellPath = "/bin/git-podman-shell"; + }; + }; + + groups.git.gid = config.ids.uids.git; + }; + + services.openssh.extraConfig = '' + Match User git + AuthorizedKeysCommandUser git + AuthorizedKeysCommand ${podmanAsUser} exec -i gitea gitea keys -c /etc/gitea/app.ini -e git -u %u -t %t -k %k + ''; + + home-manager.users.${user} = { + sops = { + secrets = { + "gitea/postgresql".sopsFile = ../../../../../../secrets/secrets.yaml; + "gitea/smtp".sopsFile = ../../../../../../secrets/secrets.yaml; + "gitea/secretKey".sopsFile = ../../../../../../secrets/secrets.yaml; + "gitea/internalToken".sopsFile = ../../../../../../secrets/secrets.yaml; + "gitea/jwtSecret".sopsFile = ../../../../../../secrets/secrets.yaml; + "gitea/lfsJwtSecret".sopsFile = ../../../../../../secrets/secrets.yaml; + "gitea/authelia/password".sopsFile = ../../../../../../secrets/secrets.yaml; + "gitea/authelia/digest".sopsFile = ../../../../../../secrets/secrets.yaml; + }; + + templates = { + gitea-postgresql-env.content = '' + POSTGRES_PASSWORD=${hmConfig.sops.placeholder."gitea/postgresql"} + ''; + + gitea-env.content = '' + GITEA_OAUTH_SECRET=${hmConfig.sops.placeholder."gitea/authelia/password"} + ''; + + gitea.content = builtins.readFile ( + (pkgs.formats.iniWithGlobalSection { }).generate "app.ini" { + globalSection = { + I_AM_BEING_UNSAFE_RUNNING_AS_ROOT = true; + }; + + sections = { + server = { + ROOT_URL = "https://git.karaolidis.com:443/"; + + # FIXME: https://github.com/go-gitea/gitea/issues/31112 + OFFLINE_MODE = false; + + SSH_USER = "git"; + SSH_DOMAIN = "karaolidis.com"; + SSH_CREATE_AUTHORIZED_KEYS_FILE = false; + + LFS_START_SERVER = true; + LFS_ALLOW_PURE_SSH = true; + LFS_JWT_SECRET = hmConfig.sops.placeholder."gitea/lfsJwtSecret"; + }; + + service = { + ALLOW_ONLY_EXTERNAL_REGISTRATION = true; + SHOW_REGISTRATION_BUTTON = false; + }; + + openid = { + ENABLE_OPENID_SIGNUP = true; + WHITELISTED_URIS = "id.karaolidis.com"; + }; + + oauth2 = { + JWT_SECRET = hmConfig.sops.placeholder."gitea/jwtSecret"; + }; + + oauth2_client = { + ENABLE_AUTO_REGISTRATION = true; + USERNAME = "preferred_username"; + }; + + repository = { + ENABLE_PUSH_CREATE_USER = true; + }; + + database = { + DB_TYPE = "postgres"; + HOST = "gitea-postgresql:5432"; + NAME = "gitea"; + USER = "gitea"; + PASSWD = hmConfig.sops.placeholder."gitea/postgresql"; + }; + + mailer = { + ENABLE = true; + PROTOCOL = "smtp+starttls"; + SMTP_ADDR = "smtp.protonmail.ch"; + SMTP_PORT = 587; + USER = "jupiter@karaolidis.com"; + PASSWD = hmConfig.sops.placeholder."gitea/smtp"; + FROM = "jupiter@karaolidis.com"; + }; + + security = { + INSTALL_LOCK = true; + SECRET_KEY = hmConfig.sops.placeholder."gitea/secretKey"; + INTERNAL_TOKEN = hmConfig.sops.placeholder."gitea/internalToken"; + }; + + metrics = { + ENABLED = true; + }; + }; + } + ); + + authelia-gitea.content = builtins.readFile ( + (pkgs.formats.yaml { }).generate "gitea.yaml" { + identity_providers.oidc = { + authorization_policies.git = { + default_policy = "deny"; + rules = [ + { + policy = "one_factor"; + subject = "group:git"; + } + ]; + }; + + clients = [ + { + client_id = autheliaClientId; + client_name = "Gitea"; + client_secret = hmConfig.sops.placeholder."gitea/authelia/digest"; + redirect_uris = [ "https://git.karaolidis.com/user/oauth2/authelia/callback" ]; + authorization_policy = "git"; + } + ]; + }; + } + ); + }; + }; + + virtualisation.quadlet = { + networks.gitea.networkConfig.internal = true; + + volumes = { + gitea-postgresql = { }; + gitea = { }; + }; + + containers = { + gitea = + let + entrypoint = pkgs.writeTextFile { + name = "entrypoint.sh"; + executable = true; + text = builtins.readFile ./entrypoint.sh; + }; + in + { + containerConfig = { + image = "docker-archive:${selfPkgs.docker-gitea}"; + networks = [ + networks.gitea.ref + networks.traefik.ref + ]; + volumes = [ + "${volumes.gitea.ref}:/var/lib/gitea/data" + "${hmConfig.sops.templates.gitea.path}:/etc/gitea/app.ini:ro" + "${entrypoint}:/entrypoint.sh:ro" + ]; + environments.GITEA_OAUTH_KEY = autheliaClientId; + environmentFiles = [ hmConfig.sops.templates.gitea-env.path ]; + entrypoint = "/entrypoint.sh"; + labels = [ + "traefik.enable=true" + "traefik.http.routers.gitea.rule=Host(`git.karaolidis.com`)" + ]; + }; + + unitConfig.After = [ "sops-nix.service" ]; + }; + + gitea-postgresql = { + containerConfig = { + image = "docker-archive:${selfPkgs.docker-postgresql}"; + networks = [ networks.gitea.ref ]; + volumes = [ "${volumes.gitea-postgresql.ref}:/var/lib/postgresql/data" ]; + environments = { + POSTGRES_DB = "gitea"; + POSTGRES_USER = "gitea"; + }; + environmentFiles = [ hmConfig.sops.templates.gitea-postgresql-env.path ]; + }; + + unitConfig.After = [ "sops-nix.service" ]; + }; + + authelia-init.containerConfig.volumes = [ + "${hmConfig.sops.templates.authelia-gitea.path}:/etc/authelia/conf.d/gitea.yaml:ro" + ]; + }; + }; + }; +} diff --git a/hosts/jupiter/users/storm/configs/console/podman/gitea/entrypoint.sh b/hosts/jupiter/users/storm/configs/console/podman/gitea/entrypoint.sh new file mode 100644 index 0000000..9d2b4ab --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/gitea/entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +gitea migrate -c /etc/gitea/app.ini + +gitea admin auth add-oauth \ + -c /etc/gitea/app.ini \ + --name=authelia \ + --provider=openidConnect \ + --key="$GITEA_OAUTH_KEY" \ + --secret="$GITEA_OAUTH_SECRET" \ + --auto-discover-url=https://id.karaolidis.com/.well-known/openid-configuration \ + --scopes='openid email profile groups' \ + --skip-local-2fa \ + --group-claim-name=groups \ + --admin-group=admins 2>&1 || true + +exec gitea web -c /etc/gitea/app.ini diff --git a/hosts/jupiter/users/storm/configs/console/podman/grafana/dashboards/system.json b/hosts/jupiter/users/storm/configs/console/podman/grafana/dashboards/system.json index 26cdbc1..d509270 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/grafana/dashboards/system.json +++ b/hosts/jupiter/users/storm/configs/console/podman/grafana/dashboards/system.json @@ -71,9 +71,7 @@ "orientation": "auto", "percentChangeColorMode": "standard", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -145,9 +143,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -217,9 +213,7 @@ "orientation": "auto", "percentChangeColorMode": "inverted", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -285,9 +279,7 @@ "orientation": "auto", "percentChangeColorMode": "inverted", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -353,9 +345,7 @@ "orientation": "auto", "percentChangeColorMode": "inverted", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -419,9 +409,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -502,9 +490,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -572,9 +558,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -642,9 +626,7 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -748,9 +730,7 @@ "orientation": "auto", "percentChangeColorMode": "inverted", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -816,9 +796,7 @@ "orientation": "auto", "percentChangeColorMode": "inverted", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -884,9 +862,7 @@ "orientation": "auto", "percentChangeColorMode": "inverted", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -952,9 +928,7 @@ "orientation": "auto", "percentChangeColorMode": "inverted", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1020,9 +994,7 @@ "orientation": "auto", "percentChangeColorMode": "inverted", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1088,9 +1060,7 @@ "orientation": "auto", "percentChangeColorMode": "inverted", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1148,9 +1118,7 @@ "orientation": "auto", "percentChangeColorMode": "standard", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1332,9 +1300,7 @@ "orientation": "auto", "percentChangeColorMode": "standard", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1395,9 +1361,7 @@ "orientation": "auto", "percentChangeColorMode": "standard", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1458,9 +1422,7 @@ "orientation": "auto", "percentChangeColorMode": "standard", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1525,9 +1487,7 @@ "orientation": "auto", "percentChangeColorMode": "standard", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1589,9 +1549,7 @@ "orientation": "auto", "percentChangeColorMode": "standard", "reduceOptions": { - "calcs": [ - "lastNotNull" - ], + "calcs": ["lastNotNull"], "fields": "", "values": false }, @@ -1861,9 +1819,7 @@ "footer": { "countRows": false, "fields": "", - "reducer": [ - "sum" - ], + "reducer": ["sum"], "show": false }, "showHeader": true, diff --git a/hosts/jupiter/users/storm/configs/console/podman/grafana/default.nix b/hosts/jupiter/users/storm/configs/console/podman/grafana/default.nix index aef364f..104a47f 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/grafana/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/grafana/default.nix @@ -26,7 +26,7 @@ in }; templates = { - "authelia-grafana.yaml".content = builtins.readFile ( + authelia-grafana.content = builtins.readFile ( (pkgs.formats.yaml { }).generate "grafana.yaml" { identity_providers.oidc.clients = [ { @@ -42,7 +42,7 @@ in } ); - "grafana.ini".content = builtins.readFile ( + grafana.content = builtins.readFile ( (pkgs.formats.ini { }).generate "grafana.ini" { server.root_url = "https://stats.karaolidis.com"; @@ -132,7 +132,7 @@ in networks.grafana.ref networks.traefik.ref ]; - volumes = [ "${hmConfig.sops.templates."grafana.ini".path}:/etc/grafana/grafana.ini" ]; + volumes = [ "${hmConfig.sops.templates.grafana.path}:/etc/grafana/grafana.ini" ]; labels = [ "traefik.enable=true" "traefik.http.routers.grafana.rule=Host(`stats.karaolidis.com`)" @@ -147,8 +147,8 @@ in networks = [ networks.grafana.ref ]; }; - authelia.containerConfig.volumes = [ - "${hmConfig.sops.templates."authelia-grafana.yaml".path}:/etc/authelia/conf.d/grafana.yaml:ro" + authelia-init.containerConfig.volumes = [ + "${hmConfig.sops.templates.authelia-grafana.path}:/etc/authelia/conf.d/grafana.yaml:ro" ]; }; }; diff --git a/hosts/jupiter/users/storm/configs/console/podman/ntfy/default.nix b/hosts/jupiter/users/storm/configs/console/podman/ntfy/default.nix index 81c8d11..611b4a1 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/ntfy/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/ntfy/default.nix @@ -25,7 +25,7 @@ in }; templates = { - "ntfy-server.yml".content = + ntfy.content = let dbStartupQueries = '' pragma journal_mode = WAL; @@ -35,7 +35,7 @@ in ''; in builtins.readFile ( - (pkgs.formats.yaml { }).generate "server.yml" { + (pkgs.formats.yaml { }).generate "server.yaml" { log-level = "warn"; base-url = "https://ntfy.karaolidis.com"; @@ -77,34 +77,9 @@ in ); # FIXME: https://github.com/binwiederhier/ntfy/issues/464 - "ntfy-init.sh" = { - content = '' - #!/bin/sh - - mkdir -p /tmp - PIPE=$(mktemp -u) - mkfifo "$PIPE" - trap 'rm -f "$PIPE"' EXIT - - ntfy serve > "$PIPE" 2>&1 & - - NTFY_PID=$! - grep -q "INFO Listening on :80\[http\]" < "$PIPE" - kill "$NTFY_PID" - wait "$NTFY_PID" || true - - NTFY_PASSWORD="${ - hmConfig.sops.placeholder."ntfy/users/karaolidis" - }" ntfy user add karaolidis || true - NTFY_PASSWORD="${ - hmConfig.sops.placeholder."ntfy/users/karaolidis" - }" ntfy user change-pass karaolidis - ntfy user change-role karaolidis admin - - exec ntfy serve - ''; - mode = "0500"; - }; + ntfy-env.content = '' + NTFY_ADMIN_PASSWORD=${hmConfig.sops.placeholder."ntfy/users/karaolidis"} + ''; }; }; @@ -115,31 +90,41 @@ in containers = { ntfy = { - containerConfig = { - image = "docker-archive:${selfPkgs.docker-ntfy}"; - networks = [ - networks.ntfy.ref - networks.traefik.ref - networks.prometheus.ref - ]; - volumes = [ - "${volumes.ntfy.ref}:/var/lib/ntfy" - "${hmConfig.sops.templates."ntfy-server.yml".path}:/etc/ntfy/server.yml:ro" - "${hmConfig.sops.templates."ntfy-init.sh".path}:/entrypoint.sh:ro" - ]; - entrypoint = "/entrypoint.sh"; - labels = [ - "traefik.enable=true" - "traefik.http.routers.ntfy.rule=Host(`ntfy.karaolidis.com`)" - ]; - }; + containerConfig = + let + entrypoint = pkgs.writeTextFile { + name = "entrypoint.sh"; + executable = true; + text = builtins.readFile ./entrypoint.sh; + }; + in + { + image = "docker-archive:${selfPkgs.docker-ntfy}"; + networks = [ + networks.ntfy.ref + networks.traefik.ref + networks.prometheus.ref + ]; + volumes = [ + "${volumes.ntfy.ref}:/var/lib/ntfy" + "${hmConfig.sops.templates.ntfy.path}:/etc/ntfy/server.yml:ro" + "${entrypoint}:/entrypoint.sh:ro" + ]; + environments.NTFY_ADMIN_USER = "karaolidis"; + environmentFiles = [ hmConfig.sops.templates.ntfy-env.path ]; + entrypoint = "/entrypoint.sh"; + labels = [ + "traefik.enable=true" + "traefik.http.routers.ntfy.rule=Host(`ntfy.karaolidis.com`)" + ]; + }; unitConfig.After = [ "sops-nix.service" ]; }; prometheus-init.containerConfig.volumes = let - ntfyConfig = (pkgs.formats.yaml { }).generate "ntfy.yml" { + ntfyConfig = (pkgs.formats.yaml { }).generate "ntfy.yaml" { scrape_configs = let hostname = config.networking.hostName; @@ -160,7 +145,7 @@ in ]; }; in - [ "${ntfyConfig}:/etc/prometheus/conf.d/ntfy.yml" ]; + [ "${ntfyConfig}:/etc/prometheus/conf.d/ntfy.yaml" ]; }; }; }; diff --git a/hosts/jupiter/users/storm/configs/console/podman/ntfy/entrypoint.sh b/hosts/jupiter/users/storm/configs/console/podman/ntfy/entrypoint.sh new file mode 100644 index 0000000..0f767ea --- /dev/null +++ b/hosts/jupiter/users/storm/configs/console/podman/ntfy/entrypoint.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +mkdir -p /tmp +PIPE=$(mktemp -u) +mkfifo "$PIPE" +trap 'rm -f "$PIPE"' EXIT + +ntfy serve > "$PIPE" 2>&1 & + +NTFY_PID=$! +grep -q "INFO Listening on :80\[http\]" < "$PIPE" +kill "$NTFY_PID" +wait "$NTFY_PID" || true + +export NTFY_PASSWORD="$NTFY_ADMIN_PASSWORD" +ntfy user add "$NTFY_ADMIN_USER" || true +ntfy user change-pass "$NTFY_ADMIN_USER" +ntfy user change-role "$NTFY_ADMIN_USER" admin + +exec ntfy serve diff --git a/hosts/jupiter/users/storm/configs/console/podman/prometheus/default.nix b/hosts/jupiter/users/storm/configs/console/podman/prometheus/default.nix index 42808e3..aa1b813 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/prometheus/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/prometheus/default.nix @@ -60,20 +60,20 @@ in prometheus-podman-exporter.containerConfig = { image = "docker-archive:${selfPkgs.docker-prometheus-podman-exporter}"; - publishPorts = [ "9882:9882" ]; + publishPorts = [ "9882:9882/tcp" ]; volumes = [ "/run/podman/podman.sock:/run/podman/podman.sock:ro" ]; exec = [ "--collector.enable-all" ]; }; prometheus-fail2ban-exporter.containerConfig = { image = "docker-archive:${selfPkgs.docker-prometheus-fail2ban-exporter}"; - publishPorts = [ "9191:9191" ]; + publishPorts = [ "9191:9191/tcp" ]; volumes = [ "/run/fail2ban/fail2ban.sock:/var/run/fail2ban/fail2ban.sock:ro" ]; }; prometheus-smartctl-exporter.containerConfig = { image = "docker-archive:${selfPkgs.docker-prometheus-smartctl-exporter}"; - publishPorts = [ "9633:9633" ]; + publishPorts = [ "9633:9633/tcp" ]; podmanArgs = [ "--privileged" ]; }; }; @@ -120,7 +120,7 @@ in prometheus-init = let - prometheusConfig = (pkgs.formats.yaml { }).generate "prometheus.yml" { + prometheusConfig = (pkgs.formats.yaml { }).generate "prometheus.yaml" { global.scrape_interval = "15s"; scrape_configs = @@ -242,12 +242,12 @@ in image = "docker-archive:${selfPkgs.docker-yq}"; volumes = [ "${volumes.prometheus-config.ref}:/etc/prometheus" - "${prometheusConfig}:/etc/prometheus/conf.d/prometheus.yml" + "${prometheusConfig}:/etc/prometheus/conf.d/prometheus.yaml" ]; entrypoint = "/bin/bash"; exec = [ "-c" - "yq eval-all '. as $item ireduce ({}; . *+ $item)' /etc/prometheus/conf.d/*.yml > /etc/prometheus/prometheus.yml" + "yq eval-all '. as $item ireduce ({}; . *+ $item)' /etc/prometheus/conf.d/*.yaml > /etc/prometheus/prometheus.yaml" ]; }; @@ -272,7 +272,7 @@ in ]; exec = [ "--log.level=debug" - "--config.file=/etc/prometheus/prometheus.yml" + "--config.file=/etc/prometheus/prometheus.yaml" "--storage.tsdb.path=/var/lib/prometheus" "--storage.tsdb.retention.time=1y" ]; diff --git a/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix b/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix index 71504c5..387d115 100644 --- a/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix +++ b/hosts/jupiter/users/storm/configs/console/podman/traefik/default.nix @@ -29,7 +29,7 @@ in home-manager.users.${user} = { sops = { secrets."cloudflare/letsencrypt".sopsFile = ../../../../../../../../secrets/personal/secrets.yaml; - templates."traefik.env".content = '' + templates.traefik-env.content = '' CF_DNS_API_TOKEN=${hmConfig.sops.placeholder."cloudflare/letsencrypt"} ''; }; @@ -104,7 +104,7 @@ in "traefik.http.middlewares.compress.compress=true" # TODO: Middlewares: Headers ]; - environmentFiles = [ hmConfig.sops.templates."traefik.env".path ]; + environmentFiles = [ hmConfig.sops.templates.traefik-env.path ]; }; serviceConfig.Sockets = [ @@ -127,7 +127,7 @@ in }; }; - authelia.containerConfig.volumes = + authelia-init.containerConfig.volumes = let config = (pkgs.formats.yaml { }).generate "traefik.yaml" { access_control.rules = [ @@ -143,7 +143,7 @@ in prometheus-init.containerConfig.volumes = let - traefikConfig = (pkgs.formats.yaml { }).generate "traefik.yml" { + traefikConfig = (pkgs.formats.yaml { }).generate "traefik.yaml" { scrape_configs = let hostname = config.networking.hostName; @@ -164,7 +164,7 @@ in ]; }; in - [ "${traefikConfig}:/etc/prometheus/conf.d/traefik.yml" ]; + [ "${traefikConfig}:/etc/prometheus/conf.d/traefik.yaml" ]; }; }; diff --git a/hosts/jupiter/users/storm/default.nix b/hosts/jupiter/users/storm/default.nix index bab04ad..2914482 100644 --- a/hosts/jupiter/users/storm/default.nix +++ b/hosts/jupiter/users/storm/default.nix @@ -26,24 +26,26 @@ in neededForUsers = true; }; - users.users.${user} = { - inherit home; - isSystemUser = true; - createHome = true; - description = "Container Runner"; - hashedPasswordFile = config.sops.secrets."${user}-password".path; - extraGroups = [ "wheel" ]; - linger = true; - uid = lib.strings.toInt (builtins.readFile ./uid); - group = user; - autoSubUidGidRange = true; - useDefaultShell = true; - openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEWDA5vnIB7KE2VG28Ovg5rXtQqxFwMXsfozLsH0BNZS nick@karaolidis.com" - ]; - }; + users = { + users.${user} = { + inherit home; + isSystemUser = true; + createHome = true; + description = "Container Runner"; + hashedPasswordFile = config.sops.secrets."${user}-password".path; + extraGroups = [ "wheel" ]; + linger = true; + uid = lib.strings.toInt (builtins.readFile ./uid); + group = user; + autoSubUidGidRange = true; + useDefaultShell = true; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEWDA5vnIB7KE2VG28Ovg5rXtQqxFwMXsfozLsH0BNZS nick@karaolidis.com" + ]; + }; - users.groups.${user}.gid = lib.strings.toInt (builtins.readFile ./uid); + groups.${user}.gid = lib.strings.toInt (builtins.readFile ./uid); + }; home-manager.users.${user}.home = { username = user; diff --git a/packages/default.nix b/packages/default.nix index bb982ee..398cbd3 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -11,6 +11,7 @@ docker-authelia = import ./docker/authelia { inherit pkgs; }; docker-base = import ./docker/base { inherit pkgs; }; + docker-gitea = import ./docker/gitea { inherit pkgs; }; docker-grafana = import ./docker/grafana { inherit pkgs; }; docker-grafana-image-renderer = import ./docker/grafana-image-renderer { inherit pkgs; }; docker-ntfy = import ./docker/ntfy { inherit pkgs; }; diff --git a/packages/docker/base/default.nix b/packages/docker/base/default.nix index 63442de..74034f5 100644 --- a/packages/docker/base/default.nix +++ b/packages/docker/base/default.nix @@ -5,17 +5,21 @@ pkgs.dockerTools.buildImage { copyToRoot = pkgs.buildEnv { name = "root"; paths = with pkgs; [ + dockerTools.usrBinEnv dockerTools.binSh dockerTools.caCertificates bashInteractive coreutils gnugrep + findutils + curl ]; pathsToLink = [ "/bin" "/lib" "/share" "/etc" + "/usr" ]; }; } diff --git a/packages/docker/gitea/default.nix b/packages/docker/gitea/default.nix new file mode 100644 index 0000000..478e160 --- /dev/null +++ b/packages/docker/gitea/default.nix @@ -0,0 +1,36 @@ +{ pkgs, ... }: +pkgs.dockerTools.buildImage { + name = "gitea"; + fromImage = import ../base { inherit pkgs; }; + + copyToRoot = pkgs.buildEnv { + name = "root"; + paths = with pkgs; [ + gitea + git + ]; + pathsToLink = [ "/bin" ]; + }; + + runAsRoot = '' + ${pkgs.dockerTools.shadowSetup} + ''; + + config = { + Entrypoint = [ "/bin/gitea" ]; + Cmd = [ + "web" + "-c" + "/etc/gitea/app.ini" + ]; + ExposedPorts = { + "3000/tcp" = { }; + }; + Env = [ "GITEA_WORK_DIR=/var/lib/gitea/" ]; + Volumes = { + "/var/lib/gitea/data" = { }; + "/var/lib/gitea/log" = { }; + "/var/lib/gitea/custom" = { }; + }; + }; +}