A deep dive into my Forgejo setup

alexfortin1 pts1 comments

A deep dive into my Forgejo setup • Alexander FortinA deep dive into my Forgejo setup<br>2026-07-2019 min#forgejo<br>#selfhost<br>#ansible<br>#docker<br>#podman<br>#systemd<br>#devops<br>#terraform<br>#opentofu<br>#gitops<br>#axiom

Like many others recently I got fed up by what seems to be a steady and inexorable degradation of GitHub quality of service (more on that later) and decided to walk down the self host path for all my things Git, Docker, PRs and CI/CD .

In this article I’m going to show you with some level of detail how my new self hosted Forgejo 1 setup currently looks like and how well it fits me as a near total replacement for GitHub (spoilers ahead: very well).

I’ll provide links to actual repositories plus snippets of reusable configuration in case you might want to try it for yourself.

Why Forgejo#

To be honest I didn’t spend much time selecting which OpenSource git forge to adopt.

I heard well about other options like SourceHut for example BUT

I already had a Codeberg (the company behind Forgejo development) account and I like their mission

it exposes most of GitHub APIs verbatim so things like GitHub actions should work out of the box

it’s feature rich, considered stable and follows a regular release cycle

the UI is almost identical to GitHub’s

it’s written in Go, I like Go

Not exhaustive and much for an heuristic, I suppose, but has been enough for me.

How it looks like#

The forge is live at https://forge.l3x.in and is already home for a few of my OpenSource projects and all of my private repositories, with plans to migrate there most of the others I currently have on GitHub (more on that later).

Everything so far works pretty well: the web UI feels familiar and snappy, migrating / mirroring repos is just a click away, and CI/CD latency and build times are fantastic ⚡️ Just a quick comparison from a single project involving Docker (Podman) build to prove the point:

on GitHub: 20m 54s

on my Forgejo Runner: 3m 19s

Almost 18 minutes saved for building (and pushing to registry) the very same application, not to mention from now on I won’t have to wait for my turn in the GH build queue.

This win alone might have been worth the effort, I’ll expand on what works better than on GitHub and what not later on but let’s get into some technical details first.

The Stack#

A comprehensive list of the components making up my forge:

a small Debian Trixie amd64 VPS to host all the things

Systemd and Podman (Quadlets) to manage the services and recurring tasks

Caddy to terminate TLS requests and auto renew certificates

Forgejo and Forgejo runner for CI/CD

Webhook to restart services programmatically

Ansible and OpenTofu to configure all the things the GitOps way

Renovate to keep everything installed up to date

Restic to backup Podman volumes2 daily

Axiom (via Vector) to collect Journald logs and alert on errors

Virtual Private Server#

I pay an annual subscription (~60€) to OVH3 in exchange for a dedicated Linux amd64 VPS with 4 vCPUs cores, 8GB of ram, 75 GB of storage, plus one fixed IPv4 and one IPv6 address. It might not sound like much but you’d be surprised by how much something so low profile can still punch nowadays 🥊

Nothing fancy on the OS side either: I’m an old time Debian user and I already have a bunch of Ansible roles to setup on said VPS common services like SSHd, Postfix and so on; it comes natural to just drop another role for a new service whenever a new itch needs scratching.

What changed now thanks to having my personal Forgejo is how I run config management / IaC tools like Ansible and OpenTofu. More on that later.

Service Managers#

For this project I decided to teach myself some Podman, with me having been using Docker for all of my containerize history so far.

TL;DR : Docker Desktop is gone from my MacBook as I now use Podman exclusively for all the things containers both on my macOS workstation and Linux servers.

Contrary as with Docker, with Podman there’s no need for any dedicated daemon process proxying commands and Quadlets work remarkably well in tandem with Systemd to run containerized services.

I now run all Podman containers as rootless and once the service unit files are created I can for example start/stop/inspect services with the usual systemctl / journalctl commands you might be already familiar with.

Once services are enabled (systemctl enable), Systemd will take care of keeping them up and running after a host reboot, application crash, accidental podman kill, etc.

Example: manage Forgejo process#

This is how the unit file for Forgejo looks like:

#...

forgejo like podman github docker services

Related Articles