GitLab Exit Strategy: Open-Source Forge, Agent Automation, Backup, and Disaster-Recovery Plan¶
Prepared: September 23, 2026
Decision deadline: before GitLab subscription A-S00141074 expires December 15, 2026
Primary objectives: reduce recurring cost, preserve all code and collaboration history, support AI/automation agents safely, provide a usable team collaboration environment, and make a catastrophic loss of the home/NAS survivable.
Recommendation in one sentence: Move the primary forge to self-hosted Forgejo on a small cloud VPS, use native Forgejo Actions with isolated runners, continuously back it up to the home NAS, make a second encrypted offsite backup, and keep an independent Git mirror; use the NAS as a backup/runner node rather than the sole production server.
Executive summary¶
The most important architectural decision is not simply “GitLab versus Gitea.” It is deciding where the authoritative copy of Bluefly's engineering system lives, what is required to rebuild it, and whether losing one building can destroy it.
A home NAS can be an excellent backup target, build-runner host, archive, cache, and even emergency forge. It should not be the only authoritative home of the company’s repositories. RAID and local snapshots address disk failures and accidental changes; they do not address fire, theft, electrical events, ISP failure, ransomware reaching the NAS, or loss of the building.
The best fit for the stated priorities is Forgejo. Its current official documentation covers repository hosting, pull requests, issues, projects, integrated wikis, repository permissions, scoped access tokens, APIs, webhooks, repository mirrors, native Forgejo Actions and runners, package registries including a container registry, branch protection, and installation/upgrade administration. That makes it possible to obtain the GitLab-like core without assembling a bespoke forge or writing a Bluefly-specific orchestration system. citeturn4search0
Gitea is an extremely close second and should be the comparison candidate in the proof of concept. Gitea has an official GitLab migration facility, making it particularly suitable for a GitLab exit. citeturn4search1
Self-managed GitLab CE is the continuity option, not my preferred cost/complexity option. It minimizes conceptual and CI migration because the team stays inside GitLab, while moving hosting under Bluefly's control. The tradeoff is that you retain much of the operational weight you are trying to escape. GitLab itself maintains dedicated backup-and-restore procedures, demonstrating that a self-managed installation needs to be treated as a substantial stateful service, not merely “a Git server.” citeturn4search2
The proposed ordering is therefore:
| Rank | Option | Recommendation |
|---|---|---|
| A | Forgejo on cloud VPS + NAS + independent offsite backup | Recommended production architecture |
| A- | Gitea on cloud VPS + NAS + independent offsite backup | Excellent fallback if POC reveals a Forgejo-specific gap |
| B+ | Hosted service + independent Bluefly backup | Lowest administration; sacrifices some sovereignty depending on provider |
| B | GitLab CE self-managed | Best compatibility; materially heavier operations |
| B- | Forgejo/Gitea hosted only on home NAS | Cheapest cash cost, but poor availability/failure-domain design |
| C+ | SourceHut | Strong open-source philosophy, but a substantially different collaboration model |
| C | Gogs | Lightweight Git hosting, but adding modern CI/automation means more components |
| C | Gitea + separate Drone-style CI | Functional, but unnecessary when native Actions satisfies requirements |
| D | Phabricator-derived/Phorge migration | Migration effort and workflow mismatch outweigh advantages for this case |
The guiding principle should be:
Own the data, identity boundaries, backup, and composition. Do not build a forge, workflow engine, scheduler, runner protocol, or agent orchestration system that upstream software already provides.
What “agentic” should mean here¶
The forge itself does not need an embedded autonomous-agent framework.
For Bluefly, an agent-ready forge needs five primitives:
- an authenticated API;
- scoped service credentials;
- webhooks/events;
- Git/SSH access;
- a CI/action runner that can validate changes.
Forgejo exposes an API, authorized integrations, scoped access-token facilities, webhooks, repository permissions and Actions/runners, so an external coding agent can create branches, commits, issues and pull requests without Bluefly inventing an “agentic Git platform.” citeturn4search0
The safe pattern is:
flowchart LR
H[Humans] --> F[Forgejo]
A[AI Agents] -->|scoped API token| F
F -->|webhook| A
A -->|branch + pull request| F
F --> CI[Forgejo Actions]
CI --> R[Isolated Runner]
R --> T[Tests / Build / Deploy]
F --> P[Protected Main Branch]
H -->|review / approval| P
Agents should normally open branches and pull requests, not possess unrestricted direct-write access to production branches. Forgejo's documented repository permissions, access-token scopes and branch-protection facilities provide the underlying controls for this model. citeturn4search0
Bottom-line decision¶
Do not wait until December.
Set November 15, 2026 as the internal production cutover deadline. That leaves one month in which GitLab can remain a read-only safety net and gives time to test disaster recovery before access expires on December 15, 2026.
By December 1, Bluefly should be operationally capable of deleting its GitLab credentials and still functioning.
Requirements, assumptions, and unanswered questions¶
The current design can be chosen without knowing every detail, but the migration plan cannot be considered complete until the following inventory exists.
Working assumptions¶
This report assumes a relatively small engineering organization, mostly private repositories, standard GitLab merge-request/issue workflows, some CI/CD, and possibly Git LFS and container-registry data. It also assumes Bluefly already owns or operates a NAS and values open-source control more highly than eliminating every hour of infrastructure administration.
The recommendation changes if Bluefly has hundreds of developers, terabytes of registry artifacts, stringent regulated-industry requirements, GitLab-specific security/compliance functionality, or mission-critical 24×7 availability.
Forgejo's currently documented feature surface is broad enough to cover the expected baseline: issues, pull requests, projects, wiki, permissions, APIs, webhooks, mirrors, Actions, package/container registry, releases, branch protection and token scopes. citeturn4search0
Questions that must be answered during inventory¶
| Question | Why it matters | Decision affected |
|---|---|---|
| How many active, archived and forked repositories exist? | Determines migration volume and validation work | All |
| Total Git repository storage? | Sizes production disks and backups | Hosting |
| Largest individual repository? | Exposes storage/performance issues | Hosting |
| Is Git LFS used? How many GB? | LFS objects require explicit validation during migration | Storage/migration |
| How much GitLab Container Registry storage exists? | Registry objects need their own migration | Registry |
| Are GitLab Packages used? | Package formats must be migrated or rebuilt | Forge selection |
| How many GitLab issues and merge requests matter historically? | A plain Git mirror does not preserve these | Import method |
| Are project/group wikis used? | Wiki Git repositories must be included | Migration |
| Are snippets used? | They can otherwise be silently lost | Migration |
| Are project boards, epics or roadmaps heavily used? | Feature parity varies | Forge selection |
| How many users and external collaborators? | Determines identity/permission work | IAM |
| Is SSO/LDAP/OIDC required? | May change deployment/configuration | IAM |
How many .gitlab-ci.yml files exist? |
Quantifies CI conversion work | Timeline |
| Are scheduled pipelines used? | Scheduled jobs need recreation | CI |
| How many CI/CD variables/secrets exist? | Secrets must be safely recreated | Security |
| Are there environment-scoped/protected variables? | Flat secret migration could weaken controls | Security |
| Are self-hosted GitLab runners already in use? | Existing machines may become Forgejo runners | Cost |
| Are Pages, Releases, Environments or deployment dashboards used? | Not all concepts map one-to-one | Migration |
| What services consume GitLab webhooks? | Every integration needs repointing | Cutover |
| What deploy keys/tokens reference GitLab? | Hidden dependencies can break after expiry | Cutover |
| What SaaS services install GitLab OAuth apps? | Authentication may stop working | Cutover |
| What uptime is actually required? | Decides home NAS versus datacenter primary | Architecture |
| Acceptable RPO: 15 min, 4 h, 24 h? | Controls backup frequency | DR |
| Acceptable RTO: 1 h, 8 h, 24 h? | Controls standby strategy | DR |
| What NAS model, filesystem and RAM exist? | Determines VM/container/snapshot options | NAS role |
| Does the house have UPS/generator power? | Affects NAS-primary viability | Availability |
| Is the internet connection static-IP and symmetric? | Affects public self-hosting | Availability |
| Is source subject to client residency requirements? | May restrict offsite locations/providers | Compliance |
| Does any contract require SOC 2/ISO evidence from the hosting provider? | Self-hosting could shift obligations to Bluefly | Compliance |
| May AI agents push code? create PRs? merge? deploy? | Determines identity and authorization model | Agent security |
Inventory artifacts that should exist before migration¶
Create one machine-readable inventory containing:
projects.csv
users-and-teams.csv
git-storage.csv
lfs-usage.csv
container-images.csv
packages.csv
ci-pipelines.csv
ci-variables-inventory.csv
webhooks.csv
deploy-keys.csv
access-tokens.csv
scheduled-pipelines.csv
protected-branches.csv
integrations.csv
migration-status.csv
Do not put secret values into the CSV inventory. Record identifiers, owners, scopes and rotation requirements.
Every project should end with an explicit disposition:
MIGRATE
ARCHIVE
DELETE
REPLACE
UNKNOWN
Nothing should simply disappear because it looked inactive.
Candidate evaluation and decision matrix¶
Weighted decision model¶
For Bluefly, I would weight sovereignty and recoverability more heavily than feature count:
| Criterion | Weight |
|---|---|
| Open-source / organizational control | 15% |
| GitLab migration practicality | 12% |
| Agent/API/webhook readiness | 10% |
| CI/CD capability | 10% |
| Team collaboration / modern UX | 10% |
| Operational burden | 12% |
| Backup / disaster-recovery controllability | 9% |
| Registry / package / LFS coverage | 8% |
| Permissions / security | 7% |
| Ecosystem / project viability | 7% |
| Total | 100% |
The scores below are architectural judgments on a five-point scale rather than vendor benchmarks. For Forgejo, the underlying capability assessment is supported by its current first-party documentation; for Gitea, its GitLab migration path is documented directly. citeturn4search0turn4search1
| Platform | Open | Migration | Agents | CI | UX/collab | Ops | DR control | Registry/LFS | Security | Overall fit |
|---|---|---|---|---|---|---|---|---|---|---|
| Forgejo self-hosted | 5 | 4.5 | 5 | 4.5 | 4.5 | 4 | 5 | 4.5 | 4.5 | Excellent |
| Gitea self-hosted | 5 | 5 | 5 | 4.5 | 4.5 | 4 | 5 | 4.5 | 4.5 | Excellent |
| GitLab CE self-managed | 4.5 | 5 | 5 | 5 | 5 | 2 | 5 | 5 | 5 | Very good, heavy |
| Codeberg hosted | 5 | 4 | 4.5 | 3–4* | 4.5 | 5 | 3 | 3–4* | 4 | Good if terms fit |
| GitHub Cloud | 1 | 4 | 5 | 5 | 5 | 5 | 2.5 | 4.5 | 5 | Excellent UX, not sovereign |
| Bitbucket Cloud | 1 | 3.5 | 4 | 4.5 | 4 | 5 | 2.5 | 3.5 | 4.5 | Good SaaS |
| SourceHut hosted | 5 | 3 | 4 | 4 | 2.5 | 5 | 3 | 2.5 | 4 | Strong philosophy, different UX |
| SourceHut self-hosted | 5 | 3 | 4 | 4 | 2.5 | 2.5 | 5 | 2.5 | 4 | Specialized |
| Gogs | 5 | 3.5 | 3.5 | 1.5 | 3 | 4.5 | 5 | 3 | 3.5 | Too minimal for goal |
| Gitea + separate Drone CI | 4 | 4.5 | 4.5 | 4.5 | 4.5 | 2.5 | 4.5 | 4.5 | 4 | Unnecessary complexity |
| Gitea + native Actions | 5 | 5 | 5 | 4.5 | 4.5 | 4 | 5 | 4.5 | 4.5 | Excellent |
| Phorge / Phabricator-derived | 5 | 2 | 3 | 2 | 2.5 | 2 | 4 | 1.5 | 3.5 | Poor fit |
* Hosted-service quotas and CI policies must be checked against Bluefly's private/commercial usage before relying on them. The final research retrieval available for this report did not return a current first-party Codeberg pricing/quota document, so I would not make a go/no-go decision from an assumed free allowance.
Forgejo¶
Why it is the leading candidate: Forgejo gives Bluefly a cohesive upstream system instead of requiring it to compose several internal products. Its documentation currently includes Docker and binary installation, databases, upgrades, authentication, OIDC group mappings, repository permissions, issue tracking, projects, integrated wikis, APIs, scoped tokens, webhooks, repository mirrors, Actions, runner configuration, Actions security, branch protection, package registries and a container registry. citeturn4search0
Pros: open-source ownership; comparatively small operational footprint; GitHub-style interface familiar to developers; modern pull-request and issue workflows; native automation; no requirement to introduce Drone merely to obtain CI; APIs/webhooks suitable for coding agents; integrated package/container facilities; straightforward backup architecture because the service can be decomposed into application data, Git/LFS/package storage, database and configuration. citeturn4search0
Cons: .gitlab-ci.yml is not something I would assume can simply be copied and run. CI should be treated as a deliberate port to Forgejo Actions. GitLab-specific issue concepts or advanced project-management features may not map perfectly. A full migration test is therefore mandatory.
Migration complexity: medium. Git itself is easy; collaboration metadata and CI are the actual project.
Recommendation: Yes. POC immediately.
Gitea¶
Gitea should be tested in parallel only far enough to discover whether it provides a decisive advantage. Its first-party migration documentation explicitly provides a migration workflow, including migration from supported external Git services such as GitLab. citeturn4search1
Pros: mature Git forge; low infrastructure footprint; API/webhook ecosystem; GitLab importer; familiar user experience; native Actions model; easy Docker-style deployment.
Cons: for Bluefly, choosing between Gitea and Forgejo is largely an upstream/governance preference unless the POC discovers a concrete capability gap. Running both would be pointless.
Migration complexity: medium.
Recommendation: Strong fallback/benchmark.
GitLab CE self-hosted¶
This is the lowest-workflow-change solution. Existing GitLab concepts, CI definitions and team habits transfer more naturally than they do to a different forge.
GitLab maintains explicit self-managed backup and restore tooling. A production self-managed deployment therefore needs disciplined backup of the state necessary to reproduce the installation; GitLab's backup documentation should be part of the runbook from day one. citeturn4search2
Pros: strongest compatibility; GitLab CI remains GitLab CI; user retraining minimized; broad integrated feature set.
Cons: greater application and upgrade complexity, greater resource requirements, more components to patch and monitor, and less reduction in platform complexity than Forgejo/Gitea.
Migration complexity: low to medium functionally; medium operationally.
Recommendation: Use only if the POC shows that converting important GitLab-specific functionality costs more than operating GitLab itself.
Gogs¶
Gogs is attractive where the requirement is principally “small, fast Git server.”
That is no longer Bluefly's requirement.
You need issue collaboration, safe agent APIs, modern CI, runner management, registry integration, backups and a healthy automation surface. If those gaps require adding a second and third service, the simplicity advantage disappears.
Recommendation: not a finalist.
Gitea plus Drone versus native Actions¶
This deserves an explicit architectural decision.
A separate CI engine means another:
- database/state model;
- authentication boundary;
- secret store;
- webhook integration;
- upgrade path;
- backup target;
- security boundary;
- failure mode.
Native Actions already supplies the orchestration primitive the forge needs. Forgejo documents its own Actions administration, runner registration and Actions security controls. citeturn4search0
Therefore:
Do not deploy Drone merely because it is possible. Start with native Forgejo/Gitea Actions.
A separate upstream CI such as Woodpecker should enter the architecture only if a demonstrated requirement cannot be met by native Actions.
SourceHut¶
SourceHut deserves respect as an open-source development suite, but its interaction model is deliberately different from the conventional GitHub/GitLab pull-request experience.
That may be desirable for an individual or a team deliberately adopting an email/patch-oriented workflow. It is not the best choice for a time-constrained migration where minimizing disruption is a key requirement.
Recommendation: keep as a strategic open-source alternative, not the December migration target.
Phorge / Phabricator-derived systems¶
A Phabricator-derived environment would require Bluefly to change both infrastructure and collaboration conventions while solving CI/package/registry integration separately.
There is no compelling reason to take that migration risk when Forgejo/Gitea already provide the cohesive Git-forge model needed here.
Recommendation: eliminate from the final round.
Fully hosted alternatives¶
Cloud-hosted services solve a different problem: operational labor.
| Provider/style | Biggest advantage | Biggest disadvantage | Appropriate when |
|---|---|---|---|
| GitHub Free/paid plans | Very low operational burden; huge automation/agent ecosystem | Core hosted forge is proprietary and creates another vendor dependency | Ops time matters more than sovereignty |
| Bitbucket Cloud | Managed service; strong Atlassian-oriented workflow | Proprietary SaaS; migration/CI rewrite | Team already relies heavily on Atlassian |
| Codeberg | Forgejo-based/open-source-aligned hosting model | Must validate current private/commercial capacity and CI policies | Usage aligns with its hosting model |
| SourceHut hosted | Open-source-oriented hosted development stack | Workflow differs substantially from GitLab | Team actively wants SourceHut's model |
I would not make current Free/Pro price promises in this document. Those are changeable commercial terms, and the source retrieval available for this final pass did not return current first-party pricing pages for these providers. Validate the actual December 2026 seat, Actions/minute, storage, LFS and private-repository terms before contract selection.
That limitation does not materially change the architecture recommendation: SaaS minimizes infrastructure labor but does not achieve the same independence as a forge whose complete state Bluefly can restore itself.
Recommended architecture, backup, disaster recovery, security, and cost¶
Preferred architecture: datacenter primary, home NAS secondary¶
This is the best balance.
flowchart TB
Internet((Internet))
subgraph People["People and Automation"]
Dev[Developers]
Bot[AI Coding Agents]
end
subgraph Cloud["Cloud / Datacenter — Primary Failure Domain"]
RP[HTTPS / Reverse Proxy]
F[Forgejo]
DB[(PostgreSQL)]
DATA[(Git / LFS / Packages)]
RUN[Isolated Action Runner]
end
subgraph Home["Home — Secondary Failure Domain"]
NAS[(NAS Backup)]
HRUN[Optional Build Runner]
end
subgraph Offsite["Independent Offsite Failure Domain"]
OBJ[(Encrypted Object Backup)]
MIRROR[(Optional Git Mirror)]
end
Dev --> Internet --> RP --> F
Bot --> Internet
Internet -->|Scoped API| F
F --> DB
F --> DATA
F --> RUN
F -. webhook .-> Bot
DB -->|scheduled encrypted backup| NAS
DATA -->|scheduled encrypted backup| NAS
F -->|config backup| NAS
NAS -->|encrypted replication| OBJ
F -->|repository mirror| MIRROR
F --> HRUN
Forgejo directly provides the forge-side features needed for this design, including APIs, token scoping, webhooks, Actions/runners, repository mirrors, package/container registry support and administrative installation/upgrade tooling. citeturn4search0
Why the primary should not live only on the NAS¶
Consider the correlated failures:
| Incident | NAS-only | Cloud primary + NAS |
|---|---|---|
| NAS disk failure | RAID/snapshot may save you | Production unaffected |
| NAS chassis failure | Outage | Production unaffected |
| Home power failure | Outage | Production unaffected |
| Home ISP failure | Outage | Production unaffected |
| Fire/flood/theft | Potential total loss | Production unaffected |
| Cloud VPS loss | N/A | Restore from NAS/offsite |
| Cloud account suspension | N/A | Restore elsewhere from independent backup |
| Ransomware reaches primary | Risk | NAS/offsite retention gives recovery path |
| Developer accidentally deletes repo | Snapshot/backup dependent | Multiple recovery layers |
A home NAS is therefore valuable precisely because it is not the production VPS.
Likewise, the cloud server is valuable because it is not physically located with the NAS.
Backup design¶
There should be four distinct mechanisms because they solve different problems:
| Layer | Purpose | Frequency recommendation | Retention recommendation |
|---|---|---|---|
| Application-consistent Forge backup | Database + application state | Every 4 hours | Several days |
| NAS snapshots | Fast recovery from local errors | Hourly/daily | Daily + weekly |
| Encrypted independent offsite backup | Building/NAS/cloud disaster | Daily | 30 daily + monthly |
| Git mirror | Fast code-only recovery/read access | Near-real-time or hourly | Current mirror |
The exact retention policy is a Bluefly decision; the table represents a reasonable small-team target rather than a vendor requirement.
The key principle is:
A Git mirror is not a complete forge backup.
It can preserve repository refs, but your recovery objective includes users, teams, permissions, issues, PR metadata, Actions configuration, package data, registry information and application configuration. Forgejo's documented feature set illustrates how much valuable state exists beyond bare Git repositories. citeturn4search0
GitLab similarly documents application backup/restore as a distinct administrative process; the existing GitLab system should receive a real final backup/export, not just git clone operations. citeturn4search2
Suggested recovery objectives¶
For Bluefly's apparent scale, start with:
RPO: four hours. In a catastrophic failure, no more than roughly four hours of forge metadata should be at risk.
RTO: eight hours. A catastrophic production loss should be recoverable on replacement infrastructure during a working day.
Those are design targets, not statements about what any particular vendor guarantees.
For Git repositories specifically, frequent mirroring can make the effective code RPO much smaller.
Restore must be tested¶
A backup that has never been restored is an assumption.
Before deleting GitLab dependency:
- create an empty replacement VM;
- install the supported Forgejo release;
- restore configuration;
- restore database;
- restore Git/LFS/package data;
- start the instance under a temporary hostname;
- clone multiple repositories;
- open issues/PRs;
- authenticate;
- run an Action;
- pull a container/package if those facilities are used;
- record actual RTO.
Forgejo publishes installation and upgrade administration alongside its operational functionality, which supports treating recovery as a reproducible deployment rather than as a one-off machine repair. citeturn4search0
Optional warm disaster-recovery host¶
If eight-hour restoration is not adequate:
flowchart LR
PROD[Primary Forgejo VPS]
DB[(Primary DB)]
BK[Encrypted Backup]
NAS[(Home NAS)]
COLD[Warm/Cold Standby VPS]
PROD --> DB
PROD --> BK
DB --> BK
BK --> NAS
BK -. periodic restore/sync .-> COLD
I would not begin with active-active multi-region Forgejo.
For a small organization that adds distributed-database, shared-object-storage, consistency and failover problems whose cost is disproportionate to the goal.
A reproducible cold or warm standby is simpler.
NAS-primary alternative¶
Where absolute minimum cash expense matters more than availability:
flowchart TB
Internet((Internet))
RP[Reverse Proxy / VPN]
NAS[Home NAS]
F[Forgejo VM/Container]
DB[(DB)]
BK[(Local snapshots)]
OFF[(Encrypted offsite backup)]
VM[Emergency cloud VM template]
Internet --> RP --> F
NAS --> F
F --> DB
F --> BK
BK --> OFF
OFF -. catastrophe restore .-> VM
This can work, but it carries:
- home power dependence;
- home ISP dependence;
- physical-site dependence;
- greater responsibility for firewalling;
- potentially awkward inbound networking;
- harder uptime guarantees.
For company infrastructure, I would save the few extra dollars per month and use the cloud-primary arrangement.
SaaS-primary alternative¶
The lowest-ops design is:
flowchart LR
TEAM[Team + Agents] --> SAAS[Hosted Forge]
SAAS --> NAS[(NAS Mirror / Exports)]
NAS --> OFF[(Encrypted Offsite Backup)]
SAAS --> RUN[Self-hosted Runner]
This is a valid architecture, particularly with GitHub, but it achieves portability rather than complete sovereignty.
Security model for agents¶
Do not give agents a human administrator's token.
Create identities by responsibility:
| Identity | Suggested rights |
|---|---|
agent-read |
Repository/issues read |
agent-author |
Create branch, commits, issues and PRs |
agent-maintainer |
Limited maintenance automation |
ci-runner |
Runner-specific registration/execution |
deploy-prod |
Deployment only, isolated from general agents |
| human admin | Instance administration |
Forgejo documents token scopes, repository permissions, branch protection, authorized integrations and Actions security controls that can underpin this separation. citeturn4search0
Production rules should be:
Agent
-> feature branch
-> pull request
-> CI tests
-> policy checks
-> human approval when required
-> protected main
-> deployment workflow
A general-purpose coding agent should not possess the same credential that can administer Forgejo, read all client repositories, decrypt production secrets and deploy production.
Runner isolation¶
CI runners execute code from repositories. Treat them as compute workers, not as part of the trusted forge database tier.
Forgejo explicitly publishes separate runner-registration/configuration documentation and Actions security guidance. citeturn4search0
Prefer:
Forge server
!=
CI runner
!=
production server
The NAS could run a trusted internal runner, but code from untrusted external pull requests should never automatically gain access to NAS files, backups or LAN credentials.
Credential and secrets rules¶
During migration:
- recreate secrets rather than copying uncontrolled exports;
- rotate long-lived deploy tokens;
- issue new agent tokens;
- remove obsolete GitLab credentials;
- protect primary branches;
- enable MFA for humans;
- keep break-glass administrator credentials outside ordinary development machines;
- encrypt offsite backup content before or at storage;
- separate backup credentials from forge administrator credentials.
Planning cost model¶
Because current provider prices were not fully verified from first-party pages during the final source retrieval, these are deliberately budget bands, not vendor quotes.
| Architecture | Approximate infrastructure budget | Admin burden | Overall |
|---|---|---|---|
| Forgejo cloud primary + NAS + offsite | $15–$60/mo | ~1–3 h/mo after stabilization | Best balance |
| Gitea cloud primary + NAS + offsite | $15–$60/mo | ~1–3 h/mo | Excellent |
| Forgejo NAS primary + offsite | $3–$25/mo + power/hardware | ~1–4 h/mo | Cheapest cash, weaker availability |
| GitLab CE cloud self-hosted | $30–$100+/mo | ~2–5 h/mo | Compatibility choice |
| Managed SaaS | Provider/seat dependent | ~0.5–1.5 h/mo | Lowest operational work |
| Multi-region active-active | Much higher | High | Not justified initially |
The most important cost is likely not storage.
Use:
true monthly cost =
infrastructure
+ backup storage
+ bandwidth
+ hardware depreciation
+ electricity
+ (maintenance hours * loaded labor rate)
For example, at an illustrative loaded engineering rate of $150/hour:
2 hours/month * $150 = $300/month
That dwarfs a $10–$30 difference in VPS cost.
This is why minimizing moving parts matters financially.
NAS electricity calculation¶
Do not guess the NAS power cost. Calculate it:
monthly electricity =
watts / 1000
* 24
* 365 / 12
* electricity_rate_per_kWh
A NAS already running for other purposes has a very different marginal cost from purchasing and operating a dedicated GitLab server.
Installation and migration runbooks¶
Forgejo production installation¶
The Forgejo project publishes current binary/package/Docker installation, database preparation, reverse-proxy configuration, authentication, storage, Actions/runner setup, upgrade guidance and security documentation. Use that upstream deployment path instead of Bluefly writing an installation framework. citeturn4search0
A production rollout should proceed in this order:
-
Provision a small VPS. Start conservatively rather than over-sizing. Keep build workloads off the application host.
-
Create DNS, for example:
git.bluefly.io
-
Install a supported container/runtime or native package method from Forgejo's official deployment guidance. Pin an explicit supported release rather than
latest. citeturn4search0 -
Use a persistent database. For a business production installation I would choose PostgreSQL rather than optimizing around the absolute fewest processes.
-
Create persistent application storage for:
Git repositories
Git LFS
attachments
packages
container data
configuration
database
-
Terminate TLS using the upstream-supported reverse-proxy pattern. Forgejo documents reverse proxy configuration. citeturn4search0
-
Configure:
external URL
SSH clone URL/port
SMTP
registration policy
session/security settings
storage
logging
-
Create the Bluefly organization and administrator.
-
Configure human authentication and MFA policy.
-
Recreate teams and least-privilege repository permissions. Forgejo provides repository permissions and authentication/integration facilities. citeturn4search0
-
Install the Forgejo runner on another machine, not the production forge. Follow the project's runner registration and security documentation. citeturn4search0
-
Create the backup job.
-
Perform a restoration test before importing production data.
-
Only then migrate the first pilot repository.
Per-repository Forgejo migration¶
Use the platform importer where it preserves metadata; independently validate the Git object set.
For every repository:
-
Record source project ID, canonical path and owner.
-
Export GitLab project metadata where supported.
-
Create/import the destination repository.
-
Verify all branches:
git branch -a
- Verify tags:
git tag
- For independent Git verification, create a bare/mirror clone:
git clone --mirror [email protected]:GROUP/REPO.git
- Add the destination and push refs only after reviewing the command:
cd REPO.git
git push --mirror ssh://[email protected]/GROUP/REPO.git
--mirror is destructive if pointed at a destination containing refs that should not be removed. Use it only inside the controlled migration process.
- Where LFS is used:
git lfs fetch --all
git lfs push --all DESTINATION
-
Migrate/validate the wiki separately where present.
-
Compare:
default branch
branches
tags
commits
releases
issues
issue comments
merge/pull requests
labels
milestones
wiki
attachments
protected branches
deploy keys
webhooks
collaborators
permissions
-
Recreate Actions workflows from
.gitlab-ci.yml. -
Recreate secrets through the destination secret system rather than committing them.
-
Move container images/packages separately where applicable.
-
Run the destination CI pipeline.
-
Clone the new repo onto a clean machine.
-
Open a test PR.
-
Merge it through branch protections.
-
Mark that project
VALIDATED.
Forgejo's documented issues, pull requests, repository permissions, Actions, webhooks, package/container registries and integrated wiki establish the destination capabilities that should be tested. citeturn4search0
Gitea installation/migration¶
The installation architecture is almost identical:
VPS
-> reverse proxy/TLS
-> Gitea
-> PostgreSQL
-> persistent Git/LFS/package data
separate worker
-> Gitea Actions runner
backup
-> NAS
-> independent encrypted offsite
Use the official Gitea Git migration workflow to import GitLab repositories and migration-supported metadata. Gitea documents its migration mechanism directly. citeturn4search1
The validation checklist should be identical to Forgejo's because the dangerous migration failures are not “can Git be cloned?” but missing LFS objects, issues, CI behavior, permissions, webhooks, packages and secrets.
GitLab CE self-managed installation/migration¶
The continuity path is:
flowchart LR
GL[Existing GitLab] --> EXP[Project Exports / Repository Transfer]
EXP --> CE[Self-managed GitLab]
CE --> RUN[GitLab Runner]
CE --> BK[GitLab Backup]
BK --> NAS[(NAS)]
NAS --> OFF[(Encrypted Offsite)]
Runbook:
- Provision a supported self-managed environment.
- Install GitLab CE through an official supported installation method.
- Configure the production hostname/TLS.
- Create administrative credentials.
- Configure mail and authentication.
- Install/register a runner.
- Configure GitLab's native backup facility before production cutover. GitLab documents backup and restore administration for self-managed installations. citeturn4search2
- Import a low-risk project.
- Validate repository, MR/issues, wiki, CI, artifacts/packages/registry as applicable.
- Run the existing
.gitlab-ci.yml. - Test backup.
- Destroy a test instance and restore it.
- Bulk migrate only after that restore succeeds.
The major advantage is that this route minimizes CI conversion.
The major disadvantage is that Bluefly remains the operator of GitLab's broader application stack.
CI migration¶
Do not mechanically translate all GitLab pipelines at once.
Inventory pipeline capabilities first:
stages
includes
templates
images
services
variables
protected variables
environments
rules
needs/dependencies
artifacts
caches
scheduled pipelines
manual jobs
deployment credentials
child pipelines
Then convert one representative project from each pipeline class:
Drupal/PHP
Node
Python/AI
container build
deployment
scheduled automation
documentation
Forgejo documents its Actions model, runner configuration and use of actions. citeturn4search0
The target principle is:
.gitlab-ci.yml
↓ intentional conversion
.forgejo/workflows/*.yml
↓
Forgejo Actions
↓
isolated Forgejo Runner
Do not write a Bluefly CI translation/orchestration service.
Container registry migration¶
Treat container images as an independent dataset.
For each image that must survive:
inventory source tags
pull source image
verify digest
tag for destination
push to destination
verify destination digest
Forgejo documents a built-in Container Registry as part of its package-registry suite. citeturn4search0
Do not assume a Git repository importer also copied registry blobs.
LFS migration¶
For every repository identified as using LFS:
git lfs fetch --all
git lfs push --all DESTINATION
Then clone on a machine with an empty LFS cache and verify the actual large files.
Checking only Git commits is insufficient.
Wiki migration¶
Treat each wiki as data.
Validate:
pages
page history
links
attachments
permissions
Forgejo includes an integrated wiki destination. citeturn4search0
Agent migration¶
Do not preserve old GitLab personal tokens as the new control plane.
Create fresh destination service identities:
flowchart LR
Agent[Agent Runtime]
Token[Scoped Forge Token]
API[Forgejo API]
Branch[Agent Branch]
PR[Pull Request]
Actions[Actions]
Main[Protected Main]
Agent --> Token --> API
API --> Branch --> PR --> Actions --> Main
Forgejo's API, authorized integrations, access-token scope, webhooks and permission documentation are designed to provide these integration primitives. citeturn4search0
GitHub Cloud migration¶
For GitHub, distinguish Git data migration from platform migration.
At minimum:
Git refs -> GitHub
LFS -> GitHub LFS
issues/MRs -> migration/import process
CI -> GitHub Actions
registry -> GHCR or retained external registry
secrets -> GitHub secrets
webhooks -> GitHub integrations
permissions -> organizations/teams
agents -> GitHub API/app/token integration
Do not infer from a successful git push --mirror that GitLab has been successfully decommissioned.
Bitbucket migration¶
The same principle applies:
Git -> Bitbucket repositories
GitLab CI -> Bitbucket Pipelines or external CI
issues -> validated migration path
LFS -> validate explicitly
registry -> external/selected registry
secrets -> new secret store
webhooks -> recreate
permissions -> workspace/repository controls
Its case is strongest where Atlassian integration already reduces organizational complexity.
Codeberg migration¶
Because Codeberg runs the same general Forgejo-style development model, it is conceptually appealing for an open-source-first organization.
Before selecting it as Bluefly's primary commercial/private forge, confirm the current:
private repository policy
organizational/commercial-use expectations
storage quota
LFS quota
package/container policy
Actions/CI availability
runner policy
backup/export guarantees
support expectations
Those current policies were not sufficiently verified from primary sources in the final retrieval used for this report, so they remain a decision gate rather than an assumption.
SourceHut migration¶
Plan it as a workflow migration rather than a drop-in GitLab replacement:
Git repositories
issue/ticket system
build manifests
mail/patch workflow
access controls
deployment automation
Use it only after the team has intentionally chosen the SourceHut collaboration model.
Gogs migration¶
Gogs could accept the repository-hosting portion of the workload, but CI/agent workflows would need external services.
Under the upstream-first design rule, adding those components provides little advantage over selecting a forge that already contains the needed workflow capabilities.
Phorge migration¶
A serious Phorge move would require explicit mapping of:
GitLab repository -> repository hosting
MR -> Differential-like review
issues -> task system
CI -> separate CI
registry -> separate registry
packages -> separate package service
agent events -> custom integration/API mapping
That is the opposite direction from the goal of reducing maintenance.
Migration, cutover, rollback, and no-interruption plan¶
Schedule to beat the December deadline¶
The subscription expiration is December 15, 2026. The operational deadline should be one month earlier.
| Date | Milestone | Exit condition |
|---|---|---|
| Sep 23–30 | Inventory GitLab | Every project/integration accounted for |
| Oct 1–7 | Forgejo POC | Git + issue/PR + Actions + agent + registry test |
| Oct 8–14 | Backup/DR POC | Restore into fresh machine succeeds |
| Oct 15–21 | Pilot migration | Several representative repos fully migrated |
| Oct 22–31 | CI conversion | Representative pipeline classes working |
| Nov 1–7 | Production platform | DNS, security, monitoring, backup ready |
| Nov 8–14 | Bulk migration | All repos staged and validated |
| Nov 15 | Production cutover | New forge becomes authoritative |
| Nov 16–23 | Soak period | Team operates entirely on new forge |
| Nov 24–30 | DR exercise | Full restore proven |
| Dec 1 | GitLab independence date | Nothing operational depends on GitLab |
| Dec 1–14 | Read-only safety period | Final exports/checksums retained |
| Dec 15 | Subscription expires | No service interruption |
The central point is that December 15 is not the migration date.
It is the date by which the migration should already be boring history.
Cutover runbook¶
Two days before cutover:
- Confirm every repository has a migration-status record.
- Confirm new CI workflows.
- Confirm agent credentials.
- Confirm registry/package targets.
- Confirm users can authenticate.
- Confirm branch protections.
- Confirm NAS backup has completed.
- Confirm offsite backup has completed.
- Confirm a restoration test succeeded.
- Lower any DNS TTLs relevant to the change.
At cutover:
- Announce the short write freeze.
- Stop new GitLab merges/issue mutations.
- Run the final repository synchronization.
- Run final LFS synchronization.
- Complete final metadata/import delta.
- Transfer registry/package deltas.
- Recreate final secrets/variables.
- Trigger backup.
- Validate backups.
- Change canonical repository URLs.
- Update documentation.
- Repoint webhooks.
- Repoint deployment integrations.
- Change agent API endpoints.
- Update local remotes.
- Run representative CI.
- Merge one controlled test PR.
- Run one controlled deployment.
- Lift the write freeze on the new forge.
- Leave GitLab untouched as the fallback system.
Developer remote change¶
Typical developers would change:
git remote -v
git remote set-url origin ssh://[email protected]/ORG/REPO.git
git remote -v
Automation should be updated through configuration management rather than manually wherever possible.
Rollback plan¶
Rollback must be possible without inventing a new migration strategy during the incident.
flowchart LR
GL[GitLab<br/>old authority]
Freeze[Write Freeze]
F[New Forge<br/>candidate authority]
Validate{Acceptance<br/>tests pass?}
GL --> Freeze --> F --> Validate
Validate -->|Yes| Prod[New Forge Production]
Validate -->|No| Back[Rollback]
Back --> GL
During the initial cutover window, GitLab remains intact.
If acceptance fails before significant work begins on the new system:
- stop writes on the new forge;
- determine whether new commits exist;
- sync any required Git commits back;
- repoint developers/integrations to GitLab;
- re-enable GitLab as authoritative;
- diagnose the new environment offline.
The difficult rollback data is not Git commits. It is issue comments, PR activity, merges, CI state and other metadata created after cutover.
Therefore keep the hard cutover window short and perform all realistic tests before lifting the freeze.
Rollback decision triggers¶
Rollback rather than debug live if:
repositories cannot reliably clone/push
LFS object integrity fails
authentication fails broadly
branch protections are ineffective
critical CI cannot execute
critical deployments fail
agent credentials exceed intended scope
backup cannot be produced
database exhibits corruption
critical integrations are missing
Final GitLab preservation¶
Before expiry, retain:
GitLab project exports
bare Git mirrors
LFS copies
wiki copies
registry inventory / required images
package inventory / required packages
issues/MR exports where available
CI configuration
integration inventory
user/team mapping
audit/migration logs
checksums
GitLab's own self-managed documentation distinguishes application backup and restoration from simply possessing repositories, reinforcing the importance of preserving system state rather than only .git directories. citeturn4search2
Store the final migration archive in at least two independent locations.
Final acceptance checklist¶
The GitLab subscription is safe to expire only when every relevant box is true:
| Area | Acceptance test |
|---|---|
| Repositories | All expected repositories present |
| Commits | Representative commit IDs match |
| Branches | All expected branches present |
| Tags | Tags/releases validated |
| LFS | Fresh clones retrieve LFS content |
| Issues | Required issues/history available |
| PR/MR history | Required review history available |
| Wiki | Required wiki data available |
| Users | Active people can authenticate |
| Teams | Permissions match intended access |
| Protected branches | Direct unauthorized pushes rejected |
| Agents | Dedicated scoped credentials working |
| CI | Required pipelines pass |
| Runners | Isolated and operational |
| Secrets | Recreated and old tokens rotated |
| Webhooks | External integrations receiving events |
| Registry | Required images pull successfully |
| Packages | Required packages available |
| Deployments | Representative production deploy succeeds |
| Backups | Automated backup completes |
| Offsite | Independent offsite copy exists |
| Restore | Fresh-host restore has succeeded |
| Monitoring | Failure/backup health observable |
| Documentation | New canonical URLs documented |
| Developer machines | Remotes moved |
| Production automation | No GitLab URLs/tokens remain |
| External services | No hidden GitLab OAuth/webhook dependency |
| GitLab | Final export retained and checksum verified |
A useful automated final search is to scan configuration and documentation repositories for:
gitlab.com
GITLAB_
gitlab-ci
old SSH URLs
old registry URLs
GitLab webhook URLs
GitLab access tokens
A hit does not necessarily mean a problem, but every hit should be explained.
Final recommendation and decision record¶
Recommended target state¶
Adopt this as the default design:
flowchart TB
subgraph USERS["Bluefly"]
Dev[Humans]
Agents[AI Agents]
end
subgraph DC["Independent Datacenter"]
Forge[Forgejo<br/>Primary Forge]
PG[(PostgreSQL)]
Store[(Git / LFS / Packages)]
Runner[Isolated Actions Runner]
end
subgraph HOME["Home"]
NAS[(NAS<br/>Backup + Snapshots)]
Runner2[Optional Trusted Runner]
end
subgraph THIRD["Independent Backup Domain"]
Cloud[(Encrypted Object Backup)]
Mirror[(Secondary Git Mirror)]
end
Dev --> Forge
Agents -->|Scoped API/Webhooks| Forge
Forge --> PG
Forge --> Store
Forge --> Runner
Forge --> Runner2
Forge -->|Application backup| NAS
PG -->|DB backup| NAS
Store -->|Data backup| NAS
NAS -->|Encrypted replication| Cloud
Forge -->|Code mirror| Mirror
Forgejo's first-party documentation confirms that the platform exposes the key integrated building blocks required for this design: repository collaboration, permissions, API, scoped token access, webhooks, mirrors, Actions and runners, wiki, package registry and container registry, with documented installation and upgrade processes. citeturn4search0
Why this wins¶
It addresses each goal directly:
| Goal | Architecture response |
|---|---|
| Save money | Small forge instead of a large GitLab subscription/stack |
| Own the code | Complete self-hosted forge under Bluefly control |
| Back up code | VPS + NAS + independent encrypted offsite + Git mirror |
| Survive house fire | Primary and another backup do not live in the house |
| Survive NAS death | Production remains online; offsite copy also exists |
| Survive VPS death | Restore from NAS/offsite onto replacement VPS |
| Manage agents | Scoped API identities + webhooks + protected PR workflow |
| CI/CD | Native Actions first |
| Team collaboration | Issues, PRs, wiki, projects, permissions |
| Container images | Integrated registry capability |
| Avoid custom code | Use upstream forge/actions/runner implementations |
| Avoid lock-in | Git, exports, backups and second independent mirror |
| Control operational burden | One primary application stack rather than forge + custom CI + custom agent platform |
Architecture decisions I would explicitly reject¶
Do not use the home NAS as the only copy.
Do not call RAID a backup.
Do not call a Git mirror a complete forge backup.
Do not install both Gitea and Forgejo in production.
Do not add Drone merely because GitLab used an external-looking runner model.
Do not build a Bluefly CI scheduler.
Do not build a Bluefly agent orchestration layer into the forge.
Do not give agents administrator tokens.
Do not run untrusted PR workloads on a runner that can read NAS backups.
Do not wait until December to discover that .gitlab-ci.yml needs conversion.
Do not let December 15, 2026 become the production migration day.
Decision gates for the first week¶
Forgejo becomes the selected platform if the POC proves all of these:
| Gate | Required result |
|---|---|
| GitLab import | Representative repo migrated |
| Metadata | Critical issues/PR history acceptable |
| LFS | Fresh clone works |
| CI | Representative pipeline works in Actions |
| Agent | Agent creates branch/PR through scoped token |
| Permissions | Agent cannot bypass protected branch |
| Webhooks | Agent/integration receives events |
| Registry | Required image can push/pull |
| Backup | Full backup produced |
| Restore | Fresh instance restored |
| UX | Team finds review workflow acceptable |
If Forgejo fails one or more material gates, repeat against Gitea. Gitea's documented GitLab migration mechanism makes it the natural second candidate. citeturn4search1
If both fail because Bluefly depends deeply on GitLab-only semantics, move to self-managed GitLab CE rather than writing compatibility infrastructure. GitLab's documented backup/restore operations then become a core production requirement. citeturn4search2
Final decision¶
Target: Forgejo
Primary location: small cloud VPS/datacenter
Database: PostgreSQL
CI: Forgejo Actions
Runners: separate isolated worker(s)
Agent integration: API + webhooks + scoped service accounts
Human workflow: agents submit PRs into protected branches
First backup: home NAS
Second backup: independently administered encrypted offsite object storage
Additional resilience: independent Git mirror
Internal cutover deadline: November 15, 2026
GitLab independence deadline: December 1, 2026
Subscription expiry: December 15, 2026
The strategic change is larger than replacing GitLab with another logo:
Bluefly should own a portable, reproducible development system whose loss of any one vendor, server, NAS, account, network, or physical building does not result in loss of the company's code.
Forgejo is currently the strongest match because the upstream project already supplies the collaboration, permissions, API, automation, runner, registry and administration primitives that Bluefly needs without requiring Bluefly to become the maintainer of another custom platform. citeturn4search0
Research limitations and source status¶
This report intentionally gives the highest confidence to the candidates for which current first-party material was retrieved during the research session. Forgejo's current official documentation was available and directly documents its broad feature and operations surface. citeturn4search0 Gitea's official migration documentation was retrieved and supports the GitLab-migration assessment. citeturn4search1 GitLab's current official backup/restore documentation was retrieved and supports the self-managed continuity and DR analysis. citeturn4search2
Current first-party pricing/quota pages for GitHub, Bitbucket, Codeberg and hosted SourceHut, and current first-party capability pages for Gogs, Phorge and Drone/Woodpecker, were not successfully retrieved in the final source set. Consequently, this document deliberately does not present exact 2026 prices, storage quotas, CI-minute allowances or private/commercial-use allowances for those services as established facts. Those values should be treated as final procurement checks, not assumptions.
That evidence gap does not undermine the principal architecture decision: the decisive requirements—open-source ownership, GitLab migration, integrated collaboration, native automation, API/webhook-based agent access, independent backups, and survivability after loss of the home NAS—can be evaluated directly against the verified Forgejo, Gitea and GitLab paths above.