krz/gitbay

A CLI-first git forge.

clone: git clone https://gitbay.org/krz/gitbay.git

main: docs/admin.org · raw

  1#+title: gitbay admin guide
  2
  3One static binary (=gitbayd=), one SQLite file, bare repositories on
  4disk, and the system =git=. Schema migrations run automatically on
  5startup and on every admin command.
  6
  7* Install
  8
  9#+begin_src sh
 10install -m 755 gitbayd /usr/local/bin/
 11adduser --system --group --home /var/lib/gitbay --shell /usr/sbin/nologin gitbay
 12install -d -o gitbay -g gitbay -m 750 /var/lib/gitbay
 13gitbayd --config /etc/gitbay/config.toml check-config
 14#+end_src
 15
 16=deploy/= in the source tree has a cloud-init file, a hardened systemd
 17unit, and a nightly backup timer. Run as the unprivileged =gitbay= user;
 18the unit's =AmbientCapabilities=CAP_NET_BIND_SERVICE= covers ports
 1922/80/443 without root.
 20
 21** The SSH port decision
 22
 23- =ssh.mode = "embedded"= (default): gitbayd itself listens, normally on
 24  22 — move the host's admin sshd to another port. Remotes read
 25  =git@host:owner/repo= with no port gymnastics.
 26- =ssh.mode = "system"=: the host sshd owns 22 and invokes gitbayd via
 27  =AuthorizedKeysCommand=:
 28  #+begin_example
 29  AuthorizedKeysCommand /usr/local/bin/gitbayd --config /etc/gitbay/config.toml authorized-keys %t %k
 30  AuthorizedKeysCommandUser gitbay
 31  #+end_example
 32  sshd requires that binary to be root-owned and not group/world
 33  writable. Unknown keys fail authentication inside sshd, so system mode
 34  requires =registration.mode = "closed"= (check-config enforces this).
 35
 36* Configuration reference
 37
 38=/etc/gitbay/config.toml=. =check-config= validates and names every
 39contradiction; =--no-host-checks= skips port/path probes.
 40
 41** [server]
 42- =root= (default =/var/lib/gitbay=) — repositories, database, host
 43  keys, ACME cache all live here.
 44- =site_url= (required) — canonical =https://host=; drives ACME, clone
 45  URLs, mail links.
 46
 47** [ssh]
 48- =mode==embedded= | =system= (above).
 49- =port= (22) — embedded listener port.
 50- =host_keys= — list of private key paths; empty generates an ed25519
 51  key at =<root>/ssh/host_ed25519=.
 52
 53** [http]
 54- =addr= (=:443=), =tls==acme= | =files= | =off=.
 55- =acme=: certificates via TLS-ALPN-01 on the HTTPS port, cached at
 56  =<root>/acme=; =acme_email= for the CA account; =acme_http_addr=
 57  (=:80=, ="off"= to disable) adds HTTP-01 and an https redirect —
 58  failing to bind it is a warning, not fatal. Requires an =https://=
 59  site_url with a public DNS name.
 60- =files=: =cert_file= + =key_file=.
 61- =off=: plain HTTP — development, or behind a TLS-terminating proxy.
 62
 63** [web]
 64- =mode==view_only= (default) | =accounts=. In view_only the mutating
 65  web routes are never registered; in accounts, browser sessions are
 66  minted over SSH (=web login=), and users with write access can create
 67  repos, comment, and make simple file edits (which commit unsigned,
 68  honestly). =password_auth= is reserved and currently rejected.
 69
 70** [registration]
 71- =mode==closed= (default) | =invite= | =open=. invite/open require
 72  [mail]. See the user guide for the flows.
 73
 74** [mail]
 75- =smtp_host= (host:port, 587 assumed), =from=, optional =smtp_user= /
 76  =smtp_pass=. STARTTLS when offered. Required for invite/open
 77  registration and self-service =email add=; in closed mode you may omit
 78  it entirely and assert addresses by hand (below).
 79
 80** [api]
 81- =enabled= (false) — the JSON API surface; see =docs/api.org=. Off
 82  means no credential-bearing HTTP endpoint exists at all.
 83
 84** [webhooks]
 85- =allow_local= (false) — permit webhook targets on loopback/private
 86  addresses. Leave off unless you know why you need it (SSRF).
 87
 88** [limits]
 89- =clone_timeout= (3600s) — cap on =repo import= fetches.
 90- =max_blob_bytes= (100MB) — cap on raw file serving over the web.
 91- =max_pack_bytes=, =ssh_auth_rate= — reserved, not yet enforced.
 92
 93** [git_daemon]
 94- =enabled= (false), =port= (9418) — the anonymous =git://= listener.
 95  Serves only public repositories that additionally ran
 96  =repo settings git-daemon <repo> on=.
 97
 98* Users, email, invites
 99
100#+begin_src sh
101gitbayd admin user create alice --key alice.pub --email a@example.org --verified [--admin]
102gitbayd admin email verify alice a@example.org   # admin assertion, no SMTP needed
103gitbayd admin invite --email b@example.org       # mails a code; prints it if no SMTP
104#+end_src
105
106"Verified" means SMTP-confirmed or host-admin-asserted; the database
107records which. Verified emails are what make commit signatures
108meaningful — an unverified address never produces a =verified= badge.
109
110* Backup and restore
111
112#+begin_src sh
113gitbayd admin backup --out /var/backups/gitbay/backup.tar.gz
114#+end_src
115
116One archive: a consistent SQLite snapshot (taken *before* the
117repositories are read, so the database never references objects the
118archive missed), every repository, and the SSH host keys. Excluded:
119hook socket, regenerated hook scripts, WAL files. Safe to run against a
120live daemon.
121
122Restore: extract into an empty directory, point =server.root= at it,
123start gitbayd. Host keys are preserved, so clients keep their
124known_hosts entries; hooks regenerate at startup.
125
126* Upgrades
127
128Replace the binary, restart the unit. Migrations apply automatically and
129are transactional; hook scripts under =<root>/hooks= are rewritten at
130startup to point at the current binary path.
131
132* Odds and ends
133
134- deleting a fork marks MRs sourced from it =source_gone=; their diffs
135  remain viewable and mergeable because the target repo owns the
136  objects.
137- =refs/merge-requests/*= is server-owned and unpushable by clients.
138- audit-relevant activity (issue/MR lifecycle, imports, pushes) lands in
139  the =events= table, which also feeds webhooks.
140- the daemon idles under 10MB RSS; the smallest VPS tier is adequate.