From 92ea15f91927876296c68141471ecb7379cb6232 Mon Sep 17 00:00:00 2001 From: Max Koon Date: Fri, 26 Sep 2025 09:46:57 -0400 Subject: [PATCH] feat: add elytra --- flake.lock | 102 +++++++++++++++++++++++++++++++++--- flake.nix | 8 ++- host/ark/default.nix | 4 ++ host/ark/service/docs.nix | 19 ------- host/ark/service/elytra.nix | 83 +++++++++++++++++++++++++++++ host/ark/sops.nix | 8 ++- host/max/default.nix | 2 + secrets | 2 +- 8 files changed, 200 insertions(+), 28 deletions(-) create mode 100644 host/ark/service/elytra.nix diff --git a/flake.lock b/flake.lock index 86a6ad2..540123d 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,27 @@ { "nodes": { + "elytrarides": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1758288107, + "narHash": "sha256-5RSrpXvOixzXGUKagXHkcJyXe0MzBLSF36SELu9welg=", + "owner": "k2on", + "repo": "elytrarides", + "rev": "dc282388bbfa41c61dc0f04f582c09361c9b22c8", + "type": "github" + }, + "original": { + "owner": "k2on", + "repo": "elytrarides", + "type": "github" + } + }, "flake-compat": { "locked": { "lastModified": 1688025799, @@ -75,6 +97,24 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -127,7 +167,7 @@ "nixos-apple-silicon": { "inputs": { "flake-compat": "flake-compat", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs_2" }, "locked": { "lastModified": 1748659443, @@ -145,6 +185,22 @@ } }, "nixpkgs": { + "locked": { + "lastModified": 1744536153, + "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { "locked": { "lastModified": 1748460289, "narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=", @@ -160,7 +216,7 @@ "type": "github" } }, - "nixpkgs_2": { + "nixpkgs_3": { "locked": { "lastModified": 1754563854, "narHash": "sha256-YzNTExe3kMY9lYs23mZR7jsVHe5TWnpwNrsPOpFs/b8=", @@ -183,7 +239,7 @@ "nixpkgs" ], "nuschtosSearch": "nuschtosSearch", - "systems": "systems_2" + "systems": "systems_3" }, "locked": { "lastModified": 1754262585, @@ -202,7 +258,7 @@ }, "nuschtosSearch": { "inputs": { - "flake-utils": "flake-utils", + "flake-utils": "flake-utils_2", "ixx": "ixx", "nixpkgs": [ "nixvim", @@ -248,9 +304,10 @@ }, "root": { "inputs": { + "elytrarides": "elytrarides", "home-manager": "home-manager", "nixos-apple-silicon": "nixos-apple-silicon", - "nixpkgs": "nixpkgs_2", + "nixpkgs": "nixpkgs_3", "nixvim": "nixvim", "plasma-manager": "plasma-manager", "sops-nix": "sops-nix", @@ -258,6 +315,24 @@ "unstable": "unstable" } }, + "rust-overlay": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1758204348, + "narHash": "sha256-jkz/NihbcEwy1EHDv/6g0HEqkpyIWCnQ1siGrhHEtFM=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "067b3536e55341f579385ce8593cdcc9d022972b", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, "sops-nix": { "inputs": { "nixpkgs": [ @@ -323,13 +398,28 @@ "type": "github" } }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "terranix": { "inputs": { "flake-parts": "flake-parts_2", "nixpkgs": [ "nixpkgs" ], - "systems": "systems_3" + "systems": "systems_4" }, "locked": { "lastModified": 1749381683, diff --git a/flake.nix b/flake.nix index cf12f93..34b4397 100644 --- a/flake.nix +++ b/flake.nix @@ -34,10 +34,15 @@ url = "github:terranix/terranix"; inputs.nixpkgs.follows = "nixpkgs"; }; + + elytrarides = { + url = "github:k2on/elytrarides"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = { self, nixpkgs, unstable, nixos-apple-silicon, home-manager - , plasma-manager, nixvim, sops-nix, terranix, ... }: + , plasma-manager, nixvim, sops-nix, terranix, elytrarides, ... }: let forAllSystems = function: nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed @@ -122,6 +127,7 @@ ark = let system = "x86_64-linux"; in unstable.lib.nixosSystem { inherit system; + specialArgs = { inherit elytrarides; }; modules = [ ./host/ark/default.nix sops-nix.nixosModules.sops diff --git a/host/ark/default.nix b/host/ark/default.nix index cd86467..f126ed2 100644 --- a/host/ark/default.nix +++ b/host/ark/default.nix @@ -14,6 +14,8 @@ ./service/photos.nix ./service/radicale.nix ./service/wakapi.nix + + ./service/elytra.nix ]; # Use the systemd-boot EFI boot loader. @@ -48,6 +50,8 @@ "audio.koon.us" = "http://localhost:8021"; "radicale.koon.us" = "http://localhost:5232"; "waka.koon.us" = "http://localhost:3006"; + "ride.koon.us" = "http://localhost:3007"; + "ride-api.koon.us" = "http://localhost:8080"; }; default = "http_status:404"; }; diff --git a/host/ark/service/docs.nix b/host/ark/service/docs.nix index c3d4084..5ee323a 100644 --- a/host/ark/service/docs.nix +++ b/host/ark/service/docs.nix @@ -72,23 +72,4 @@ ${cfg.package}/bin/outline-server ''; }; - # systemd.services.outline = { - # serviceConfig = { - # # Load the client ID from the sops secret file - # ExecStartPre = let - # script = pkgs.writeShellScript "outline-set-oauth" '' - # CLIENT_ID=$(cat ${config.sops.secrets."docs/clientId".path}) - # # Export as environment variable that Outline will use - # echo "OIDC_CLIENT_ID=$CLIENT_ID" >> $RUNTIME_DIRECTORY/env - # ''; - # in "+${script}"; - # - # # Load the environment file - # EnvironmentFile = "-/run/outline/env"; - # }; - # - # # Ensure sops secrets are available before starting - # after = [ "sops-nix.service" ]; - # wants = [ "sops-nix.service" ]; - # }; } diff --git a/host/ark/service/elytra.nix b/host/ark/service/elytra.nix new file mode 100644 index 0000000..bb7f74d --- /dev/null +++ b/host/ark/service/elytra.nix @@ -0,0 +1,83 @@ +{ config, pkgs, elytrarides, ... }: + +{ + users.users.elytra-web = { + isSystemUser = true; + group = "elytra-web"; + description = "Elytra Rides web service user"; + }; + + users.users.backend = { + isSystemUser = true; + home = "/var/lib/elytra-backend"; + createHome = true; + group = "backend"; + }; + + users.groups.elytra-web = {}; + users.groups.backend = {}; + + systemd.services.elytra-web = { + description = "Elytra Rides Next.js Web Application"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + environment = { + PORT = "3007"; + HOST = "127.0.0.1"; + NODE_ENV = "production"; + }; + + serviceConfig = { + Type = "simple"; + User = "elytra-web"; + Group = "elytra-web"; + + WorkingDirectory = "${elytrarides.packages.${pkgs.system}.web}/lib/node_modules/web"; + ExecStart = + "${pkgs.nodejs}/bin/node ${elytrarides.packages.${pkgs.system}.web}/lib/node_modules/web/node_modules/next/dist/bin/next start"; + EnvironmentFile = config.sops.secrets."elytra-frontend-env".path; + + + Restart = "on-failure"; + RestartSec = 10; + + # Security hardening + NoNewPrivileges = true; + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = true; + + # State directory for Next.js cache/data + StateDirectory = "elytra-web"; + StateDirectoryMode = "0750"; + + # Logging + StandardOutput = "journal"; + StandardError = "journal"; + SyslogIdentifier = "elytra-web"; + }; + }; + + systemd.services.elytra-backend = { + description = "Elytra Rides Backend Service"; + after = [ "network.target" "postgresql.service" ]; + wants = [ "network-online.target" ]; + + serviceConfig = { + ExecStart = "${elytrarides.packages.${pkgs.system}.backend}/bin/backend"; + Restart = "always"; + RestartSec = 5; + User = "backend"; + WorkingDirectory = "/var/lib/elytra-backend"; + Environment = "RUST_LOG=info"; + EnvironmentFile = config.sops.secrets."elytra-backend-env".path; + }; + + environment = { + DATABASE_URL="postgresql://backend:password@localhost:5432/backend"; + }; + + wantedBy = [ "multi-user.target" ]; + }; +} diff --git a/host/ark/sops.nix b/host/ark/sops.nix index 577429f..130bfb7 100644 --- a/host/ark/sops.nix +++ b/host/ark/sops.nix @@ -24,6 +24,13 @@ owner = config.users.users.wakapi.name; }; + "elytra-backend-env" = { + owner = config.users.users.backend.name; + }; + "elytra-frontend-env" = { + owner = config.users.users.elytra-web.name; + }; + "photos/clientId" = { sopsFile = ../../secrets/sops/host/ark/oauth.yaml; }; @@ -48,7 +55,6 @@ sopsFile = ../../secrets/sops/host/ark/oauth.yaml; owner = config.services.outline.user; }; - }; }; } diff --git a/host/max/default.nix b/host/max/default.nix index 619b842..1467292 100644 --- a/host/max/default.nix +++ b/host/max/default.nix @@ -53,6 +53,8 @@ in powerOnBoot = true; }; + services.tailscale.enable = true; + environment.variables = { XDG_DATA_HOME = "/home/max/.local/share"; GSK_RENDERER = "ngl"; diff --git a/secrets b/secrets index 7a4d9d5..cfc7b11 160000 --- a/secrets +++ b/secrets @@ -1 +1 @@ -Subproject commit 7a4d9d5e4783115c397624304930ce1b79422a4c +Subproject commit cfc7b119bd5162a05336165f944f9a44d222e961