I wanted johnie.eu's code on a platform that gave me git, issues, and CI without pulling the project back into US jurisdiction. I also wanted software I could self-host if I ever had to leave. That platform turned out to be Codeberg.
Codeberg, briefly
Codeberg is operated by Codeberg e.V., a German non-profit association registered in Berlin. It runs on Forgejo, the community-led fork of Gitea. That matters because the hosted service and the self-hosted software are the same thing. If I ever want to leave Codeberg, I do not have to leave the platform model with it.
Why over GitHub
GitHub works. It is also a Microsoft-owned US service, which puts it on the wrong side of the jurisdiction line for this project.
A few other differences mattered too:
- AI scraping. Codeberg's robots.txt blocks the major AI crawlers. GitHub's public-repo story has moved the other way since Copilot.
- Self-hosting stays real. Forgejo is AGPL, so the path from hosted forge to self-hosted forge stays open.
- The pricing model is simple. Codeberg is free for open-source projects under fair use. There is no enterprise funnel sitting behind every workflow run.
- The service has less friction. No mandatory phone number, lighter ceremony, fewer nudges.
None of this makes Codeberg the default answer for every team. It made it the right answer for a site built around an EU-first stack.
The Forgejo question
Codeberg's workflow story is Forgejo Actions, which stays very close to GitHub Actions. The YAML shape is the same. Jobs, steps, matrices, secrets, artifacts, and expressions work the way you expect.
The two changes I actually had to care about were small:
- Action references use full URLs. Instead of
actions/checkout@v4, you writehttps://code.forgejo.org/actions/checkout@v4. Forgejo's runner is happy to fetch from any HTTPS source, includinggithub.com, but the convention is to point at the Forgejo-mirrored copy so a GitHub outage doesn't break Codeberg CI. forgejo.refinstead ofgithub.ref. The context is renamed. Otherwise the keys are the same.
That is most of the adjustment.
What a Forgejo workflow looks like
This site builds on every push to main, publishes a container image, then asks bunny.net Magic Containers to redeploy. The Forgejo-specific parts look like this:
jobs:
publish-latest:
if: ${{ forgejo.ref == 'refs/heads/main' }}
runs-on: codeberg-small
steps:
- uses: https://code.forgejo.org/actions/checkout@v4
- run: build-and-push-image
- run: trigger-bunny-redeploy
The verbatim workflow lives at .forgejo/workflows/publish-docker.yml. The rest is normal CI work: run Buildah, push an image, call an API. If you already know GitHub Actions, Forgejo will not slow you down.
Trade-offs, honestly
- Smaller action ecosystem. No GitHub Marketplace equivalent. Most of the actions you reach for (
checkout,setup-node,cache,upload-artifact) are mirrored atcode.forgejo.org/actionsand run unmodified. Niche third-party actions sometimes assume agithub.*context key or hit GitHub's API in ways that need patching. - CI is a shared resource. Hosted runners are fine for small open-source builds. Heavier jobs should move to a self-hosted runner.
- No Codespaces. No browser IDE. Bring your own editor.
- No first-party preview-deploy story. Vercel-style PR previews require wiring something up yourself.
- Search and discovery are thinner. GitHub still wins on ecosystem gravity.
- Network effect. Some collaborators won't have an account yet. For a personal blog this is a non-issue; for a project that depends on drive-by contributors, factor it in.
One remaining US link on my stack
The bunny.net post covers the one part of this chain that still sits in the US: the container registry. Forgejo has its own package registry, but bunny.net Magic Containers only pulls from Docker Hub or GHCR. The day Bunny accepts Codeberg or any custom OCI registry, this workflow gets one-line simpler.
Migrating from GitHub
If you already have a GitHub repo, the move is light. Forgejo imports code, issues, pull requests, releases, wiki, and labels. SSH works the same way. Codeberg Pages covers static hosting. If you still want GitHub for SEO or discoverability, you can keep a one-way mirror and treat Codeberg as the source of truth.
What I got
johnie.eu's code now lives on a non-profit code host under German law, on software I could run myself, with CI that looks almost exactly like GitHub Actions. I gave up some ecosystem weight and close to no daily workflow.
If you want a European alternative to GitHub for a personal project, Codeberg takes the least explaining. This post, like the workflow behind it, fits the same theme as the Mistral and bunny.net pieces: the EU version of the usual stack is already usable.