DEPLOYMENT.md raw

Deploying torly

This is the deployment used for torly.smesh.lol: one TinyGo binary behind Caddy, serving the relay and Blossom endpoints. The old orly service and its database have been removed from the host.

Host layout

/usr/local/bin/torly              torly binary
/usr/local/bin/torly-monitor      health check
/etc/torly/torly.env              torly environment
/etc/systemd/system/torly.service
/etc/systemd/system/torly-monitor.{service,timer}
/home/mleku/.local/share/torly/
  relay.key                       stable relay signing key
  db/                             torly WAL and indexes
  blossom/blobs/                  content-addressed Blob files
  blossom/index.log               Blob ownership index
  monitor-status.json             last health check

torly listens on 127.0.0.1:3336. Caddy terminates TLS and proxies https://torly.smesh.lol/, https://relay.orly.dev/ and https://relay.mleku.dev/ and their WebSocket endpoints to that port. All three names serve the same relay identity 350abd25b77d4d6a11e66e022efa181c759e07a2828b8cc9a80034bcf4161d88.

Service control

systemctl status torly
systemctl restart torly
journalctl -u torly -n 100
curl -sS http://127.0.0.1:3336/health

torly.service uses TORLY_CONN_WORKERS=256 and TORLY_BLOSSOM_MAX_BLOB_MB=128 from /etc/torly/torly.env. The worker pool is fixed; the acceptor is a raw nonblocking IPv4 socket with a 1024-connection backlog. Database startup waits up to two minutes because replaying a large WAL after an unclean shutdown can take that long.

Monitor

torly-monitor.timer runs every five minutes. It checks /health, the NIP-11 document and that torly.service is active, then writes monitor-status.json. After three consecutive health failures it restarts torly. It does not depend on orly or a mirror process.

cat /home/mleku/.local/share/torly/monitor-status.json
journalctl -u torly-monitor -n 50
systemctl list-timers torly-monitor.timer

Blossom backup and restore

The backup is a tar with manifest.json first, followed by blobs/<sha256>. Blob metadata (owner pubkey, MIME type, upload time) is in the manifest. The offline backup command requires the relay to be stopped because it opens the Blob store directly.

systemctl stop torly
runuser -u mleku -- /usr/local/bin/torly blossom-backup \
  --data-dir /home/mleku/.local/share/torly \
  --out /home/mleku/torly-blossom-$(date +%Y%m%d-%H%M%S).tar
systemctl start torly

The default restore is live. The CLI copies the tar atomically to DATA/blossom/restore.tar; the running Blossom domain notices it within one second, imports every blob, writes restore.status.json, and removes the spool:

runuser -u mleku -- /usr/local/bin/torly blossom-restore \
  --data-dir /home/mleku/.local/share/torly \
  --file /home/mleku/torly-blossom-YYYYmmdd-HHMMSS.tar

Use --offline to open the store directly while torly is stopped. Restore verifies every SHA-256, skips blobs already present, and preserves metadata. The live path is safe to repeat: the import is idempotent.

For a database backup, stop torly and copy the whole data directory; the WAL and index files are only consistent while the process is stopped.

Migrating Blossom out of orly

The old Blossom data lived in Badger. tools/orly-blossom-extract is a standalone Go module that scans blob:meta: records and files and writes a torly backup tar. It must run as the orly user with orly stopped so Badger can take the lock:

cd tools/orly-blossom-extract
go build -o /usr/local/bin/orly-blossom-extract .
runuser -u mleku -- /usr/local/bin/orly-blossom-extract \
  --db /home/mleku/.local/share/ORLY \
  --out /home/mleku/torly-blossom.tar

The migration used here produced 659 blobs (564 MB); the live restore reported {"ok":true,"restored":68,"skipped":591} because most blobs were already present from an earlier partial run. The old orly database has since been deleted.

Caddy

The site block is kept in deploy/Caddyfile.torly and appended to /etc/caddy/Caddyfile:

torly.smesh.lol {
	import compress
	import block_bots
	import no_adtech
	header Access-Control-Allow-Origin *
	header Access-Control-Allow-Headers "Accept, Authorization, Content-Type"
	reverse_proxy 127.0.0.1:3336
	log {
		output file /var/log/caddy/torly.smesh.lol.log
		format json
		level INFO
	}
}

The relay.orly.dev and relay.mleku.dev blocks also reverse-proxy to 127.0.0.1:3336. caddy validate --config /etc/caddy/Caddyfile must be run as root only after the log file exists with owner caddy; caddy validate run as root can create the log file as root and make the subsequent reload fail with permission denied. If that happens, remove the root-owned file and reload Caddy again.

Migration notes

malformed JSON (out of 2,114,719 lines). torly's strict decoder rejected them and the importer counted them under invalid; they are not present in torly. This loss was accepted.

Badger extractor above.

identity and graph-result signatures.

queries but are skipped entirely by the graph index.