From 6379ff4662d4f077a643ef75e3ba27b41dfa8bd1 Mon Sep 17 00:00:00 2001 From: tux Date: Sun, 9 Aug 2026 14:36:16 +0530 Subject: [PATCH] feat: add pangolin and newt modules --- modules/hosts/alpha/config.nix | 23 +++++--- modules/hosts/alpha/secrets.yaml | 7 ++- modules/hosts/arcturus/config.nix | 9 +++ modules/hosts/arcturus/secrets.yaml | 15 ++--- modules/nixos/networking/newt.nix | 30 ++++++++++ modules/nixos/services/pangolin.nix | 91 +++++++++++++++++++++++++++++ 6 files changed, 156 insertions(+), 19 deletions(-) create mode 100644 modules/nixos/networking/newt.nix create mode 100644 modules/nixos/services/pangolin.nix diff --git a/modules/hosts/alpha/config.nix b/modules/hosts/alpha/config.nix index b59a165..bebf96b 100644 --- a/modules/hosts/alpha/config.nix +++ b/modules/hosts/alpha/config.nix @@ -39,9 +39,11 @@ }; services = { - nginx = { + pangolin = { enable = true; - domain = "lab.tux.rs"; + domain = "pangolin.lab.tux.rs"; + baseDomain = "lab.tux.rs"; + environmentFile = innerArgs.config.sops.secrets."pangolin".path; }; uptime-kuma = { @@ -50,18 +52,17 @@ domain = "status.lab.tux.rs"; }; - mediaflow-proxy = { - enable = true; - port = 8888; - domain = "mf-proxy.lab.tux.rs"; - environmentFile = innerArgs.config.sops.secrets."mediaflow-proxy".path; - }; - vaultwarden = { enable = true; port = 9999; domain = "bw.lab.tux.rs"; }; + + mediaflow-proxy = { + enable = true; + port = 8888; + environmentFile = innerArgs.config.sops.secrets."mediaflow-proxy".path; + }; }; virtualisation = { @@ -110,6 +111,10 @@ mediaflow-proxy = { sopsFile = ./secrets.yaml; }; + + pangolin = { + sopsFile = ./secrets.yaml; + }; }; # --- Networking --- diff --git a/modules/hosts/alpha/secrets.yaml b/modules/hosts/alpha/secrets.yaml index fee5d3f..38cad75 100644 --- a/modules/hosts/alpha/secrets.yaml +++ b/modules/hosts/alpha/secrets.yaml @@ -8,6 +8,7 @@ cloudflare-credentials: dns-api-token: ENC[AES256_GCM,data:aLZqasMaxpv08KuGqhe66J/jHqEnMNdZrYtIurv01xk2/5OW//PaHQ==,iv:7tZYpOT27n/RWaj1CqiZbhA/g3aKbxjdkMA6SuW/YpQ=,tag:oetxyD9XMrihSLyDvl7qfw==,type:str] aiostreams: ENC[AES256_GCM,data:HeV4NONoqTti/4GBpzYaUEGgrSpDfCfcGJ3kbZAUtg5hm1zQCcelx3N4b/woSjaNZrDj98P5R3oZUkgVfv0RS2PKdJc3EdLaPFwXcuJ+W0U373sryU85uIIZi4BvQ4LyCCpuclPU5dgQmb9rzbIvhlu/ftfpKJsRbH2bUgMMo2nohMWUtg==,iv:V60U/omnN+09cSOQGvwwN8DC6/D++MB0axQyzIG97zo=,tag:vwNbXRj3CS+okb0NSwxgYw==,type:str] mediaflow-proxy: ENC[AES256_GCM,data:jk2eYyOmO3XpqFNo3jucB/VvL6pWBGrquYi/OpIwvSPqjbo=,iv:DIsqykv77/TlLhT9uIPGJRBlCQHVdhcuYlc56qQGZgk=,tag:phMXArjIrNNI51U9hpaUzg==,type:str] +pangolin: ENC[AES256_GCM,data:G6TscTsWsyvBM/L2boxpDIrczV0cycQNT51mOf0vPKOHdifdBxT6Q3PY+Ms5arc=,iv:qh655lwIcD89D8ufIzJWYrDqPKGCrGMUXsgcFYwm9zY=,tag:kGlGzaOADZyY6gsLuI6EHw==,type:str] sops: age: - enc: | @@ -28,7 +29,7 @@ sops: 4TkObqH8ddGpbd7cX5a/wboTjYuEdAviWxjK2oBPgtcFc1f03X3tmA== -----END AGE ENCRYPTED FILE----- recipient: age1mzxxxzhy3us3rd960ufqv7vlxj5cnug86md6x69llg9ujzw2pqws057llf - lastmodified: "2026-07-13T15:24:16Z" - mac: ENC[AES256_GCM,data:5NOOqdtJJj0ph3apCwaokiRySW9QIlmR01I7fFZDT2sNHqrJSgVVN8U5WtOnM1S61ID7MRxGLpSegU9M8lPnZd2WmhGIlactJjoSTE9+Xy5hj4m9mdWW0TZg9w4qmyIo8o8DuoDa2LiyilT97XaMnvoDz2ZqWcJxi44URLmk9o0=,iv:czkDfHv9eg1VzyMUT48W4OmmeSaUu6TzeYcyYSBu/+w=,tag:140ldPXqetX3733QnoOU0g==,type:str] + lastmodified: "2026-08-07T20:02:00Z" + mac: ENC[AES256_GCM,data:VrA2OPCcVvAzYjZTkHPxytclISP24P1FqiIQjSGQItkMLieom80N6933hB0Tdn3BM6600bHt2NweSqHjGx//pn2Gbur4pxeN3TpF9tKXc12IcAThUL9g48fMbk5y+kWWVUF1Pezod0YnzWAlalUXFqvKinfm4RqPNjDjndA/dcI=,iv:xfs9XD5ZIQ6dyMMZ8OE5FEs/hrSr/T2VwC7XvZ7xC2A=,tag:jYWo2kgwwltKB+njiYaPkQ==,type:str] unencrypted_suffix: _unencrypted - version: 3.13.1 + version: 3.13.3 diff --git a/modules/hosts/arcturus/config.nix b/modules/hosts/arcturus/config.nix index d70f4a6..a079304 100644 --- a/modules/hosts/arcturus/config.nix +++ b/modules/hosts/arcturus/config.nix @@ -42,6 +42,10 @@ networking = { openssh.enable = true; netbird-client.enable = true; + newt = { + enable = true; + environmentFile = innerArgs.config.sops.secrets.newt.path; + }; }; services = { @@ -86,6 +90,11 @@ sopsFile = ./secrets.yaml; owner = userName; }; + + newt = { + sopsFile = ./secrets.yaml; + owner = userName; + }; }; # --- Networking --- diff --git a/modules/hosts/arcturus/secrets.yaml b/modules/hosts/arcturus/secrets.yaml index bc4960e..eddc366 100644 --- a/modules/hosts/arcturus/secrets.yaml +++ b/modules/hosts/arcturus/secrets.yaml @@ -4,10 +4,10 @@ gemini-api-key: ENC[AES256_GCM,data:gLZSoYTdKY+rwIpYiXvN9n9PGkUD6q8Oe7dHnYkjEjwD openrouter-api-key: ENC[AES256_GCM,data:6xONCl9lqOoO7b4CEyCz9607tICDUAkpglRjGS5nYq2ppg2UKqYTrWD1BGCA5Xfs/CWskniVhoNG3vscjKiYCCh9gbM6aqdmTQ==,iv:7Iwc9t00HOOBjA7URXcUO41badqYyJCkFHM/uPkLFxY=,tag:Cl39kitr2e0//HVwAdsdUQ==,type:str] opencode-go-api-key: ENC[AES256_GCM,data:dmeRKn7TWHnqvpyPQpcEG6yHTb2bRby/rh10ytL0jHj5R+lRmNVdmqUF92GTznY9vEaB6ZYCJecWhpm8g4upNfOWBg==,iv:9UMJpAlD8gpcNiN+liu3nawoAZQKapEg7sCp561N9E8=,tag:OZlASpOa5BQaQwFWjoLCRw==,type:str] netbird-key: ENC[AES256_GCM,data:q6eKisca04qn/CvALrvXF79MsToDhvLRLv2JTiUBAZglCC9m,iv:jj0/ZD7IDgopprTVUgSfJmdAJmUP3iqewU3dqssGYbk=,tag:6IPRdCm2FGdlTEIX7jt3qA==,type:str] +newt: ENC[AES256_GCM,data:r5Rd81ZrzrIYbXtFkypbJltoGCOYrW6P4IpwGCtaH7lqCg7wD/WMboMx13HN4Mm0J4qbBpDakpfVv9qUTrisYP1xwpKkmY1kqPlFWRZN8hzuuNS2Tv3qUjavTp5XGotVPLHj1Cg/cwGcf8EAssYTwTy7H0PgdQKwqigQD1f1s/j4iXQ=,iv:1xP38/Ayt1xvn2fJGa5zgOrVNOw2J5taG1Orx6uNgZI=,tag:H9JXu9gzyyvTPWgXaoTsiw==,type:str] sops: age: - - recipient: age14vktfes95f33vuefwnmuvryas7az04u76dsgyhfvsx73czkvmp2q7njkl4 - enc: | + - enc: | -----BEGIN AGE ENCRYPTED FILE----- YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3Qkh0cmdHNGJTYmFNUFZW c244RjlyNjlrSWh1bG1IRFFFeFZZVzhaYVdBCmd1N3JNS0IzWDlUMUJSM0pYdi9L @@ -15,8 +15,8 @@ sops: Z3hhRitmdEwxbzcrS0cwNTZVK1lXYlUKSFfKk7JGzxRq9weL4NKJqfmAige2O+1T 59PvEFKvvkGb6ajkzwTw0lB3UFzly6FuTnbSLY9r+oT9AMbxLoKdcQ== -----END AGE ENCRYPTED FILE----- - - recipient: age1huqa3hc7wcxk4dpelrzny437nzrx4fnll3d8g9ahznzk268yju5qufapxy - enc: | + recipient: age14vktfes95f33vuefwnmuvryas7az04u76dsgyhfvsx73czkvmp2q7njkl4 + - enc: | -----BEGIN AGE ENCRYPTED FILE----- YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOYlZiak1CSW1NSGt5QTRi RjlUeG5EODVkTVJDY1RrZXJ6OU5NQ0RIOG5jCnJxZ1R6MmlGWXY2SmtaY1pQSWdZ @@ -24,7 +24,8 @@ sops: V3h4dUZLcktrTUZvUm44eVZOWEl4VmMKMTvajoWcktb4jVIP4HyzQiR41Wg8Gdqi TLKEYsPQgOJ7s8P9gw2uPUY6HRz86CtiC6EbO27u0+8BbI85x1QScg== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-05-10T00:36:06Z" - mac: ENC[AES256_GCM,data:nD0exblrbheP1C5lK8V17V/gkHJO6s6yVjXtQWcUOLVGrzkPSxkymYBHUFMTLVyYQNLCVMc8AHkuHVuJ1tBfXNll1f6/SGtfaBQcOLct70U7nFxd/XybTUlscNp2KafJWy/n4ZUfNDbfrWN1R463CN/M50jGqJPDWYuP9ah2JcI=,iv:izQUT/+HQqJZ48X5bXobFSaWcdcXQ/7eh+SCd9i4YYo=,tag:FJlR2wI4rWQ/SDfQGtQ7AQ==,type:str] + recipient: age1huqa3hc7wcxk4dpelrzny437nzrx4fnll3d8g9ahznzk268yju5qufapxy + lastmodified: "2026-08-09T11:21:03Z" + mac: ENC[AES256_GCM,data:XFy+AiJRfrLhbX3j+0oO24qiHD5Hj2bVFqTMbUOOzsJzR0r8FBrwSNAZ0FVlFPFPAMitAIpZySS+kvbmEdZUfZ0soo83F5qwH6i/H5PZxqyDHst/Ig6Mrypp2DZMNZXNlqyLLmuaNGDf2pqApxCM3eSsgvCsNxdapRKlLSFJou4=,iv:D7gB4J4dhCfRo+1DaUAvOe3dWpoGvzIFouCJBNpwKiY=,tag:eLBZq/+Lce2S5Hu9OIC3gw==,type:str] unencrypted_suffix: _unencrypted - version: 3.12.2 + version: 3.13.3 diff --git a/modules/nixos/networking/newt.nix b/modules/nixos/networking/newt.nix new file mode 100644 index 0000000..82fa749 --- /dev/null +++ b/modules/nixos/networking/newt.nix @@ -0,0 +1,30 @@ +{ + flake.modules.nixos.networking = + { + config, + lib, + ... + }: + with lib; + let + cfg = config.tnix.networking.newt; + in + { + options.tnix.networking.newt = { + enable = mkEnableOption "Newt"; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = "Environment file with secrets passed to Newt"; + }; + }; + + config = mkIf cfg.enable { + services.newt = { + enable = true; + environmentFile = cfg.environmentFile; + }; + }; + }; +} diff --git a/modules/nixos/services/pangolin.nix b/modules/nixos/services/pangolin.nix new file mode 100644 index 0000000..77373e5 --- /dev/null +++ b/modules/nixos/services/pangolin.nix @@ -0,0 +1,91 @@ +{ + flake.modules.nixos.services = + { + config, + lib, + userEmail, + pkgs, + ... + }: + with lib; + let + cfg = config.tnix.services.pangolin; + in + { + options.tnix.services.pangolin = { + enable = mkEnableOption "Pangolin"; + + domain = mkOption { + type = types.str; + default = ""; + description = "Domain on which nginx serves MediaFlow Proxy (disabled when empty)"; + }; + + baseDomain = mkOption { + type = types.str; + default = ""; + description = "Domain on which nginx serves MediaFlow Proxy (disabled when empty)"; + }; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = "Environment file with secrets passed to Pangolin"; + }; + }; + + config = mkIf cfg.enable { + services = { + pangolin = { + enable = true; + package = ( + pkgs.fosrl-pangolin.override { + databaseType = "pg"; + } + ); + openFirewall = true; + baseDomain = cfg.baseDomain; + dashboardDomain = cfg.domain; + environmentFile = cfg.environmentFile; + letsEncryptEmail = userEmail; + + settings = { + app.dashboard_url = "https://${config.services.pangolin.dashboardDomain}"; + domains.domain1 = { + base_domain = config.services.pangolin.baseDomain; + prefer_wildcard_cert = false; + }; + server = { + external_port = 3000; + internal_port = 3001; + next_port = 3002; + integration_port = 3003; + # needs to be set, otherwise this fails silently + # see https://github.com/fosrl/newt/issues/37 + internal_hostname = "localhost"; + }; + gerbil.base_endpoint = config.services.pangolin.dashboardDomain; + flags = { + disable_signup_without_invite = true; + enable_integration_api = false; + allow_raw_resources = true; + disable_enterprise_features = true; + }; + postgres.connection_string = "postgresql:///pangolin?host=/run/postgresql"; + }; + }; + + postgresql = { + enable = true; + ensureDatabases = [ "pangolin" ]; + ensureUsers = [ + { + name = "pangolin"; + ensureDBOwnership = true; + } + ]; + }; + }; + }; + }; +}