Skip to content

Repository files navigation

githttp-fs

Test and Build Build and Release dependency status

githttp-fs is a single Rust binary that wraps git repositories and exposes them as a file-system-over-HTTP API. Each tenant gets its own git repository on disk.

Clients can create, read, update, delete, and move eg. .md/.mdx files via REST — which is the initial usecase githttp-fs was written for — and optionally pin the presentation order of any directory's entries. Every write produces a Git commit. A configurable webhook fires after each commit so downstream systems (e.g. a read-only SQL database) can update themselves.

Tested at Rust version: rustc 1.94.0 (4a4ef493e 2026-03-02)

🇵🇹 Crafted in Lisbon, Portugal.

How to use it?

Installation

Install from Docker Hub:

You might find it convenient to run githttp-fs via Docker. You can find the pre-built githttp-fs image on Docker Hub as crispim/githttp-fs.

First, pull the crispim/githttp-fs image:

docker pull crispim/githttp-fs:v1.10.1

Then, provide a configuration file and run it (replace /path/to/your/githttp-fs/config.toml with the path to your configuration file):

docker run -p 5355:5355 -v /path/to/your/githttp-fs/config.toml:/etc/githttp-fs.cfg crispim/githttp-fs:v1.10.1

In the configuration file, ensure that:

  • server.host is set to 0.0.0.0 (this lets githttp-fs be reached from outside the container)
  • server.port is set to 5355 (this lets githttp-fs be reached from outside the container)

githttp-fs will be reachable from http://localhost:5355.

Install from packages:

githttp-fs provides pre-built packages for Debian-based systems (Debian, Ubuntu, etc.).

Important: githttp-fs only provides 64 bits packages targeting Debian 11 & 12 for now (codenames: bullseye & bookworm). You will still be able to use them on other Debian versions, as well as Ubuntu.

First, add the githttp-fs APT repository (eg. for Debian bookworm):

echo "deb [signed-by=/usr/share/keyrings/crisp-im_githttp-fs.gpg] https://packagecloud.io/crisp-im/githttp-fs/debian/ bookworm main" > /etc/apt/sources.list.d/crisp-im_githttp-fs.list
curl -fsSL https://packagecloud.io/crisp-im/githttp-fs/gpgkey | gpg --dearmor -o /usr/share/keyrings/crisp-im_githttp-fs.gpg
apt-get update

Then, install the githttp-fs package:

apt-get install githttp-fs

Then, edit the pre-filled githttp-fs configuration file:

nano /etc/githttp-fs.toml

Finally, restart githttp-fs:

service githttp-fs restart

Install from binary:

A pre-built binary of githttp-fs is shared in the releases on GitHub. You can simply download the latest binary version from the releases page, and run it on your server.

You will still need to provide the binary with the configuration file, so make sure you have a githttp-fs config.toml file ready somewhere.

The binary provided is statically-linked, which means that it will be able to run on any Linux-based system. Still, it will not work on MacOS or Windows machines.

Install from Cargo:

If you prefer managing githttp-fs via Rust's Cargo, install it directly via cargo install:

cargo install githttp-fs

Ensure that your $PATH is properly configured to source the Crates binaries, and then run githttp-fs using the githttp-fs command.

Install from source:

The last option is to pull the source code from Git and compile githttp-fs via cargo:

cargo build --release

You can find the built binaries in the ./target/release directory.

Configuration

Use the sample config.toml configuration file and adjust it to your own environment.

Available configuration options are commented below, with allowed values:

[server]

  • host (type: string, allowed: IPv4 / IPv6, default: 0.0.0.0) — Host the githttp-fs server should listen on
  • port (type: string, allowed: TCP ports, default: 5355) — Port the githttp-fs server should listen on
  • api_key (type: string, allowed: any string, no default) — API key for the githttp-fs HTTP API
  • repos_path (type: string, allowed: UNIX path, no default) — Path to all Git repositories (all tenants are stored in this path)
  • log_level (type: string, allowed: debug, info, warn, error, default: info) — Verbosity of logging, set it to error in production
  • allowed_extensions (type: array[string], allowed: file extensions eg. ["md", "mdx"], default: none) — Optional whitelist of file extensions accepted for file writes and move destinations; when unset, all extensions are accepted

[hooks]

  • url (type: string, allowed: URL, default: no default) — URL of the hook receiver, eg. HTTP URL (if any)
  • events (type: array[string], allowed: file.created, file.updated, file.deleted, file.moved, order.updated or order.deleted, Default: no default) — List of events to send hooks for (the order.* events cover changes to a directory's file order index)
  • retry_attempts (type: number, allowed: any number, Default: no default) — Number of re-delivery attempts to run for a Web Hook that failed delivery
  • retry_backoff_ms (type: number, allowed: time in milliseconds, Default: no default) — How long to back-off between re-delivery attempts

[hooks.auth]

  • header (type: string, allowed: any HTTP header name, default: no default) — Authorization header name, as sent to the hook receiver (if any)
  • value (type: string, allowed: any HTTP header value, default: no default) — Authorization header value, as sent to the hook receiver (if any)

[maintenance]

  • enabled (type: boolean, allowed: true, false, default: true) — Whether to run background repository maintenance (repacks Git objects into a single packfile and expires reflogs, so long-lived repositories stay fast and compact)
  • delay_secs (type: number, allowed: seconds, default: 86400) — How long after the first write to a repository its maintenance pass should run; the timer re-arms on the next write after each pass, and repositories that receive no writes are never maintained
  • destructive_prune (type: boolean, allowed: true, false, default: false) — Whether the maintenance repack may permanently drop unreachable Git objects (garbage left behind by interrupted writes); commit history and past file versions are never affected either way, but with the default false maintenance retains every object and can never destroy data

Considerations

Reserved files

githttp-fs stores one file of its own inside a tenant repository, holding data Git itself cannot express: .order.json, the presentation order of the directory it sits in (Git tree entries are name-sorted and carry no metadata slot).

{
  "order": ["intro.md", "getting-started/", "advanced.mdx"]
}
  • Entirely opt-in: no .order.json is ever written unless you call PUT /v1/:collection_id/:tenant_id/order[/*path] or POST /v1/:collection_id/:tenant_id/files/*path/reorder. Never use those routes and no reserved file exists anywhere.
  • A separate resource, not an addressable file: read and write it through GET / PUT / DELETE on /order[/*path], exchanging a plain JSON array of names. To move a single entry instead of replacing the whole list, POST /files/*path/reorder with a numerical position shifts that one entry into place, or drops it from the index with position: -1 (files only, unless you pass allow_prefix_path: true to position a folder too).
  • Invisible to every /files route — list, count, read, HEAD, batch (where it is null) — regardless of include_hidden_files. PUT and move destinations refuse the path with 400; move sources and DELETE answer 404.
  • Delivers order.updated / order.deleted webhooks, never file.* ones. order.updated carries the directory's complete resulting order, so downstream it is a replace, not a diff. Both are ordinary [hooks] events subscriptions, so a receiver that does not list them gets none.
  • Kept up to date automatically: deleting or moving a file rewrites the affected index in the same commit. Renames keep their position, cross-directory moves append only to an index that already exists, and an emptied index is removed.
  • Applied on read only if asked: pass apply_order_index=true on the file listing route (default false); unlisted entries follow in the ordinary order, or pass implicit_order_default_index (e.g. 0 or -1) to lift them above the ordered ones instead. Reading a single file always reports its own position in its parent's index, -1 when unlisted.

🔥 Report A Vulnerability

If you find a vulnerability in githttp-fs, you are more than welcome to report it directly to @crisp-oss by sending an encrypted email to security@crisp.chat. Do not report vulnerabilities in public GitHub issues, as they may be exploited by malicious people to target production servers running an unpatched githttp-fs server.

⚠️ You must encrypt your email using @crisp-oss GPG public key available at: Vulnerability Disclosures.

About

A git-backed content management database served over HTTP.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages