hostthis - pipe a rendered file in, get a public URL out
cat <file> | ssh -T hostthis.dev
cat <file> | ssh -T hostthis.dev <slug>
tar czf - <dir> | ssh -T hostthis.dev [<slug>]
ssh hostthis.dev <command> [<args>]
-T is for piped uploads only: it disables the ssh client's
pseudo-terminal request so the client stops printing
Pseudo-terminal will not be allocated because stdin is not a terminal..
It changes nothing on the server. Verb commands (list, get, …) pass
a command argument and never trigger the warning.
Publishes HTML, Markdown, a unified diff, a Mermaid diagram, a PDF, a CSV or JSON document, a profile as an interactive flame graph, structured logs, or plain text with linkable lines, for a configurable window (30 days by default; the operator can change or disable it) at a random subdomain. One ssh pipe, no signup, no install. Identity is your ssh public key: anyone with a different key can read the URL but cannot update, rename, pin, or delete the paste.
A Markdown paste renders in the browser; so does a diff (line-by-line
or side-by-side, with syntax highlighting). Append ?raw to any
rendered paste's URL for the raw source.
cat file | ssh -T hostthis.dev- upload a paste. The URL prints on stdout; a QR code of it prints on
stderr (drop it with
2>/dev/null). To set a label or force the content type, pass--name "label"or--type html|markdown|diff|mermaid|pdf|csv|json|flamegraph|log|textafter a literal--. ssh otherwise parses a leading--nameas one of its own options. cat file | ssh -T hostthis.dev slug- replace slug's content; the URL stays the same
ssh hostthis.dev list [-o json]- your pastes, most recently updated first
ssh hostthis.dev get slug- print content to stdout
ssh hostthis.dev url slug- re-show just the URL for any existing paste or site (no ownership check; not found on an unknown slug)
ssh hostthis.dev qr slug- re-show the URL (stdout) and a QR code (stderr) for any existing paste or site
ssh hostthis.dev rename slug [label]- set the owner label from the remaining words; omit them to clear it
ssh hostthis.dev versions slug [-o json]- list versions
ssh hostthis.dev pin slug ver- stick the URL to ver; survives future updates
ssh hostthis.dev unpin slug- clear the pin; URL serves the latest version
ssh hostthis.dev delete slug- wipe the entire paste; permanent
ssh hostthis.dev delete slug ver- free one version's bytes; keeps the history row as a tombstone
ssh hostthis.dev whoami [-o json]- identity, active count, and quota usage
Pipe a gzip-tar instead of a single file to deploy a multi-file static site.
tar czf - site/ | ssh -T hostthis.dev # deploy, get a URL
tar czf - site/ | ssh -T hostthis.dev abc12345 # re-deploy in place
Served at <slug>.hostthis.dev/<path>, with content type by file
extension. A request that matches no file serves index.html, so
single-page apps route client-side. A single leading directory is
flattened, so tar czf - site/ serves at the root. macOS sidecar files
._*, .DS_Store, and __MACOSX/ are skipped. Delete a site with
delete <slug>, the same as a paste.
A deployed site or paste can store and sync state in a room, with no backend of your own. The room's UUID is the only key. The API is served on the app's own origin.
Durable key-value over HTTP:
POST /api/rooms -> {"id":"<uuid>"} mint a room
GET /api/rooms/<uuid> -> {key: value, ...} read the whole room
GET /api/rooms/<uuid>/<key> -> value read one key
PUT /api/rooms/<uuid>/<key> write one key, body is the value
DELETE /api/rooms/<uuid>/<key> delete one key
Realtime over WebSocket, on the same origin:
GET /api/rooms/<uuid>/ws
On connect you receive a snapshot of the room, then a live stream:
every durable PUT/DELETE is mirrored to all clients as
{"type":"put"|"delete", ...}. Frames you send are broadcast verbatim
to other clients and never stored, for ephemeral motion.
A value is opaque bytes. The whole-room read and the snapshot/put
frames embed each value as JSON when it parses as JSON - a value you PUT
as a JSON object comes back as a nested object, not a quoted string - and
as a JSON string otherwise. Reading a single key returns the raw bytes.
Limits: 256 KiB and 256 keys per room; 64 MiB per app. Deployments without a room store return 404.
100 MiB per identity, counting post-compression bytes across every active version of every active paste. Text compresses 5-10x under zstd, so the real raw-payload ceiling is typically 50-100 MiB.
Pastes are HTML, Markdown, a unified diff, a Mermaid diagram, a PDF, a CSV or JSON document, folded stacks as a flame graph, NDJSON logs, or plain text; sites are a gzip-tar archive. Pastes and sites persist indefinitely.
0 success
1 generic failure
2 usage error: bad arguments or unknown verb
3 identity required: no ssh key presented
4 not found, or not yours
6 refused by the per-subnet rate limit
NO_COLOR set to any value to disable color output
TERM=dumb also disables color output
Read from the environment your ssh client forwards.
# upload, get a URL on stdout (and a QR code on stderr)
cat index.html | ssh -T hostthis.dev
# capture just the URL; 2>/dev/null drops the QR + narration
url=$(cat index.html | ssh -T hostthis.dev 2>/dev/null)
# upload with a label; --name and --type follow a literal --
cat notes.md | ssh -T hostthis.dev -- --name "alpha notes"
# update an existing paste; same URL, bumps to v2, v3, ...
cat v2.html | ssh -T hostthis.dev abc12345
# force content type when sniffing gets it wrong
cat tricky.html | ssh -T hostthis.dev -- --type html
# render a unified diff (auto-detected, or force it with --type diff)
git diff | ssh -T hostthis.dev
cat review.patch | ssh -T hostthis.dev -- --type diff
# a mermaid diagram, a pdf, a csv, a json document - all auto-detected
cat architecture.mmd | ssh -T hostthis.dev
cat q3-review.pdf | ssh -T hostthis.dev
cat sales.csv | ssh -T hostthis.dev
cat events.json | ssh -T hostthis.dev
# a profile renders as an interactive flame graph. The accepted format is
# folded stacks ("a;b;c 123" per line), which every profiler can emit:
# perf via stackcollapse-perf.pl, Go pprof, py-spy --format raw, async-profiler
cat cpu.folded | ssh -T hostthis.dev
# NDJSON logs get levels, filtering and per-line links. This is the shape
# Loki and OpenSearch both work in; their stream and bulk wrappers unwrap.
cat app.ndjson | ssh -T hostthis.dev
# anything else textual renders with a line gutter and citable ranges
cat nginx.conf | ssh -T hostthis.dev
# link to a place INSIDE a paste
# <url>#some-heading markdown heading
# <url>#page=3 pdf page
# <url>#row=42 csv row
# <url>#F1L42-L48 diff lines of file 1 (shift-click, or tap, for a range)
# <url>#focus=main;serve flame graph: zoom to that stack
# <url>#q=malloc flame graph: highlight matching frames
# read your content back
ssh hostthis.dev get abc12345
# re-show the link for an existing paste (URL only, or URL + QR)
ssh hostthis.dev url abc12345
ssh hostthis.dev qr abc12345
# set the owner label from the words, or omit it to clear
ssh hostthis.dev rename abc12345 design notes v2
ssh hostthis.dev rename abc12345
# stick the URL on v1 even though v3 is the latest
ssh hostthis.dev pin abc12345 1
ssh hostthis.dev unpin abc12345
# free one version's bytes; leaves a tombstone row
ssh hostthis.dev delete abc12345 2
# deploy a static site
tar czf - site/ | ssh -T hostthis.dev
Source: github.com/Zamua/hostthis
MIT - see LICENSE.