Kieran's opinionated (and probably slightly dumb) nix config
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.atelier.services.hn-alerts; 9in 10{ 11 options.atelier.services.hn-alerts = { 12 enable = lib.mkEnableOption "HN Alerts Hacker News monitoring service"; 13 14 domain = lib.mkOption { 15 type = lib.types.str; 16 description = "Domain to serve hn-alerts on"; 17 }; 18 19 port = lib.mkOption { 20 type = lib.types.port; 21 default = 3001; 22 description = "Port to run hn-alerts on"; 23 }; 24 25 dataDir = lib.mkOption { 26 type = lib.types.path; 27 default = "/var/lib/hn-alerts"; 28 description = "Directory to store hn-alerts data"; 29 }; 30 31 secretsFile = lib.mkOption { 32 type = lib.types.path; 33 description = "Path to secrets file containing SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET, SLACK_CHANNEL, SENTRY_DSN, DATABASE_URL"; 34 }; 35 36 repository = lib.mkOption { 37 type = lib.types.str; 38 default = "https://github.com/taciturnaxolotl/hn-alerts.git"; 39 description = "Git repository URL (optional, for auto-deployment)"; 40 }; 41 42 autoUpdate = lib.mkEnableOption "Automatically git pull on service restart"; 43 }; 44 45 config = lib.mkIf cfg.enable { 46 users.groups.services = { }; 47 48 users.users.hn-alerts = { 49 isSystemUser = true; 50 group = "hn-alerts"; 51 extraGroups = [ "services" ]; 52 home = cfg.dataDir; 53 createHome = true; 54 shell = pkgs.bash; 55 }; 56 57 users.groups.hn-alerts = { }; 58 59 security.sudo.extraRules = [ 60 { 61 users = [ "hn-alerts" ]; 62 commands = [ 63 { 64 command = "/run/current-system/sw/bin/systemctl restart hn-alerts.service"; 65 options = [ "NOPASSWD" ]; 66 } 67 ]; 68 } 69 ]; 70 71 systemd.services.hn-alerts = { 72 description = "HN Alerts Hacker News monitoring service"; 73 wantedBy = [ "multi-user.target" ]; 74 after = [ "network.target" ]; 75 path = [ pkgs.git ]; 76 77 preStart = '' 78 if [ ! -d ${cfg.dataDir}/app/.git ]; then 79 ${pkgs.git}/bin/git clone ${cfg.repository} ${cfg.dataDir}/app 80 fi 81 82 cd ${cfg.dataDir}/app 83 '' + lib.optionalString cfg.autoUpdate '' 84 ${pkgs.git}/bin/git pull 85 '' + '' 86 87 if [ ! -f src/index.ts ]; then 88 echo "No code found at ${cfg.dataDir}/app/src/index.ts" 89 exit 1 90 fi 91 92 echo "Installing dependencies..." 93 ${pkgs.unstable.bun}/bin/bun install 94 95 echo "Initializing database..." 96 ${pkgs.unstable.bun}/bin/bun run db:push 97 ''; 98 99 serviceConfig = { 100 Type = "simple"; 101 User = "hn-alerts"; 102 Group = "hn-alerts"; 103 EnvironmentFile = cfg.secretsFile; 104 Environment = [ 105 "NODE_ENV=production" 106 "PORT=${toString cfg.port}" 107 ]; 108 ExecStart = "${pkgs.bash}/bin/bash -c 'cd ${cfg.dataDir}/app && ${pkgs.unstable.bun}/bin/bun start'"; 109 Restart = "always"; 110 RestartSec = "10s"; 111 }; 112 }; 113 114 services.caddy.virtualHosts.${cfg.domain} = { 115 extraConfig = '' 116 tls { 117 dns cloudflare {env.CLOUDFLARE_API_TOKEN} 118 } 119 120 reverse_proxy localhost:${toString cfg.port} 121 ''; 122 }; 123 }; 124}