Garage¶
A single node, configured in nix/hosts/s3-01/garage.nix.
| Endpoint | Bound to | Reachable from |
|---|---|---|
S3 API, :3900 |
[::] |
The mesh and 10.82.50.0/24. The host has no WAN leg, so opening the port in the firewall is exactly that reach and nothing wider. |
RPC, :3901 |
[::1] |
Nothing. A one-node cluster has no peer to talk to, and the CLI is local. |
Admin API, :3903 |
[::] |
The mesh and 10.82.50.0/24, same reach as the S3 API. terraform/garage-buckets drives it from an operator workstation on the campus LAN. |
replication_factor = 1, so this stores one copy of every object and
tolerates no failure at all. It is a single VM on a single storage
repository; treat it as such and keep a backup elsewhere. Raising the factor
later is not a config edit — it means deleting cluster_layout on every node
and rebalancing from scratch.
Buckets are addressed path-style, http://<host>:3900/<bucket>/<key>.
root_domain is deliberately unset, because vhost-style addressing needs a
wildcard DNS record and the host's LAN address moves with DHCP. Point clients
at region garage and set force_path_style (boto3: addressing_style =
"path").
rpc_secret and admin_token come from secrets/s3-01.yaml through
rpc_secret_file/admin_token_file, never inline in /etc/garage.toml, which
is world-readable in the store. Garage refuses to start on a world-readable
secret file, so the sops secrets are 0400 garage:garage.
Why the static user¶
DynamicUser = false plus a static garage user is load-bearing, not
tidiness. The nixpkgs module defaults metadata_dir/data_dir under
/var/lib/garage and reacts to that prefix with StateDirectory = "garage"
alongside DynamicUser = lib.mkDefault true. systemd only uses the
/var/lib/private indirection for dynamic users, so that combination puts the
real data on the 40 GiB root disk and leaves a symlink where the mount should
be.
The users.users.garage/users.groups.garage declarations are not optional
either. The module creates no static account, so overriding User without
declaring it makes the unit fail at step USER on start. The build succeeds
either way; it only surfaces at runtime. Verify with readlink
/var/lib/garage (must print nothing) and findmnt /var/lib/garage.
The layout is not in Nix¶
Garage stores its cluster layout in its own metadata, so it is bootstrapped
once by hand and then survives reboots and rebuilds. Done already; repeat it
only after a reinstall, which wipes xvdb:
garage status # read the node ID
garage layout assign <node-id> -z gewis -c 90G
garage layout apply --version 1
-c is the capacity the node advertises, not a quota — keep it under the
partition size. 90G on the 100 GiB disk leaves headroom; Garage reports the
usable figure as 83.8 GiB.
Buckets and access keys are not managed here. They are declared in
terraform/garage-buckets, which also mints the credentials into OpenBao — see
garage-buckets.md. Creating them with garage bucket
create puts them outside that state, where the next apply will not see them.
The layout commands above need root on the host: the CLI reads
/etc/garage.toml for the RPC secret path, and that secret is only readable by
root and garage.