Scenario

The Personal Cloud

Replace Dropbox / Google Drive / iCloud.

Replace Dropbox / Google Drive / iCloud with three nodes you already own: a VPS for availability, a desktop for the bulk of your files, and a phone for automatic photo upload. Encrypted before it leaves any of them.

What you'll end up with: a vault called Photos replicated across three nodes (RF = 2 reliable + 1 mobile seeder), auto-syncing your phone's camera roll, browsable from any device's web UI.

Prerequisites

  • Any small VPS β€” 1 vCPU, 1 GB RAM, 25 GB disk is enough for ~20 GB of replicated photos.
  • Your usual desktop / laptop (Linux, macOS, or Windows).
  • An Android phone with the MeshHold APK installed. iOS is not supported yet.
  • A domain pointing at the VPS β€” optional, but it gives you free Let's Encrypt TLS.

1. Install the first node (VPS)

Start with the VPS β€” it's the only node guaranteed to be online, so it's our bootstrap peer.

# Ubuntu / Debian
ssh root@vps.example.com
wget https://meshhold.dev/dl/linux/meshhold-amd64.deb
apt-get install -y ./meshhold-amd64.deb

# Set a password for the web UI (daemon stays running)
sudo -u meshhold meshhold set-password -c /etc/meshhold/config.yaml

Prefer Docker? Same binary, no apt step, no system user. Works the same on any host with Docker installed:

bash curl -fsSL https://meshhold.dev/dl/docker/meshhold-amd64.tar.gz \ | gunzip | docker load docker volume create meshhold-data docker run -d --name meshhold --restart unless-stopped \ -p 7777:7777 -p 8080:8080 \ -v meshhold-data:/var/lib/meshhold \ -e MESHHOLD_PASSWORD=changeme \ meshhold:latest-amd64

The image is distroless static and runs as uid 65532. The meshhold-data named volume picks that ownership up automatically; a host-path bind-mount needs chown 65532:65532 first.

Open https://vps.example.com:8080/ and accept the self-signed cert (or configure api.tls.acme_domain in config.yaml for Let's Encrypt). The Setup Wizard greets you with three choices:

  • Create new network β€” pick this on the first node; it mints a fresh swarm-key.
  • Join existing β€” for nodes #2, #3, …
  • Continue offline β€” for trying it out on a laptop with no peers yet.

2. Create a vault

In the web UI, click Vaults β†’ New. Pick:

  • Name: Photos
  • Type: storage
  • Key: any strong passphrase β€” write it down, this is the encryption key.
  • Replication factor: 2 (we want two reliable copies).

RF counts only reliable nodes. Your phone defaults to reliable=false, so it seeds blocks but doesn't count toward the factor. That's the point β€” phones come and go; reliable nodes stay.

3. Pair your desktop

On the VPS, hit Network β†’ Add peer and copy the invite QR or the host:port string. On the desktop:

# Install the desktop binary (Linux example β€” Windows uses the MSI).
sudo apt-get install -y ./meshhold-amd64.deb
systemctl start meshhold

# Open https://localhost:8080/, pick "Join existing", paste the invite.

Within ~20 seconds the desktop appears in the VPS's Network page. Open Vaults, you'll see Photos listed β€” click it and add the same passphrase.

4. Pair your phone

  1. Install the APK and open the app.
  2. Tap Scan invite, point it at the QR from the VPS.
  3. Open Vaults β†’ Photos, enter the passphrase.
  4. Toggle Camera-roll auto-upload. New photos appear on the other nodes in seconds.

5. Set replication and walk away

The defaults are already sane, but you can tune them on the VPS:

vaults:
  - vault_id: "..."
    name: "Photos"
    key: "your-passphrase"
    storage_path: "/var/lib/meshhold/photos"
    full_sync: true               # keep a full copy on the VPS
    replication_factor: 2
    type: "storage"

Restart the daemon. The VPS will pull and decrypt every block; the desktop already has a local copy of files it created; the phone keeps the encrypted ciphertext but can decrypt anything you scroll to.

Troubleshooting

Nodes don't see each other

  • Check the swarm-key matches on both β€” meshhold keygen output, exactly.
  • Open 0.0.0.0:7777 in the VPS firewall.
  • On the second node, paste the VPS's public address into bootstrap_peers.

Phone keeps going offline

Battery optimisation. In Android settings, mark MeshHold as unrestricted β€” and enable UnifiedPush in Profile so wake-ups still reach you when the foreground service is paused.

RF stuck at 1

Open the vault's Health panel. If only one reliable node is online, RF can't climb. Bring up the second reliable node, or temporarily mark a third as reliable: true in its config.

Next up

Add a chat vault for your household (see The Secure Comms Hub), or expose Photos over S3 to back up your Immich instance (see The S3-compatible Backend).