Skip to content
solutionforestPublic

About

Lightweight, self-hosted S3-compatible object store in Rust: soft delete, point-in-time recovery, built-in MCP. AGPL-3.0.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Tidemark

Self-hosted S3-compatible object storage in Rust, with undo built in.
One static binary, one data directory, no external services.

ci security release licence s3-tests 88%

Quick start · Features · Maturity · S3 compatibility · Operations · MCP

Admin UI: deleted objects with a Restore button

Warning

Beta (v0.1.0-beta.2). Single node, tested but young. The on-disk format is frozen: data written by this release opens in every later one. Keep an independent backup. Formerly named Cairn.

Why Tidemark

Most self-hosted object stores lose a deleted object for good unless you turned versioning on beforehand. Tidemark keeps history for every bucket, always:

  • Undo mistakes. Deleted or overwritten objects, and whole buckets, go to a trash you restore from (30 days by default).
  • Time travel. Read or restore any bucket as it was at any instant in that window. No snapshot needed.
  • Store once. Identical content is written to disk once; copies and restores cost no space.
  • Built-in MCP. AI agents use the same storage under the same IAM rules as everyone else.
  • Small. 14.6 MiB static binary, about 10 MiB idle memory on Linux (measured in CI).

Quick start

git clone https://github.com/solutionforest/tidemark && cd tidemark
scripts/start.sh --ui

scripts/start.sh output

This downloads the release binary (checksum verified), creates ./tidemark-data with random root keys, and serves S3 on 127.0.0.1:9000 and the admin UI on 127.0.0.1:9080. Ctrl-C stops it.

source tidemark-data/credentials.env
aws s3 mb s3://photos
aws s3 cp ./cat.jpg s3://photos/
aws s3 rm s3://photos/cat.jpg                                  # oops
./tidemark admin trash restore --bucket photos --key cat.jpg   # back, byte-identical

Connect any S3 app (rclone, restic, Cyberduck, Nextcloud, Immich, Velero…): endpoint http://127.0.0.1:9000, region us-east-1, path-style, keys from credentials.env.

Docker Compose
printf 'TIDEMARK_ROOT_ACCESS_KEY=%s\nTIDEMARK_ROOT_SECRET=%s\n' \
  "$(openssl rand -hex 10)" "$(openssl rand -base64 30)" > .env && chmod 600 .env
docker compose up -d                 # S3 on 127.0.0.1:9000
docker compose --profile ui up -d    # plus admin UI on 127.0.0.1:9080

Image ghcr.io/solutionforest/tidemark (amd64, arm64) runs read-only as non-root; data lives in the tidemark-data volume.

Plain Linux binary
v=v0.1.0-beta.2; t=$(uname -m)-unknown-linux-musl
base=https://github.com/solutionforest/tidemark/releases/download/$v
curl -fLO "$base/tidemark-$v-$t.tar.gz" -fLO "$base/SHA256SUMS"
grep " tidemark-$v-$t.tar.gz\$" SHA256SUMS | sha256sum -c - && tar xzf "tidemark-$v-$t.tar.gz"
./tidemark-$v-$t/tidemark init --data-dir ./tidemark-data
./tidemark-$v-$t/tidemark serve --config ./tidemark-data/tidemark.toml

Start at boot with deploy/tidemark.service. Put TLS and a firewall in front before exposing it to a network.

Admin UI by hand

One HTML page plus a one-file Python or PHP backend that keeps your keys out of the browser. Local machine only.

export TIDEMARK_ENDPOINT=http://127.0.0.1:9000 TIDEMARK_ACCESS_KEY=... TIDEMARK_SECRET_KEY=...
python3 admin-ui/server.py        # or: php -S 127.0.0.1:9080 admin-ui/server.php

Features

S3 API Buckets, objects, versioning, multipart, CopyObject, ListObjects v1/v2/versions, tagging, Range and conditional requests, 5 checksum algorithms, presigned URLs, lifecycle expiration. Operation list
Recovery Trash for objects, versions and buckets; point-in-time reads (x-tidemark-as-of) and bucket restore. Guide
Access control IAM users, keys and policies, bucket policies, PublicAccessBlock, SigV4. Actions
Encryption SSE-S3 (AES256) and bucket default encryption, master key sealed at rest. Config
Malware scanning Uploads are streamed to ClamAV or your own HTTP endpoint before they are stored; infected files land in a quarantine bucket. Guide
AI agents MCP over stdio or HTTP; every tool call is an IAM-checked request. Guide
Operations Backups of the running server, restore, fsck and scrub, disk-full handling, Prometheus metrics with tested alert rules and a Grafana dashboard (deploy/), health endpoints. Guide
flowchart LR
    apps["S3 apps"] -->|S3 API| api
    agents["AI agents"] -->|MCP| api
    ui["Admin UI / CLI"] -->|admin API| api
    subgraph tidemark["tidemark (one binary)"]
        api["IAM check"] --> engine["Engine"]
        engine --> meta[("metadata + history")]
        engine --> blobs[("blobs, stored once")]
    end
Loading

Maturity

Area State Evidence
S3 API, single node 🟡 Alpha 324 of 370 ceph s3-tests (88%) gate every push; aws-cli, rclone, mc and aws-sdk-s3 tested
Trash, time travel, dedupe 🟡 Alpha Integration tests; restores checked byte-identical
Upgrades 🟢 Beta On-disk format frozen at beta.1; data from 0.1.0-alpha.3 on opens in every later release, checked in CI on every push
Security 🟡 Alpha Self-review of the auth code (5 fixes, each with a test), nightly fuzzing, cargo audit and cargo deny in CI; no external audit yet
Crash safety 🟡 Alpha kill -9 mid-write tests, weekly 2 h soak with a kill every 10 min and a disk-full window, fsck clean after; 13.5 h soak with 81 crashes clean, 24 h run open
Performance 🟡 Alpha Measured on 4 vCPU cloud disk: ~2 100 small PUT/s, ~5 000 small GET/s, 200–1 100 MiB/s large objects
Backups and monitoring 🧪 New Live-server backups, 11 alert rules with unit tests and a Grafana dashboard, all run against a real server and Prometheus in CI; new in beta.1
Malware scanning 🧪 New ClamAV + EICAR tested end to end; new in beta.1
Clustering, erasure coding, replication, OIDC, Object Lock ⛔ Not in v0.1 Single node by design

Road to stable: the data format is frozen and every upgrade is tested. v0.1.0 needs a clean 24 h soak and comes after two betas at least two weeks apart with no data-affecting bug open. Full checklist: PRODUCTION-READINESS.md.

When to pick something else

RustFS VaultS3 Garage Tidemark
Undo an unplanned delete no only if versioning was on no yes, every bucket
Read a bucket at time T no prior snapshot only no any T in the window
Identical bytes stored once no no no yes
MCP with the same IAM rules separate server no no built in
Clustering / erasure coding yes yes replication no
Built-in file browser yes yes no no (use any S3 app)

Need several nodes, a file browser or OIDC today? Use VaultS3, RustFS or Garage.

Getting your data out

Nothing locks you in: it is plain S3. rclone sync or aws s3 sync to any other S3 store while Tidemark keeps serving reads. Every release stays AGPL, forkable and buildable.

Docs

Operations Config S3 compatibility
MCP Extensions Design
Readiness Changelog Security

Contributing

Issues only, no pull requests. Open an issue; our AI agent reproduces and fixes it, a maintainer reviews. Details in CONTRIBUTING.md. Security reports go private: SECURITY.md.

No telemetry, no account, no licence key, no CLA.

Licence

AGPL-3.0-only. Self-hosting, even commercially, has no obligations beyond the notice. If you modify Tidemark and offer it to others over a network, you must share your changes.

About

Lightweight, self-hosted S3-compatible object store in Rust: soft delete, point-in-time recovery, built-in MCP. AGPL-3.0.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages