resticDedup, compression, and encrypt-then-upload straight to object storage. The workhorse for files, buckets, and most datastores.
On a schedule, the agent restores a backup into a throwaway sandbox, runs the checks for its type, and tears it down. Pass or fail, with the observed RTO, lands on your board and in your notifications. Older backups are proven in turn, and a restic repository is read in parts until every stored byte is checked. A run’s stores verify and restore together as of one moment where each store’s backup allows it, versioned buckets included; the run says plainly when a store can’t, and every row that names a missing object is reported.
› Read the docsWAL-G or pgBackRest archives PostgreSQL’s write-ahead log to your targets as it is written, so a restore can land on any moment in the window, not only on a backup. Anti-affinity keeps every copy on another vendor and region.
› Read the docsMove a PostgreSQL primary to a replica on request, or automatically when observers agree it is down, even while TillArk itself is unreachable: the old primary is fenced first, and a replica is promoted only when its measured lag is in bounds. Your Cloudflare DNS records, or your webhook, move clients to it before it takes writes. Runs on Neon and on PostgreSQL you run, with logical replication or streaming replication across up to nine servers.
› Read the docsThe agent encrypts every backup before it leaves your environment, so the storage vendor only sees ciphertext. Credentials reach the agent sealed with hybrid post-quantum key exchange.
› Read the docsWith object lock, a backup can’t be deleted or overwritten inside its retention window, and the agent confirms the lock before every write. A policy can require copies under separate credentials.
› Read the docsrestic, WAL-G, pgBackRest and clickhouse-backup, plus each datastore’s own dump tools, driven by a Go agent you run, across S3, R2, B2, Wasabi, GCS, Azure, MinIO and SFTP. We own the manifest, not a backup engine.
› Read the docsOn a cadence, TillArk restores a real backup into an ephemeral, network-isolated, per-tenant sandbox, asserts its integrity — signature, schema hash, row counts, checksums — tears it down, and emits the result. Every bar below is one real restore that actually happened, with the RPO and RTO it measured.
This turns “we take backups” into “we’ve proven the last N restores worked.” A silent failure — expired credentials, a changed bucket policy, quiet corruption — surfaces as a red restore on a board, not as a discovery at 3 a.m. during the outage you were saving for.
It is the honest, monitored SLA the incumbents don’t offer — and each policy sets its own verification schedule, so you choose how often proof runs.
Proof covers what you keep, not just the newest copy. Verifications on one schedule start staggered, older backups are proven in turn, and on restic each verification reads one more part of the stored data against its hashes, so over thirty runs every stored byte has been read.
Restore-verification guide →Scheduled backups and a continuous WAL archive go to the targets you choose, and residency-aware anti-affinity makes sure each copy lands on a different vendor and region than the source — but never outside the residency zone it’s allowed in. A copy in the same blast radius isn’t a backup.
Keep every policy in one file next to your code. A plan shows exactly what a change does and flags one that keeps fewer backups or loosens where copies may land; apply makes every change or none, each in the audit log. Hourly backups, two copies on other vendors and regions inside the EU under separate keys, and a real restore proven every day at 04:00 UTC.
There is a primary role and a replica role, and roles move between nodes — which dissolves the “original vs backup” confusion at the heart of a botched failback. A failover fences the old primary first, then promotes a replica whose lag is measured and in bounds. Before it takes writes, the agent points your DNS records at it or tells your webhook; without either, you repoint your app. To come home, reseed the old primary from the new one and fail back: the agent proves it holds every committed write before it switches. Or finish the failover and keep the new primary.
Automatic failover is opt-in. By default a failover waits for an admin and a second approver, because the fast wrong answer during an incident is worse than the careful right one. Arm it per source once observers watch the primary from where your application runs, and turn on autonomy so an outage that also cuts you off from TillArk still fails over. Failover is in preview, on Neon and on PostgreSQL you run.
Failover reference →four-eyesAn owner or admin requests the failover, or arms automatic failover, and a different one approves it. One person, or one leaked token, can’t move your primary.
confirmAutomatic failover waits until a quorum of observers, one of them where your application runs, has not reached the primary for the whole confirm window. A partition or a blip is not an outage.
fenceThe old primary is fenced before promotion — on Neon its compute is suspended and its role password reset; on PostgreSQL you run, your application’s roles are locked out and it turns read-only — so your application can’t write to it even if it is still alive. Nothing is fenced unless a replica could be promoted, and if fencing fails, nothing is promoted.
lag boundA replica is promoted only with a lag measured in the last 5 minutes and at most 30 seconds, measured again just before promoting; in an outage, as it stood when the primary went down. Unknown lag is never treated as zero.
autonomyOpt in, with a second approver, and the replica’s agent can fail over on its own when TillArk itself is unreachable: on the same rules, under a grant TillArk signs with Ed25519 and ML-DSA-65, and rechecked from the observers’ signed reports once it reports back.
anti-flapA cap per window and a cooldown after any failover stop ping-pong, and a failed failover stops automatic failover until someone re-arms it.
catch up firstOne failover at a time per source. Failback is a deliberate switchover once the old primary has caught up — never an automatic flip.
clients followAfter fencing and before the promoted node takes writes, the agent points your Cloudflare DNS records at it and reads them back, or calls your signed webhook, which can refuse. If the promotion fails, clients are pointed back. Records that drift from the primary are flagged.
synchronousOn PostgreSQL you run, see whether each replica holds every commit the primary acknowledged, and why not; let the agent keep synchronous replication set, on one standby or a quorum of several. When one of up to nine servers is promoted, the other standbys follow it, and it never inherits a wait for a standby that isn’t there.
three tiersEach source shows three durability tiers side by side: a synchronous replica, a replica on another provider that could take over, and a continuous WAL archive. When one lapses, an alarm opens; when it holds again, it closes.
Backups are the single highest-value target an attacker can steal once and hold forever, so TillArk is designed as if the ciphertext is already stolen. Data is encrypted inside the agent, before it leaves your environment, and written to object-locked storage with credentials sealed to one approved agent.
Whole classes of bug are made structurally absent, not merely filtered: command injection (CWE-78) can’t occur because the agent only ever builds argv arrays, and SSRF (CWE-918) can’t reach your metadata endpoint because every storage host is re-resolved and IP-pinned, and link-local and metadata addresses never pass.
restic, WAL-G and pgBackRest encrypt every backup, clickhouse-backup’s included, before upload — the storage vendor only ever sees ciphertext.
Hybrid-signed manifests (Ed25519 + ML-DSA-65) are checked before a single byte is trusted.
The agent confirms a target’s lock before every write; a locked backup can’t be deleted or overwritten inside its retention window.
A policy can keep its copies under different keys, so one leaked key can’t reach them all; under compliance-mode lock, no key can erase a backup early.
Every envelope names its suite, so primitives rotate without breaking old backups. Hybrid post-quantum ready.
Real restores, failover and unmasked clones need a second, distinct owner or admin to approve.
A homegrown backup engine’s failure mode is silent data loss you discover at restore time. TillArk doesn’t build one — it drives proven engines with a self-hostable Go agent (a single static binary that runs in your environment, so data and credentials stay on your side). Our originality goes into the manifest, the verification, and the orchestration.
resticDedup, compression, and encrypt-then-upload straight to object storage. The workhorse for files, buckets, and most datastores.
WAL-GParallel physical backups and continuous WAL archive for Postgres — the foundation under point-in-time recovery. Delta backups store only the pages that changed, and every backup a chain holds is checked against its signed manifest.
pgBackRestThe same continuous WAL archive, on object storage or an SFTP server, with differential and incremental backups between fulls. Every file is checked against its checksum on restore, and every WAL segment before recovery replays it.
clickhouse-backupCopies MergeTree tables’ data parts from a snapshot instead of reading every row, so large ClickHouse servers back up without a full export. Proven by restoring the parts and running CHECK TABLE on every table.
native dump toolspg_dump, mysqldump or mariadb-dump, mongodump, the Redis protocol, Meilisearch’s API, ClickHouse’s native format and a TillForge git server’s own sealed backup, streamed straight into restic.
A backup system sees every byte’s compressibility. When a datastore’s backups turn high-entropy and stop deduplicating, something is encrypting your data. TillArk raises the alarm on the first backup that shows it, quarantines that backup so no one restores it, and can pause the source.
HOW IT WORKS · Every backup’s entropy and dedup ratio are signed into its manifest and charted on your Recovery Board. When entropy jumps and dedup collapses together, judged against that source’s own history, the canary fires.
A PostgreSQL clone of last night’s backup with personal data masked column by column, using the same rules as the SDK’s on-device scrub (M-Pesa, national ID, phone, email). Realistic data to build and test against, without real customer data on a dev box.
HOW IT WORKS · An agent on your own host masks rows as it copies them, so unmasked rows never reach the clone, then serves it over verified TLS with a list of every masked column. It expires on a timer; an unmasked clone needs four-eyes approval.
TillArk isn’t a separate DR appliance to run — it’s the recovery layer of the TillDev workspace you already have. It reuses TillSecrets for keys, TillAuth for approvals, and reports every number to TillPulse.
Live RPO/RTO, replication lag with SLO alarms, restore-verification green/red history, and failover transitions land in the same observability surface as the app they protect.
Keys come from TillSecrets, RBAC and four-eyes approvals from TillAuth, and outbound safety from the shared SSRF guard. TillArk is enterprise-grade because the suite already is.
Every backup, restore, promotion, fence and key rotation lands in an audit log where each entry is chained to the one before by hash and TillArk signs checkpoints over the chain. Check it on your own machine with tilldev ark audit verify. It sits in your workspace audit log next to your Pulse, Auth and Shield events.
Backups, restores, verification, the canary and masked clones are ready. Failover is in preview and runs on Neon. Whatever TillArk runs, it never reports a backup or a restore that didn’t happen.
Stop hoping your backups restore. Prove it — cross-vendor, encrypted before it leaves your box, immutable at rest, and verified on a schedule you can watch.
TillArk protects the rest of the suite — same workspace, same audit log, same login. Add what you need when you need it.