spiped: The Symmetric-Key Encrypted Pipe Daemon That Replaces ssh -L When You Don't Actually Want SSH

2026-08-25

Colin Percival (of tarsnap and scrypt fame) wrote spiped in 2011 for tarsnap's own infrastructure. It creates authenticated, encrypted TCP pipes between two IP:port pairs using a preshared 32-byte key. No SSH daemon. No user accounts. No TLS certs to rotate. Just a keyfile on both ends.

Install: apt install spiped — it's been in Debian since 2013 and nobody uses it.

The setup

Generate a key once and copy it (mode 600) to both hosts:

dd if=/dev/urandom of=pg.key bs=32 count=1

Server side — accept encrypted traffic on 8022, forward plaintext to local Postgres:

spiped -d -s '[0.0.0.0]:8022' \
       -t '[127.0.0.1]:5432' \
       -k /etc/spiped/pg.key

Client side — accept plaintext on 15432, encrypt, ship to the server:

spiped -e -s '[127.0.0.1]:15432' \
       -t 'db.example.com:8022' \
       -k /etc/spiped/pg.key

Now psql -h 127.0.0.1 -p 15432 talks to remote Postgres over an authenticated, encrypted pipe with perfect forward secrecy. No SSH tunnel. No stunnel. No HAProxy.

Why not just ssh -L?

ssh -L is a jack-of-all-trades tunnel: it requires sshd running on the far end, a user account, keys or passwords for that user, and an SSH session that stays up (which is why autossh exists). Every one of those is a moving part. spiped needs one file and a daemon that starts at boot.

The wire protocol is deliberately narrow: HMAC-SHA-256 authenticates the handshake, then per-connection ephemeral Diffie-Hellman produces AES-CTR + HMAC-SHA-256 session keys. A compromised keyfile today does not decrypt yesterday's captured traffic.

The tricks that actually pay off

Exposing an unauthenticated service. Redis, memcached, and old-school Postgres have laughable or no wire security. Bind them to 127.0.0.1 and let spiped be the internet-facing listener. Port scanners just see a socket that accepts and drops — no version banner, no error message, no distinguishing feature.

Machine-to-machine trust without users. In replication or monitoring flows you want host A to talk to host B, not user shaun@A to log into B. spiped models that directly: the trust lives between the hosts, not between a person and a host. No authorized_keys to audit.

Timing-safe handshake. Both sides run the full protocol before either learns whether the peer has the right key. Nmap sees the same behavior whether you know the secret or not.

Slow-loris resistant. -o <seconds> bounds the handshake; incomplete connections get axed. -n <count> caps concurrent connections. Real production knobs.

systemd-friendly. Foreground mode with -F, a real pidfile with -p, and a clean exit on SIGTERM. Drop it into a unit file and forget it exists.

Key rotation without downtime. Start a second spiped on a new port with the new key, migrate clients, kill the old daemon. No CA to reissue, no cert chain to rebuild.

Weight: about 3,000 lines of C, one dependency (OpenSSL for AES/SHA primitives), no config file format to memorize. It has been running unchanged in tarsnap's production since before Docker existed.

Key Takeaway: When two hosts you control need an authenticated encrypted TCP pipe, spiped replaces the SSH tunnel, the stunnel config, and the cert rotation cron with one 32-byte keyfile and a daemon that just runs.

All newsletters