fabrica

hanna/fabrica

.githubassetscratesdatadocsmigrationssrc.gitignoreCargo.lockCargo.tomlchallenge.txtchallenge.txt.ascCLAUDE.mdcompose.ymlconfig.tomldeny.tomlDockerfilefabrica.example.tomlflake.lockflake.nixjustfileLICENSEREADME.mdrust-toolchain.tomlspec.md

fabrica

fabrica (Latin: forge) is a self-hosted git server — a single Rust binary that serves your repositories over HTTPS (read) and SSH (read + write) behind a fast, themeable, htmx-driven web UI. Private by default, no sign-up required.

It is already a complete forge, feature-comparable to Forgejo/Gitea, with CI as the one planned feature still to come: code browsing, nested groups, three-level visibility, issues and pull requests with server-side merge machinery, and a full account-settings area — all from one binary, one config file, and one data directory.

Features

Planned: CI — the seams already exist (routes, tables, and the post-receive hook entry point, inert behind ui.show_runs = false); the runner (HCL config, Docker execution) is the next thing to be built.

Out of scope: orgs, forks, stars, followers, notifications, wikis, releases-as-a-feature, git-LFS, webhooks, mirroring, federation.

Requirements

The git binary (≥ 2.41) must be on PATH at runtime — fabrica shells out to it for pack transport (upload-pack / receive-pack) and maintenance, while using libgit2 in-process for browsing. Every deployment path below guarantees it; verify with fabrica doctor.

Quick start

Docker / Compose

docker compose up

Builds the image and starts fabrica on :8080 (HTTP) and :2222 (SSH) with named volumes for data and repos. SQLite is the default database; add --profile postgres and point FABRICA__DATABASE__URL at it to use Postgres.

From source (Nix)

The toolchain (Rust nightly via fenix) is pinned in the flake:

nix develop                 # enter the dev shell
just check                  # fmt + check + clippy + test (the quality gate)
cargo run -- serve          # serve with the built-in defaults

serve runs in the foreground (correct for systemd/Docker) and applies pending migrations on startup. Create the first administrator:

cargo run -- user add alice alice@example.com --admin

Then open http://localhost:8080.

Configuration

Copy fabrica.example.toml, edit it, and point the binary at it with --config <path> (or place it at /etc/fabrica/fabrica.toml or under $XDG_CONFIG_HOME/fabrica/). Every key can be overridden by an environment variable FABRICA__<SECTION>__<KEY> (double underscores nest), and any *_file key reads its value from a file — for agenix, systemd-creds, or Docker secrets. Unknown keys are a hard error.

fabrica config check        # validate
fabrica config show         # print the merged config, secrets redacted

On first run fabrica generates its HS256 secret and SSH host key. See docs/configuration.md and docs/deployment.md for details — including the reverse-proxy rule that pack routes must not be buffered.

CLI

Every subcommand touches the store and filesystem directly; there is no running-server IPC.

Command Purpose
fabrica serve Run the HTTP + SSH server (foreground)
fabrica user Manage accounts (add, passwd, admin, verify, disable, del)
fabrica repo Manage repositories (add, rename, visibility, collaborator, archive, path…)
fabrica group Manage groups
fabrica key / token Manage SSH/GPG keys and API tokens
fabrica config Validate / show the effective configuration
fabrica migrate Apply database migrations
fabrica doctor Check the runtime environment (git on PATH, etc.)

Architecture

A single root binary (src/main.rs) dispatches into library crates under crates/, with a strictly one-way dependency direction:

model  ←  store / git / auth  ←  web / api / ssh / cli

Repositories are stored on disk by ULID ({repo_dir}/{id[0..2]}/{id}.git); the database is the only name→path authority, so renames and group moves are metadata-only. See spec.md for the full design contract and docs/decisions.md for the running log of design decisions and deviations.

Development

just check          # cargo fmt --check + check + clippy -D warnings + test
nix flake check     # the superset: clippy, fmt, test, deny, doc

The workspace forbids unsafe_code and denies unwrap/panic/todo outside tests. cargo test alone suffices with no external services (Postgres tests are feature-gated). Commits follow Conventional Commits, scoped by crate/area.

License

MPL-2.0.