fabrica

hanna/fabrica

3679 bytes

Deployment

fabrica is one binary, one config file, one data directory. It needs the git binary (≥ 2.41) on PATH at runtime — every deployment path below guarantees it.

Configuration

Copy fabrica.example.toml, edit it, and point the binary at it with --config (or place it at /etc/fabrica/fabrica.toml or $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 / Docker secrets). Validate with fabrica config check; inspect the merged result (secrets redacted) with fabrica config show.

On first run fabrica generates its HS256 secret (auth.secret_file, default {data_dir}/secret, mode 0600) and its SSH host key (ssh.host_key_path).

Docker / Compose

docker compose up builds the image (Dockerfile) and starts fabrica on :8080 (HTTP) and :2222 (SSH), with named volumes for the data and repos. The default database is SQLite; add --profile postgres to bring up Postgres and point FABRICA__DATABASE__URL at it.

The image is multi-stage: the builder compiles with --features vendored (libgit2 is statically linked), so the runtime (debian:stable-slim) needs only git, ca-certificates, tini, and libssl3. It runs as a non-root user, git --version is verified at build time, and the health check is fabrica doctor --quiet.

Reverse proxy — read this

A proxy in front MUST NOT buffer the git pack routes, or clones stall. For nginx:

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_buffering off;          # critical for /info/refs and /git-upload-pack
    proxy_request_buffering off;
    proxy_read_timeout 3600s;
}

Set server.behind_proxy = true so X-Forwarded-For/-Proto are trusted, and auth.cookie_secure = true once you terminate TLS at the proxy.

NixOS

The flake exposes nixosModules.default:

{
  inputs.fabrica.url = "github:you/fabrica";
  # …
  nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
    modules = [
      fabrica.nixosModules.default
      {
        services.fabrica = {
          enable = true;
          openFirewall = true;
          environmentFile = "/run/secrets/fabrica.env";   # FABRICA__* secrets
          settings = {
            instance.url = "https://git.example.com";
            instance.name = "our forge";
            server.port = 8080;
            ssh.port = 2222;
            database.url = "sqlite:///var/lib/fabrica/fabrica.db";
          };
        };
      }
    ];
  };
}

The module renders settings to a TOML file, runs a hardened systemd unit (DynamicUser off, StateDirectory=fabrica, ProtectSystem=strict, NoNewPrivileges, CAP_NET_BIND_SERVICE only when a privileged port is configured), and opens the firewall when asked. The package wraps the binary with git on PATH.

Nix container

nix build .#container produces an OCI image (dockerTools.buildLayeredImage) with git and ca-certificates in the closure — a Nix-native alternative to the Dockerfile. Load it with docker load < result.

First user

There is no web sign-up. Create the first account from the CLI (the same binary):

fabrica --config /etc/fabrica/fabrica.toml user add alice alice@example.com --admin
# prints an activation link; or set a password directly:
fabrica --config /etc/fabrica/fabrica.toml user passwd alice
fabrica --config /etc/fabrica/fabrica.toml key add --type ssh alice @~/.ssh/id_ed25519.pub

Run fabrica doctor to confirm git, the config, and the database are healthy.