Skip to content

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. citeturn4search0

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. citeturn4search1

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.” citeturn4search2

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:

  1. an authenticated API;
  2. scoped service credentials;
  3. webhooks/events;
  4. Git/SSH access;
  5. 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.” citeturn4search0

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. citeturn4search0

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. citeturn4search0

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. citeturn4search0turn4search1

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. citeturn4search0

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. citeturn4search0

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. citeturn4search1

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. citeturn4search2

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. citeturn4search0

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.

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. citeturn4search0

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. citeturn4search0

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. citeturn4search2

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:

  1. create an empty replacement VM;
  2. install the supported Forgejo release;
  3. restore configuration;
  4. restore database;
  5. restore Git/LFS/package data;
  6. start the instance under a temporary hostname;
  7. clone multiple repositories;
  8. open issues/PRs;
  9. authenticate;
  10. run an Action;
  11. pull a container/package if those facilities are used;
  12. 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. citeturn4search0

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. citeturn4search0

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. citeturn4search0

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. citeturn4search0

A production rollout should proceed in this order:

  1. Provision a small VPS. Start conservatively rather than over-sizing. Keep build workloads off the application host.

  2. Create DNS, for example:

git.bluefly.io
  1. Install a supported container/runtime or native package method from Forgejo's official deployment guidance. Pin an explicit supported release rather than latest. citeturn4search0

  2. Use a persistent database. For a business production installation I would choose PostgreSQL rather than optimizing around the absolute fewest processes.

  3. Create persistent application storage for:

Git repositories
Git LFS
attachments
packages
container data
configuration
database
  1. Terminate TLS using the upstream-supported reverse-proxy pattern. Forgejo documents reverse proxy configuration. citeturn4search0

  2. Configure:

external URL
SSH clone URL/port
SMTP
registration policy
session/security settings
storage
logging
  1. Create the Bluefly organization and administrator.

  2. Configure human authentication and MFA policy.

  3. Recreate teams and least-privilege repository permissions. Forgejo provides repository permissions and authentication/integration facilities. citeturn4search0

  4. Install the Forgejo runner on another machine, not the production forge. Follow the project's runner registration and security documentation. citeturn4search0

  5. Create the backup job.

  6. Perform a restoration test before importing production data.

  7. 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:

  1. Record source project ID, canonical path and owner.

  2. Export GitLab project metadata where supported.

  3. Create/import the destination repository.

  4. Verify all branches:

git branch -a
  1. Verify tags:
git tag
  1. For independent Git verification, create a bare/mirror clone:
git clone --mirror [email protected]:GROUP/REPO.git
  1. 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.

  1. Where LFS is used:
git lfs fetch --all
git lfs push --all DESTINATION
  1. Migrate/validate the wiki separately where present.

  2. Compare:

default branch
branches
tags
commits
releases
issues
issue comments
merge/pull requests
labels
milestones
wiki
attachments
protected branches
deploy keys
webhooks
collaborators
permissions
  1. Recreate Actions workflows from .gitlab-ci.yml.

  2. Recreate secrets through the destination secret system rather than committing them.

  3. Move container images/packages separately where applicable.

  4. Run the destination CI pipeline.

  5. Clone the new repo onto a clean machine.

  6. Open a test PR.

  7. Merge it through branch protections.

  8. 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. citeturn4search0

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. citeturn4search1

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:

  1. Provision a supported self-managed environment.
  2. Install GitLab CE through an official supported installation method.
  3. Configure the production hostname/TLS.
  4. Create administrative credentials.
  5. Configure mail and authentication.
  6. Install/register a runner.
  7. Configure GitLab's native backup facility before production cutover. GitLab documents backup and restore administration for self-managed installations. citeturn4search2
  8. Import a low-risk project.
  9. Validate repository, MR/issues, wiki, CI, artifacts/packages/registry as applicable.
  10. Run the existing .gitlab-ci.yml.
  11. Test backup.
  12. Destroy a test instance and restore it.
  13. 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. citeturn4search0

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. citeturn4search0

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. citeturn4search0

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. citeturn4search0

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:

  1. Confirm every repository has a migration-status record.
  2. Confirm new CI workflows.
  3. Confirm agent credentials.
  4. Confirm registry/package targets.
  5. Confirm users can authenticate.
  6. Confirm branch protections.
  7. Confirm NAS backup has completed.
  8. Confirm offsite backup has completed.
  9. Confirm a restoration test succeeded.
  10. Lower any DNS TTLs relevant to the change.

At cutover:

  1. Announce the short write freeze.
  2. Stop new GitLab merges/issue mutations.
  3. Run the final repository synchronization.
  4. Run final LFS synchronization.
  5. Complete final metadata/import delta.
  6. Transfer registry/package deltas.
  7. Recreate final secrets/variables.
  8. Trigger backup.
  9. Validate backups.
  10. Change canonical repository URLs.
  11. Update documentation.
  12. Repoint webhooks.
  13. Repoint deployment integrations.
  14. Change agent API endpoints.
  15. Update local remotes.
  16. Run representative CI.
  17. Merge one controlled test PR.
  18. Run one controlled deployment.
  19. Lift the write freeze on the new forge.
  20. 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:

  1. stop writes on the new forge;
  2. determine whether new commits exist;
  3. sync any required Git commits back;
  4. repoint developers/integrations to GitLab;
  5. re-enable GitLab as authoritative;
  6. 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. citeturn4search2

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

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. citeturn4search0

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. citeturn4search1

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. citeturn4search2

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. citeturn4search0

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. citeturn4search0 Gitea's official migration documentation was retrieved and supports the GitLab-migration assessment. citeturn4search1 GitLab's current official backup/restore documentation was retrieved and supports the self-managed continuity and DR analysis. citeturn4search2

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.