@jaspermayone.com's dotfiles

Add Spindle CI/CD runners to alastor and dippet

- alastor: Configure spindle nixosModule with Caddy reverse proxy at 1.alastor.spindle.hogwarts.dev
- dippet: Add launchd service for spindle at 1.dippet.spindle.hogwarts.dev
- Both use DID did:plc:abgthiqrd7tczkafjm4ennbo
- Add Docker Desktop to dippet homebrew casks
- Include setup documentation with Cloudflare tunnel instructions

+311
+237
SPINDLE_SETUP.md
··· 1 + # Spindle Setup Guide 2 + 3 + This document outlines the Spindle CI/CD runner setup for alastor and dippet. 4 + 5 + ## Overview 6 + 7 + Spindles are configured on two hosts: 8 + - **alastor** (NixOS, aarch64-linux): `1.alastor.spindle.hogwarts.dev` 9 + - **dippet** (macOS, aarch64-darwin): `1.dippet.spindle.hogwarts.dev` 10 + 11 + Both spindles are configured to run under the DID: `did:plc:abgthiqrd7tczkafjm4ennbo` 12 + 13 + ## Alastor Setup (NixOS) 14 + 15 + ### Configuration 16 + The alastor spindle is configured using the official Tangled nixosModule: 17 + 18 + - **Service**: `services.tangled.spindle` 19 + - **Listen Address**: `127.0.0.1:6555` 20 + - **Database**: `/var/lib/spindle/spindle.db` (default) 21 + - **Logs**: `/var/log/spindle` (default) 22 + - **Public URL**: `https://1.alastor.spindle.hogwarts.dev` 23 + 24 + ### Deployment 25 + To deploy to alastor: 26 + 27 + ```bash 28 + # From macOS (using deploy-rs) 29 + deploy .#alastor --skip-checks 30 + 31 + # Or via SSH 32 + ssh alastor 33 + cd ~/dots 34 + sudo nixos-rebuild switch --flake .#alastor 35 + ``` 36 + 37 + ### Reverse Proxy 38 + Caddy is configured to proxy the spindle service with: 39 + - TLS via Cloudflare DNS challenge 40 + - HSTS headers 41 + - Proxying from port 443 to local port 6555 42 + 43 + ### Monitoring 44 + The spindle service (`tangled-spindle`) is included in the status monitoring dashboard at `alastor.hogwarts.channel`. 45 + 46 + ## Dippet Setup (macOS) 47 + 48 + ### Configuration 49 + The dippet spindle is configured as a launchd daemon: 50 + 51 + - **Service**: `launchd.daemons.tangled-spindle` 52 + - **Listen Address**: `127.0.0.1:6556` 53 + - **Database**: `/Users/jsp/Library/Application Support/spindle/spindle.db` 54 + - **Logs**: `/Users/jsp/Library/Logs/spindle/` 55 + - **Public URL**: `https://1.dippet.spindle.hogwarts.dev` (requires tunnel setup) 56 + 57 + ### Prerequisites 58 + 1. **Docker Desktop**: Added to homebrew casks - install with: 59 + ```bash 60 + brew install --cask docker 61 + ``` 62 + 63 + 2. **Cloudflare Tunnel**: Required for public access (see below) 64 + 65 + ### Deployment 66 + To deploy to dippet: 67 + 68 + ```bash 69 + # From dippet 70 + darwin-rebuild switch --flake ~/dev/dots#dippet 71 + 72 + # Or from remote 73 + ssh dippet 'cd ~/dev/dots && darwin-rebuild switch --flake .#dippet' 74 + ``` 75 + 76 + ### Cloudflare Tunnel Setup (Using Existing Tunnel) 77 + 78 + Since you already have a running Cloudflare tunnel on dippet, you just need to add a route for the spindle service. 79 + 80 + #### Option 1: Using cloudflared CLI 81 + ```bash 82 + # Add DNS route to your existing tunnel 83 + cloudflared tunnel route dns <your-tunnel-id> 1.dippet.spindle.hogwarts.dev 84 + ``` 85 + 86 + #### Option 2: Update tunnel config file 87 + If you're using a config file (usually at `~/.cloudflared/config.yml`), add the spindle ingress rule: 88 + 89 + ```yaml 90 + tunnel: <your-tunnel-id> 91 + credentials-file: /path/to/credentials.json 92 + 93 + ingress: 94 + # Add this entry 95 + - hostname: 1.dippet.spindle.hogwarts.dev 96 + service: http://localhost:6556 97 + 98 + # Keep your existing rules here 99 + 100 + # Catch-all rule (must be last) 101 + - service: http_status:404 102 + ``` 103 + 104 + Then restart cloudflared: 105 + ```bash 106 + sudo launchctl restart <your-cloudflared-service-name> 107 + ``` 108 + 109 + #### Option 3: Using Cloudflare Dashboard 110 + 1. Go to Zero Trust > Networks > Tunnels 111 + 2. Select your tunnel 112 + 3. Go to Public Hostname tab 113 + 4. Click "Add a public hostname" 114 + 5. Set: 115 + - Subdomain: `1.dippet.spindle` 116 + - Domain: `hogwarts.dev` 117 + - Service: `http://localhost:6556` 118 + 6. Save 119 + 120 + ### Verifying the tunnel 121 + After setup, verify the tunnel is running: 122 + 123 + ```bash 124 + # Check tunnel status 125 + sudo launchctl list | grep cloudflared 126 + 127 + # Check logs 128 + tail -f ~/Library/Logs/cloudflared-spindle.log 129 + ``` 130 + 131 + ## Service Management 132 + 133 + ### Alastor (NixOS) 134 + ```bash 135 + # Check status 136 + sudo systemctl status tangled-spindle 137 + 138 + # View logs 139 + sudo journalctl -u tangled-spindle -f 140 + 141 + # Restart 142 + sudo systemctl restart tangled-spindle 143 + 144 + # Stop 145 + sudo systemctl stop tangled-spindle 146 + ``` 147 + 148 + ### Dippet (macOS) 149 + ```bash 150 + # Check status 151 + sudo launchctl list | grep tangled-spindle 152 + 153 + # View logs 154 + tail -f ~/Library/Logs/spindle.log 155 + 156 + # Restart 157 + sudo launchctl kickstart -k system/org.nixos.tangled-spindle 158 + 159 + # Stop 160 + sudo launchctl stop org.nixos.tangled-spindle 161 + ``` 162 + 163 + ## Testing 164 + 165 + Once both spindles are running and accessible, test them: 166 + 167 + ```bash 168 + # Test alastor spindle 169 + curl https://1.alastor.spindle.hogwarts.dev 170 + 171 + # Test dippet spindle (after tunnel setup) 172 + curl https://1.dippet.spindle.hogwarts.dev 173 + ``` 174 + 175 + ## Adding Spindles to Repositories 176 + 177 + To use these spindles for your repositories: 178 + 179 + 1. Go to your repository settings on Tangled 180 + 2. Navigate to the Spindles section 181 + 3. Add the spindle hostnames: 182 + - `1.alastor.spindle.hogwarts.dev` 183 + - `1.dippet.spindle.hogwarts.dev` 184 + 185 + ## Troubleshooting 186 + 187 + ### Docker not available 188 + **Symptom**: Spindle fails to start containers 189 + 190 + **Solution**: 191 + - On alastor: Docker is managed by NixOS, check `sudo systemctl status docker` 192 + - On dippet: Ensure Docker Desktop is installed and running 193 + 194 + ### Connection refused 195 + **Symptom**: Cannot connect to spindle endpoint 196 + 197 + **Solution**: 198 + - Check if the service is running 199 + - Verify firewall rules (alastor: port 443 should be open) 200 + - For dippet: Verify Cloudflare tunnel is active 201 + 202 + ### Pipeline failures 203 + **Symptom**: Pipelines fail to execute 204 + 205 + **Solution**: 206 + - Check spindle logs for errors 207 + - Verify Docker is running and accessible 208 + - Check disk space: `df -h` 209 + - Verify Nixery is accessible: `curl https://nixery.tangled.sh` 210 + 211 + ### Database corruption 212 + **Symptom**: Spindle fails to start with database errors 213 + 214 + **Solution**: 215 + - Backup the database 216 + - On alastor: `/var/lib/spindle/spindle.db` 217 + - On dippet: `~/Library/Application Support/spindle/spindle.db` 218 + - Delete and restart the service (will create fresh database) 219 + 220 + ## OpenBao Secrets (Optional) 221 + 222 + If you want to use OpenBao for secrets management instead of the default SQLite backend, refer to the [Tangled Spindle documentation](https://docs.tangled.org/spindles.html#secrets-with-openbao) for setup instructions. 223 + 224 + ## Next Steps 225 + 226 + 1. ✅ Deploy to alastor 227 + 2. ⏳ Install Docker Desktop on dippet 228 + 3. ⏳ Set up Cloudflare tunnel for dippet 229 + 4. ⏳ Deploy to dippet 230 + 5. ⏳ Test both spindles 231 + 6. ⏳ Add spindles to your repositories 232 + 233 + ## References 234 + 235 + - [Tangled Spindle Documentation](https://docs.tangled.org/spindles.html) 236 + - [Spindle Self-hosting Guide](https://docs.tangled.org/spindles.html#self-hosting-guide) 237 + - [Cloudflare Tunnel Documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/)
+27
hosts/alastor/configuration.nix
··· 19 19 ../../modules/restic 20 20 inputs.strings.nixosModules.default 21 21 inputs.tangled.nixosModules.knot 22 + inputs.tangled.nixosModules.spindle 22 23 ]; 23 24 24 25 # System version ··· 229 230 "caddy" 230 231 "tailscaled" 231 232 "tangled-knot" 233 + "tangled-spindle" 232 234 "atuin-server" 233 235 "strings-hogwarts" 234 236 "strings-witcc" ··· 248 250 owner = "did:plc:abgthiqrd7tczkafjm4ennbo"; 249 251 hostname = "knot.jaspermayone.com"; 250 252 listenAddr = "127.0.0.1:5555"; 253 + }; 254 + }; 255 + 256 + # Tangled Spindle CI/CD runner (official module) 257 + services.tangled.spindle = { 258 + enable = true; 259 + package = inputs.tangled.packages.${pkgs.stdenv.hostPlatform.system}.spindle; 260 + server = { 261 + owner = "did:plc:abgthiqrd7tczkafjm4ennbo"; 262 + hostname = "1.alastor.spindle.hogwarts.dev"; 263 + listenAddr = "127.0.0.1:6555"; 251 264 }; 252 265 }; 253 266 ··· 352 365 header_up X-Forwarded-Proto {scheme} 353 366 header_up X-Forwarded-For {remote} 354 367 header_up X-Forwarded-Host {host} 368 + } 369 + ''; 370 + }; 371 + virtualHosts."1.alastor.spindle.hogwarts.dev" = { 372 + extraConfig = '' 373 + tls { 374 + dns cloudflare {env.CLOUDFLARE_API_TOKEN} 375 + } 376 + header { 377 + Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 378 + } 379 + reverse_proxy localhost:6555 { 380 + header_up X-Forwarded-Proto {scheme} 381 + header_up X-Forwarded-For {remote} 355 382 } 356 383 ''; 357 384 };
+47
hosts/dippet/default.nix
··· 34 34 35 35 echo "Sync complete: $(date)" 36 36 ''; 37 + 38 + spindle-run = pkgs.writeShellScript "spindle-run" '' 39 + set -euo pipefail 40 + 41 + export SPINDLE_SERVER_HOSTNAME="1.dippet.spindle.hogwarts.dev" 42 + export SPINDLE_SERVER_OWNER="did:plc:abgthiqrd7tczkafjm4ennbo" 43 + export SPINDLE_SERVER_LISTEN_ADDR="127.0.0.1:6556" 44 + export SPINDLE_SERVER_DB_PATH="/Users/jsp/Library/Application Support/spindle/spindle.db" 45 + export SPINDLE_PIPELINES_LOG_DIR="/Users/jsp/Library/Logs/spindle" 46 + 47 + # Create necessary directories 48 + mkdir -p "/Users/jsp/Library/Application Support/spindle" 49 + mkdir -p "/Users/jsp/Library/Logs/spindle" 50 + 51 + # Run spindle 52 + exec ${inputs.tangled.packages.${pkgs.stdenv.hostPlatform.system}.spindle}/bin/spindle 53 + ''; 37 54 in 38 55 { 39 56 # Disable nix-darwin's Nix management (using Determinate Nix installer) ··· 74 91 }; 75 92 }; 76 93 94 + # Tangled Spindle CI/CD runner 95 + launchd.daemons.tangled-spindle = { 96 + script = '' 97 + ${spindle-run} 98 + ''; 99 + serviceConfig = { 100 + KeepAlive = true; 101 + RunAtLoad = true; 102 + StandardOutPath = "/Users/jsp/Library/Logs/spindle.log"; 103 + StandardErrorPath = "/Users/jsp/Library/Logs/spindle.log"; 104 + UserName = "jsp"; 105 + GroupName = "staff"; 106 + EnvironmentVariables = { 107 + HOME = "/Users/jsp"; 108 + PATH = "${pkgs.docker}/bin:/usr/bin:/bin"; 109 + }; 110 + }; 111 + }; 112 + 113 + # Cloudflare tunnel for Spindle 114 + # Add this route to your existing cloudflared tunnel config: 115 + # - hostname: 1.dippet.spindle.hogwarts.dev 116 + # service: http://localhost:6556 117 + 77 118 # Agenix identity path (use user SSH key on macOS) 78 119 age.identityPaths = [ "/Users/jsp/.ssh/id_ed25519" ]; 79 120 ··· 92 133 owner = "jsp"; 93 134 mode = "400"; 94 135 }; 136 + 95 137 96 138 # Server packages (dippet-specific) 97 139 homebrew.brews = [ ··· 105 147 "augeas" 106 148 "poppler" 107 149 "python@3.14" 150 + ]; 151 + 152 + # Docker Desktop for macOS (required for Spindle) 153 + homebrew.casks = [ 154 + "docker" 108 155 ]; 109 156 110 157 # Dippet-specific homebrew casks