Skip to content

SFTP

SFTP is the right pick when WebDAV is unavailable or awkward — a NAS that only exposes SSH, a Hetzner Storage Box, an SSH-only VPS. Browsers cannot speak SSH directly, so the relay performs the SSH transport on the SPA’s behalf. The SPA still does all the cryptography; the relay only sees V7 ciphertext crossing the SSH session.

FieldExampleNotes
Hostnamenas.example.comDNS or IP.
Port22Defaults to 22. Override for non-standard SSH ports.
UsernamealiceWhatever the SFTP server expects.
Base path/dataOptional. Vault root becomes <base path>/WattcloudVault/. Empty places the vault at the SFTP session root.
Password or Private key (PEM)Either is sufficient. Both are AES-GCM-wrapped on device and forwarded to the relay only at session start.

On first connect the SPA shows the host’s SSH key fingerprint for TOFU (trust-on-first-use) confirmation. After accept, a fingerprint mismatch on a later connect blocks the session — the same way ssh itself behaves.

  • Synology, QNAP, TrueNAS, Unraid (built-in SSH)
  • Hetzner Storage Box (SFTP-only access plan)
  • Plain Linux hosts running OpenSSH
  • Any russh_sftp-compatible server
┌──────────────┐ V7 ciphertext over WSS ┌──────────────┐ SSH (SFTP) ┌──────────────┐
│ Browser │ ───────────────────────▶ │ byo-relay │ ───────────▶ │ SFTP server │
│ (SPA + WW) │ ◀─────────────────────── │ (proxy) │ ◀─────────── │ (your NAS) │
└──────────────┘ └──────────────┘ └──────────────┘
  • Credentials reach the relay per session over TLS, are held only in memory, and are dropped when the session ends or the browser tab closes. Relay disk never sees them.
  • The relay’s SFTP gateway has two protocols: v3 for streaming reads (256 KiB chunks straight from ssh2::File, bounded at 8 concurrent open reads per session) and v2 for resumable writes (≤ 200 MiB server-side buffer, never persisted beyond the upload session).
  • File content the relay forwards is V7 ciphertext — encrypted in the browser before it ever enters the WebSocket. Filenames are AES-GCM-SIV ciphertext, deterministic so the SFTP server doesn’t see plaintext.

The relay caps concurrent SFTP sessions to keep the gateway from being abused as a generic SSH proxy:

VarDefaultMeaning
SFTP_MAX_CONCURRENT_PER_IP3Concurrent SFTP sessions per source IP. Returns 429 at handshake when exceeded.

The default is comfortable for two-device-per-user households. Bump it in /etc/wattcloud/wattcloud.env if you need more parallelism.

  • Key auth is recommended. Generate a dedicated key, paste the PEM into the Private key field, and put the public half in the SFTP server’s authorized_keys. The PEM is encrypted at rest on device and never written to relay disk.
  • Password auth works and is fine for low-stakes or quick setups. Hetzner Storage Boxes accept either.

If a key has a passphrase, the SPA holds it in memory only for the duration of the connect; it is not persisted alongside the key.

  • “Permission denied” on a fresh key. OpenSSH refuses keys whose authorized_keys line is on a 0644 file inside a 0755 ~/.ssh/. Check chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys on the server.
  • Hetzner Storage Box paths. The SSH session lands in your account’s home directory. The vault wants to live somewhere stable — set Base path to /home/wattcloud (or similar) so the vault root doesn’t drift if your home dir changes.
  • Relay’s IP appearing in the SFTP server’s logs. Connections come from your VPS, not from your home IP — that’s expected. If the SFTP server is on the same LAN as the SPA browser and you’d rather skip the relay round-trip, WebDAV is the alternative.
  • WebDAV — usually faster for small-file workloads.
  • S3-compatible — when storage is object rather than filesystem.