Sourced from previous audits + agent-wave outputs (2026-05-05): AUDIT-2026-05-05.md — 5-agent stack synthesis forgejo/DEPLOY.md — git.s8n.ru deploy runbook forgejo/forgejo-compose.yml — production compose forgejo/runner-compose.yml — forgejo-runner forgejo/migration-report-... — GH→Forgejo migration audit (6/6 green) runbooks/MIGRATION-... — nullstone→cobblestone runbook runbooks/DE-DECISION-... — keep-vs-strip DE on cobblestone repos/REPO-AUDIT-2026-05-05.md — repo trees + ownership
176 lines
5.3 KiB
Markdown
176 lines
5.3 KiB
Markdown
# Forgejo deploy runbook — nullstone
|
|
|
|
Self-host plan: replace GH Actions free-tier (quota-bound) with
|
|
Forgejo + forgejo-runner running on nullstone. Same `build-iso.yml`
|
|
workflow, no GH dependency.
|
|
|
|
## Pre-flight
|
|
|
|
- nullstone reachable at 192.168.0.100 (LAN) and via tailscale (mesh)
|
|
- Traefik running, `proxy` docker network exists
|
|
- Gandi API token configured in traefik env (LiveDNS scope, s8n.ru only)
|
|
→ letsencrypt resolver works for new hostnames automatically
|
|
- DNS for `git.s8n.ru` must point at nullstone's public IP (Gandi
|
|
manual web UI; API can't add new records per memory
|
|
reference_gandi_api.md)
|
|
|
|
## Step 1 — DNS
|
|
|
|
Add A record `git.s8n.ru → <nullstone public IP>` via Gandi web UI.
|
|
Wait ~2min for propagation. Verify:
|
|
|
|
```bash
|
|
dig +short git.s8n.ru @1.1.1.1
|
|
```
|
|
|
|
## Step 2 — copy compose files to nullstone
|
|
|
|
```bash
|
|
scp /home/admin/ai-lab/nullstone-server/forgejo/docker-compose.yml \
|
|
nullstone:/tmp/forgejo-compose.yml
|
|
scp /home/admin/ai-lab/nullstone-server/forgejo/runner-compose.yml \
|
|
nullstone:/tmp/forgejo-runner-compose.yml
|
|
|
|
ssh nullstone bash <<'EOF'
|
|
sudo mkdir -p /opt/docker/forgejo/{data,config}
|
|
sudo mkdir -p /opt/docker/forgejo-runner/{data,cache}
|
|
sudo chown -R 1000:1000 /opt/docker/forgejo
|
|
sudo mv /tmp/forgejo-compose.yml /opt/docker/forgejo/docker-compose.yml
|
|
sudo mv /tmp/forgejo-runner-compose.yml /opt/docker/forgejo-runner/docker-compose.yml
|
|
EOF
|
|
```
|
|
|
|
## Step 3 — first-start Forgejo
|
|
|
|
```bash
|
|
ssh nullstone 'cd /opt/docker/forgejo && docker compose up -d'
|
|
ssh nullstone 'docker logs -f forgejo' & # watch first-start
|
|
```
|
|
|
|
When you see `Listen: http://0.0.0.0:3000`, Forgejo is up. Hit
|
|
<https://git.s8n.ru/> in your browser. Traefik gets the LE cert
|
|
automatically.
|
|
|
|
## Step 4 — initial admin user
|
|
|
|
The first-time wizard at `/install` is *disabled* by env (we set
|
|
`FORGEJO__service__DISABLE_REGISTRATION=true`). Create the admin via
|
|
CLI inside the container:
|
|
|
|
```bash
|
|
ssh nullstone 'docker exec -u 1000 forgejo \
|
|
forgejo admin user create \
|
|
--admin \
|
|
--username admin \
|
|
--email <your-email> \
|
|
--random-password \
|
|
--must-change-password=false'
|
|
```
|
|
|
|
The random password gets printed once — save it somewhere safe.
|
|
Login at git.s8n.ru with `admin` + that password, change it via the
|
|
web UI's user settings.
|
|
|
|
## Step 5 — generate runner registration token
|
|
|
|
```bash
|
|
ssh nullstone 'docker exec -u 1000 forgejo \
|
|
forgejo actions generate-runner-token'
|
|
```
|
|
|
|
Output is a single line — copy it into `.env` next to the runner
|
|
compose:
|
|
|
|
```bash
|
|
echo "RUNNER_TOKEN=<token>" | ssh nullstone 'sudo tee /opt/docker/forgejo-runner/.env'
|
|
ssh nullstone 'sudo chmod 600 /opt/docker/forgejo-runner/.env'
|
|
```
|
|
|
|
## Step 6 — start runner
|
|
|
|
```bash
|
|
ssh nullstone 'cd /opt/docker/forgejo-runner && docker compose up -d'
|
|
ssh nullstone 'docker logs -f forgejo-runner'
|
|
```
|
|
|
|
Look for `Runner registered successfully`. Verify in Forgejo web UI:
|
|
Site Administration → Actions → Runners — should list `nullstone`.
|
|
|
|
## Step 7 — mirror veilor-os repo
|
|
|
|
In the Forgejo web UI:
|
|
1. Create org `veilor-org` (matches GH org name).
|
|
2. Click + → Migrate Repository.
|
|
3. Type: GitHub. URL: `https://github.com/veilor-org/veilor-os`.
|
|
4. Mirror = ON. Description: "self-hosted mirror; primary dev here".
|
|
5. Click Migrate.
|
|
|
|
Forgejo pulls the repo + all branches + tags + actions config. Once
|
|
done, push from local will go to BOTH (set as second remote):
|
|
|
|
```bash
|
|
cd ~/ai-lab/_github/veilor-os
|
|
git remote add nullstone https://git.s8n.ru/veilor-org/veilor-os
|
|
git push nullstone main v0.7-bluebuild-spike
|
|
```
|
|
|
|
## Step 8 — flip workflow to nullstone runner
|
|
|
|
Change `build-iso.yml`:
|
|
|
|
```yaml
|
|
runs-on: ubuntu-24.04 # before
|
|
runs-on: nullstone # after — picks up our forgejo runner
|
|
```
|
|
|
|
Push to nullstone remote. Watch Forgejo Actions tab. Same workflow,
|
|
runs on our hardware, no GH minutes.
|
|
|
|
## Step 9 — close the loop
|
|
|
|
Mirror Forgejo → GitHub for public visibility. Forgejo settings on
|
|
the repo → Mirror → Push mirror → `https://github.com/veilor-org/veilor-os`
|
|
with a GH PAT that has write access. Forgejo pushes on every commit.
|
|
|
|
End state:
|
|
- `git push origin` → GH (public mirror)
|
|
- `git push nullstone` → Forgejo (primary; runs CI)
|
|
- Forgejo auto-pushes to GH for visibility
|
|
- ISO builds run unlimited on nullstone hardware
|
|
- 0 GH Actions minutes consumed
|
|
|
|
## Disk needs
|
|
|
|
- Forgejo data: ~1GB initial, grows ~100MB/yr per repo
|
|
- Runner workspace: ~80GB free recommended for ISO builds (squashfs
|
|
+ downloaded RPMs + xorriso staging)
|
|
- Runner cache: ~20GB for `actions/cache`-style hits across builds
|
|
|
|
Confirm with `df -h /` on nullstone before kickoff.
|
|
|
|
## Resource cost
|
|
|
|
- Forgejo: ~200MB RAM idle, ~500MB during build queues
|
|
- Runner: idle 50MB, ~4GB during ISO build (depsolve + squashfs)
|
|
- Network: ~2GB/build (Fedora package download)
|
|
|
|
Should fit alongside existing nullstone services without contention.
|
|
|
|
## Rollback
|
|
|
|
If anything breaks:
|
|
|
|
```bash
|
|
ssh nullstone 'cd /opt/docker/forgejo && docker compose down'
|
|
ssh nullstone 'cd /opt/docker/forgejo-runner && docker compose down'
|
|
```
|
|
|
|
Local repo `origin` still points at GH; nothing on the dev side
|
|
changes. ISO builds fall back to GH Actions until quota cycles.
|
|
|
|
## See also
|
|
|
|
- veilor-os roadmap: `_github/veilor-os/docs/ROADMAP.md`
|
|
- nullstone service inventory: `~/ai-lab/SYSTEM.md`
|
|
- Existing service patterns: `/opt/docker/headscale/`,
|
|
`/opt/docker/authentik/`
|