438 lines
11 KiB
Markdown
438 lines
11 KiB
Markdown
# 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 <TOKEN_AUS_GITHUB> --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'
|
||
<PUBLIC_KEY_VON_OBEN>
|
||
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`
|