A write-only backup vault that fronts your own git host — client-side encrypted, driven entirely from your machine.
0
stars
70
commits
Rust
primary language
Aug 29, 2026
updated
A write-only backup vault that fronts your own git host — set up and driven entirely from your machine.
Push to a box you already SSH into — a NAS, a VPS, any Linux host. git-ark
auto-creates the repo on first push (no flags, no web UI), and fans every
successful push out to durable, client-side encrypted storage in an S3
bucket — AWS S3, or any S3-compatible store (MinIO, Cloudflare R2, Backblaze B2,
…) — plus an optional GitHub mirror. The host that stores your code can never
decrypt the backups, and (on AWS) the credentials it holds can only write —
never read, list, or delete.
You set the whole thing up from your own machine: discover a box on your LAN,
wire it with one command, and push. A dead disk, a stolen box, or a fat-fingered
rm -rf can't take everything — and nothing touches the public internet unless
you opt a repo in by name.
Installs the client — the command you run on your own machine. Hosts get
their binary automatically from git-ark host add, so they never need this.
macOS / Linux — Homebrew, or a checksum-verified download:
brew tap boomctl/tap
brew install git-ark
# Homebrew 6+ gates third-party taps — if it refuses, run: brew trust boomctl/tap
# or, without Homebrew:
curl -fsSL https://raw.githubusercontent.com/boomctl/git-ark/main/install.sh | sh
Windows — Scoop, or PowerShell:
scoop bucket add git-ark https://github.com/boomctl/scoop-bucket; scoop install git-ark
# or:
irm https://raw.githubusercontent.com/boomctl/git-ark/main/install.ps1 | iex
With Rust:
cargo install git-ark # build from source (crates.io)
cargo binstall git-ark # prebuilt release binary, no compile
Or grab a binary directly from the releases.
Everything below runs on your machine (the client). You never hand-edit files on the host.
# 1. One-time: provision the S3 vault from your machine — picks your AWS
# profile, creates the bucket + write-only key, prints it as export lines.
# (AWS S3 only; for MinIO/R2 bring your own bucket. See docs/provisioning.md.)
git-ark vault provision --bucket git-ark-vault-example
# 2. If you can't already key-auth into the box, set that up (optional):
git-ark host setup-key user@nas.lan # generates + copies a key
# 3. Add the host — probes it, fetches the matching git-ark binary for its arch,
# ships it, wires the forced-command key, writes config + the write-only
# secret, verifies, and registers it:
export GIT_ARK_HOST_S3_KEY_ID=… GIT_ARK_HOST_S3_SECRET=… # the write-only key
git-ark host add nas user@nas.lan \
--bucket git-ark-vault-example --region us-east-1 \
--recipient age1… # your age *public* key
# 4. In a repo, route it and push:
git-ark route . --to nas
git push git-ark # → encrypted backup in S3
# 5. Check on your fleet anytime:
git-ark status
No toolchain, no cross-compile: host add (and upgrade) fetch the right host
binary for your client's version straight from the release and verify it against
the release SHA256SUMS. Pass --binary <path> only for an air-gapped host or a
custom build.
Don't have an age keypair yet? age-keygen -o ~/.config/git-ark/identity.txt
prints the age1… public recipient — keep the private identity off the host;
it's what git-ark restore needs.
The usual advice — "just push to GitHub" — assumes you're ready to put your code
on the internet. Sometimes you're not, but you still need it to survive a
hardware failure. git-ark makes your own host the primary and gives you real
durability without publishing anything:
git push git-ark:new-project just works — the bare
repo is created on first contact.git bundle of the whole repo + history, encrypted with
age to a key the host never holds, and uploaded
to your object store (set s3.endpoint for anything other than AWS S3).s3:PutObject
and nothing else; retention is a bucket lifecycle rule, not the host — so a
compromised host can't wipe your history. (On coarser-token stores like R2 you
keep confidentiality but lose that hardening — see the security model.)git-ark route <repo> --to nas,ec2 → one
git push lands on every host, each keeping its own independent encrypted
copy. Local-fast plus offsite-durable..git-ark.yml; the client designates a single host as the mirror,
keeps the GitHub token only there, and moves/revokes it when you reassign.git-ark restore <repo> pulls from S3, decrypts with
your private key, and clones it back.You run git-ark on your machine to manage a fleet of dumb, write-only hosts. Keys and credentials originate on the client and only their public/least- privilege parts ever reach a host.
| Command | What it does |
|---|---|
git-ark vault provision | create the S3 vault + write-only IAM key from your machine (AWS S3 only) |
git-ark host discover | scan your LAN for sshable hosts to add |
git-ark host setup-key <target> | generate + copy a client SSH key to a box you can't key-auth into yet |
git-ark host add <name> <target> … | probe → ship binary → install forced-command key → write config/secret → verify → register |
git-ark host adopt <name> <target> | register an already-deployed host without touching it — recovery, or a host wired before the registry existed |
git-ark host list / host remove <name> | the host registry |
git-ark route <repo> --to <names> | point a repo's git push git-ark at one or more hosts |
git-ark mirror set <name> / mirror show | designate / show the single GitHub-mirror host (token follows it, revoked from the old) |
git-ark mirror check | preflight the GitHub token against a repo's .git-ark.yml (auth, repo access, workflow scope) |
git-ark status | fleet health: reachable? version? disk? which host mirrors? |
git-ark upgrade <host>│--all | fetch the current release binary (or --binary <path>) and re-verify |
git-ark restore <repo> --identity <key> | restore from S3 on a trusted machine |
Two planes, deliberately separate:
host add installs, which
can run only git verbs. git push rides this.On the host, git-ark is an SSH forced command — no daemon, nothing to keep
running, and your normal login is untouched. When git connects, the shim
resolves (and if needed creates) the bare repo, then hands off to real
git-receive-pack / git-upload-pack. A post-receive hook runs the backup
pipeline synchronously, so progress streams back to your terminal:
$ git push git-ark:myproject main
…
remote: bundling myproject …
remote: encrypting 18874368 bytes …
remote: ✓ backup → s3://git-ark-vault-example/git-ark/nas/myproject/latest.age + …/history/2026-…Z.age
remote: ✓ main NAS + encrypted S3 + GitHub
remote: ✓ disk 56.0 TB free (98%)
Per-repo policy lives in a committed
.git-ark.yml. A repo declares which branches earn the encrypted S3 backup and, via an optionalgithub:block, which branches mirror to GitHub. See.git-ark.example.yml. A repo with no.git-ark.ymluses the host's centralbackup_refsand mirrors nowhere.
See docs/DESIGN.md for the full architecture and threat model,
and docs/deploy.md for the by-hand setup path that host add
automates. For what's proposed — and how we reason about features before
building them — see docs/designs/.
s3:PutObject only — no
read/list/delete. Stores with coarser tokens (e.g. Cloudflare R2 has no
put-only tier) lose that hardening — a compromised host could read/list/delete
the objects, but they're still age ciphertext it can't decrypt.Contributions are welcome — including AI-assisted and AI-authored contributions. This project is built with AI in the loop and embraces it; a good patch is a good patch regardless of how it was written. See CONTRIBUTING.md for details.
git-ark was co-built with Claude
(Anthropic's Claude Code) working alongside its author.
70 commits
Rust
94.6%
Shell
4.5%
A write-only backup vault that fronts your own git host — client-side encrypted, driven entirely from your machine.
0
stars
70
commits
Rust
primary language
Aug 29, 2026
updated
A write-only backup vault that fronts your own git host — set up and driven entirely from your machine.
Push to a box you already SSH into — a NAS, a VPS, any Linux host. git-ark
auto-creates the repo on first push (no flags, no web UI), and fans every
successful push out to durable, client-side encrypted storage in an S3
bucket — AWS S3, or any S3-compatible store (MinIO, Cloudflare R2, Backblaze B2,
…) — plus an optional GitHub mirror. The host that stores your code can never
decrypt the backups, and (on AWS) the credentials it holds can only write —
never read, list, or delete.
You set the whole thing up from your own machine: discover a box on your LAN,
wire it with one command, and push. A dead disk, a stolen box, or a fat-fingered
rm -rf can't take everything — and nothing touches the public internet unless
you opt a repo in by name.
Installs the client — the command you run on your own machine. Hosts get
their binary automatically from git-ark host add, so they never need this.
macOS / Linux — Homebrew, or a checksum-verified download:
brew tap boomctl/tap
brew install git-ark
# Homebrew 6+ gates third-party taps — if it refuses, run: brew trust boomctl/tap
# or, without Homebrew:
curl -fsSL https://raw.githubusercontent.com/boomctl/git-ark/main/install.sh | sh
Windows — Scoop, or PowerShell:
scoop bucket add git-ark https://github.com/boomctl/scoop-bucket; scoop install git-ark
# or:
irm https://raw.githubusercontent.com/boomctl/git-ark/main/install.ps1 | iex
With Rust:
cargo install git-ark # build from source (crates.io)
cargo binstall git-ark # prebuilt release binary, no compile
Or grab a binary directly from the releases.
Everything below runs on your machine (the client). You never hand-edit files on the host.
# 1. One-time: provision the S3 vault from your machine — picks your AWS
# profile, creates the bucket + write-only key, prints it as export lines.
# (AWS S3 only; for MinIO/R2 bring your own bucket. See docs/provisioning.md.)
git-ark vault provision --bucket git-ark-vault-example
# 2. If you can't already key-auth into the box, set that up (optional):
git-ark host setup-key user@nas.lan # generates + copies a key
# 3. Add the host — probes it, fetches the matching git-ark binary for its arch,
# ships it, wires the forced-command key, writes config + the write-only
# secret, verifies, and registers it:
export GIT_ARK_HOST_S3_KEY_ID=… GIT_ARK_HOST_S3_SECRET=… # the write-only key
git-ark host add nas user@nas.lan \
--bucket git-ark-vault-example --region us-east-1 \
--recipient age1… # your age *public* key
# 4. In a repo, route it and push:
git-ark route . --to nas
git push git-ark # → encrypted backup in S3
# 5. Check on your fleet anytime:
git-ark status
No toolchain, no cross-compile: host add (and upgrade) fetch the right host
binary for your client's version straight from the release and verify it against
the release SHA256SUMS. Pass --binary <path> only for an air-gapped host or a
custom build.
Don't have an age keypair yet? age-keygen -o ~/.config/git-ark/identity.txt
prints the age1… public recipient — keep the private identity off the host;
it's what git-ark restore needs.
The usual advice — "just push to GitHub" — assumes you're ready to put your code
on the internet. Sometimes you're not, but you still need it to survive a
hardware failure. git-ark makes your own host the primary and gives you real
durability without publishing anything:
git push git-ark:new-project just works — the bare
repo is created on first contact.git bundle of the whole repo + history, encrypted with
age to a key the host never holds, and uploaded
to your object store (set s3.endpoint for anything other than AWS S3).s3:PutObject
and nothing else; retention is a bucket lifecycle rule, not the host — so a
compromised host can't wipe your history. (On coarser-token stores like R2 you
keep confidentiality but lose that hardening — see the security model.)git-ark route <repo> --to nas,ec2 → one
git push lands on every host, each keeping its own independent encrypted
copy. Local-fast plus offsite-durable..git-ark.yml; the client designates a single host as the mirror,
keeps the GitHub token only there, and moves/revokes it when you reassign.git-ark restore <repo> pulls from S3, decrypts with
your private key, and clones it back.You run git-ark on your machine to manage a fleet of dumb, write-only hosts. Keys and credentials originate on the client and only their public/least- privilege parts ever reach a host.
| Command | What it does |
|---|---|
git-ark vault provision | create the S3 vault + write-only IAM key from your machine (AWS S3 only) |
git-ark host discover | scan your LAN for sshable hosts to add |
git-ark host setup-key <target> | generate + copy a client SSH key to a box you can't key-auth into yet |
git-ark host add <name> <target> … | probe → ship binary → install forced-command key → write config/secret → verify → register |
git-ark host adopt <name> <target> | register an already-deployed host without touching it — recovery, or a host wired before the registry existed |
git-ark host list / host remove <name> | the host registry |
git-ark route <repo> --to <names> | point a repo's git push git-ark at one or more hosts |
git-ark mirror set <name> / mirror show | designate / show the single GitHub-mirror host (token follows it, revoked from the old) |
git-ark mirror check | preflight the GitHub token against a repo's .git-ark.yml (auth, repo access, workflow scope) |
git-ark status | fleet health: reachable? version? disk? which host mirrors? |
git-ark upgrade <host>│--all | fetch the current release binary (or --binary <path>) and re-verify |
git-ark restore <repo> --identity <key> | restore from S3 on a trusted machine |
Two planes, deliberately separate:
host add installs, which
can run only git verbs. git push rides this.On the host, git-ark is an SSH forced command — no daemon, nothing to keep
running, and your normal login is untouched. When git connects, the shim
resolves (and if needed creates) the bare repo, then hands off to real
git-receive-pack / git-upload-pack. A post-receive hook runs the backup
pipeline synchronously, so progress streams back to your terminal:
$ git push git-ark:myproject main
…
remote: bundling myproject …
remote: encrypting 18874368 bytes …
remote: ✓ backup → s3://git-ark-vault-example/git-ark/nas/myproject/latest.age + …/history/2026-…Z.age
remote: ✓ main NAS + encrypted S3 + GitHub
remote: ✓ disk 56.0 TB free (98%)
Per-repo policy lives in a committed
.git-ark.yml. A repo declares which branches earn the encrypted S3 backup and, via an optionalgithub:block, which branches mirror to GitHub. See.git-ark.example.yml. A repo with no.git-ark.ymluses the host's centralbackup_refsand mirrors nowhere.
See docs/DESIGN.md for the full architecture and threat model,
and docs/deploy.md for the by-hand setup path that host add
automates. For what's proposed — and how we reason about features before
building them — see docs/designs/.
s3:PutObject only — no
read/list/delete. Stores with coarser tokens (e.g. Cloudflare R2 has no
put-only tier) lose that hardening — a compromised host could read/list/delete
the objects, but they're still age ciphertext it can't decrypt.Contributions are welcome — including AI-assisted and AI-authored contributions. This project is built with AI in the loop and embraces it; a good patch is a good patch regardless of how it was written. See CONTRIBUTING.md for details.
git-ark was co-built with Claude
(Anthropic's Claude Code) working alongside its author.
70 commits
Rust
94.6%
Shell
4.5%