Ligit
Self-hosted Git server with integrated CI/CD engine and web UI
The problem
I wanted a small self-hosted Git host with built-in CI that I could run on my own machine. Gitea and GitLab are heavy to operate, and I wanted to understand how the pieces fit together. If you just need a Git server, Gitea is the better choice. Ligit was about building one. The users were me and small side-project setups.
Key decisions
Split Git access in two. Browsing (trees, logs, diffs, branches, tags) goes through a C++ library on libgit2, exposed to Java over JNI, which gives fast in-process reads for the UI. Clone, fetch and push go through the real git-upload-pack and git-receive-pack subprocesses. Reimplementing the wire protocol is risky and gains nothing.
Run CI steps in Docker. A push creates a pipeline run. Each job with an image gets a container with the workspace mounted, and steps run through docker exec. Containers drop all capabilities, set no-new-privileges, and are capped at 512 MB and 1 CPU. Workflows use GitHub-Actions-style YAML, so the format is familiar. Step output streams live into the database and reaches the UI over SSE.
Tradeoffs
- Execution is basic. Each pipeline runs in a single
@Asyncmethod, with no real queue, concurrency limits, retries or persisted scheduling. If the app restarts mid-run, that run is lost. - Isolation isn’t hardened. Jobs with no image fall back to running bash on the host, which is unsafe for untrusted code.
- Workspaces are fresh every run in
/tmp, with no caching. - Auth was bolted on late. JWT, an admin user, and an SSH server on Apache Mina, with HTTP push blocked. It works, but it was retrofitted instead of designed in.
- JNI plus C++ in a Java service adds build and deploy complexity for a modest gain.
If I rebuilt it: a real job queue with worker limits, every job in a container, and auth designed from the start.
Outcome
I built it in early 2026 (first commit 27 February). It runs as a single container plus Postgres via Docker Compose. I’ve stopped running it for now, because the machine that hosted it is being used for other learning.
What I took from it: Git’s smart-HTTP protocol, JNI, subprocess streaming, and how much of a CI system is process and lifecycle management. The source is private for now.