Krolyxon
Tag v0.2.0

ferrenium

12 entries · Tree a374baf · History

README.md

Ferrenium

A read-only Git repository browser, like cgit, as a single Rust daemon. It serves every bare repository under one directory and keeps no state on disk.

Pages: repo index, summary + README, tree, file (highlighted), raw, log (path filter, message search), commit + diff, .patch, blame, refs, file finder, .tar.gz/.zip snapshots, Atom feed. git clone over HTTPS (read-only).

Install

On a Linux host with systemd (x86_64 or aarch64, glibc 2.28+):

curl -fsSL https://github.com/krolyxon/ferrenium/releases/latest/download/install.sh | sudo FERRENIUM_DOMAIN=git.example.com sh

This:

  • downloads the latest release binary, verifies its checksum and installs it to /usr/local/bin/ferrenium
  • creates the git user if it doesn't exist (home /home/git, shell git-shell)
  • writes /etc/ferrenium/ferrenium.toml (never overwritten on later runs)
  • installs /etc/systemd/system/ferrenium.service and runs systemctl enable --now ferrenium

Variables: FERRENIUM_DOMAIN (fills base_url and clone URLs in a new config), FERRENIUM_USER (default git), FERRENIUM_VERSION (e.g. v0.1.0, default latest).

Run the same command again to upgrade: it replaces the binary and unit and restarts the service. To remove it: … | sudo sh -s -- --uninstall. This keeps /etc/ferrenium and the repositories.

The service

It's a normal system service. The unit has User=git, so systemd starts it as the repo owner. You don't need su git or systemctl --user.

sudo systemctl status ferrenium
sudo systemctl reload ferrenium      # after editing the config
sudo journalctl -u ferrenium -f
sudo systemctl edit ferrenium        # overrides; survive upgrades

The unit is sandboxed: the filesystem is read-only, there are no capabilities, a syscall filter applies, and only localhost may connect.

Reverse proxy

Ferrenium listens on 127.0.0.1:8080 (plain HTTP/1.1). Caddy:

git.example.com {
	reverse_proxy 127.0.0.1:8080
}

If Caddy runs in Docker, use network_mode: host so it can reach 127.0.0.1.

Repositories

Put bare repositories anywhere under /home/git (up to 3 levels deep). Ferrenium picks up new repos and pushes within about a second.

sudo -u git git init --bare /home/git/project.git
git push git@git.example.com:project.git main   # after adding your key to /home/git/.ssh/authorized_keys

Configuration

Edit /etc/ferrenium/ferrenium.toml. Every key is optional and unknown keys are errors. The file lists all keys with their defaults (ferrenium example config prints the same). To validate the config and list the repositories it finds:

ferrenium check --config /etc/ferrenium/ferrenium.toml

listen, base_path, compression, cache.size_mb and the limits.*_parallel/max_requests settings need a restart; everything else applies on reload.

Per-repository metadata comes from the first source that sets it:

  1. [[repo]] in the config (name, description, section, owner, hidden, readme, default_branch)
  2. the repo's git config: ferrenium.{description,owner,section,hidden,readme}, or the gitweb/cgit keys
  3. the repo's description file
sudo -u git git -C /home/git/secret.git config ferrenium.hidden true

Limits

Defaults are sized for a small VPS:

Key Default
limits.git_parallel CPUs, max 8 concurrent git work
limits.heavy_parallel 2 concurrent blame / archive / clone / log search
limits.heavy_wait_secs 10 queue time for those before 503
limits.max_requests 512 in-flight requests before 503
limits.request_timeout_secs 30 until the response starts
limits.diff_files / diff_lines 300 / 10000 larger diffs are truncated
ui.max_blob_kb / max_highlight_kb 1024 / 256 larger files: raw link / no highlighting
cache.size_mb 64 in-memory cache

/robots.txt keeps crawlers off the expensive pages. Memory use at idle is about 10 MB.

Building from source

Requires Rust 1.89+.

cargo build --release              # target/release/ferrenium
ferrenium example config|systemd|caddy

Development

cargo test                         # needs the git CLI
cargo test --release
cargo clippy --all-targets -- -D warnings
cargo run -- serve --config dev.toml
tools/gen-languages/gen.py         # regenerate the Linguist language table

To release: bump version in Cargo.toml, commit, then push a vX.Y.Z tag. The release workflow tests, builds x86_64 and aarch64 binaries, and publishes them with install.sh and SHA256SUMS.

License

GPL-3.0 (see LICENSE). Bundled fonts (Doto, Space Grotesk, Space Mono) are licensed under the OFL; see assets/fonts/OFL.txt. Icons come from Lucide (ISC license).