Getting Started

End-to-end in seven steps: install the CLI, register on a public node, publish your identity, add a friend, send a message. ~5 minutes.

Prefer a GUI? An alpha desktop + Android app ships installers for macOS, Linux, Windows, and Android — see the clients page. Same protocol, same DNS plumbing; the rest of this walkthrough sticks with the Python CLI.

  1. What you need
  2. 1. Install the CLI
  3. 2. Set a passphrase
  4. 3. Create your config
  5. 4. Register on the node
  6. 5. Publish your identity
  7. 6. Add a friend
  8. 7. Send and receive
  9. Try it with a friend
  10. Troubleshooting
  11. Next

What you need

  • Python 3.10+ (or use the standalone binary, no Python required)
  • A passphrase you’ll remember — it’s the only thing protecting your keys

You don’t need to run a node. This guide uses the public reference node at dnsmesh.io. Run your own later if you want to — see Deployment.

1. Install the CLI

Pick one:

# PyPI (recommended)
pip install dnsmesh

# or single-file binary, no Python:
#   https://github.com/oscarvalenzuelab/DNSMeshProtocol/releases

Verify:

dnsmesh --help

2. Set a passphrase

The passphrase derives your identity keys (Argon2id). The CLI reads it from DMP_PASSPHRASE first, then a file you point at, then an interactive prompt.

The simplest persistent setup is a passphrase file:

umask 077
mkdir -p ~/.dmp
openssl rand -base64 32 > ~/.dmp/passphrase
chmod 400 ~/.dmp/passphrase

You’ll point the config at it in step 3. Back this file up to a password manager — losing it loses your identity.

Don’t export DMP_PASSPHRASE='hunter2' directly: that lands in your shell history. Use read -rs DMP_PASSPHRASE if you really want an env var.

3. Create your config

Pick a username. Addresses look like <username>@dmp.dnsmesh.io.

dnsmesh init alice \
    --domain dmp.dnsmesh.io \
    --endpoint https://dnsmesh.io

Then wire up the passphrase file:

echo 'passphrase_file: ~/.dmp/passphrase' >> ~/.dmp/config.yaml

Sanity-check that the keys derive cleanly:

dnsmesh identity show

That prints your Ed25519 + X25519 public keys. If you see them, you’re set — the first successful derive also writes a typo-tripwire into the config so a wrong passphrase later fails loudly instead of producing a silent second identity.

4. Register on the node

This is the one HTTPS hop in the entire flow. The node mints a per-user TSIG key scoped to your identity’s DNS owner names. Every record write after this is RFC 2136 DNS UPDATE under that key — no further HTTPS.

dnsmesh tsig register --node dnsmesh.io

You’ll see the minted key name and its scope (which owner names it can write to). The token is saved to ~/.dmp/tokens/dnsmesh.io.json.

5. Publish your identity

dnsmesh identity publish
dnsmesh identity refresh-prekeys

The first command publishes your identity record so others can resolve you via DNS. The second pre-positions a pool of one-time prekeys for forward secrecy — without them, your first inbound message degrades to long-term-key encryption (still encrypted, just not forward-secret).

You’re now reachable as alice@dmp.dnsmesh.io.

6. Add a friend

To send to someone, the CLI needs their identity record pinned. Get it via DNS and add as a contact in one step:

dnsmesh identity fetch bob@dmp.dnsmesh.io --add

The --add flag pins their signing pubkey. Future messages from unknown signers are rejected unless explicitly accepted via dnsmesh intro.

7. Send and receive

# Send
dnsmesh send bob@dmp.dnsmesh.io "hello bob"

# On bob's side:
dnsmesh recv

That’s the whole loop. Receive shows decrypted messages with the sender’s signing-key prefix and a timestamp.

Try it with a friend

Two CLIs, two passphrases, two DMP_CONFIG_HOME directories — same flow on one machine. Replace alice/bob and the passphrase paths:

# Terminal 1 — alice
export DMP_CONFIG_HOME=/tmp/alice
export DMP_PASSPHRASE="$(cat /path/to/alice-passphrase)"
dnsmesh init alice --domain dmp.dnsmesh.io --endpoint https://dnsmesh.io
dnsmesh tsig register --node dnsmesh.io
dnsmesh identity publish

# Terminal 2 — bob
export DMP_CONFIG_HOME=/tmp/bob
export DMP_PASSPHRASE="$(cat /path/to/bob-passphrase)"
dnsmesh init bob --domain dmp.dnsmesh.io --endpoint https://dnsmesh.io
dnsmesh tsig register --node dnsmesh.io
dnsmesh identity publish
dnsmesh identity fetch alice@dmp.dnsmesh.io --add
dnsmesh send alice@dmp.dnsmesh.io "hi alice"

# Back in terminal 1 — alice
dnsmesh identity fetch bob@dmp.dnsmesh.io --add
dnsmesh recv

Troubleshooting

registration rate-limited (429) — public nodes cap registrations per IP. Default budget is generous; hit it only if you’re testing in a tight loop. Wait a minute and retry.

subject already held by a different key (409) — your username is taken on this node, OR you registered before from a different machine and don’t have the matching passphrase here. Pick another username, or restore the passphrase that originally registered.

no identity record at id-... — the address you’re fetching hasn’t published an identity yet, or hasn’t published at the zone you think they have. Verify with: dig _dnsmesh-heartbeat.<their-zone> TXT.

no claim provider accepted the discovery pointer — first-contact reach needs a claim provider both ends agree on. The default dmp.dnsmesh.io works for users on the public node. Operators of private deployments can pin one with dnsmesh config set claim-provider <url>.

Next