The developer ecosystem is showing increasing signs of unease with centralized git hosting, and the reasons go beyond mere sentiment. Vendor lock-in has become a tangible risk as pricing tiers shift without warning, feature access is bundled into expensive enterprise plans, and usage data is fed into AI training pipelines—a concern that escalated when GitHub defaulted to opting public repositories into Copilot training, raising questions about code exposure and privacy erosion. These developments have pushed many teams to reevaluate their dependency on a single platform. Consider the post-acquisition uncertainty surrounding GitHub under Microsoft, or the introduction of Copilot’s paid features that surprised many open-source contributors. The discomfort is pragmatic: what happens when the platform you trusted changes its policies overnight? This guide explores the two primary paths forward. For teams that want to remove GitHub from their stack without managing infrastructure, there is Codeberg, a non-profit, community-run platform built on Forgejo. For those needing full control, compliance, or customization, self-hosting with Gitea or Forgejo on a VPS or local server offers complete autonomy. This article is not a rant against centralized hosting—it is a practical comparison and migration guide to help you choose and execute the right alternative for your team’s size, budget, and governance needs.
Why Teams Are Questioning Their GitHub Dependency
The initial discomfort with centralized git hosting has evolved into a strategic reevaluation for many teams. While GitHub remains a powerful platform, practical risks are pushing developers to consider alternatives.
Rising Costs: What started as a generous free tier now feels like a subscription creep. Private repositories are free for small teams, but features like GitHub Actions, large file storage, and advanced code review tools quickly inflate monthly bills. A team needing 3,000 minutes of Actions minutes per month, for example, could spend $50 or more monthly—costs that grow linearly with team size, outpacing the value for many bootstrapped projects.
Governance Instability: Microsoft’s 2018 acquisition introduced an underlying concern: GitHub is now a product owned by a corporation with shifting priorities. When Microsoft integrated Copilot and later changed its terms of service for data usage, it showed that governance can change without user consent. If Microsoft decides to overhaul the free tier, introduce new licensing restrictions, or pivot toward enterprise-only features, users have no recourse. This lack of democratic control makes GitHub a liability for teams that value long-term stability.
Privacy and Training Data Concerns: Copilot’s training practices have amplified privacy anxieties. Code pushed to public repositories has been used to train machine learning models without explicit opt-in. For teams working on proprietary algorithms or client projects, this raises legitimate concerns about intellectual property exposure. Even with private repositories, the underlying infrastructure—now tightly integrated with Microsoft’s AI services—creates uncertainty around data boundaries.
Single Point of Failure: Relying on one service means accepting its downtime and terms changes without recourse. An hours-long GitHub outage can halt deployments, block PR reviews, and stop your entire software delivery pipeline. Terms changes often come with short notice, leaving teams scrambling to adapt. This fragility is especially dangerous for organizations that need guaranteed uptime or compliance with data residency laws, as GitHub’s global infrastructure may not align with local regulations.
For teams that feel these pressures, the question is not whether to leave GitHub, but which alternative—community-run Codeberg or self-hosted Gitea/Forgejo—offers the right balance of control, cost, and reliability.
Codeberg vs Self-Hosting: Which Path Fits Your Team?
Once you've decided to move away from GitHub, the next choice is between a community-run platform and full self-hosting. Both paths offer meaningful advantages over centralized services, but they serve different needs.
Codeberg is a non-profit, community-governed platform hosted in the EU. It operates without ads, venture capital pressure, or the risk of acquisition-led changes. For individual developers or small, non-commercial projects, Codeberg is the easiest drop-in alternative. You get free, ethical hosting with built-in issue tracking, pull requests, and a UI similar to GitHub. However, Codeberg runs on shared infrastructure with limited resources. There is no service-level agreement (SLA), and feature updates often lag behind GitHub or self-hosted options. If your project needs guaranteed uptime or specialized CI/CD runners, Codeberg may feel constrained.
Self-hosting with Gitea or Forgejo hands you complete control over your data, workflows, and hosting environment. This path suits teams that must comply with data residency regulations, need custom hooks or CI integrations, or simply want to own their infrastructure. You choose the hardware, set the update schedule, and configure access policies exactly to your needs. The trade-off is maintenance overhead. You are responsible for backups, security patches, database tuning, and disaster recovery. A misconfigured self-hosted server can be a greater liability than relying on GitHub's managed platform. This path demands at least one person on the team comfortable with Linux administration and database management.
| Decision Factor | Codeberg | Self-Hosted (Gitea/Forgejo) |
|---|---|---|
| Team size | Solo to small team | Any, but best for teams with ops support |
| Budget | Free | VPS/server + maintenance time |
| Technical ability | Basic git knowledge | Server admin skills required |
| Compliance needs | Minimal | Full control for strict requirements |
| Uptime commitment | Best-effort | You own the SLA |
A solo developer building an open-source side project is well served by Codeberg. A startup handling customer data under GDPR or SOC 2 is better off self-hosting with Gitea on a VPS in a compliant region. Consider your team's capacity for ongoing maintenance as seriously as its need for control.
Setting Up Your First Self-Hosted Git Server with Gitea
Let’s move from theory to practice. By the end of this section, you’ll have a live Gitea instance running on a basic VPS, with SSH access and HTTPS enabled. This tutorial assumes you have a server with at least 1 GB RAM, 1 vCPU, and 20 GB storage — the minimum needed for a small team. A $10/month Linode or DigitalOcean droplet works perfectly.
Option 1: Docker Compose (Easiest)
If you have Docker and Docker Compose installed, this is the fastest path. Create a docker-compose.yml file:
version: "3"
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
restart: always
volumes:
- ./gitea_data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "22:22"
Run docker compose up -d, and Gitea will be available on port 3000. The key volume mapping is ./gitea_data:/data — this persists your repositories, database, and configuration. Never skip this; losing it means losing all your code.
Option 2: Binary Install
For those avoiding Docker, Gitea offers a standalone binary. Download the latest release for your architecture, make it executable, and run:
wget -O gitea https://dl.gitea.io/gitea/1.21.5/gitea-1.21.5-linux-amd64
chmod +x gitea
./gitea web
Gitea launches on port 3000 by default. For production, create a dedicated git user and set up a systemd service so it restarts automatically on reboot.
Initial Configuration & HTTPS
Open http://your-server-ip:3000 in your browser. The setup page asks for database type (SQLite is fine for small teams), admin credentials, and server domain. For HTTPS, the simplest method is to put Gitea behind a reverse proxy (like Caddy or Nginx) and use Let’s Encrypt. Here’s a minimal Caddyfile:
yourdomain.com {
reverse_proxy localhost:3000
}
Caddy automatically provisions and renews SSL certificates via Let’s Encrypt.
SSH Access & First Repository
In the Gitea admin panel, ensure SSH is enabled (it is by default). Add your public SSH key under your user settings. Now create a new repository — call it my-project — and push existing code from your local machine:
git remote add origin git@yourdomain.com:username/my-project.git
git push -u origin main
Common Pitfalls
-
Firewall ports: Ensure your VPS firewall allows traffic on ports 22 (SSH), 80 (HTTP), and 443 (HTTPS). With
ufw, runsudo ufw allow 22 80 443. -
Persistent storage: If using Docker, never delete the
gitea_datavolume. Back it up regularly. - SSH host key verification: When clients connect the first time, they’ll see a warning about an unknown host key. This is normal — just verify the fingerprint during setup.
Gitea gives you a GitHub-like experience in under 10 minutes. Your code stays on your server, under your control.
Migrating a Real Repository from GitHub to Codeberg
Moving an active repository from GitHub to Codeberg is a straightforward process if you follow a clear, step-by-step migration plan. The goal is to preserve your code history, issues, and pull requests so your team can continue working without disruption.
Step 1: Export your full repository data from GitHub
GitHub provides a built-in export tool under Settings > Archive. This creates a downloadable bundle containing all branches, tags, issues, pull requests, wiki pages, and repository metadata. While the export is being prepared, you can continue pushing to your GitHub repo. This is your safety net — keep the archive stored locally in case you need to restore anything later.
Step 2: Create a new repository on Codeberg
Log into Codeberg and create a new empty repository with the same name as your GitHub repo. Do not initialize it with a README, license, or .gitignore — you want a completely blank target.
Step 3: Push all branches and tags
Clone your GitHub repository with all branches: git clone --mirror https://github.com/your-org/your-repo.git. Then add Codeberg as a remote: git remote add codeberg https://codeberg.org/your-org/your-repo.git. Finally, push everything: git push --mirror codeberg. This transfers your entire commit history, all branches, and all tags.
Step 4: Migrate issues and pull requests
This is the trickiest part. GitHub's export tool gives you JSON files for issues and pull requests, but Codeberg uses a different data model. For a small number of issues (under 50), manual recreation is fastest. For larger repositories, use a migration tool like gitea-github-migrator (Gitea and Forgejo underpin Codeberg). This tool can import issues, comments, labels, milestones, and pull requests directly from your GitHub export. Be aware that issue and PR numbers will not match — you should communicate this change to your team in advance.
Step 5: Handle webhooks, CI/CD integrations, and secrets
After migration, update all webhooks that pointed to your GitHub repo. Common integrations include Slack notifications, CI runners, and deployment pipelines. On Codeberg, navigate to Settings > Webhooks and add each hook with the same payload URL and secret you used on GitHub. Regenerate any API tokens or deployment keys — never reuse secrets across platforms.
Step 6: Test the migrated repository
Before redirecting your team, clone the new Codeberg repo fresh: git clone https://codeberg.org/your-org/your-repo.git. Verify that:
- All branches are present:
git branch -a - Tags exist:
git tag - Issues and pull requests are visible in the Codeberg web interface
- A test commit is detected by any connected CI/CD tool
- Wiki pages render correctly if you migrated the wiki separately
Step 7: Redirect your team and set a cutoff
Communicate the new clone URL to your team and update any CI/CD pipeline configuration files. Set a clear date after which GitHub will no longer be the source of truth. Use git remote set-url origin to point local clones to Codeberg. Keep the GitHub repo as an archived backup for a month before deleting it.
This migration process ensures you don't lose history, active work, or team context. The key is methodical testing — rushing the transition is the most common cause of post-migration headaches.
Forgejo vs Gitea: Which Self-Hosted Fork Should You Choose?
In 2022, the Gitea project experienced a significant fork that created Forgejo, driven by governance disagreements. While Gitea originated as a community fork of Gogs, its trademark and infrastructure gradually came under the control of a for-profit company. Forgejo was forked by contributors who wanted a truly community-governed alternative. They established an open governance model, transferred trademark ownership to the Software Freedom Conservancy, and committed to transparent decision-making.
Forgejo's strengths center on its governance. It is managed via an open steering committee with rotating membership, ensuring no single entity can dictate direction. It also leads in federation via ActivityPub, enabling cross-instance interactions on issues, pull requests, and repositories—a step toward decentralized code collaboration. Stability is a core principle: releases are thoroughly tested, and breaking changes are rare. For teams that value long-term trust and community ownership, Forgejo is a natural fit.
Gitea, on the other hand, prioritizes velocity. New features ship more frequently—like advanced CI/CD integrations, a richer plugin ecosystem, and expanded API capabilities. Its documentation is more extensive, and the larger user base means more community-contributed guides and templates. If you need cutting-edge functionality or want to integrate with many third-party tools, Gitea likely offers what you need. However, some teams express concern over corporate influence and potential feature bloat.
When choosing between them, ask whether your team prizes governance and federation or rapid feature access and ecosystem breadth. For long-term community trust and alignment with ethical hosting values, Forgejo is recommended. If you want the most integrations and are comfortable with some corporate involvement, Gitea serves well. Both are excellent self-hosted git alternatives to GitHub—the decision ultimately reflects your team's priorities.
Critical Security and Maintenance Gotchas for Self-Hosted Git
Moving off GitHub means you inherit all the operational overhead that Microsoft’s SRE team used to handle for you. Without a disciplined maintenance routine, a self-hosted server can become a liability. Here are the specific pitfalls to watch for.
Automated Backup Plan
Your Git repositories are only as safe as your backup process. Set up a cron job that runs a nightly gitea dump (or forgejo dump) to create a compressed archive of the database, repositories, and config files. Transfer this dump to an off-server location such as an S3-compatible object store or a separate NAS. Test restores quarterly—an untested backup is no backup at all.
Keeping Software Up-to-Date
Both Gitea and Forgejo release security patches regularly. Subscribe to their GitHub release feeds or join the project mailing lists. Before applying updates, review the changelog for breaking changes (e.g., database migration scripts). Schedule updates during low-traffic windows and always snapshot your database first. A common regret is ignoring a patch for two months, then facing a forced upgrade that breaks custom integrations.
User Management Without GitHub’s UI
GitHub’s interface makes adding users, rotating keys, and enabling two-factor authentication (2FA) trivial. In a self-hosted environment, you must enforce these manually. Create a policy that requires all team members to upload SSH keys on account creation. Enable 2FA via TOTP in the admin panel. Regularly audit the user list and remove dormant accounts—especially if former employees still have access.
Disk Space and Resource Monitoring
Git repositories grow over time, especially those with large binary assets or many branches. Set up a monitoring tool like Netdata or Prometheus to track disk usage, memory, and CPU load. Configure alerts at 80% disk capacity. You can run git gc --aggressive periodically on large repos to reclaim space, but plan for storage expansion early—adding a new disk to a full server is stressful.
Server Compromise Response Plan
If an attacker gains access to your self-hosted git server, act immediately: isolate the server from the network, rotate all SSH keys and passwords, and audit logs for unauthorized pushes or changes. Restore the entire system from your most recent verified backup onto a clean machine. Then, investigate how the breach occurred—was it a vulnerable web UI, an exposed SSH port, or a weak credential? Document the incident to prevent recurrence. Many teams realize too late that they had no recovery drill; you can build one in an afternoon with a spare VM.
By addressing these gotchas upfront, you avoid the 'we should have stayed on GitHub' regret and gain the true benefit of self-hosting: control without chaos.
Building Your Hosting Strategy: From Codeberg to Production Apps
Self-hosting your Git repositories is a powerful first step, but it’s only the beginning of true stack ownership. Once you control your code, the next logical move is to take charge of how that code runs in the real world. A complete self-hosted stack includes CI/CD pipelines, automated deployments, staging environments, and production app hosting — all running on infrastructure you control.
Consider this practical progression: after migrating your repositories to Forgejo or Gitea, set up a CI runner that automatically tests and builds your code on every push. Tools like Woodpecker CI or Drone integrate directly with self-hosted Git forges and can deploy your application to a staging environment on the same VPS. That staging setup gives you the confidence to push to production without relying on a third-party platform’s availability or pricing changes.
To get started, pick one small project — maybe a personal blog or a team tool — and migrate it this week. Use that project to build a complete deployment pipeline: commit to your self-hosted forge, trigger a build, run tests, and deploy to a staging VM. Paradane’s guide at https://paradane.com offers complementary resources on deploying and managing full-stack applications, helping you connect the dots between source control and live hosting. Each deployment you automate reinforces your independence from centralized platforms and builds the operational muscle your team needs for the long haul.
Top comments (0)