# Self-Hosted GitHub Actions Runner Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Betreiben eines self-hosted GitHub Actions Runners auf `api.trucko.org` (128.140.47.53) mit dem Label `raynis-builder`, um Backend- und Admin-Builds für das rebreak-monorepo kostenlos auszuführen und weiterhin auf `staging.rebreak.org` zu deployen. **Architecture:** Code-Hosting bleibt auf GitHub. GitHub Actions Workflows werden auf `runs-on: [self-hosted, raynis-builder]` umgestellt. Der Runner auf `api.trucko.org` checkt aus, baut das Artifact und kopiert es per SCP auf `staging.rebreak.org`. Dort übernimmt das bestehende `deploy-from-artifact.sh` das Entpacken, Migrations-Check und PM2-Restart. **Tech Stack:** GitHub Actions, self-hosted Runner, Hetzner VPS, pnpm, Node.js 24.11.1, SSH/SCP, PM2. --- ## File Structure | File / Pfad | Verantwortung | Aktion | |---|---|---| | `api.trucko.org` (Server) | Self-hosted Runner + Build-Umgebung | Einrichten | | `staging.rebreak.org` (Server) | Production/Staging + Deploy-Script | SSH-Key hinzufügen | | `.github/workflows/deploy-staging.yml` | Backend-Deploy-Workflow | Ändern: `runs-on` + SSH-Secret | | `.github/workflows/deploy-admin-staging.yml` | Admin-Deploy-Workflow | Ändern: `runs-on` + SSH-Secret | | GitHub Repo → Settings → Environments → staging | Secrets/Variables | `STAGING_DEPLOY_KEY` hinzufügen | --- ### Task 1: Server `api.trucko.org` vorbereiten **Files:** - Ausführen auf: `api.trucko.org` (per SSH) - [ ] **Step 1: SSH auf Server verbinden** ```bash ssh root@128.140.47.53 ``` - [ ] **Step 2: System aktualisieren und Basis-Tools installieren** ```bash apt-get update && apt-get install -y curl git build-essential ``` - [ ] **Step 3: Node.js 24.11.1 installieren (via nvm)** ```bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source ~/.bashrc nvm install 24.11.1 nvm use 24.11.1 node -v ``` Expected output: `v24.11.1` - [ ] **Step 4: pnpm 10.23.0 installieren** ```bash corepack enable corepack prepare pnpm@10.23.0 --activate pnpm -v ``` Expected output: `10.23.0` - [ ] **Step 5: Git-Config für den Runner setzen** ```bash git config --global user.name "Raynis Builder" git config --global user.email "builder@raynis.dev" ``` - [ ] **Step 6: Workspace-Verzeichnis anlegen** ```bash mkdir -p /srv/raynis-builder chown root:root /srv/raynis-builder ``` --- ### Task 2: GitHub Actions Runner installieren und registrieren **Files:** - Ausführen auf: `api.trucko.org` - Zu prüfen in GitHub: Settings → Actions → Runners - [ ] **Step 1: Runner-Version ermitteln (aktuellste)** ```bash RUNNER_VERSION=$(curl -sL https://api.github.com/repos/actions/runner/releases/latest | jq -r '.tag_name' | sed 's/^v//') echo "$RUNNER_VERSION" ``` - [ ] **Step 2: Runner herunterladen und entpacken** ```bash cd /srv/raynis-builder curl -o actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz -L https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz tar xzf actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz rm actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz ``` - [ ] **Step 3: Runner konfigurieren (Token aus GitHub holen)** In GitHub: Repository `rebreak-monorepo` → Settings → Actions → Runners → New self-hosted runner → Linux → x64. Dort angezeigte `config.sh`-Befehle auf dem Server ausführen, z. B.: ```bash cd /srv/raynis-builder ./config.sh --url https://github.com/RaynisDev/rebreak --token --name raynis-builder-01 --labels raynis-builder --work _work ``` - [ ] **Step 4: Runner als systemd-Service registrieren** ```bash cd /srv/raynis-builder ./svc.sh install ./svc.sh start ./svc.sh status ``` Expected: `active (running)` - [ ] **Step 5: Runner in GitHub UI als Online verifizieren** In GitHub: Settings → Actions → Runners → Status muss `Idle` oder `Online` zeigen. --- ### Task 3: SSH-Deploy-Key zwischen Servern einrichten **Files:** - Ausführen auf: `api.trucko.org` und `staging.rebreak.org` - [ ] **Step 1: SSH-Key auf `api.trucko.org` erzeugen** ```bash ssh-keygen -t ed25519 -f /root/.ssh/rebreak-deploy -C "raynis-builder@api.trucko.org" -N "" cat /root/.ssh/rebreak-deploy.pub ``` - [ ] **Step 2: Public Key auf `staging.rebreak.org` autorisieren** ```bash ssh root@staging.rebreak.org mkdir -p /root/.ssh cat >> /root/.ssh/authorized_keys << 'EOF' EOF chmod 600 /root/.ssh/authorized_keys ``` - [ ] **Step 3: Verbindung vom Builder zum Staging testen** ```bash ssh -i /root/.ssh/rebreak-deploy root@staging.rebreak.org "whoami" ``` Expected output: `root` - [ ] **Step 4: SSH-Konfiguration für einfacheren Zugriff anlegen** Auf `api.trucko.org`: ```bash cat >> /root/.ssh/config << 'EOF' Host rebreak-staging HostName staging.rebreak.org User root IdentityFile ~/.ssh/rebreak-deploy StrictHostKeyChecking no UserKnownHostsFile /dev/null EOF chmod 600 /root/.ssh/config ``` - [ ] **Step 5: Verbindung mit Alias testen** ```bash ssh rebreak-staging "whoami" ``` Expected output: `root` --- ### Task 4: GitHub Secrets aktualisieren **Files:** - GitHub Repository: Settings → Environments → staging - [ ] **Step 1: Neuen Private Key als Secret hinzufügen** Auf `api.trucko.org`: ```bash cat /root/.ssh/rebreak-deploy ``` Inhalt kopieren und in GitHub einfügen: - Environment: `staging` - Secret-Name: `STAGING_DEPLOY_KEY` - Wert: Inhalt von `/root/.ssh/rebreak-deploy` - [ ] **Step 2: Bestehende Secrets überprüfen** In GitHub prüfen, dass folgende Secrets/Vars im Environment `staging` vorhanden sind: - `HETZNER_SSH_KEY` → kann später entfernt werden, wenn neuer Key funktioniert - `HETZNER_HOST` → `staging.rebreak.org` - `HETZNER_USER` → `root` - [ ] **Step 3: Altes Secret nicht löschen (Fallback)** `HETZNER_SSH_KEY` erst nach erfolgreichem Test-Deploy entfernen. --- ### Task 5: Workflows auf self-hosted Runner umstellen **Files:** - Modify: `.github/workflows/deploy-staging.yml` - Modify: `.github/workflows/deploy-admin-staging.yml` - [ ] **Step 1: `deploy-staging.yml` anpassen** Ändere in beiden Jobs `runs-on: ubuntu-latest` zu: ```yaml runs-on: [self-hosted, raynis-builder] ``` Ändere den SSH-Setup-Step, sodass er `STAGING_DEPLOY_KEY` verwendet: ```yaml - name: Setup SSH env: SSH_PRIVATE_KEY: ${{ secrets.STAGING_DEPLOY_KEY }} SSH_HOST: ${{ vars.HETZNER_HOST }} run: | if [ -z "$SSH_PRIVATE_KEY" ] || [ -z "$SSH_HOST" ]; then echo "FATAL: STAGING_DEPLOY_KEY oder HETZNER_HOST nicht gesetzt" exit 1 fi mkdir -p ~/.ssh printf '%s\n' "$SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keyscan -H "$SSH_HOST" >> ~/.ssh/known_hosts ``` - [ ] **Step 2: `deploy-admin-staging.yml` analog anpassen** Gleiche Änderungen wie bei `deploy-staging.yml`: ```yaml runs-on: [self-hosted, raynis-builder] ``` und SSH-Setup-Step auf `STAGING_DEPLOY_KEY` umstellen. - [ ] **Step 3: Node-Setup überprüfen** Da der Runner Node.js 24.11.1 und pnpm 10.23.0 bereits hat, kann der Schritt `actions/setup-node` theoretisch entfallen. Für Robustheit aber beibehalten: ```yaml - uses: actions/setup-node@v4 with: node-version: 24.11.1 cache: pnpm ``` **Hinweis:** `cache: pnpm` funktioniert auf self-hosted Runnern nur, wenn der Runner persistent ist. Da der Server nicht bei jedem Job neu aufgesetzt wird, ist das gegeben. - [ ] **Step 4: Beide Dateien lokal validieren** ```bash cd /Users/chahinebrini/mono/rebreak-monorepo git diff .github/workflows/deploy-staging.yml .github/workflows/deploy-admin-staging.yml ``` - [ ] **Step 5: Änderungen commiten** ```bash git add .github/workflows/deploy-staging.yml .github/workflows/deploy-admin-staging.yml git commit -m "ci: use self-hosted runner raynis-builder on api.trucko.org" ``` --- ### Task 6: Test-Deploy durchführen **Files:** - GitHub Actions UI - Server-Logs auf `api.trucko.org` und `staging.rebreak.org` - [ ] **Step 1: Workflow manuell triggern** In GitHub: Actions → Deploy Staging → Run workflow → Branch: main → Run. - [ ] **Step 2: Build-Logs auf Runner verfolgen** Auf `api.trucko.org`: ```bash tail -f /srv/raynis-builder/_diag/Worker_*.log tail -f /srv/raynis-builder/_diag/SelfUpdate-*.log ``` - [ ] **Step 3: Deploy-Logs auf Staging verfolgen** Auf `staging.rebreak.org`: ```bash pm2 logs rebreak-staging --lines 50 ``` - [ ] **Step 4: Health-Check manuell ausführen** Lokal oder auf `api.trucko.org`: ```bash for i in $(seq 1 12); do STATUS=$(curl -sS -o /dev/null -w '%{http_code}' https://staging.rebreak.org/api/auth/me 2>/dev/null || echo "000") echo "Attempt $i: $STATUS" [ "$STATUS" = "401" ] || [ "$STATUS" = "200" ] && echo "PASSED" && break sleep 5 done ``` Expected: `PASSED` - [ ] **Step 5: Admin-Deploy testen** In GitHub: Actions → Deploy Admin Staging → Run workflow. Health-Check: ```bash curl -sS -o /dev/null -w '%{http_code}' https://admin.staging.rebreak.org/ ``` Expected: Nicht `000`, `502` oder `503`. --- ### Task 7: Alten Webhook-Deploy abschalten (optional, nach stabilem Betrieb) **Files:** - Ausführen auf: `staging.rebreak.org` - GitHub Repo: Settings → Webhooks - [ ] **Step 1: Mindestens 3–5 erfolgreiche Deploys über neuen Runner abwarten** - [ ] **Step 2: GitHub-Webhook deaktivieren** In GitHub: Settings → Webhooks → `https://staging.rebreak.org/webhook` → Active: aus. - [ ] **Step 3: Webhook-Service auf Server stoppen** ```bash ssh root@staging.rebreak.org pm2 stop rebreak-webhook pm2 save ``` - [ ] **Step 4: Legacy-Dateien archivieren (nicht löschen)** ```bash cd /srv/rebreak mkdir -p scripts/legacy mv scripts/deploy.sh scripts/legacy/deploy.sh mv scripts/deploy-webhook scripts/legacy/deploy-webhook ``` - [ ] **Step 5: `ecosystem.config.js` bereinigen** Entferne den Block für `rebreak-webhook` aus `ecosystem.config.js` und deploye die Änderung. --- ### Task 8: Cleanup und Monitoring - [ ] **Step 1: Altes `HETZNER_SSH_KEY` Secret aus GitHub entfernen** Nur nachdem `STAGING_DEPLOY_KEY` erfolgreich getestet wurde. - [ ] **Step 2: Runner-Verfügbarkeit überwachen** In GitHub: Settings → Actions → Runners → Status regelmäßig prüfen. - [ ] **Step 3: Log-Rotation auf Runner einrichten** ```bash logrotate --version || apt-get install -y logrotate cat > /etc/logrotate.d/github-runner << 'EOF' /srv/raynis-builder/_diag/*.log { daily rotate 7 compress missingok notifempty } EOF ``` - [ ] **Step 4: pnpm-Store auf Runner bereinigen (monatlich)** ```bash pnpm store prune ``` --- ## Self-Review ### Spec coverage - Self-hosted Runner auf `api.trucko.org`: Task 1 + 2 - Label `raynis-builder`: Task 2 - Code-Hosting bleibt auf GitHub: implizit durch GitHub Actions - Workflows auf `runs-on: [self-hosted, raynis-builder]`: Task 5 - Deploy zu `staging.rebreak.org`: Task 3 + 4 + 6 - Sicherheit (kein PR-Trigger): Task 5 (Workflow-Trigger bleibt `push: branches: [main]`) - Webhook abschalten: Task 7 ### Placeholder scan Keine TBD/TODO. Alle Befehle sind konkret. ### Konsistenz - Label durchgehend `raynis-builder` - Secret-Name durchgehend `STAGING_DEPLOY_KEY` - Node-Version durchgehend `24.11.1` - pnpm-Version durchgehend `10.23.0` - Server-IP durchgehend `128.140.47.53`