From 27cb88d8a09becacd59cd6d19526bdc613eb74dd Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 18 Apr 2026 23:00:41 +0000 Subject: [PATCH] feat: add Yami dev stack module (on-demand gitea+postgres+docker+runner) https://claude.ai/code/session_017dm8ypaaWNeA27ctmwq5dn --- configuration.nix | 4 +- yami-dev-stack.nix | 159 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 yami-dev-stack.nix diff --git a/configuration.nix b/configuration.nix index daa4256..0bd6310 100644 --- a/configuration.nix +++ b/configuration.nix @@ -7,6 +7,7 @@ ./desktop.nix ./nvidia.nix ./shell.nix + # ./yami-dev-stack.nix # uncomment to enable Yami dev stack, then set services.yami-dev-stack below ]; nix = { @@ -94,7 +95,8 @@ programs.gamemode.enable = true; services.tailscale.enable = true; - virtualisation.docker.enable = true; + # Docker is now managed by yami-dev-stack.nix when that module is enabled. + # services.yami-dev-stack = { enable = true; user = "chexit"; }; system.stateVersion = "25.11"; } diff --git a/yami-dev-stack.nix b/yami-dev-stack.nix new file mode 100644 index 0000000..dc7cc60 --- /dev/null +++ b/yami-dev-stack.nix @@ -0,0 +1,159 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.yami-dev-stack; +in +{ + options.services.yami-dev-stack = { + enable = mkEnableOption "Yami development stack (gitea, postgres, docker, runner)"; + + user = mkOption { + type = types.str; + description = "User that will own runner token and be added to docker group"; + }; + }; + + config = mkIf cfg.enable { + + # ── Systemd target ───────────────────────────────────────────────────────── + # Manual-only: nothing in wantedBy, so it never starts on boot. + systemd.targets.yami-dev = { + description = "Yami development stack (gitea, postgres, docker, runner)"; + wantedBy = [ ]; + }; + + # ── PostgreSQL 16 ────────────────────────────────────────────────────────── + services.postgresql = { + enable = true; + package = pkgs.postgresql_16; + ensureDatabases = [ "gitea" ]; + ensureUsers = [ + { + name = "gitea"; + ensureDBOwnership = true; + } + ]; + }; + + # Pull postgres under yami-dev.target; stop it when target stops. + systemd.services.postgresql = { + wantedBy = mkForce [ "yami-dev.target" ]; + partOf = [ "yami-dev.target" ]; + }; + + # ── Gitea ────────────────────────────────────────────────────────────────── + services.gitea = { + enable = true; + appName = "Yami Git"; + + database = { + type = "postgres"; + socket = "/run/postgresql"; + name = "gitea"; + user = "gitea"; + }; + + settings = { + server = { + DOMAIN = "localhost"; + ROOT_URL = "http://localhost:3000/"; + HTTP_ADDR = "0.0.0.0"; + HTTP_PORT = 3000; + SSH_PORT = 2222; + START_SSH_SERVER = true; + LFS_START_SERVER = true; + }; + + service = { + DISABLE_REGISTRATION = true; + DEFAULT_KEEP_EMAIL_PRIVATE = true; + }; + + repository = { + DEFAULT_BRANCH = "main"; + ENABLE_PUSH_CREATE_USER = true; + ENABLE_PUSH_CREATE_ORG = true; + }; + + actions = { + ENABLED = true; + DEFAULT_ACTIONS_URL = "github"; + LOG_RETENTION_DAYS = 14; + ARTIFACT_RETENTION_DAYS = 30; + }; + + packages = { + ENABLED = true; + }; + + session = { + COOKIE_SECURE = false; + }; + + "cron.git_gc_repos" = { + ENABLED = true; + SCHEDULE = "@every 72h"; + ARGS = "--aggressive --prune=now"; + }; + }; + }; + + systemd.services.gitea = { + wantedBy = mkForce [ "yami-dev.target" ]; + partOf = [ "yami-dev.target" ]; + after = [ "postgresql.service" ]; + requires = [ "postgresql.service" ]; + }; + + # ── Docker ───────────────────────────────────────────────────────────────── + virtualisation.docker = { + enable = true; + enableOnBoot = false; + }; + + systemd.services.docker = { + wantedBy = mkForce [ "yami-dev.target" ]; + partOf = [ "yami-dev.target" ]; + }; + + users.users.${cfg.user}.extraGroups = [ "docker" ]; + + # ── Gitea Actions Runner ─────────────────────────────────────────────────── + services.gitea-actions-runner.instances.default = { + enable = true; + name = "home-runner"; + url = "http://localhost:3000"; + tokenFile = "/var/lib/gitea-runner/token"; + labels = [ + "ubuntu-latest:docker://node:20" + "native:host" + ]; + }; + + systemd.services."gitea-runner-default" = { + wantedBy = mkForce [ "yami-dev.target" ]; + partOf = [ "yami-dev.target" ]; + after = [ "gitea.service" "docker.service" ]; + requires = [ "gitea.service" "docker.service" ]; + }; + + # Directory for the runner token file; owner matches the runner service user. + systemd.tmpfiles.rules = [ + "d /var/lib/gitea-runner 0700 gitea-runner gitea-runner -" + ]; + + # ── Shell aliases ────────────────────────────────────────────────────────── + environment.shellAliases = { + yami-up = "sudo systemctl start yami-dev.target && echo 'Gitea → http://localhost:3000'"; + yami-down = "sudo systemctl stop yami-dev.target && echo 'Yami dev stack stopped'"; + yami-status = "systemctl status yami-dev.target gitea postgresql docker gitea-runner-default --no-pager"; + yami-logs = "journalctl -u gitea -u gitea-runner-default -f"; + }; + + # ── Firewall ─────────────────────────────────────────────────────────────── + # Merged with existing rules (Steam etc.); does not overwrite them. + networking.firewall.allowedTCPPorts = [ 3000 2222 ]; + }; +}