Jump to content

Garage Object Storage on PMSS

From Pulsed Media Wiki


Garage turns two or three Pulsed Media boxes into a single S3 cluster you own outright, with every object replicated across the nodes so one box can go down and your data stays readable. It is a single, dependency-free binary that speaks the Amazon S3 API, built by the French collective Deuxfleurs to run over the open Internet between machines that do not share a backbone. Where rclone serve s3 and MinIO put an S3 endpoint on one box, Garage is the option when you want the endpoint spread across several boxes for redundancy — and the keys, the data, and the failure domain all stay in your hands, inside Pulsed Media's Finnish datacenters.

When Garage is the right tool

On a single box, rclone serve s3 is simpler and lighter — use that. Garage earns its place when you run more than one Pulsed Media box and want them to back each other up automatically:

  • A storage box in Lauttasaari and another in Kerava, replicating every object across both — an object survives the loss of an entire node.
  • A storage box plus a home server or a friend's box, stitched into one bucket namespace.
  • Any S3 application (rclone, restic, Nextcloud, PeerTube, a Proxmox Backup Server S3 datastore) pointed at a cluster instead of a single point of failure.

You get the S3 interface without renting cloud object storage, without per-request or egress fees, and without a single box being able to take the whole store down with it.

What people run on it

Because Garage speaks the S3 API, it fits anywhere an application expects a bucket. The Garage project and its community run it as a backup target for restic and rclone, as the media backend for Matrix, Mastodon and PeerTube servers, as storage behind Nextcloud, and as a host for static websites, since a bucket can serve a site directly over HTTP. On Pulsed Media the fits are the same, with one difference: the cluster, the keys, and the hardware are all yours, in Finland. Common uses:

  • Offsite backups that survive the loss of a whole box, not just a disk.
  • A media library for a self-hosted Plex or Jellyfin setup, or for a Matrix/Mastodon/PeerTube instance.
  • Object storage for any app you run on a Seedbox or storage box that wants S3 instead of a filesystem.
  • A self-owned alternative to cloud object storage, with no per-request or egress fees.

What one node needs

Garage is deliberately light. Per node: 1 GB RAM, at least 16 GB of disk, any x86-64 CPU from the last decade (or ARMv7/ARMv8), and a network link under 200 ms with 50 Mbps or more between nodes. Three nodes is the natural minimum, because Garage replicates each chunk of data across three separate zones.

The 1 GB figure is a headroom recommendation, not a hard floor, and what it sizes is metadata. In a test cluster a garage server process held about 15 to 20 MB of resident memory when empty, both idle and while writing a 20 MB object at full speed: Garage streams data in fixed-size blocks rather than buffering whole objects, so a large upload passes through in pieces instead of being held in memory. Memory then grows with the number of stored objects, because each object's metadata lives in a memory-mapped database. Measured on a single node, that cost is about 0.9 KB per object (counted as total container memory, some of which is reclaimable cache, so the hard floor is a little lower): roughly 65 MB at 50,000 objects, and by extrapolation on the order of 1 GB only as a node nears a million objects. A node holding thousands to tens of thousands of objects runs in tens of megabytes and fits inside a storage box's resources with room to spare; the full 1 GB earns its place when a node holds hundreds of thousands of objects or serves heavy concurrent traffic.

How replication works

Garage splits objects into chunks and stores a copy of each chunk in three different zones. A zone is a failure domain you define — on PMSS, put each box in its own zone, and ideally split them across both Finnish datacenters so the loss of one site cannot take out more than one copy. The cluster agrees on where each chunk lives using a layout you assign; when a node goes away, reads are served from the surviving copies, and when it returns, Garage re-syncs it. This is the same class of design as Amazon's Dynamo paper, built on conflict-free replicated data types.

Availability and redundancy

Garage keeps three copies of every data block by default (replication factor 3), one per zone, and it decides reads and writes by quorum. In the default consistent mode a write is acknowledged once a majority of zones (two of three) have stored it, and reads need the same majority, so the cluster keeps full read-after-write consistency even while an entire zone is offline. Lose one zone of three and it keeps serving both reads and writes; the object read back with a node stopped, below, is exactly this at work.

Two looser modes exist when availability matters more than strict consistency. degraded drops the read quorum to 1, so data stays readable when more than one zone is down, at the cost of read-after-write consistency. dangerous drops both quorums to 1, giving up most durability guarantees, and is for niche cases only. The replication factor and consistency mode live in each node's config and must match across the cluster.

Garage also heals itself. Block-resync workers rebuild missing copies onto a returning or replacement node, and an automatic scrub runs every 25 to 35 days, reading every block and checking it against its hash so silent disk corruption is caught and repaired from a healthy replica. A scrub or rebuild can also be started by hand with garage repair.

Verified behaviour

A three-node cluster (replication factor 3, one zone per node) was exercised end to end: create a bucket and key, upload an object over the S3 API, then stop one node. With a third of the cluster down, the same object still read back byte for byte — Garage served it from the surviving replicas. Restarting the node let it rejoin and resync. This exercise validates Garage's own clustering and replication behaviour; running a cluster across separate Pulsed Media boxes follows the identical steps, with per-box network reachability (the RPC port reaching between boxes) being the setup-specific part to confirm.

A 3-node Garage cluster (zones dc1/dc2/dc3, replication factor 3): garage status, layout show, and a successful S3 read with one node stopped.

Building a cluster on PMSS

The shape is the same on every node: drop the Garage binary into your home directory, give all nodes the same shared secret and a minimal config, connect them, assign a layout, then create a bucket and a key. Everything lives under your home directory — nothing touches the system.

1. Install the binary on each box

mkdir -p ~/bin
# download the static garage binary for your architecture from garagehq.deuxfleurs.fr/download
chmod +x ~/bin/garage
garage --version

2. Write a config on each box

Every node shares one rpc_secret (a 32-byte hex value from openssl rand -hex 32). Metadata and data directories go under your home; bind the RPC and S3 ports to ports you control.

metadata_dir = "/home/USERNAME/garage/meta"
data_dir     = "/home/USERNAME/garage/data"
replication_factor = 3
rpc_bind_addr = "[::]:3901"
rpc_secret    = "PASTE-openssl-rand-hex-32-HERE"
[s3_api]
api_bind_addr = "[::]:3900"

Start the daemon on each node with garage server.

3. Form the cluster

garage node id                                   # get each node's identifier
garage node connect <node-id>@<box>:3901         # connect the other nodes (one direction is enough)
garage layout assign <node-id> -z <zone> -c <capacity> -t <tag>   # -z is the zone (put each DC in its own)
garage layout show
garage layout apply --version 1
garage status                                    # all three nodes HEALTHY

4. Create a bucket and a key

garage bucket create mybucket
garage key create mykey                          # prints the access key and secret
garage bucket allow --read --write mybucket --key mykey

5. Point an S3 client at it

Configure rclone (pre-installed on every box) with an s3 remote using the access key, the secret, and your S3 endpoint (http://BOX:3900), then upload as normal. Any S3 client works the same way.

Managing the cluster

Everything runs from the garage command-line tool: garage status shows node health and zones, garage layout manages capacity and placement, garage bucket and garage key handle buckets and access keys, garage worker and garage stats expose the background workers and per-table counts, and garage repair runs scrubs and rebuilds. For automation there is an HTTP Admin API (guarded by an admin token) and a Prometheus metrics endpoint, so a cluster wires into the same dashboards and alerting as the rest of your infrastructure. Garage ships as a single binary with systemd, Docker, Kubernetes and Ansible deployment paths, and a community-maintained web UI exists for operators who prefer a dashboard to the command line.

Security

Use long, random values for the RPC secret and every access key — these are what stand between your cluster and anyone who can reach the ports. Bind the S3 and admin ports to a VPN or a known client IP if you do not need them public. Garage moves and replicates bytes; it does not encrypt them for you, so combine it with client-side encryption when the data is sensitive.

Garage vs the single-box options

Option Nodes Survives a node loss? Best for
rclone serve s3 1 No The simplest S3 endpoint on one box
MinIO (rootless Docker) 1 No One box, plus a web console and bucket policies
Garage 3+ Yes A self-owned, redundant S3 spread across boxes

For a single box, use rclone serve s3. Reach for Garage when you have the boxes to spread the risk across.

See also