From dddb070b69cf73cdc9cdb6b613111a040155e4fc Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Sat, 9 May 2026 11:20:03 +0200 Subject: [PATCH 01/10] Disabled paperless --- hosts/cyper-controller/configuration.nix | 2 +- nixos/roles/adguard.nix | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hosts/cyper-controller/configuration.nix b/hosts/cyper-controller/configuration.nix index 975d6ea..1e9d6a4 100644 --- a/hosts/cyper-controller/configuration.nix +++ b/hosts/cyper-controller/configuration.nix @@ -11,7 +11,7 @@ ../../nixos/roles/gitea.nix ../../nixos/roles/vaultwarden.nix ../../nixos/roles/frontpage - ../../nixos/roles/paperless-ngx.nix + # ../../nixos/roles/paperless-ngx.nix ../../nixos/roles/octoprint.nix ]; diff --git a/nixos/roles/adguard.nix b/nixos/roles/adguard.nix index d1211cd..67405c4 100644 --- a/nixos/roles/adguard.nix +++ b/nixos/roles/adguard.nix @@ -5,7 +5,7 @@ let primaryInterface = config.systemd.network.networks."10-ethernet".matchConfig.Name; - adguardPort = 3000; + adguardPort = 3010; in { services = { @@ -50,7 +50,7 @@ in }; dhcp = { - enabled = true; + enabled = false; interface_name = primaryInterface; local_domain_name = "lan"; dhcpv4 = { From cb297406eae6fc3b4eaa57612449d5d45641cc66 Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Wed, 13 May 2026 22:42:11 +0200 Subject: [PATCH 02/10] Activated GIT LFS --- hosts/cyper-proxy/configuration.nix | 17 ++++++++++++++ nixos/roles/gitea.nix | 11 +++++++++ nixos/roles/matrix/synapse.nix | 36 ++++++++++++++++++++++++++--- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/hosts/cyper-proxy/configuration.nix b/hosts/cyper-proxy/configuration.nix index 22152cb..3c04997 100644 --- a/hosts/cyper-proxy/configuration.nix +++ b/hosts/cyper-proxy/configuration.nix @@ -17,8 +17,20 @@ prefixLength = 23; } ]; + ipv6.addresses = [ + { + address = "2a00:6800:3:1094::1"; + prefixLength = 64; + } + ]; }; defaultGateway = "178.254.8.1"; + + defaultGateway6 = { + address = "2a00:6800:3::1"; + interface = "ens3"; + }; + nameservers = [ "178.254.16.151" "178.254.16.141" @@ -34,6 +46,11 @@ "cyperpunk.de" "matrix.cyperpunk.de" ]; + + "2a00:6800:3:1094::1" = [ + "cyperpunk.de" + "matrix.cyperpunk.de" + ]; }; }; diff --git a/nixos/roles/gitea.nix b/nixos/roles/gitea.nix index 590787d..c83fb2e 100644 --- a/nixos/roles/gitea.nix +++ b/nixos/roles/gitea.nix @@ -79,6 +79,11 @@ in user = "gitea"; group = "gitea"; + lfs = { + enable = true; + #contentDir = "${config.services.gitea.stateDir}/data/lfs"; + }; + database = { type = "postgres"; host = "127.0.0.1"; @@ -98,6 +103,12 @@ in ROOT_URL = "https://${domain}/"; DISABLE_SSH = false; START_SSH_SERVER = true; + LFS_START_SERVER = true; + LFS_JWT_SECRET_URI = "file://${config.sops.secrets."gitea/lfsJwtSecret".path}"; + }; + + lfs = { + PATH = "${config.services.gitea.stateDir}/data/lfs"; }; metrics = { diff --git a/nixos/roles/matrix/synapse.nix b/nixos/roles/matrix/synapse.nix index 47318fd..4194074 100644 --- a/nixos/roles/matrix/synapse.nix +++ b/nixos/roles/matrix/synapse.nix @@ -34,7 +34,10 @@ in owner = "matrix-synapse"; group = "matrix-synapse"; }; - pg_replication_password = { }; + pg_replication_password = { + owner = "postgres"; + group = "postgres"; + }; }; services = { @@ -66,6 +69,21 @@ in # msc4222_enabled = true; #}; + rc_login = { + address = { + per_second = 0.17; + burst_count = 10; + }; + account = { + per_second = 0.17; + burst_count = 10; + }; + failed_attempts = { + per_second = 0.17; + burst_count = 10; + }; + }; + listeners = [ { port = 8008; @@ -91,7 +109,10 @@ in port = 9009; tls = false; type = "metrics"; - bind_addresses = [ "127.0.0.1" ]; + bind_addresses = [ + "127.0.0.1" + "100.109.10.91" + ]; resources = [ ]; } ]; @@ -155,13 +176,22 @@ in settings = { wal_level = "replica"; - max_wal_senders = 3; + max_wal_senders = 5; wal_keep_size = "512MB"; + listen_addresses = lib.mkForce "127.0.0.1,100.109.10.91"; }; authentication = lib.mkAfter '' host replication replicator 100.0.0.0/8 scram-sha-256 ''; + + }; + + prometheus.exporters.postgres = { + enable = true; + port = 9188; + runAsLocalSuperUser = true; + dataSourceName = "postgresql:///postgres?host=/run/postgresql&sslmode=disable"; }; }; From c0b0d89fcfff7c062d3a4a41193951ec37cea0f6 Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Wed, 13 May 2026 22:59:35 +0200 Subject: [PATCH 03/10] Added nginx upload limit --- hosts/cyper-controller/configuration.nix | 1 + nixos/roles/gitea.nix | 7 +- nixos/roles/matrix/postgres-backup.nix | 156 ++++++++++++----------- nixos/roles/monitoring.nix | 24 +++- nixos/roles/nginx.nix | 6 +- 5 files changed, 114 insertions(+), 80 deletions(-) diff --git a/hosts/cyper-controller/configuration.nix b/hosts/cyper-controller/configuration.nix index ee2be17..750ed91 100644 --- a/hosts/cyper-controller/configuration.nix +++ b/hosts/cyper-controller/configuration.nix @@ -13,6 +13,7 @@ ../../nixos/roles/frontpage # ../../nixos/roles/paperless-ngx.nix ../../nixos/roles/octoprint.nix + ../../nixos/roles/matrix/postgres-backup.nix ]; networking = { diff --git a/nixos/roles/gitea.nix b/nixos/roles/gitea.nix index c83fb2e..4d3a6b9 100644 --- a/nixos/roles/gitea.nix +++ b/nixos/roles/gitea.nix @@ -81,7 +81,7 @@ in lfs = { enable = true; - #contentDir = "${config.services.gitea.stateDir}/data/lfs"; + contentDir = "${config.services.gitea.stateDir}/data/lfs"; }; database = { @@ -104,11 +104,6 @@ in DISABLE_SSH = false; START_SSH_SERVER = true; LFS_START_SERVER = true; - LFS_JWT_SECRET_URI = "file://${config.sops.secrets."gitea/lfsJwtSecret".path}"; - }; - - lfs = { - PATH = "${config.services.gitea.stateDir}/data/lfs"; }; metrics = { diff --git a/nixos/roles/matrix/postgres-backup.nix b/nixos/roles/matrix/postgres-backup.nix index 752acd2..1bf7055 100644 --- a/nixos/roles/matrix/postgres-backup.nix +++ b/nixos/roles/matrix/postgres-backup.nix @@ -7,96 +7,108 @@ { sops.secrets = { pg_replication_password = { - owner = "postgres"; - group = "postgres"; + owner = "root"; + group = "root"; }; }; - services.postgresql = { - enable = true; - package = pkgs.postgresql_15; # must match cyper-proxy's PG version exactly + virtualisation.docker.enable = true; - settings = { - hot_standby = true; - hot_standby_feedback = true; - max_standby_streaming_delay = "30s"; - listen_addresses = "127.0.0.1"; # only local, no external exposure - wal_receiver_timeout = "60s"; - recovery_min_apply_delay = "0"; # set e.g. "1h" for a delayed safety replica - }; - }; - - # Writes standby.signal and primary_conninfo before PostgreSQL starts. - systemd.services.postgresql = { - preStart = lib.mkAfter '' - DATADIR="${config.services.postgresql.dataDir}" - PG_PASS=$(cat ${config.sops.secrets.pg_replication_password.path}) - - # Tell Postgres to start as a hot standby - if [ ! -f "$DATADIR/standby.signal" ]; then - touch "$DATADIR/standby.signal" - chown postgres:postgres "$DATADIR/standby.signal" - fi - - # primary_conninfo via Tailscale — no public IP involved - CONNINFO="host=100.109.10.91 port=5432 user=replicator password=$PG_PASS application_name=cyper-controller sslmode=require" - - grep -v "^primary_conninfo" "$DATADIR/postgresql.auto.conf" 2>/dev/null > /tmp/auto.conf.tmp || true - echo "primary_conninfo = '$CONNINFO'" >> /tmp/auto.conf.tmp - mv /tmp/auto.conf.tmp "$DATADIR/postgresql.auto.conf" - chown postgres:postgres "$DATADIR/postgresql.auto.conf" - ''; - }; - - # Run once manually to seed the standby: systemctl start postgresql-basebackup - # Do NOT add it to wantedBy — it would wipe the data dir on every reboot. - systemd.services.postgresql-basebackup = { - description = "Bootstrap PostgreSQL standby via pg_basebackup from cyper-proxy"; + systemd.services.postgresql-replica = { + description = "PostgreSQL WAL streaming replica (Docker)"; requires = [ - "network-online.target" + "docker.service" "tailscaled.service" + "network-online.target" ]; after = [ - "network-online.target" + "docker.service" "tailscaled.service" + "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; serviceConfig = { - Type = "oneshot"; - User = "postgres"; - RemainAfterExit = false; + Type = "simple"; + Restart = "on-failure"; + RestartSec = "10s"; }; + preStart = '' + DATADIR="/storage/backup/postgresql-replica" + PG_PASS=$(cat ${config.sops.secrets.pg_replication_password.path}) + + ${pkgs.docker}/bin/docker pull postgres:17 + + if [ ! -f "$DATADIR/PG_VERSION" ]; then + echo "No data dir found — running pg_basebackup..." + rm -rf "$DATADIR" + + ${pkgs.docker}/bin/docker run --rm \ + -e PGPASSWORD="$PG_PASS" \ + -v "/storage/backup:/out" \ + --network host \ + postgres:17 \ + pg_basebackup \ + --host=100.109.10.91 \ + --port=5432 \ + --username=replicator \ + --pgdata=/out/postgresql-replica \ + --wal-method=stream \ + --checkpoint=fast \ + --progress \ + --verbose + + # standby signal + touch "$DATADIR/standby.signal" + + # primary conninfo + cat > "$DATADIR/postgresql.auto.conf" < "$DATADIR/postgresql.conf" < "$DATADIR/postgresql.conf" </dev/null || true ''; }; - # Block any external access to postgres on the public interface - networking.firewall = { - interfaces."tailscale0".allowedTCPPorts = [ ]; # replication is outbound only + services.prometheus.exporters.postgres = { + enable = true; + port = 9188; + runAsLocalSuperUser = false; + dataSourceName = "postgresql://postgres@localhost:5434/postgres?sslmode=disable"; }; } diff --git a/nixos/roles/monitoring.nix b/nixos/roles/monitoring.nix index 4c9c14c..16e4479 100644 --- a/nixos/roles/monitoring.nix +++ b/nixos/roles/monitoring.nix @@ -134,7 +134,7 @@ in metrics_path = "/_synapse/metrics"; static_configs = [ { - targets = [ "127.0.0.1:9009" ]; + targets = [ "100.109.10.91:9009" ]; labels = { instance = config.networking.hostName; job = "master"; @@ -143,6 +143,28 @@ in } ]; } + { + job_name = "postgresql-replica"; + static_configs = [ + { + targets = [ "localhost:9188" ]; + labels = { + instance = config.networking.hostName; + }; + } + ]; + } + { + job_name = "postgresql-proxy"; + static_configs = [ + { + targets = [ "100.109.10.91:9188" ]; + labels = { + instance = "cyper-proxy"; + }; + } + ]; + } ] ++ (lib.mapAttrsToList mkNodeJob extraNodes) ++ (mkWeatherScrapeConfigs weatherCities); diff --git a/nixos/roles/nginx.nix b/nixos/roles/nginx.nix index ece3997..6792839 100644 --- a/nixos/roles/nginx.nix +++ b/nixos/roles/nginx.nix @@ -40,7 +40,11 @@ in virtualHosts = { # controller services (proxied to upstream tailscale node) - "git.cyperpunk.de" = mkProxy 9000; + "git.cyperpunk.de" = (mkProxy 9000) // { + extraConfig = '' + client_max_body_size 500m; + ''; + }; "search.cyperpunk.de" = mkProxy 11080; "file.cyperpunk.de" = mkProxy 10000; "ngx.cyperpunk.de" = mkWsProxy 28101; From 8201bc4bf590f9c0f32177cdf2c6d6326c08213d Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Fri, 15 May 2026 10:31:31 +0200 Subject: [PATCH 04/10] Added Kanidm with nginx --- hosts/cyper-controller/configuration.nix | 1 + nixos/roles/gitea.nix | 2 +- nixos/roles/kanidm.nix | 58 ++++++++++++++++++++++++ nixos/roles/keycloack.nix | 28 ------------ nixos/roles/nginx.nix | 10 ++++ 5 files changed, 70 insertions(+), 29 deletions(-) create mode 100644 nixos/roles/kanidm.nix delete mode 100644 nixos/roles/keycloack.nix diff --git a/hosts/cyper-controller/configuration.nix b/hosts/cyper-controller/configuration.nix index 750ed91..b88947d 100644 --- a/hosts/cyper-controller/configuration.nix +++ b/hosts/cyper-controller/configuration.nix @@ -14,6 +14,7 @@ # ../../nixos/roles/paperless-ngx.nix ../../nixos/roles/octoprint.nix ../../nixos/roles/matrix/postgres-backup.nix + ../../nixos/roles/kanidm.nix ]; networking = { diff --git a/nixos/roles/gitea.nix b/nixos/roles/gitea.nix index 4d3a6b9..ad1386d 100644 --- a/nixos/roles/gitea.nix +++ b/nixos/roles/gitea.nix @@ -81,7 +81,7 @@ in lfs = { enable = true; - contentDir = "${config.services.gitea.stateDir}/data/lfs"; + contentDir = "/storage/fast/lfs"; }; database = { diff --git a/nixos/roles/kanidm.nix b/nixos/roles/kanidm.nix new file mode 100644 index 0000000..57868d7 --- /dev/null +++ b/nixos/roles/kanidm.nix @@ -0,0 +1,58 @@ +# FIRST TIME SETUP (after nixos-rebuild switch on cyper-controller): +# $ sudo kanidmd recover-account admin +# $ sudo kanidmd recover-account idm_admin +# +{ pkgs, ... }: +let + domain = "auth.cyperpunk.de"; + port = 8443; + certDir = "/var/lib/kanidm/tls"; +in +{ + systemd.services.kanidm-selfsigned-cert = { + description = "Generate self-signed TLS certificate for Kanidm"; + wantedBy = [ "kanidm.service" ]; + before = [ "kanidm.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + if [ ! -f ${certDir}/cert.pem ]; then + mkdir -p ${certDir} + ${pkgs.openssl}/bin/openssl req -x509 \ + -newkey rsa:4096 \ + -keyout ${certDir}/key.pem \ + -out ${certDir}/cert.pem \ + -days 3650 \ + -nodes \ + -subj "/CN=${domain}" + chown -R kanidm:kanidm ${certDir} + chmod 750 ${certDir} + chmod 640 ${certDir}/cert.pem ${certDir}/key.pem + fi + ''; + }; + + services.kanidm = { + enableServer = true; + + serverSettings = { + inherit domain; + origin = "https://${domain}"; + + tls_chain = "${certDir}/cert.pem"; + tls_key = "${certDir}/key.pem"; + + bindaddress = "0.0.0.0:${toString port}"; + + db_path = "/var/lib/kanidm/kanidm.db"; + log_level = "info"; + }; + + enableClient = true; + clientSettings.uri = "https://${domain}"; + }; + + networking.firewall.allowedTCPPorts = [ port ]; +} diff --git a/nixos/roles/keycloack.nix b/nixos/roles/keycloack.nix deleted file mode 100644 index 0d7f491..0000000 --- a/nixos/roles/keycloack.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ config, ... }: -{ - services = { - nginx.virtualHosts."www.cyperpunk.de".locations."/cloak" = { - proxyPass = "http://localhost:${toString config.services.keycloak.settings.http-port}/cloak/"; - }; - - keycloak = { - enable = true; - - database = { - type = "postgresql"; - createLocally = true; - - username = "keycloak"; - passwordFile = "/etc/nixos/secrets/keycloak_psql_pass"; - }; - - settings = { - hostname = "cyperpunk.de"; - http-relative-path = "/cloak"; - http-port = 38080; - proxy = "passthrough"; - http-enabled = true; - }; - }; - }; -} diff --git a/nixos/roles/nginx.nix b/nixos/roles/nginx.nix index 6792839..68e8343 100644 --- a/nixos/roles/nginx.nix +++ b/nixos/roles/nginx.nix @@ -19,6 +19,15 @@ let proxyWebsockets = true; }; }; + + mkHttpsProxy = port: { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "https://${upstream}:${toString port}"; + extraConfig = "proxy_ssl_verify off;"; + }; + }; in { networking.firewall.allowedTCPPorts = [ @@ -50,6 +59,7 @@ in "ngx.cyperpunk.de" = mkWsProxy 28101; "vault.cyperpunk.de" = mkWsProxy 8222; "calvin.cyperpunk.de" = mkWsProxy 15006; + "auth.cyperpunk.de" = mkHttpsProxy 8443; "www.cyperpunk.de" = { forceSSL = true; From 94ddd0c3b652285971015103d7368ab9bcc09776 Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Fri, 15 May 2026 10:47:39 +0200 Subject: [PATCH 05/10] Added Kanidm with nginx --- nixos/roles/kanidm.nix | 38 ++++++++++++++++++++++---------------- nixos/roles/nginx.nix | 2 +- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/nixos/roles/kanidm.nix b/nixos/roles/kanidm.nix index 57868d7..a4b73c4 100644 --- a/nixos/roles/kanidm.nix +++ b/nixos/roles/kanidm.nix @@ -1,11 +1,7 @@ -# FIRST TIME SETUP (after nixos-rebuild switch on cyper-controller): -# $ sudo kanidmd recover-account admin -# $ sudo kanidmd recover-account idm_admin -# { pkgs, ... }: let domain = "auth.cyperpunk.de"; - port = 8443; + port = 8444; certDir = "/var/lib/kanidm/tls"; in { @@ -35,23 +31,33 @@ in }; services.kanidm = { - enableServer = true; + package = pkgs.kanidm_1_10; - serverSettings = { - inherit domain; - origin = "https://${domain}"; + server = { + enable = true; + settings = { + inherit domain; + origin = "https://${domain}"; - tls_chain = "${certDir}/cert.pem"; - tls_key = "${certDir}/key.pem"; + tls_chain = "${certDir}/cert.pem"; + tls_key = "${certDir}/key.pem"; - bindaddress = "0.0.0.0:${toString port}"; + bindaddress = "0.0.0.0:${toString port}"; - db_path = "/var/lib/kanidm/kanidm.db"; - log_level = "info"; + log_level = "info"; + + online_backup = { + versions = 7; + path = "/var/lib/kanidm/backups"; + schedule = "00 22 * * *"; + }; + }; }; - enableClient = true; - clientSettings.uri = "https://${domain}"; + client = { + enable = true; + settings.uri = "https://${domain}"; + }; }; networking.firewall.allowedTCPPorts = [ port ]; diff --git a/nixos/roles/nginx.nix b/nixos/roles/nginx.nix index 68e8343..ff8e765 100644 --- a/nixos/roles/nginx.nix +++ b/nixos/roles/nginx.nix @@ -59,7 +59,7 @@ in "ngx.cyperpunk.de" = mkWsProxy 28101; "vault.cyperpunk.de" = mkWsProxy 8222; "calvin.cyperpunk.de" = mkWsProxy 15006; - "auth.cyperpunk.de" = mkHttpsProxy 8443; + "auth.cyperpunk.de" = mkHttpsProxy 8444; "www.cyperpunk.de" = { forceSSL = true; From 72d9a66b4f05a9c46f3ff17dfe6845f11672f855 Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Fri, 15 May 2026 11:06:51 +0200 Subject: [PATCH 06/10] Added SSO to synapse --- nixos/roles/matrix/synapse.nix | 34 ++++++++++++++++++++++++---------- secrets/secrets.yaml | 5 +++-- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/nixos/roles/matrix/synapse.nix b/nixos/roles/matrix/synapse.nix index 4194074..bf8b498 100644 --- a/nixos/roles/matrix/synapse.nix +++ b/nixos/roles/matrix/synapse.nix @@ -38,6 +38,10 @@ in owner = "postgres"; group = "postgres"; }; + kanidm_synapse_secret = { + owner = "matrix-synapse"; + group = "matrix-synapse"; + }; }; services = { @@ -60,14 +64,6 @@ in } ]; }; - #experimental_features = { - # msc3266_enabled = true; - # msc3779_enabled = true; - # msc3401_enabled = true; - # msc4143_enabled = true; - # msc4195_enabled = true; - # msc4222_enabled = true; - #}; rc_login = { address = { @@ -117,11 +113,30 @@ in } ]; enable_metrics = true; + + oidc_providers = [ + { + idp_id = "kanidm"; + idp_name = "Kanidm"; + issuer = "https://auth.cyperpunk.de/oauth2/openid/synapse"; + client_id = "synapse"; + client_secret_path = config.sops.secrets.kanidm_synapse_secret.path; + scopes = [ + "openid" + "profile" + "email" + ]; + allow_existing_users = true; + user_mapping_provider.config = { + localpart_template = "{{ user.preferred_username }}"; + display_name_template = "{{ user.displayname }}"; + }; + } + ]; }; }; nginx.virtualHosts = { - # Matrix homeserver "cyperpunk.de" = { forceSSL = true; enableACME = true; @@ -184,7 +199,6 @@ in authentication = lib.mkAfter '' host replication replicator 100.0.0.0/8 scram-sha-256 ''; - }; prometheus.exporters.postgres = { diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml index 895789d..ebaa6d0 100644 --- a/secrets/secrets.yaml +++ b/secrets/secrets.yaml @@ -4,6 +4,7 @@ smb_passwd: ENC[AES256_GCM,data:+9RYomcnCZSME5DzuJWTLbS3IGJHhIYWZ5SmsgOn6YQ=,iv: grafana_secret_key: ENC[AES256_GCM,data:d6tu4kL7flfbdeOYk21zkSRmVe+NvVwd14jgr9Ds0adfgYetN852G25Z8/g=,iv:uWuwGBZVK1syhEfO9nLZUWwa801759tNJx+Pmnz3xeg=,tag:X6/NcdGZHAdIlOwxNPo/Ew==,type:str] matrix_macaroon_secret: ENC[AES256_GCM,data:a9nMar+p+FXIsxxSqO/to2OJOvD1erfwLwwBeKOcWBu7xykHxqD+pCmrGhg=,iv:rp4ZDVIlZ7SN1RFHB2CfSV5ISPMl9pC4U8Jgqpz48Qs=,tag:LxmWUZE3mG4acagQmlieag==,type:str] matrix_registration_secret: ENC[AES256_GCM,data:KhKkJZqwE8xk4/tuQ7NYTv/Ot1qCAiy8yUbDyVvRa0H5BT4amCBIdATfR4Q=,iv:HBN+GorT1VpWCVkDugk4UxYLEYKJIoDZh2d+oUDLc8g=,tag:hHus458yVnH0qaQ4u37IZg==,type:str] +kanidm_synapse_secret: ENC[AES256_GCM,data:F770siYcYLm3RAQ+3epfVTyp5mv0OJfiOdFiHD8CudjceNkkSuXIX7pxQYkhS3VY,iv:hqYMKLS5m+o3leFE0gBS05Npjy9uyqgSe7yJpPzxvQY=,tag:lLjVZ7/iYoIZh06VyF8zSw==,type:str] vaultwarden_admin_token: ENC[AES256_GCM,data:yoBs4CaIEJXB5b3PEwTpXFgxpX39hR9A4r9yamwDV7cTSRRp3n3O2VjDKTcI5Vo6RP2QUjcqUqYf98cZ09wDMc+6+oHHJke7+O0FgRgOC0vOQFs4bfZCBJBLxogrGiwtLGkyykR6VYhrT64AN3CbrXflj82OED2Hl8WwEdruBzGIcfnh6FqQowDx6vDR/kXXJHk=,iv:PJQo5V7FaKPQ+GzZNsy3KB+xyjcDKJ1UBHErrqgn/1U=,tag:BRIDJEDOAeToqio/DHMQaA==,type:str] flame_phil_password: ENC[AES256_GCM,data:Xy2ixMeRlnzC2gjKGrjfSbz/ee4=,iv:WFuBS8jn7WYRxEDG3XBzCMnm4eNkHQpSs5+GUwq/dcg=,tag:1zzj0eB9/4KrmYAqcxJMlg==,type:str] flame_calvin_password: ENC[AES256_GCM,data:P5ppyqTjAJ1TL4hXtx5WyoS9a+g=,iv:sq98P3Oqud2FXfqsD76YS/p5NEF2xlN0MfG+ukCB9B0=,tag:AeKnu4Hg4xQ3tII0y6oNpQ==,type:str] @@ -32,7 +33,7 @@ sops: N3I5dzUwc3JtYzczMUhyT04vSHlZamMKT+FzYcDLmlEFYxm/XoBpJb8XaZzBH1v9 6fuez+zApathZfl14w41kAUojPWBznnxDqYtNvzVVLXwnpp3BMx+7w== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-05-09T09:12:42Z" - mac: ENC[AES256_GCM,data:sTVJcBb8cBzixOBQNlx44/m8W3smfwP5fhmnm9hlr5iwMuPJ7JeKTUqqlQaeL4RX/MpEuLc+Rm4thromJ11M/aA5yiqgWOY7vn8xYPoScGzx6HfV1cRJTofmrWmpxrDICQULwOaO+c8vwFBPy7fVqF/AacRtejx5sEOxsMzrYR8=,iv:/Fc5//8coI/rdQIyGcxCTgXPzOS9xNd0ChDHNs4yffw=,tag:8w6bbZcWMBZQWkujhXQY0w==,type:str] + lastmodified: "2026-05-15T09:03:17Z" + mac: ENC[AES256_GCM,data:1rSwkArJPxLpyatnp+EJDX4//B7aWUScfM5u0XEQlWeKWjHPYxvZ7b2Vvqx8RFJcWp3QgqQf3f+Mp2DmuDdxAuK94XxHIRk3c1bimKeNrCBPZqQkTjJH8tyklrW1Grob7Xi82GXhk96/s0bTzU58uSdvJXGReYraqvnAuitehPY=,iv:JsImUF/7zQCmIRz34LEOJStL2kAqw8QcARE5eHGsGyU=,tag:8CpmWPVozDPTyNwhoZqC9A==,type:str] unencrypted_suffix: _unencrypted version: 3.12.2 From ebcb37773ab6aa772f4c16e78724e369c7489656 Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Fri, 15 May 2026 13:02:23 +0200 Subject: [PATCH 07/10] Added SSO to Grafana & Gitea --- nixos/roles/gitea.nix | 5 ++ nixos/roles/monitoring.nix | 119 ++++++++----------------------------- secrets/secrets.yaml | 6 +- 3 files changed, 33 insertions(+), 97 deletions(-) diff --git a/nixos/roles/gitea.nix b/nixos/roles/gitea.nix index ad1386d..148354b 100644 --- a/nixos/roles/gitea.nix +++ b/nixos/roles/gitea.nix @@ -36,6 +36,11 @@ in owner = "gitea"; group = "gitea"; }; + "kanidm_gitea_secret" = { + owner = "gitea"; + group = "gitea"; + mode = "0444"; + }; }; services.postgresql = { diff --git a/nixos/roles/monitoring.nix b/nixos/roles/monitoring.nix index 16e4479..a6409e6 100644 --- a/nixos/roles/monitoring.nix +++ b/nixos/roles/monitoring.nix @@ -21,44 +21,6 @@ let "cyper-node-2" = "192.168.2.31"; "cyper-proxy" = "178.254.8.35"; }; - - mkWeatherScrapeConfigs = - cities: - map (city: { - job_name = "weather_${lib.strings.toLower (lib.strings.replaceStrings [ " " ] [ "_" ] city)}"; - scrape_interval = "5m"; - scrape_timeout = "30s"; - metrics_path = "/${city}"; - params.format = [ "p1" ]; - static_configs = [ { targets = [ "wttr.in" ]; } ]; - scheme = "https"; - metric_relabel_configs = [ - { - target_label = "location"; - replacement = city; - } - ]; - }) cities; - - weatherCities = [ - # Braunschweig itself - "Braunschweig" - - # Immediate surroundings (~15km) - "Wolfenbuettel" - "Salzgitter" - "Peine" - "Cremlingen" - "Wendeburg" - "Sickte" - - # Greater region (~50km) - "Wolfsburg" - "Gifhorn" - "Goslar" - "Hildesheim" - "Hannover" - ]; in { sops.secrets = { @@ -66,7 +28,10 @@ in owner = "grafana"; group = "grafana"; }; - + kanidm_grafana_secret = { + owner = "grafana"; + group = "grafana"; + }; }; services = { @@ -83,12 +48,6 @@ in url = "http://127.0.0.1:${toString config.services.prometheus.port}"; isDefault = true; } - { - name = "Loki"; - type = "loki"; - url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}"; - isDefault = false; - } ]; }; }; @@ -97,7 +56,7 @@ in domain = "www.cyperpunk.de"; # serverIP; # "grafana.cyperpunk.de"; http_port = 2342; http_addr = "0.0.0.0"; - root_url = "http://www.cyperpunk.de/grafana/"; + root_url = "https://www.cyperpunk.de/grafana/"; serve_from_sub_path = true; }; security = { @@ -106,6 +65,23 @@ in }; auth = { disable_login_form = false; + oauth_allow_insecure_email_lookup = true; + }; + "auth.generic_oauth" = { + enabled = true; + name = "Kanidm"; + client_id = "grafana"; + client_secret = "$__file{${config.sops.secrets.kanidm_grafana_secret.path}}"; + scopes = "openid profile email"; + auth_url = "https://auth.cyperpunk.de/ui/oauth2"; + token_url = "https://auth.cyperpunk.de/oauth2/token"; + api_url = "https://auth.cyperpunk.de/oauth2/openid/grafana/userinfo"; + use_pkce = false; + allow_sign_up = true; + auto_assign_org = true; + auto_assign_org_id = 1; + auto_assign_org_role = "Admin"; + skip_org_role_sync = true; }; }; }; @@ -136,7 +112,7 @@ in { targets = [ "100.109.10.91:9009" ]; labels = { - instance = config.networking.hostName; + instance = "cyper-proxy"; job = "master"; index = "1"; }; @@ -166,50 +142,7 @@ in ]; } ] - ++ (lib.mapAttrsToList mkNodeJob extraNodes) - ++ (mkWeatherScrapeConfigs weatherCities); - }; - - loki = { - enable = true; - configuration = { - auth_enabled = false; - server.http_listen_port = 3100; - ingester = { - lifecycler = { - address = "127.0.0.1"; - ring = { - kvstore.store = "inmemory"; - replication_factor = 1; - }; - }; - chunk_idle_period = "5m"; - chunk_retain_period = "30s"; - }; - schema_config.configs = [ - { - from = "2024-01-01"; - store = "tsdb"; - object_store = "filesystem"; - schema = "v13"; - index = { - prefix = "index_"; - period = "24h"; - }; - } - ]; - storage_config = { - tsdb_shipper = { - active_index_directory = "/var/lib/loki/tsdb-index"; - cache_location = "/var/lib/loki/tsdb-cache"; - }; - filesystem.directory = "/var/lib/loki/chunks"; - }; - limits_config = { - reject_old_samples = true; - reject_old_samples_max_age = "168h"; - }; - }; + ++ (lib.mapAttrsToList mkNodeJob extraNodes); }; }; @@ -218,8 +151,4 @@ in 9001 3100 ]; - - systemd.tmpfiles.rules = [ - "d /var/loki 0700 loki loki -" - ]; } diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml index ebaa6d0..b1b5442 100644 --- a/secrets/secrets.yaml +++ b/secrets/secrets.yaml @@ -2,6 +2,7 @@ GROQ_API_KEY: ENC[AES256_GCM,data:OyuC4jfw67sCDa0XBGr78S6pzPV1ruy7KiIqPMgWWcOCVm OPENWEATHER_API_KEY: ENC[AES256_GCM,data:bcuLz70u40nZfNgPTaeNRXdR/zjx0SQjwMbMNNFqROI=,iv:VCzse1a1/k1ZDIpFPL1QhjuS6YaDyohWi61JZaoc0Ws=,tag:UJSNyniNNLfGGRY/uiJcRA==,type:str] smb_passwd: ENC[AES256_GCM,data:+9RYomcnCZSME5DzuJWTLbS3IGJHhIYWZ5SmsgOn6YQ=,iv:VRPVR7DD+swjeUZKe54XYm3wn/KB4RqvQAyYXQbS+A8=,tag:NnA89efo6HVL0scHgyTZMQ==,type:str] grafana_secret_key: ENC[AES256_GCM,data:d6tu4kL7flfbdeOYk21zkSRmVe+NvVwd14jgr9Ds0adfgYetN852G25Z8/g=,iv:uWuwGBZVK1syhEfO9nLZUWwa801759tNJx+Pmnz3xeg=,tag:X6/NcdGZHAdIlOwxNPo/Ew==,type:str] +kanidm_grafana_secret: ENC[AES256_GCM,data:rqK3hkpvtg24P4UVV0pFuabUhxoTgtZvK+h8EiSfVyOSrnRy6jtyGvOMMlIOAQDr,iv:I6e++KrpxAFhM8VDQkx8YsrQSvT4brc+Fh1cY5PlwKY=,tag:sEq91Yucb2pUTDbRir+NyA==,type:str] matrix_macaroon_secret: ENC[AES256_GCM,data:a9nMar+p+FXIsxxSqO/to2OJOvD1erfwLwwBeKOcWBu7xykHxqD+pCmrGhg=,iv:rp4ZDVIlZ7SN1RFHB2CfSV5ISPMl9pC4U8Jgqpz48Qs=,tag:LxmWUZE3mG4acagQmlieag==,type:str] matrix_registration_secret: ENC[AES256_GCM,data:KhKkJZqwE8xk4/tuQ7NYTv/Ot1qCAiy8yUbDyVvRa0H5BT4amCBIdATfR4Q=,iv:HBN+GorT1VpWCVkDugk4UxYLEYKJIoDZh2d+oUDLc8g=,tag:hHus458yVnH0qaQ4u37IZg==,type:str] kanidm_synapse_secret: ENC[AES256_GCM,data:F770siYcYLm3RAQ+3epfVTyp5mv0OJfiOdFiHD8CudjceNkkSuXIX7pxQYkhS3VY,iv:hqYMKLS5m+o3leFE0gBS05Npjy9uyqgSe7yJpPzxvQY=,tag:lLjVZ7/iYoIZh06VyF8zSw==,type:str] @@ -15,6 +16,7 @@ coturn_static_auth_secret: ENC[AES256_GCM,data:7AI0E8Hu4WxI5q4j1GqBMSQ+evE006uPM discord_bot_token: ENC[AES256_GCM,data:j37Qo3FCyRwNFqWSWpnQKCs+AxH5HlQ8U5If7ylHilQoORp8Pb3TtNETTJSjZyvUXllldevAbHrbAEEKnNfoUJx1U8/wl6H0,iv:WQqxFXTE+0LIB2lSvVcnr4LNXPE7uzNc0Kk8NU6Z/aE=,tag:fNeQLhoThEgfa4sSGKLZCw==,type:str] discord_client_id: ENC[AES256_GCM,data:U/iUKXT6Nsl6LRN9lPh1xaIaqw==,iv:k7kQ8rJBrMs3YwD9aDfZ6qhd7H3aVsSPTOwEIxVTw2Y=,tag:2wKhxGbf+P+h3BYeWUSczA==,type:str] pg_replication_password: ENC[AES256_GCM,data:w2h07D+j3LNkcbvoKQ2Qp3HSvC2Wf5HRAPAo/HNhmUkHBOaDyILNxo7IDjqajv0jytpG7q4joCJQhS7tEUlA9Q==,iv:26ZurAq61IDqGdAl0yPpoTJElo93hJJIEUlza4DGDNc=,tag:a46FOKgeqEEZE+rC+H9NbQ==,type:str] +kanidm_gitea_secret: ENC[AES256_GCM,data:RavtSb5BaJGwwLB/oGzG/KK2AyV+IzEjihVxnD3/dVnxmxcG+CITIYPLvFUJjmvY,iv:Cg8dAhtJXDvRGULIkpWAyuhhlLEdvN+4lyjHPR/740I=,tag:8kMGrOjXEA4GWSLlP7oIkA==,type:str] gitea: dbPassword: ENC[AES256_GCM,data:S6VvRgkdYk1AzXljyQEEq68UJ9zrFy6+INBMIAspXNcqcM6o+es19o0mcXA=,iv:/pHYpkZZq+9Md+75uSCb2YXfSvaDzUh6mMfH53wb7eg=,tag:ZnbyCQwrK2JnbO5HFqgJYw==,type:str] internalToken: ENC[AES256_GCM,data:7N8TkPNb1YdCk2uAcCvVd2pKRVOf85//DYxAvz0UCg1E8ccEI5630xVyKafDFiSTM4ER7xiYelartzXL0jLWSf3QNOjSHUP8TIAz4bJRAZUJPxO917bURSLGGe7WEOfONzqy3Ts5QhrJ,iv:DiIs1ytlwLvqD/Ejep6m2fmpSqdFZkxBcgLNt6+29jY=,tag:8jsEcOkH0p+1mP9cnVjiDQ==,type:str] @@ -33,7 +35,7 @@ sops: N3I5dzUwc3JtYzczMUhyT04vSHlZamMKT+FzYcDLmlEFYxm/XoBpJb8XaZzBH1v9 6fuez+zApathZfl14w41kAUojPWBznnxDqYtNvzVVLXwnpp3BMx+7w== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-05-15T09:03:17Z" - mac: ENC[AES256_GCM,data:1rSwkArJPxLpyatnp+EJDX4//B7aWUScfM5u0XEQlWeKWjHPYxvZ7b2Vvqx8RFJcWp3QgqQf3f+Mp2DmuDdxAuK94XxHIRk3c1bimKeNrCBPZqQkTjJH8tyklrW1Grob7Xi82GXhk96/s0bTzU58uSdvJXGReYraqvnAuitehPY=,iv:JsImUF/7zQCmIRz34LEOJStL2kAqw8QcARE5eHGsGyU=,tag:8CpmWPVozDPTyNwhoZqC9A==,type:str] + lastmodified: "2026-05-15T10:39:04Z" + mac: ENC[AES256_GCM,data:wXTasAyCQWSX25Npcvg9RewgKZqRlbAtI0Mk1XXLsuvgMoLVCDQWM0VVA4IDp0SUMzU3iocP4FKjhtNve054DT6a/Fcv3laY7dMLrgdJEvGfwsR0kNtIYsTFb5vVF3+h1Za18/9S9M7UINL38Bhwa56O8jnShZpwxe3y9XqMGQ4=,iv:t4ekytZ6dy6QeWcOSho877yK/DFYYFfCi/bHHezrAIc=,tag:HZaE3bWZe+9OtZsVmb52+Q==,type:str] unencrypted_suffix: _unencrypted version: 3.12.2 From c12da16d00632da52403bbc823b456ab5ba0a7d4 Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Fri, 15 May 2026 14:49:13 +0200 Subject: [PATCH 08/10] Added SSO to Vaultwarden & NGX --- flake.lock | 17 ++++ flake.nix | 5 + hosts/cyper-controller/configuration.nix | 2 +- nixos/default.nix | 40 ++++---- nixos/packages/oidcwarden.nix | 12 +++ nixos/roles/adguard.nix | 5 +- nixos/roles/jitsi.nix | 117 ----------------------- nixos/roles/nginx.nix | 14 ++- nixos/roles/paperless-ngx.nix | 22 ++++- nixos/roles/vaultwarden.nix | 30 +++--- secrets/secrets.yaml | 8 +- 11 files changed, 111 insertions(+), 161 deletions(-) create mode 100644 nixos/packages/oidcwarden.nix delete mode 100644 nixos/roles/jitsi.nix diff --git a/flake.lock b/flake.lock index 781fc09..2d45b61 100644 --- a/flake.lock +++ b/flake.lock @@ -774,6 +774,22 @@ "type": "github" } }, + "oidcwarden": { + "flake": false, + "locked": { + "lastModified": 1778081807, + "narHash": "sha256-tHacn9RtoByWpqnWX2/gWwODDSeXJa4mk4MfxHiiJ8A=", + "owner": "Timshel", + "repo": "OIDCWarden", + "rev": "48edfc7ba54372074befa1d62c63c4babfaadc77", + "type": "github" + }, + "original": { + "owner": "Timshel", + "repo": "OIDCWarden", + "type": "github" + } + }, "pre-commit-hooks": { "inputs": { "flake-compat": "flake-compat", @@ -810,6 +826,7 @@ "nixos-generators": "nixos-generators", "nixpkgs": "nixpkgs", "nixvim": "nixvim", + "oidcwarden": "oidcwarden", "sops-nix": "sops-nix", "spicetify-nix": "spicetify-nix" } diff --git a/flake.nix b/flake.nix index be3e29e..0dbbcd6 100644 --- a/flake.nix +++ b/flake.nix @@ -72,6 +72,11 @@ url = "github:catppuccin/nix"; inputs.nixpkgs.follows = "nixpkgs"; }; + + oidcwarden = { + url = "github:Timshel/OIDCWarden"; + flake = false; + }; }; outputs = diff --git a/hosts/cyper-controller/configuration.nix b/hosts/cyper-controller/configuration.nix index b88947d..bc627b5 100644 --- a/hosts/cyper-controller/configuration.nix +++ b/hosts/cyper-controller/configuration.nix @@ -11,7 +11,7 @@ ../../nixos/roles/gitea.nix ../../nixos/roles/vaultwarden.nix ../../nixos/roles/frontpage - # ../../nixos/roles/paperless-ngx.nix + ../../nixos/roles/paperless-ngx.nix ../../nixos/roles/octoprint.nix ../../nixos/roles/matrix/postgres-backup.nix ../../nixos/roles/kanidm.nix diff --git a/nixos/default.nix b/nixos/default.nix index a3d6c6f..edf0510 100644 --- a/nixos/default.nix +++ b/nixos/default.nix @@ -2,6 +2,7 @@ pkgs, inputs, lib, + config, primaryUser, isServer, ... @@ -25,6 +26,10 @@ nix = { settings = { + trusted-users = [ + "root" + primaryUser + ]; experimental-features = [ "nix-command" "flakes" @@ -37,11 +42,13 @@ "https://cache.nixos.org" "https://hyprland.cachix.org" "https://nix-community.cachix.org" + "https://cyper-cache.cachix.org" ]; trusted-public-keys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc=" "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "cyper-cache.cachix.org-1:pOpeWFEjGHg9XvqRg+DQpYnGRQNp+z+QEF8Ev2mbSoM=" ]; }; gc = { @@ -117,32 +124,25 @@ port = 9002; }; - alloy = { - enable = true; - extraFlags = [ "--stability.level=public-preview" ]; - configPath = pkgs.writeText "config.alloy" '' - loki.write "default" { - endpoint { - url = "http://192.168.2.2:3100/loki/api/v1/push" - } - } - - loki.source.journal "journal" { - forward_to = [loki.write.default.receiver] - labels = { - job = "systemd-journal", - host = sys.env("HOSTNAME"), - } - } - ''; - }; - gnome = lib.mkIf (!isServer) { tinysparql.enable = true; localsearch.enable = true; }; }; + sops.secrets.cachix_auth_token = { }; + + systemd.services.cachix-push = { + description = "Push new store paths to Cachix"; + after = [ "multi-user.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.bash}/bin/bash -c 'CACHIX_AUTH_TOKEN=$(cat ${config.sops.secrets.cachix_auth_token.path}) ${pkgs.nix}/bin/nix path-info --recursive /run/current-system | CACHIX_AUTH_TOKEN=$(cat ${config.sops.secrets.cachix_auth_token.path}) ${pkgs.cachix}/bin/cachix push cyper-cache'"; + }; + }; + networking.firewall.allowedTCPPorts = [ 9002 3100 diff --git a/nixos/packages/oidcwarden.nix b/nixos/packages/oidcwarden.nix new file mode 100644 index 0000000..7145325 --- /dev/null +++ b/nixos/packages/oidcwarden.nix @@ -0,0 +1,12 @@ +{ pkgs, oidcwarden-src, ... }: + +pkgs.vaultwarden.overrideAttrs (old: { + pname = "oidcwarden"; + src = oidcwarden-src; + cargoDeps = pkgs.rustPlatform.importCargoLock { + lockFile = "${oidcwarden-src}/Cargo.lock"; + }; + postInstall = (old.postInstall or "") + '' + mv $out/bin/oidcwarden $out/bin/vaultwarden + ''; +}) diff --git a/nixos/roles/adguard.nix b/nixos/roles/adguard.nix index 67405c4..25e3176 100644 --- a/nixos/roles/adguard.nix +++ b/nixos/roles/adguard.nix @@ -12,12 +12,11 @@ in resolved.enable = false; adguardhome = { enable = true; - mutableSettings = true; + mutableSettings = false; allowDHCP = true; + port = adguardPort; settings = { - http.address = "0.0.0.0:${toString adguardPort}"; - users = [ { name = "DerGrumpf"; diff --git a/nixos/roles/jitsi.nix b/nixos/roles/jitsi.nix deleted file mode 100644 index fe28e16..0000000 --- a/nixos/roles/jitsi.nix +++ /dev/null @@ -1,117 +0,0 @@ -{ - pkgs, - ... -}: - -let - domain = "jitsi.cyperpunk.de"; -in -{ - nixpkgs.config.permittedInsecurePackages = [ - "jitsi-meet-1.0.8792" - ]; - - services.jitsi-meet = { - enable = true; - hostName = domain; - - config = { - enableWelcomePage = true; - prejoinPageEnabled = true; - enableInsecureRoomNameWarning = true; - disableAudioLevels = false; - enableLayerSuspension = true; - p2p.enabled = true; - analytics.disabled = true; - }; - - interfaceConfig = { - SHOW_JITSI_WATERMARK = false; - SHOW_WATERMARK_FOR_GUESTS = false; - DEFAULT_REMOTE_DISPLAY_NAME = "Meeting @ Virtual"; - TOOLBAR_BUTTONS = [ - "microphone" - "camera" - "desktop" - "fullscreen" - "fodeviceselection" - "hangup" - "profile" - "chat" - "recording" - "livestreaming" - "etherpad" - "sharedvideo" - "settings" - "raisehand" - "videoquality" - "filmstrip" - "invite" - "feedback" - "stats" - "shortcuts" - "tileview" - "select-background" - "mute-everyone" - "security" - ]; - }; - - # Enable Jibri for recording/livestreaming support - jibri = { - enable = true; - }; - - # Enable Jigasi for SIP/telephony support (optional, comment out if not needed) - # jigasi.enable = true; - - nginx.enable = true; - prosody.enable = true; - }; - - # Jitsi Videobridge — handles the actual media routing - services.jitsi-videobridge = { - enable = true; - openFirewall = true; - - config = { - videobridge = { - ice.udp.port = 10000; - apis.rest.enabled = true; - }; - }; - }; - - networking.firewall = { - allowedTCPPorts = [ - 5222 # XMPP client (Prosody) - 5269 # XMPP federation (Prosody) - ]; - allowedUDPPorts = [ - 10000 # Jitsi Videobridge RTP media - ]; - allowedUDPPortRanges = [ - { - from = 49152; - to = 65535; - } # WebRTC ephemeral ports - ]; - }; - - # Prosody needs this for XMPP - networking.extraHosts = '' - 127.0.0.1 ${domain} - 127.0.0.1 auth.${domain} - 127.0.0.1 focus.${domain} - 127.0.0.1 jitsi-videobridge.${domain} - ''; - - # Jibri requires Chromium for recording - environment.systemPackages = with pkgs; [ - chromium - ffmpeg - ]; - - # ALSA loopback device — required by Jibri for audio capture during recording - boot.kernelModules = [ "snd-aloop" ]; -} diff --git a/nixos/roles/nginx.nix b/nixos/roles/nginx.nix index ff8e765..9785fc5 100644 --- a/nixos/roles/nginx.nix +++ b/nixos/roles/nginx.nix @@ -56,7 +56,19 @@ in }; "search.cyperpunk.de" = mkProxy 11080; "file.cyperpunk.de" = mkProxy 10000; - "ngx.cyperpunk.de" = mkWsProxy 28101; + "ngx.cyperpunk.de" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://${upstream}:28101"; + proxyWebsockets = true; + extraConfig = '' + sub_filter '' ''; + sub_filter_once on; + proxy_set_header Accept-Encoding ""; + ''; + }; + }; "vault.cyperpunk.de" = mkWsProxy 8222; "calvin.cyperpunk.de" = mkWsProxy 15006; "auth.cyperpunk.de" = mkHttpsProxy 8444; diff --git a/nixos/roles/paperless-ngx.nix b/nixos/roles/paperless-ngx.nix index 387c59e..43b9237 100644 --- a/nixos/roles/paperless-ngx.nix +++ b/nixos/roles/paperless-ngx.nix @@ -1,9 +1,15 @@ { config, ... }: { - sops.secrets.paperless_admin = { - owner = "paperless"; + sops.secrets = { + paperless_admin = { + owner = "paperless"; + }; + paperless_oidc_secret = { + owner = "paperless"; + }; }; + services.paperless = { enable = true; address = "0.0.0.0"; @@ -23,6 +29,7 @@ ]; PAPERLESS_OCR_LANGUAGE = "deu+eng"; PAPERLESS_CONSUMER_POLLING = 60; + PAPERLESS_APPS = "allauth.socialaccount.providers.openid_connect"; }; exporter = { @@ -41,9 +48,14 @@ "d /storage/backup/paperless 0775 root users -" ]; - services.paperless-scheduler = { - after = [ "systemd-tmpfiles-setup.service" ]; - requires = [ "systemd-tmpfiles-setup.service" ]; + services = { + paperless-scheduler = { + after = [ "systemd-tmpfiles-setup.service" ]; + requires = [ "systemd-tmpfiles-setup.service" ]; + }; + paperless-web = { + serviceConfig.EnvironmentFiles = [ config.sops.secrets.paperless_oidc_secret.path ]; + }; }; }; networking.firewall.allowedTCPPorts = [ 28101 ]; diff --git a/nixos/roles/vaultwarden.nix b/nixos/roles/vaultwarden.nix index dbe3142..71dc39e 100644 --- a/nixos/roles/vaultwarden.nix +++ b/nixos/roles/vaultwarden.nix @@ -1,36 +1,44 @@ { config, pkgs, - lib, + inputs, ... }: let - address = config.systemd.network.networks."10-ethernet".networkConfig.Address; - ip = builtins.elemAt (lib.splitString "/" address) 0; port = 8222; + oidcwarden = import ../packages/oidcwarden.nix { + inherit pkgs; + oidcwarden-src = inputs.oidcwarden; + }; in { + sops.secrets.vaultwarden_env = { + owner = "vaultwarden"; + group = "vaultwarden"; + }; + services.vaultwarden = { enable = true; - environmentFile = config.sops.secrets.vaultwarden_admin_token.path; + package = oidcwarden; + environmentFile = config.sops.secrets.vaultwarden_env.path; backupDir = "/var/local/vaultwarden/backup"; config = { - DOMAIN = "https://vault.cyperpunk.de"; # "http://${ip}:${toString port}"; + DOMAIN = "https://vault.cyperpunk.de"; ROCKET_ADDRESS = "0.0.0.0"; ROCKET_PORT = port; ROCKET_LOG = "critical"; - SIGNUPS_ALLOWED = true; + SIGNUPS_ALLOWED = false; WEBSOCKET_ENABLED = true; + SSO_ENABLED = true; + SSO_ONLY = false; + SSO_AUTHORITY = "https://auth.cyperpunk.de/oauth2/openid/vaultwarden"; + SSO_SCOPES = "openid profile email"; + SSO_PKCE = false; }; }; - sops.secrets.vaultwarden_admin_token = { - owner = "vaultwarden"; - group = "vaultwarden"; - }; - networking.firewall.allowedTCPPorts = [ port ]; systemd = { diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml index b1b5442..69d3413 100644 --- a/secrets/secrets.yaml +++ b/secrets/secrets.yaml @@ -1,3 +1,4 @@ +cachix_auth_token: ENC[AES256_GCM,data:nR7e2ZOA3q5DmkrqFEzINpKFEHVD5nyzc3DQ3QgD42fdyABV+r1Ela3iEcbU8SWj5JMRq8T1r7QxqcYW+VSMsT2cjQV2e4ZrpUmkX2QnhfmLqQBdJLhgNKBnu+x8QGJpQ3j7mG23atJ3BDTYBEKlI8y6wLEgpTX8GIVzHJVwfbqewTX4EfFyh3mVMtxAK9II/w==,iv:CSMcUdsqC97fmu1Po3cRrUj9h51Wv+KaUPfEToE7qVs=,tag:s1XHG2eyZYJJ5xd9CZb+Pw==,type:str] GROQ_API_KEY: ENC[AES256_GCM,data:OyuC4jfw67sCDa0XBGr78S6pzPV1ruy7KiIqPMgWWcOCVm3Y/khXEYPMjUTGrq9YLOw1MLso0OE=,iv:0y9klMYVtGsqAaLc2JidjZYSLhhbcbWbnBf8sZiC3rM=,tag:r6G2pzZn2d9JIaS+ozKnmg==,type:str] OPENWEATHER_API_KEY: ENC[AES256_GCM,data:bcuLz70u40nZfNgPTaeNRXdR/zjx0SQjwMbMNNFqROI=,iv:VCzse1a1/k1ZDIpFPL1QhjuS6YaDyohWi61JZaoc0Ws=,tag:UJSNyniNNLfGGRY/uiJcRA==,type:str] smb_passwd: ENC[AES256_GCM,data:+9RYomcnCZSME5DzuJWTLbS3IGJHhIYWZ5SmsgOn6YQ=,iv:VRPVR7DD+swjeUZKe54XYm3wn/KB4RqvQAyYXQbS+A8=,tag:NnA89efo6HVL0scHgyTZMQ==,type:str] @@ -6,10 +7,11 @@ kanidm_grafana_secret: ENC[AES256_GCM,data:rqK3hkpvtg24P4UVV0pFuabUhxoTgtZvK+h8E matrix_macaroon_secret: ENC[AES256_GCM,data:a9nMar+p+FXIsxxSqO/to2OJOvD1erfwLwwBeKOcWBu7xykHxqD+pCmrGhg=,iv:rp4ZDVIlZ7SN1RFHB2CfSV5ISPMl9pC4U8Jgqpz48Qs=,tag:LxmWUZE3mG4acagQmlieag==,type:str] matrix_registration_secret: ENC[AES256_GCM,data:KhKkJZqwE8xk4/tuQ7NYTv/Ot1qCAiy8yUbDyVvRa0H5BT4amCBIdATfR4Q=,iv:HBN+GorT1VpWCVkDugk4UxYLEYKJIoDZh2d+oUDLc8g=,tag:hHus458yVnH0qaQ4u37IZg==,type:str] kanidm_synapse_secret: ENC[AES256_GCM,data:F770siYcYLm3RAQ+3epfVTyp5mv0OJfiOdFiHD8CudjceNkkSuXIX7pxQYkhS3VY,iv:hqYMKLS5m+o3leFE0gBS05Npjy9uyqgSe7yJpPzxvQY=,tag:lLjVZ7/iYoIZh06VyF8zSw==,type:str] -vaultwarden_admin_token: ENC[AES256_GCM,data:yoBs4CaIEJXB5b3PEwTpXFgxpX39hR9A4r9yamwDV7cTSRRp3n3O2VjDKTcI5Vo6RP2QUjcqUqYf98cZ09wDMc+6+oHHJke7+O0FgRgOC0vOQFs4bfZCBJBLxogrGiwtLGkyykR6VYhrT64AN3CbrXflj82OED2Hl8WwEdruBzGIcfnh6FqQowDx6vDR/kXXJHk=,iv:PJQo5V7FaKPQ+GzZNsy3KB+xyjcDKJ1UBHErrqgn/1U=,tag:BRIDJEDOAeToqio/DHMQaA==,type:str] +vaultwarden_env: ENC[AES256_GCM,data:tGAphb8y+9sdo29z1/zRe4IKKKAsKfJZIiRGSDe1Vbpn24ucjnvrDpbuI8AIf145mVckCZ6nsdB88q+XNr4jrywx3b5gGdacZn/wLx6rVpa24VdJOI685nu++CtJjUiPCOiNVRza7MGFStCWTekRGosVWwwjmu8IRHEtywO/+qkVa2tFx9SGxB9ayVHWJVJNI0V3EoWgXp0Sf+gYZvMww0Ew05xeeCdICe9Tz6ExVsI/2feq2QPBgcR4M+g47UrixWf0HmR+WU/HQygSYZ0vxau+88PyfrlOUWBZY0WtETNd0pymVHnvHyFIuBjwa8zg,iv:Oytbdz/9KS21sy2tWAws2DTKTmW8IOJcSso1K1tYm3M=,tag:iWphR6xUegNrCEsqL2o0yQ==,type:str] flame_phil_password: ENC[AES256_GCM,data:Xy2ixMeRlnzC2gjKGrjfSbz/ee4=,iv:WFuBS8jn7WYRxEDG3XBzCMnm4eNkHQpSs5+GUwq/dcg=,tag:1zzj0eB9/4KrmYAqcxJMlg==,type:str] flame_calvin_password: ENC[AES256_GCM,data:P5ppyqTjAJ1TL4hXtx5WyoS9a+g=,iv:sq98P3Oqud2FXfqsD76YS/p5NEF2xlN0MfG+ukCB9B0=,tag:AeKnu4Hg4xQ3tII0y6oNpQ==,type:str] paperless_admin: ENC[AES256_GCM,data:sVvlMQ3dDE2XsDfpwpCTbzPCEKdUMNTFtRXDIuBbgyf1gd6oiJzE23Ytc57plNUGg5h5aEtgxZ7NXeuK5vrhQw==,iv:x+QNAzY9k9t23UYlM9GcAke0urEA5jlV0VzHaBQkm7M=,tag:D/bMtjuwrX6pquZfJLwdkQ==,type:str] +paperless_oidc_secret: ENC[AES256_GCM,data:+oCeHlky5FgUR8Toue1iQiTaqVX3ZgenEv74S5Cg6XHBObyDLUgUkZNYKj7p88nR,iv:29CBYlOjpyegGwEl5lSlAirkCWtG0+4oOupOTfeI1yM=,tag:KckKGdFa9tNwigWEukLN3w==,type:str] livekit_key_file: ENC[AES256_GCM,data:wOtJhwDtZNEY+QjHyLL1FTOtkmzkNA5BoTsx0+ZMij9uUaKC28uFIkMAq2ZzIU7Nyvk8+4YjbK/Rrsoy,iv:UTDuItr0XsG+/4HFkEHDpxXy41QiVgPCisHeMMY2dQo=,tag:SkoeLWClO9I/V2sn27Y2uw==,type:str] mjolnir_access_token: ENC[AES256_GCM,data:vvrAY9CAkEIGEzah+TQiwa6PahGuXVvU7wzBpTnqeSLqe3mqtw120GRj,iv:J+/VJ40BsImr832eGUHShhDVWYC7KsEwQUH9AE6Rs9c=,tag:n+y0flxfqY47rB4yv9TnBw==,type:str] coturn_static_auth_secret: ENC[AES256_GCM,data:7AI0E8Hu4WxI5q4j1GqBMSQ+evE006uPMtwIfGn4eFz+XB2JA6fhhiGMPPxSkqOyK+3eZJ5ahiG05JpmBmmAbw==,iv:hQJQQDVo43U7lvV754PC1THeFCpZZEyag+BslXyoDos=,tag:Vkm+IXr1h8ZNpah6UYaKng==,type:str] @@ -35,7 +37,7 @@ sops: N3I5dzUwc3JtYzczMUhyT04vSHlZamMKT+FzYcDLmlEFYxm/XoBpJb8XaZzBH1v9 6fuez+zApathZfl14w41kAUojPWBznnxDqYtNvzVVLXwnpp3BMx+7w== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-05-15T10:39:04Z" - mac: ENC[AES256_GCM,data:wXTasAyCQWSX25Npcvg9RewgKZqRlbAtI0Mk1XXLsuvgMoLVCDQWM0VVA4IDp0SUMzU3iocP4FKjhtNve054DT6a/Fcv3laY7dMLrgdJEvGfwsR0kNtIYsTFb5vVF3+h1Za18/9S9M7UINL38Bhwa56O8jnShZpwxe3y9XqMGQ4=,iv:t4ekytZ6dy6QeWcOSho877yK/DFYYFfCi/bHHezrAIc=,tag:HZaE3bWZe+9OtZsVmb52+Q==,type:str] + lastmodified: "2026-05-15T12:46:25Z" + mac: ENC[AES256_GCM,data:KeBccgMJ2PLvLjKqnGcZTdVCkR60XO/H7Wy+3JvucPqRP+vdjXvSGzadgJ/d+ML04ytKk5Ffp0APnK//CLaiD+mcKlwAavtI4qKuvhtssxwsDbzYwvI/TsxFUD+BIVnvxUMDNfI//Wx1qSLb5jDdUWmiexF+bFtCwHfZFsEh4Sg=,iv:auXVwnkaCGpZcr8Jx1GSEdxab2/Y6jJhdfD4wjGBHBM=,tag:GCG7gWeAJ5nJCyY2ofZBGA==,type:str] unencrypted_suffix: _unencrypted version: 3.12.2 From ecafb32328bb8713ad82006ee263aa11daeb22c6 Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Fri, 15 May 2026 15:23:26 +0200 Subject: [PATCH 09/10] SSH access for Gitea --- home/ssh.nix | 7 +++++++ nixos/roles/gitea.nix | 2 +- nixos/roles/matrix/clients.nix | 20 ++++++++++++++++++-- nixos/roles/matrix/synapse.nix | 2 +- nixos/roles/nginx.nix | 14 +------------- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/home/ssh.nix b/home/ssh.nix index 8ad6abe..ffad008 100644 --- a/home/ssh.nix +++ b/home/ssh.nix @@ -17,6 +17,13 @@ if isDarwin then "/Users/${primaryUser}/.ssh/github" else "/home/${primaryUser}/.ssh/github"; user = "git"; }; + "git.cyperpunk.de" = { + hostname = "git.cyperpunk.de"; + port = 12222; + user = "gitea"; + identityFile = + if isDarwin then "/Users/${primaryUser}/.ssh/ssh" else "/home/${primaryUser}/.ssh/ssh"; + }; }; }; } diff --git a/nixos/roles/gitea.nix b/nixos/roles/gitea.nix index 148354b..4a75776 100644 --- a/nixos/roles/gitea.nix +++ b/nixos/roles/gitea.nix @@ -13,7 +13,7 @@ let stripRoot = false; }; - domain = "git.cyperpunk.de"; # swap to git.cyperpunk.de for prod + domain = "git.cyperpunk.de"; httpPort = 9000; sshPort = 12222; in diff --git a/nixos/roles/matrix/clients.nix b/nixos/roles/matrix/clients.nix index a7ff4c7..62c6c92 100644 --- a/nixos/roles/matrix/clients.nix +++ b/nixos/roles/matrix/clients.nix @@ -133,15 +133,31 @@ let ''; }); + cinnyConfigured = pkgs.cinny-unwrapped.overrideAttrs (_: { + postInstall = '' + cp ${ + builtins.toFile "cinny-config.json" ( + builtins.toJSON { + defaultHomeserver = 0; + homeserverList = [ "cyperpunk.de" ]; + allowCustomHomeservers = false; + } + ) + } $out/config.json + ''; + }); + in { services.nginx.virtualHosts = { "cinny.cyperpunk.de" = { forceSSL = true; enableACME = true; - root = "${pkgs.cinny}"; + root = "${cinnyConfigured}"; + locations."/" = { + tryFiles = "$uri $uri/ /index.html"; + }; }; - "element.cyperpunk.de" = { forceSSL = true; enableACME = true; diff --git a/nixos/roles/matrix/synapse.nix b/nixos/roles/matrix/synapse.nix index bf8b498..e33019f 100644 --- a/nixos/roles/matrix/synapse.nix +++ b/nixos/roles/matrix/synapse.nix @@ -128,7 +128,7 @@ in ]; allow_existing_users = true; user_mapping_provider.config = { - localpart_template = "{{ user.preferred_username }}"; + localpart_template = "{{ user.preferred_username.split('@')[0] }}"; display_name_template = "{{ user.displayname }}"; }; } diff --git a/nixos/roles/nginx.nix b/nixos/roles/nginx.nix index 9785fc5..ff8e765 100644 --- a/nixos/roles/nginx.nix +++ b/nixos/roles/nginx.nix @@ -56,19 +56,7 @@ in }; "search.cyperpunk.de" = mkProxy 11080; "file.cyperpunk.de" = mkProxy 10000; - "ngx.cyperpunk.de" = { - forceSSL = true; - enableACME = true; - locations."/" = { - proxyPass = "http://${upstream}:28101"; - proxyWebsockets = true; - extraConfig = '' - sub_filter '' ''; - sub_filter_once on; - proxy_set_header Accept-Encoding ""; - ''; - }; - }; + "ngx.cyperpunk.de" = mkWsProxy 28101; "vault.cyperpunk.de" = mkWsProxy 8222; "calvin.cyperpunk.de" = mkWsProxy 15006; "auth.cyperpunk.de" = mkHttpsProxy 8444; From 3464e55e0e1c70b062db0087e3e027594816dd59 Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Fri, 15 May 2026 15:29:52 +0200 Subject: [PATCH 10/10] SSH access for Gitea; stream config nginx --- nixos/roles/nginx.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/nixos/roles/nginx.nix b/nixos/roles/nginx.nix index ff8e765..eac88c8 100644 --- a/nixos/roles/nginx.nix +++ b/nixos/roles/nginx.nix @@ -33,6 +33,7 @@ in networking.firewall.allowedTCPPorts = [ 80 443 + 12222 ]; security.acme = { @@ -47,6 +48,14 @@ in recommendedOptimisation = true; recommendedGzipSettings = true; + # Git ssh + streamConfig = '' + server { + listen 12222; + proxy_pass ${upstream}:12222; + } + ''; + virtualHosts = { # controller services (proxied to upstream tailscale node) "git.cyperpunk.de" = (mkProxy 9000) // {