--- created: '2026-05-23' path: Sources/Homelab project: gitea-migration-to-pve tags: - git - proxmox - lovebug - pbs - traefik type: project-plan --- ## Goal Relocate Gitea so its placement matches what it has actually become: critical homelab/dev infrastructure, not a service incidentally hosted on the PBS business server. Establish a two-instance architecture with cross-mirroring so each instance is the insurance copy for the other. **Target architecture:** ``` PVE LXC Gitea PBS Gitea ───────────── ───────── Homelab projects PBS business code Lovebug pushes here (website, n8n, content automation) Canonical for Canonical for petal-power org PBS-business org ↕ cross-mirror for backup ↕ ``` ## Locked Decisions - **Host:** PVE LXC (small footprint, native install, no Docker — VM/LXC is the isolation boundary) - **Database:** SQLite on local LXC disk. Adequate for one-human + one-agent push volume; avoids the SQLite-over-NFS corruption footgun. - **Repo storage:** NFS mount from NAS for `repos/`, `lfs/`, `attachments/`. Compute is disposable (rebuildable via Ansible/Terraform), state lives on NAS where it's already in the backup story. - **Cross-mirror:** Gitea's native push-mirror feature in both directions. PVE LXC mirrors homelab repos to PBS; PBS mirrors business repos to PVE LXC. - **Lovebug access:** Only on the new PVE LXC Gitea. PBS Gitea (PBS business code) stays outside Lovebug's reach by default — a natural security boundary. - **Mirror direction:** Canonical lives where active work happens. New LXC is canonical for homelab; PBS stays canonical for PBS business code. - **Migration mechanism:** `git push --mirror` from herbys-dev for the petal-power org repos (everything was created on herbys-dev anyway). Use Gitea's "Migrate Repository" feature only if any repo has meaningful issue/PR/wiki state worth preserving. ## Open Items - [ ] Confirm petal-power repos don't have meaningful Gitea-native state (issues, PRs, wiki) that `git push --mirror` would lose. If any do, use Migrate Repository for those specific ones. - [ ] Decide naming/DNS for new instance (e.g., `gitea.herbylab.dev` vs subdomain that signals "homelab-Gitea" vs PBS-Gitea) - [ ] Verify NFS export path on NAS, sizing, and that it's covered by existing NAS backup - [ ] Identify trigger to execute (see Notes below) ## Phases ### Phase 1: Provision - [ ] Create LXC on PVE (size: small, ~2 vCPU / 2GB RAM is plenty for this workload) - [ ] Configure NFS mount from NAS for repo storage path - [ ] Install Gitea natively (no Docker) - [ ] Configure Gitea: SQLite local, repo root + LFS + attachments pointed at NFS mount - [ ] DNS record for new instance - [ ] Traefik route + Cloudflare DNS-01 wildcard TLS - [ ] Test with a throwaway repo to verify the full stack: web UI, SSH push, TLS ### Phase 2: Set up org and accounts - [ ] Create `petal-power` org on new instance - [ ] Create Lovebug user account, add SSH key, mirror permissions from PBS instance - [ ] Pre-populate `~/.ssh/known_hosts` on herbys-dev with new Gitea's host key (avoid headless SSH hang) ### Phase 3: Migrate repos - [ ] For each repo under `/opt/projects/` on herbys-dev: add new remote, `git push --mirror` to new Gitea - [ ] Spot-check several repos: full commit history present, all branches present, tags intact - [ ] If any repos have Gitea-native state worth preserving, use Migrate Repository for those specifically ### Phase 4: Cutover - [ ] Update Lovebug's SSH config and any shell aliases on herbys-dev to point at new Gitea - [ ] Update any Gitea API tokens Lovebug uses (new instance = new tokens) - [ ] Test push from Lovebug against new instance - [ ] Test push from Travis (travadmin) against new instance ### Phase 5: Invert the relationship - [ ] Configure push-mirror on new Gitea: homelab repos mirror outbound to PBS Gitea - [ ] PBS Gitea is now read-only-ish for homelab repos (writes propagate from new instance via mirror) - [ ] Verify a test push lands on PBS via mirror within expected delay - [ ] (Optional) Configure push-mirror PBS → new instance for PBS business repos, so new instance is insurance copy for those ## Notes ### The reframe that made this plan possible The starting point: Gitea-on-PBS was bothering me. The reframe: PBS Gitea isn't "where my code lives" — it's the paid offsite insurance copy I already have. PBS is in a different physical location, backed up whole-drive to Linode, and has been correctly serving an insurance role the whole time. That makes the migration a *promotion* of the new instance to canonical rather than a *rescue* of code from PBS. ### Cost story No new spend. PBS hosting is already paid. New LXC sits on existing PVE hardware. NAS storage is already in place. The "paid relationship for business-asset backup" principle is satisfied by the existing PBS arrangement — the architectural fix is about where the canonical lives, not about adding a paid service. ### Cross-domain consequence The plan implicitly couples code backup strategy to the PBS server contract. If PBS is ever cancelled or downgraded, the insurance leg evaporates and a replacement (Backblaze B2, rsync.net, etc.) needs to slot in. Worth remembering this when making future decisions about PBS. ### Trigger to execute Not scheduled. Migration is decided-and-waiting. Any of these fires it: - A Traefik or OB1 phase wraps cleanly with no immediate next work queued - Lovebug needs gnarly work against a repo where having a fully-controlled Gitea is useful prep - Gitea-on-PBS needs hands-on attention anyway (upgrade, backup restore, webhook debug) — redirect that time into the migration - A "huh, that was uncomfortable" moment on PBS that makes the coupling acute - A Saturday morning where focused infra work sounds genuinely fun Anti-pattern to avoid: letting this become a background nag. The bad state is "I keep meaning to but never do" — that converts reflection-energy into procrastination-guilt. ### Self-hosted git landscape (for future reference) - **Forgejo** — community-governed fork of Gitea, near-painless migration path if Gitea Ltd. ever takes a turn. Most plausible exit ramp. - **GitLab CE** — heavier, full DevOps platform. Overkill for this scale. - **Cgit + Gitolite** — Unix-philosophy stack, no web platform. Wrong cluster for Lovebug-style workflow. - **Sourcehut** — email-driven, niche-but-thoughtful. Wrong workflow fit. - **Gogs** — Gitea's ancestor, basically a museum piece in 2026. The Gitea-vs-Forgejo decision can be deferred indefinitely; not blocking this migration.