| 1 | # fabrica configuration — copy to /etc/fabrica/fabrica.toml (or point at it with |
| 2 | # `fabrica --config <path>`) and edit. Every value shown below is the built-in |
| 3 | # default, so you only need to keep the keys you actually change. |
| 4 | # |
| 5 | # Resolution order, later wins: built-in defaults -> /etc/fabrica/fabrica.toml |
| 6 | # -> $XDG_CONFIG_HOME/fabrica/fabrica.toml -> --config <path> -> FABRICA__* env. |
| 7 | # Environment overrides nest with double underscores, e.g. |
| 8 | # FABRICA__SERVER__PORT=8080 |
| 9 | # |
| 10 | # Any *_file key reads its value from that file and wins over its inline sibling |
| 11 | # (use it for agenix / systemd-creds / Docker secrets). Unknown keys are a hard |
| 12 | # error, so a typo fails fast rather than being silently ignored. |
| 13 | # |
| 14 | # Validate with `fabrica config check`; print the effective config (secrets |
| 15 | # redacted) with `fabrica config show`. |
| 16 | |
| 17 | [instance] |
| 18 | name = "fabrica" # shown in the header and page titles |
| 19 | url = "https://git.example.com" # canonical external URL, no trailing slash |
| 20 | description = "A small, private forge." # one line, shown on the landing page |
| 21 | default_branch = "main" # default branch for new repositories |
| 22 | allow_anonymous = true # anonymous browse + clone of public repos |
| 23 | default_visibility = "private" # new repos: public | internal | private |
| 24 | allow_registration = false # allow web self-registration (sign-up) |
| 25 | |
| 26 | [server] |
| 27 | address = "0.0.0.0" |
| 28 | port = 8080 |
| 29 | behind_proxy = false # trust X-Forwarded-For / X-Forwarded-Proto |
| 30 | graceful_shutdown_secs = 20 # drain in-flight requests for this long on shutdown |
| 31 | max_body_bytes = 1048576 # non-pack routes only |
| 32 | |
| 33 | [ssh] |
| 34 | enabled = true |
| 35 | address = "0.0.0.0" |
| 36 | port = 2222 |
| 37 | host_key_path = "/var/lib/fabrica/ssh/host_ed25519" # generated on first run if absent |
| 38 | clone_host = "git.example.com" # what the UI shows in clone URLs, may differ from bind |
| 39 | clone_port = 22 |
| 40 | |
| 41 | [storage] |
| 42 | data_dir = "/var/lib/fabrica" # secrets, host key, SQLite db, scratch |
| 43 | repo_dir = "/var/lib/fabrica/repos" # bare repos, sharded by id prefix |
| 44 | lfs_dir = "/var/lib/fabrica/lfs" # git-LFS objects (local backend only) |
| 45 | # Where uploads (avatars, release assets, LFS objects) live. Bare repos are |
| 46 | # always local — only uploads may be offloaded to S3. |
| 47 | backend = "local" # "local" (default) or "s3" |
| 48 | |
| 49 | # S3-compatible object storage (AWS S3, MinIO, Cloudflare R2, Backblaze B2, …). |
| 50 | # Required when backend = "s3". |
| 51 | # [storage.s3] |
| 52 | # bucket = "fabrica" |
| 53 | # region = "us-east-1" # many non-AWS stores accept "auto" |
| 54 | # endpoint = "https://<account>.r2.cloudflarestorage.com" # omit for AWS |
| 55 | # access_key_id = "..." |
| 56 | # secret_access_key = "..." |
| 57 | # path_style = false # true for MinIO and most non-AWS stores |
| 58 | # prefix = "" # optional key prefix, e.g. "fabrica/" |
| 59 | |
| 60 | [database] |
| 61 | url = "sqlite:///var/lib/fabrica/fabrica.db" |
| 62 | max_connections = 16 |
| 63 | # SQLite is opened with journal_mode=WAL, synchronous=NORMAL, foreign_keys=ON, |
| 64 | # busy_timeout=5000. Postgres URLs (postgres://…) are detected automatically. |
| 65 | |
| 66 | [auth] |
| 67 | # secret = "…" # HS256 key; prefer secret_file below |
| 68 | secret_file = "/var/lib/fabrica/secret" # generated on first run, mode 0600 |
| 69 | session_ttl_days = 30 |
| 70 | token_ttl_days = 90 |
| 71 | invite_ttl_hours = 72 # activation/reset link lifetime |
| 72 | cookie_name = "fabrica_session" |
| 73 | cookie_secure = true # set false only if instance.url is plain http (dev) |
| 74 | argon2_m_cost = 19456 # KiB |
| 75 | argon2_t_cost = 2 # iterations |
| 76 | argon2_p_cost = 1 # lanes |
| 77 | |
| 78 | [mail] |
| 79 | backend = "smtp" # smtp | stdout | none |
| 80 | from = "fabrica@example.com" |
| 81 | host = "smtp.example.com" # required when backend = "smtp" |
| 82 | port = 587 |
| 83 | username = "fabrica" |
| 84 | # password = "…" # prefer password_file below |
| 85 | password_file = "/run/secrets/fabrica-smtp" |
| 86 | encryption = "starttls" # starttls | tls | none |
| 87 | timeout_secs = 15 |
| 88 | |
| 89 | [ui] |
| 90 | theme = "dark" # file stem in themes_dir, or an embedded theme name |
| 91 | themes_dir = "/var/lib/fabrica/themes" |
| 92 | assets_dir = "/var/lib/fabrica/assets" |
| 93 | allow_theme_choice = true # show the theme picker; choice persists in a cookie |
| 94 | show_runs = false # CI nav slot, inert until CI ships |
| 95 | diff_context_lines = 3 |
| 96 | max_highlight_bytes = 1048576 # skip highlighting blobs larger than this |
| 97 | max_diff_bytes = 5242880 # refuse to render diffs larger than this |
| 98 | tree_history_limit = 1000 # commits walked when annotating a tree listing |
| 99 | |
| 100 | [git] |
| 101 | binary = "git" # must be >= 2.41 and on PATH |
| 102 | transport_timeout_secs = 3600 |
| 103 | max_pack_size_bytes = 536870912 # reject pushes with a larger received pack |
| 104 | |
| 105 | [search] |
| 106 | concurrency = 4 # repos searched at once in a global search |
| 107 | timeout_secs = 10 # total budget; partial results are returned past it |
| 108 | max_results = 200 # cap before truncating with a notice |
| 109 | |
| 110 | [log] |
| 111 | level = "info" # trace | debug | info | warn | error (RUST_LOG also honoured) |
| 112 | format = "pretty" # pretty | json |