English · Español
Host static websites on a peer-to-peer network: free addresses, no servers to rent, and no single point anyone can switch off.
Status: early development (v0.1). Publishing, replication, and address books work end to end and are tested against real Kubo nodes. Interfaces and formats may still change. Use disposable keys and public content only.
- Your address is a key.
meshkeep key create bloggives you an address likek51qzi5uqu5d…. Nobody sells it, nobody can take it from you, and it costs nothing. - Your site is content-addressed. Each version is an immutable IPFS directory identified by its hash. Whoever has a copy can serve it, and every visitor can check that the bytes are right.
- Anyone can keep it alive. Replicas, which are other people's machines, keep a full copy and keep your signed address record circulating. Once replicas hold it, the site stays up even if your own computer is gone, the way a torrent outlives its first seeder.
- People use names, not hashes. Everyone keeps an address book (
book add blog k51…) that maps their own nicknames to addresses. Books can be shared and imported. A browser extension that works like a contact list is planned.
There is no blockchain, no token, no central registry, and no Meshkeep server. Under the hood, Kubo (IPFS) does the storage, transfer, and signed names. Meshkeep adds the workflow, the rules, and the address book.
Meshkeep is not anonymous: peers can see the IP addresses of the nodes they talk to. It does not guarantee permanence (a site lives while someone replicates it) or deletion (copies can't be recalled). See the threat model.
You need Node.js 22.12 or later, pnpm, and a running Kubo daemon whose RPC API listens on 127.0.0.1:5001.
pnpm install && pnpm build
alias meshkeep="node $PWD/packages/cli/dist/bin.js"
# Once per Kubo node: use the import profile that makes versions reproducible.
ipfs config profile apply unixfs-v1-2025 # then restart the daemon
meshkeep doctorPublish a site:
meshkeep key create blog # prints your address, k51…
meshkeep publish ./public --key blog # imports, pins, and signs v1
# edit ./public, then publish again: same address, new versionReplicate someone's site, with a petname:
meshkeep book add their-blog k51qzi5uqu5d…
meshkeep replicate their-blog # full copy + keeps the address alive
meshkeep replica run # stays running: re-checks every site every 6 hoursInstead of replica run, you can run meshkeep sync from cron at least every 12 hours. Or run a whole replica, Kubo included, with Docker: cd examples/docker && docker compose up -d pulls the published image (ghcr.io/ericpastorm/meshkeep, amd64 and arm64) and Kubo (see the operator guide).
Replicas only fetch what they agreed to hold. Each site has a size and block limit (by default 2 GiB and 250,000 blocks). Set it with replicate --max-size 512MiB --max-blocks 50000; the value is remembered, and sync applies it. Versions over the limit are refused and left unpinned. An interrupted or timed-out fetch (--fetch-timeout, default 30 minutes) records nothing, and the next run resumes from the blocks already downloaded.
Every version stays pinned unless you choose otherwise: replicate --keep 3 keeps the three most recent versions (remembered for sync), and meshkeep unreplicate their-blog stops following a site. Both only ever unpin versions this replica pinned itself, never a pin you or meshkeep publish made on the same node.
Help keep a whole community online by following a curator's published address book, the way you would subscribe to a torrent list:
meshkeep book publish --key my-list # curator: publish your address book as a site
meshkeep follow k51…curator # replica: replicate every site it lists, and keep up
meshkeep unfollow k51…curator # stop, releasing the sites only that book wantedsync and replica run pick up the curator's changes. Sites the book stops listing are dropped unless you replicate them yourself or another followed book lists them. --max-sites (default 100) and per-site limits bound what a curator can ask of you. See ADR 0003.
Visit a site through any Kubo node's gateway: http://127.0.0.1:8080/ipns/k51…/.
Move publishing to another machine:
meshkeep key export blog blog.key # unencrypted, so move it securely and delete it after
# on the other machine:
meshkeep key import blog blog.key
meshkeep publish ./public --key blog # continues from the latest versionAdd --json to any command for machine-readable output on stdout. Diagnostics go to stderr. Meshkeep keeps its state in $MESHKEEP_HOME (default ~/.config/meshkeep).
Running a publisher or replica for real? Read the operator guide: Kubo setup, key backup, scheduling sync with systemd or cron, disk space, and troubleshooting.
publisher replicas visitor
───────── ──────── ───────
static dir ─► UnixFS CID
key ─► signed IPNS record ──────► verify signature + sequence
pin every block, verify offline
re-put record into the DHT ────► resolve address
serve blocks ──────────────────► fetch + verify by CID
See the architecture, the specification, and ADR 0002 for the reasoning.
packages/protocol addresses, keys, petnames, address book (pure TS, browser-safe)
packages/kubo narrow Kubo RPC client (loopback-only by default)
packages/cli the meshkeep command
spec/ normative rules, JSON schema, interoperability fixtures
tests/integration private Kubo network in Docker, full lifecycle test
docs/ operator guide, architecture, threat model, privacy, ADRs
examples/ demo site, Docker Compose replica, systemd units for the daemon and scheduled sync
Dockerfile the meshkeep image (Node.js + one bundled file), runs the replica daemon
pnpm install
pnpm check # lint, typecheck, unit tests, build
pnpm test:integration # needs Docker; starts five Kubo containers on a private networkThe integration test publishes v1 and replicates it to two replicas, then shuts the publisher down. It moves the key to a second publisher, publishes v2 and syncs. Finally it shuts every publisher down and checks that a brand-new visitor can still resolve and load the site from the replicas alone. It also checks that tampered and rolled-back records are rejected. Further suites cover replica size and block limits with an interrupted fetch that resumes later, the replica daemon, and the container image (built from the checkout and run next to Kubo as compose runs it).
Next up: the browser extension with an address-book UI and in-browser verified retrieval. See ROADMAP.md.
Read CONTRIBUTING.md and the Code of Conduct. Report vulnerabilities privately as described in SECURITY.md. Code is licensed under the Mozilla Public License 2.0.