Krolyxon
Branch master

ferreniumREADME.md

209 lines · 7.9 KB · Markdown

1# Ferrenium
2
3A read-only Git repository browser, like cgit, as a single Rust daemon. It
4serves every bare repository under one directory and keeps no state on disk.
5
6Pages: repo index, summary + README, tree, file (highlighted), raw, log
7(path filter, message search), commit + diff, `.patch`, blame, refs, file
8finder, `.tar.gz`/`.zip` snapshots, Atom feed. `git clone` over HTTPS
9(read-only).
10
11Themeable without rebuilding: your own stylesheet, images and fonts, plus a
12favicon, logo and accent color (see [Appearance](#appearance)).
13
14## Install
15
16On a Linux host with systemd (x86_64 or aarch64, glibc 2.28+):
17
18```sh
19curl -fsSL https://github.com/krolyxon/ferrenium/releases/latest/download/install.sh | sudo FERRENIUM_DOMAIN=git.example.com sh
20```
21
22This:
23
24- downloads the latest release binary, verifies its checksum and installs it to `/usr/local/bin/ferrenium`
25- creates the `git` user if it doesn't exist (home `/home/git`, shell `git-shell`)
26- writes `/etc/ferrenium/ferrenium.toml` (never overwritten on later runs)
27- installs `/etc/systemd/system/ferrenium.service` and runs `systemctl enable --now ferrenium`
28
29Variables: `FERRENIUM_DOMAIN` (fills `base_url` and clone URLs in a new
30config), `FERRENIUM_USER` (default `git`), `FERRENIUM_VERSION` (e.g.
31`v0.1.0`, default latest).
32
33Run the same command again to upgrade: it replaces the binary and unit
34and restarts the service. To remove it: `… | sudo sh -s -- --uninstall`.
35This keeps `/etc/ferrenium` and the repositories.
36
37### The service
38
39It's a normal system service. The unit has `User=git`, so systemd starts it
40as the repo owner. You don't need `su git` or `systemctl --user`.
41
42```sh
43sudo systemctl status ferrenium
44sudo systemctl reload ferrenium # after editing the config
45sudo journalctl -u ferrenium -f
46sudo systemctl edit ferrenium # overrides; survive upgrades
47```
48
49The unit is sandboxed: the filesystem is read-only, there are no
50capabilities, a syscall filter applies, and only localhost may connect.
51
52### Reverse proxy
53
54Ferrenium listens on `127.0.0.1:8080` (plain HTTP/1.1). Caddy:
55
56```caddy
57git.example.com {
58 reverse_proxy 127.0.0.1:8080
59}
60```
61
62If Caddy runs in Docker, use `network_mode: host` so it can reach
63`127.0.0.1`.
64
65### Repositories
66
67Put bare repositories anywhere under `/home/git` (up to 3 levels deep).
68Ferrenium picks up new repos and pushes within about a second.
69
70```sh
71sudo -u git git init --bare /home/git/project.git
72git push git@git.example.com:project.git main # after adding your key to /home/git/.ssh/authorized_keys
73```
74
75## Configuration
76
77Edit `/etc/ferrenium/ferrenium.toml`. Every key is optional and unknown
78keys are errors. The file lists all keys with their defaults
79(`ferrenium example config` prints the same). To validate the config and
80list the repositories it finds:
81
82```sh
83ferrenium check --config /etc/ferrenium/ferrenium.toml
84```
85
86`listen`, `base_path`, `compression`, `cache.size_mb` and the `limits.*_parallel`/`max_requests`
87settings need a restart; everything else applies on reload.
88
89Per-repository metadata comes from the first source that sets it:
90
911. `[[repo]]` in the config (`name`, `description`, `section`, `owner`, `hidden`, `readme`, `default_branch`)
922. the repo's git config: `ferrenium.{description,owner,section,hidden,readme}`, or the gitweb/cgit keys
933. the repo's `description` file
94
95```sh
96sudo -u git git -C /home/git/secret.git config ferrenium.hidden true
97```
98
99### Appearance
100
101These keys are optional. Files are read when the config is loaded or reloaded,
102and relative paths are resolved against the config file's directory, e.g.
103`/etc/ferrenium/`.
104
105| Key | |
106|---|---|
107| `site.title` | name in the top bar and page titles |
108| `site.favicon` | `.ico`, `.png`, `.svg`, `.webp`, `.gif` or `.jpg`, up to 1 MiB |
109| `site.logo` | image shown before the title in the top bar (same formats) |
110| `site.custom_css` | stylesheet loaded after the built-in one |
111| `site.assets_dir` | directory of images, fonts and stylesheets the custom CSS can load |
112| `site.header` / `site.footer` | HTML inserted below the top bar / in the footer |
113| `ui.theme` | default theme: `auto`, `dark` or `light` |
114| `ui.accent` | accent color as hex, e.g. `"#d71921"` |
115| `ui.code_font` | font family for code (must be installed on the client or loaded by `custom_css`) |
116
117The custom stylesheet overrides the built-in one, so it only needs the rules
118you want to change: design tokens, buttons, backgrounds, layout. Files in
119`assets_dir` are served at `/-/site/` (images, fonts and `.css` only; hidden
120files and paths leading outside the directory are refused), and the
121stylesheet refers to them with relative URLs:
122
123```toml
124[site]
125custom_css = "style.css" # /etc/ferrenium/style.css
126assets_dir = "assets" # /etc/ferrenium/assets/
127```
128
129```css
130@font-face { font-family: "Inter"; src: url("site/inter.woff2") format("woff2"); }
131:root { --font-body: "Inter", sans-serif; --interactive: light-dark(#0b57d0, #8ab4f8); }
132body { background: url("site/bg.jpg") center / cover fixed; }
133.segmented { border-radius: 4px; }
134```
135
136Edits to the stylesheet, favicon and logo need `systemctl reload ferrenium`;
137files in `assets_dir` are read on each request. Images from other `https://`
138sites work too, but fonts must come from `assets_dir` (the content security
139policy allows only same-origin fonts). Inline `<script>`/`<style>` in
140`header`/`footer` is blocked for the same reason; put styles in `custom_css`.
141
142Most of the look is driven by these CSS variables, so overriding a few of
143them on `:root` goes a long way. Colors are written as
144`light-dark(LIGHT, DARK)` to follow the theme switch; a single color applies
145to both themes.
146
147| Variable | Used for |
148|---|---|
149| `--black` | page background |
150| `--surface`, `--surface-raised` | panels, menus, code blocks |
151| `--border`, `--border-visible` | hairlines, button and field outlines |
152| `--text-display`, `--text-primary`, `--text-secondary`, `--text-disabled` | text, brightest to dimmest; syntax highlighting uses the same scale |
153| `--accent`, `--accent-subtle` | active markers, highlights and removed lines in diffs (`ui.accent` sets both) |
154| `--interactive` | links |
155| `--success` | added lines in diffs |
156| `--error` | `[ERROR: …]` messages |
157| `--font-body`, `--font-mono`, `--font-display`, `--font-code` | type families |
158| `--page-max`, `--gutter` | column width and side padding |
159
160The full list is in [`assets/css/tokens.css`](assets/css/tokens.css). For
161anything else, use the browser's inspector to find the element's class and
162override its rules.
163
164### Limits
165
166Defaults are sized for a small VPS:
167
168| Key | Default | |
169|---|---|---|
170| `limits.git_parallel` | CPUs, max 8 | concurrent git work |
171| `limits.heavy_parallel` | 2 | concurrent blame / archive / clone / log search |
172| `limits.heavy_wait_secs` | 10 | queue time for those before `503` |
173| `limits.max_requests` | 512 | in-flight requests before `503` |
174| `limits.request_timeout_secs` | 30 | until the response starts |
175| `limits.diff_files` / `diff_lines` | 300 / 10000 | larger diffs are truncated |
176| `ui.max_blob_kb` / `max_highlight_kb` | 1024 / 256 | larger files: raw link / no highlighting |
177| `cache.size_mb` | 64 | in-memory cache |
178
179`/robots.txt` keeps crawlers off the expensive pages. Memory use at idle is
180about 10 MB.
181
182## Building from source
183
184Requires Rust 1.89+.
185
186```sh
187cargo build --release # target/release/ferrenium
188ferrenium example config|systemd|caddy
189```
190
191## Development
192
193```sh
194cargo test # needs the git CLI
195cargo test --release
196cargo clippy --all-targets -- -D warnings
197cargo run -- serve --config dev.toml
198tools/gen-languages/gen.py # regenerate the Linguist language table
199```
200
201To release: bump `version` in `Cargo.toml`, commit, then push a `vX.Y.Z` tag.
202The `release` workflow tests, builds x86_64 and aarch64 binaries, and
203publishes them with `install.sh` and `SHA256SUMS`.
204
205## License
206
207GPL-3.0 (see `LICENSE`). Bundled fonts (Doto, Space Grotesk, Space Mono)
208are licensed under the OFL; see `assets/fonts/OFL.txt`. Icons come from
209Lucide (ISC license).