From bfbacbe93e97e6a6de0e0135ce6b79e17ac81e20 Mon Sep 17 00:00:00 2001 From: Noah Masur <7386960+nmasur@users.noreply.github.com> Date: Sat, 3 May 2025 19:25:32 +0000 Subject: [PATCH] update lockfile and add pgweb, fixes to cloudflare caddy --- flake.lock | 60 +++++++------- flake.nix | 1 + .../services/cloudflare/cloudflare.nix | 32 +++++--- .../modules/nmasur/presets/services/pgweb.nix | 82 +++++++++++++++++++ .../nmasur/profiles/communications.nix | 1 + .../services/cloudflare-dyndns-noproxy.nix | 44 +++++++--- 6 files changed, 168 insertions(+), 52 deletions(-) create mode 100644 platforms/nixos/modules/nmasur/presets/services/pgweb.nix diff --git a/flake.lock b/flake.lock index 4200807..72d3685 100644 --- a/flake.lock +++ b/flake.lock @@ -22,11 +22,11 @@ ] }, "locked": { - "lastModified": 1743221873, - "narHash": "sha256-i8VPNm4UBsC3Ni6VwjojVJvCpS9GZ4vPrpFRtCGJzBs=", + "lastModified": 1746254942, + "narHash": "sha256-Y062AuRx6l+TJNX8wxZcT59SSLsqD9EedAY0mqgTtQE=", "owner": "lnl7", "repo": "nix-darwin", - "rev": "53d0f0ed11487a4476741fde757d0feabef4cc4e", + "rev": "760a11c87009155afa0140d55c40e7c336d62d7a", "type": "github" }, "original": { @@ -43,11 +43,11 @@ ] }, "locked": { - "lastModified": 1741786315, - "narHash": "sha256-VT65AE2syHVj6v/DGB496bqBnu1PXrrzwlw07/Zpllc=", + "lastModified": 1745812220, + "narHash": "sha256-hotBG0EJ9VmAHJYF0yhWuTVZpENHvwcJ2SxvIPrXm+g=", "owner": "nix-community", "repo": "disko", - "rev": "0d8c6ad4a43906d14abd5c60e0ffe7b587b213de", + "rev": "d0c543d740fad42fe2c035b43c9d41127e073c78", "type": "github" }, "original": { @@ -193,11 +193,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1743346877, - "narHash": "sha256-WczB9koq4xvdBZoMLW8VFT16RGaDrJXyA0rDTg2GFVU=", + "lastModified": 1746193606, + "narHash": "sha256-LD3ce/SlIY8Wr8XG52EI5t9bNa/peBCXykIJBvcGmO8=", "owner": "helix-editor", "repo": "helix", - "rev": "e148d8b3110ace99505c0871714cd64391cc4ba3", + "rev": "12139a4c30ad20d9a1b181de69532a57601cf96f", "type": "github" }, "original": { @@ -213,11 +213,11 @@ ] }, "locked": { - "lastModified": 1743346616, - "narHash": "sha256-AB/ve2el1TB7k4iyogHGCVlWVkrhp3+4FKKMr1W5iKQ=", + "lastModified": 1746243165, + "narHash": "sha256-DQycVmlyLQNLjLJ/FzpokVmbxGQ8HjQQ4zN4nyq2vII=", "owner": "nix-community", "repo": "home-manager", - "rev": "1d2ed9c503cf41ca7f3db091edc8519dcdcd8b41", + "rev": "c0962eeeabfb8127713f859ec8a5f0e86dead0f2", "type": "github" }, "original": { @@ -259,11 +259,11 @@ ] }, "locked": { - "lastModified": 1740943170, - "narHash": "sha256-A0F7T/euSMen004cVQN/ZkMpLkgLXDs+mq/merhd+0Y=", + "lastModified": 1745846717, + "narHash": "sha256-GjwZEjCrI1/tQYylAQ+hU5JYD2hJI+rZmfICCIniWuE=", "owner": "gytis-ivaskevicius", "repo": "nix2vim", - "rev": "a562f32ff2393d0ed198103c65a3035bcdf83d4d", + "rev": "0cd899a39b56d665115f72ffc7c37e0f4cf41dbe", "type": "github" }, "original": { @@ -310,11 +310,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1743095683, - "narHash": "sha256-gWd4urRoLRe8GLVC/3rYRae1h+xfQzt09xOfb0PaHSk=", + "lastModified": 1746141548, + "narHash": "sha256-IgBWhX7A2oJmZFIrpRuMnw5RAufVnfvOgHWgIdds+hc=", "owner": "nixos", "repo": "nixpkgs", - "rev": "5e5402ecbcb27af32284d4a62553c019a3a49ea6", + "rev": "f02fddb8acef29a8b32f10a335d44828d7825b78", "type": "github" }, "original": { @@ -365,11 +365,11 @@ "treefmt-nix": "treefmt-nix" }, "locked": { - "lastModified": 1743335104, - "narHash": "sha256-wEEHpF+h+9m2QvjYtIx11EMi+sXG3wS9f/QSE6KPpJs=", + "lastModified": 1746282980, + "narHash": "sha256-KOkO6aDwI8FOmMMv3MdO2WL95lMOJR4qDMUHPOoFtyM=", "owner": "nix-community", "repo": "nur", - "rev": "374adb7fb2c751f679519f8db532f726488293a0", + "rev": "e4be6680a4b231e712fef9c1cd5714f08a1ce51b", "type": "github" }, "original": { @@ -425,11 +425,11 @@ ] }, "locked": { - "lastModified": 1737080704, - "narHash": "sha256-n+J2h9GM9ZpFOQUmtZoCr1+DFF/iO5UlmLJeHIxbZGY=", + "lastModified": 1745116541, + "narHash": "sha256-5xzA6dTfqCfTTDCo3ipPZzrg3wp01xmcr73y4cTNMP8=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "f9953fe89f8b65401fc4d4a288940bc2cb072949", + "rev": "e2142ef330a61c02f274ac9a9cb6f8487a5d0080", "type": "github" }, "original": { @@ -560,11 +560,11 @@ ] }, "locked": { - "lastModified": 1743125458, - "narHash": "sha256-0z+5AMacL2Eqo92fAd0eCWeKVecWrxPJwd5/BIfcdJ8=", + "lastModified": 1744290088, + "narHash": "sha256-/X9XVEl0EiyisNbF5srrxXRSVoRqdwExuqyspYqqEjQ=", "owner": "nix-community", "repo": "NixOS-WSL", - "rev": "394c77f61ac76399290bfc2ef9d47b1fba31b215", + "rev": "60b4904a1390ac4c89e93d95f6ed928975e525ed", "type": "github" }, "original": { @@ -582,11 +582,11 @@ "rust-overlay": "rust-overlay_2" }, "locked": { - "lastModified": 1743344227, - "narHash": "sha256-Lp1JUMrhvAmCzftOSQ2Sr0+svemxSxcLeZ4HkmdLXbE=", + "lastModified": 1746209831, + "narHash": "sha256-1R1MRxHmTbNUASTCdJTaaIEUevx18+XpVVxEcb0q7VM=", "owner": "sxyazi", "repo": "yazi", - "rev": "1765aba68440f73c590cedac14ece6778fe88ff5", + "rev": "a201c93419bede1f35c69a6b8b21ebbf4a752e6e", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 2c730cc..40f02dc 100644 --- a/flake.nix +++ b/flake.nix @@ -133,6 +133,7 @@ notifications = "ntfy.${baseName}"; paperless = "paper.${baseName}"; photos = "photos.${baseName}"; + postgresql = "pg.${baseName}"; prometheus = "prom.${baseName}"; secrets = "vault.${baseName}"; smtp = "smtp.purelymail.com"; diff --git a/platforms/nixos/modules/nmasur/presets/services/cloudflare/cloudflare.nix b/platforms/nixos/modules/nmasur/presets/services/cloudflare/cloudflare.nix index 1f04d3d..8365184 100644 --- a/platforms/nixos/modules/nmasur/presets/services/cloudflare/cloudflare.nix +++ b/platforms/nixos/modules/nmasur/presets/services/cloudflare/cloudflare.nix @@ -67,8 +67,8 @@ in # Tell Caddy to use Cloudflare DNS for ACME challenge validation services.caddy.package = pkgs.caddy.withPlugins { - plugins = [ "github.com/caddy-dns/cloudflare@v0.0.0-20250228175314-1fb64108d4de" ]; - hash = "sha256-YYpsf8HMONR1teMiSymo2y+HrKoxuJMKIea5/NEykGc="; + plugins = [ "github.com/caddy-dns/cloudflare@v0.2.1" ]; + hash = "sha256-saKJatiBZ4775IV2C5JLOmZ4BwHKFtRZan94aS5pO90="; }; nmasur.presets.services.caddy.tlsPolicies = [ { @@ -90,11 +90,14 @@ in ]; } ]; - # Allow Caddy to read Cloudflare API key for DNS validation - systemd.services.caddy.serviceConfig.EnvironmentFile = [ - config.secrets.cloudflare-api.dest - config.secrets.letsencrypt-key.dest - ]; + systemd.services.caddy.serviceConfig = { + # Allow Caddy to read Cloudflare API key for DNS validation + # Allow Caddy to use letsencrypt account key for TLS verification + EnvironmentFile = [ + config.secrets.letsencrypt-key.dest + config.secrets.cloudflare-api-prefixed.dest + ]; + }; # Private key is used for LetsEncrypt secrets.letsencrypt-key = { @@ -111,15 +114,21 @@ in owner = "caddy"; group = "caddy"; }; - + secrets.cloudflare-api-prefixed = { + source = ./cloudflare-api.age; + dest = "${config.secretsDirectory}/cloudflare-api-prefixed"; + owner = "caddy"; + group = "caddy"; + prefix = "CLOUDFLARE_API_TOKEN="; + }; # Wait for secret to exist systemd.services.caddy = { after = [ - "cloudflare-api-secret.service" + "cloudflare-api-prefixed-secret.service" "letsencrypt-key-secret.service" ]; requires = [ - "cloudflare-api-secret.service" + "cloudflare-api-prefixed-secret.service" "letsencrypt-key-secret.service" ]; }; @@ -150,5 +159,8 @@ in requires = [ "cloudflare-api-secret.service" ]; }; + # Enable the home-made service that we created for non-proxied records + services.cloudflare-dyndns-noproxy.enable = true; + }; } diff --git a/platforms/nixos/modules/nmasur/presets/services/pgweb.nix b/platforms/nixos/modules/nmasur/presets/services/pgweb.nix new file mode 100644 index 0000000..b1c19ce --- /dev/null +++ b/platforms/nixos/modules/nmasur/presets/services/pgweb.nix @@ -0,0 +1,82 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + inherit (config.nmasur.settings) username hostnames; + cfg = config.nmasur.presets.services.pgweb; +in + +{ + + options.nmasur.presets.services.pgweb = { + enable = lib.mkEnableOption "Postgres web UI"; + port = lib.mkOption { + type = lib.types.port; + description = "Port to use for the localhost"; + default = 8081; + }; + }; + + config = lib.mkIf cfg.enable { + + systemd.services.pgweb = { + description = "Postgres web UI"; + after = [ + "postgresql.target" + ]; + # requires = [ "pgweb-secret.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + DynamicUser = false; + User = "postgres"; + Group = "postgres"; + StateDirectory = "pgweb"; + ExecStart = + let + args = [ + "--url postgres:///hippocampus?host=/run/postgresql" + ]; + in + "${lib.getExe pkgs.pgweb} ${toString args}"; + }; + }; + + # Allow web traffic to Caddy + nmasur.presets.services.caddy.routes = [ + { + match = [ { host = [ hostnames.postgresql ]; } ]; + handle = [ + { + handler = "authentication"; + providers = { + http_basic = { + hash = { + algorithm = "bcrypt"; + }; + accounts = [ + { + username = username; + password = "$2a$14$dtzWBh7ZDNgqFIJTJO7Rxe15Y189agBiWKZFJbs4sZz7QhqGQAwJS"; + } + ]; + }; + }; + } + { + handler = "reverse_proxy"; + upstreams = [ { dial = "localhost:${builtins.toString cfg.port}"; } ]; + } + ]; + } + ]; + + # Configure Cloudflare DNS to point to this machine + services.cloudflare-dyndns.domains = [ hostnames.postgresql ]; + + }; +} diff --git a/platforms/nixos/modules/nmasur/profiles/communications.nix b/platforms/nixos/modules/nmasur/profiles/communications.nix index 83ed386..9d0b968 100644 --- a/platforms/nixos/modules/nmasur/profiles/communications.nix +++ b/platforms/nixos/modules/nmasur/profiles/communications.nix @@ -28,6 +28,7 @@ in grafana.enable = lib.mkDefault true; influxdb2.enable = lib.mkDefault true; litestream.enable = lib.mkDefault true; + pgweb.enable = lib.mkDefault true; minecraft-server.enable = lib.mkDefault true; n8n.enable = lib.mkDefault true; nix-autoupgrade.enable = lib.mkDefault false; # On by default for communications diff --git a/platforms/nixos/modules/services/cloudflare-dyndns-noproxy.nix b/platforms/nixos/modules/services/cloudflare-dyndns-noproxy.nix index 0303ae3..451eb33 100644 --- a/platforms/nixos/modules/services/cloudflare-dyndns-noproxy.nix +++ b/platforms/nixos/modules/services/cloudflare-dyndns-noproxy.nix @@ -6,12 +6,12 @@ }: let - cfg = config.services.cloudflare-dyndns-no-proxy; + cfg = config.services.cloudflare-dyndns-noproxy; in { - options.services.cloudflare-dyndns-no-proxy.enable = lib.mkEnableOption "Cloudflare dyndns client without proxying"; + options.services.cloudflare-dyndns-noproxy.enable = lib.mkEnableOption "Cloudflare dyndns client without proxying"; config = lib.mkIf cfg.enable { @@ -37,17 +37,37 @@ in Type = "simple"; DynamicUser = true; StateDirectory = "cloudflare-dyndns-noproxy"; - EnvironmentFile = config.services.cloudflare-dyndns.apiTokenFile; - ExecStart = - let - args = - [ "--cache-file /var/lib/cloudflare-dyndns-noproxy/ip.cache" ] - ++ (if config.services.cloudflare-dyndns.ipv4 then [ "-4" ] else [ "-no-4" ]) - ++ (if config.services.cloudflare-dyndns.ipv6 then [ "-6" ] else [ "-no-6" ]) - ++ lib.optional config.services.cloudflare-dyndns.deleteMissing "--delete-missing"; - in - "${pkgs.cloudflare-dyndns}/bin/cloudflare-dyndns ${toString args}"; + Environment = [ "XDG_CACHE_HOME=%S/cloudflare-dyndns-noproxy/.cache" ]; + LoadCredential = [ + "apiToken:${config.services.cloudflare-dyndns.apiTokenFile}" + ]; }; + + script = + let + args = + [ "--cache-file /var/lib/cloudflare-dyndns-noproxy/ip.cache" ] + ++ (if config.services.cloudflare-dyndns.ipv4 then [ "-4" ] else [ "-no-4" ]) + ++ (if config.services.cloudflare-dyndns.ipv6 then [ "-6" ] else [ "-no-6" ]) + ++ lib.optional config.services.cloudflare-dyndns.deleteMissing "--delete-missing"; + in + '' + export CLOUDFLARE_API_TOKEN_FILE=''${CREDENTIALS_DIRECTORY}/apiToken + echo $CLOUDFLARE_API_TOKEN_FILE + cat $CLOUDFLARE_API_TOKEN_FILE + + # Added 2025-03-10: `cfg.apiTokenFile` used to be passed as an + # `EnvironmentFile` to the service, which required it to be of + # the form "CLOUDFLARE_API_TOKEN=" rather than just the secret. + # If we detect this legacy usage, error out. + token=$(< "''${CLOUDFLARE_API_TOKEN_FILE}") + if [[ $token == CLOUDFLARE_API_TOKEN* ]]; then + echo "Error: your api token starts with 'CLOUDFLARE_API_TOKEN='. Remove that, and instead specify just the token." >&2 + exit 1 + fi + + exec ${lib.getExe pkgs.cloudflare-dyndns} ${toString args} + ''; }; }; }