Skip to content
ZamuaPublic

About

Pipe HTML or Markdown to ssh, get a URL.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

HOSTTHIS(1)

NAME

hostthis - pipe a file in, get a public URL out

SYNOPSIS

cat <file> | ssh -T hostthis.dev [<slug>] [-- <opts>]
tar czf - <dir> | ssh -T hostthis.dev [<slug>]
ssh hostthis.dev <command> [<args>]

DESCRIPTION

Renders HTML, Markdown, diffs, Mermaid, PDF, CSV, JSON, folded stacks (flame graph), NDJSON logs and plain text at a random subdomain. A gzip-tar is a static site. No signup: your ssh key is your identity, and only it can change what it uploaded. Everything persists until you delete it.

UPLOAD

cat <file> | ssh -T hostthis.dev           new paste; URL on stdout, QR on stderr
cat <file> | ssh -T hostthis.dev <slug>    new version; same URL
-- --name "<label>"                        set a label
-- --type <kind>                           force the renderer when detection misses (a
                                           tiny CSV reads as text): html, markdown, diff,
                                           mermaid, pdf, csv, json, flamegraph, log, text

-T silences ssh's pseudo-terminal warning. -- may go before or after the slug.

COMMANDS

Each runs as ssh hostthis.dev <command>.

list [-o json]               your pastes, most recently updated first
whoami [-o json]             identity, count, quota
get <slug>                   content to stdout
url <slug>                   the URL
qr <slug>                    the URL and a QR code
rename <slug> [<label>]      set the label; omit it to clear
versions <slug> [-o json]    version history
pin <slug> <ver>             serve <ver> until unpinned
unpin <slug>                 serve the latest version
delete <slug>                delete everything
delete <slug> <ver>          delete one version's bytes
have <slug> [-o json]        a site's files as a keep list (see SITES)
pod link|status|unlink       keep your bytes in your Solid pod (see PODS)

Sizes are stored bytes after compression, the unit of the quota.

LINKS

<url>?raw                    source bytes (pages render in the browser, so
                             curl of the page itself gets the renderer)
#<heading> #page=3 #row=42   markdown, pdf, csv
#L42-L48 #F1L42-L48          text and log lines, diff lines of file 1
#focus=<stack> #q=<term>     flame graph zoom, highlight

SITES

tar czf - <dir> | ssh -T hostthis.dev [<slug>]   deploy, or redeploy in place
routing                      a missing path without a file extension serves
                             index.html; a missing asset is 404
layout                       one top-level directory is flattened
no index.html                browsable knowledge base
redeploy                     stores only changed files
.hostthis-keep               lines from `have` for files not sent, placed
                             next to index.html; its directory is the site
                             root. A stale base is refused: run have again

To send only what changed since the latest version:

ssh hostthis.dev have abc12345 > held
(cd dist && find . -type f | sed 's|^\./||' | sort | xargs sha256sum) > local
{ grep '^base ' held; grep -Fxf local held; } > dist/.hostthis-keep
grep -vFxf held local | cut -c67- | tar czf - -C dist -T - .hostthis-keep | ssh -T hostthis.dev abc12345

PERSISTENCE

Key-value rooms at https://<slug>.hostthis.dev/api/, on your page's own origin (not the apex). No auth: a room id, issued by POST, is the only key. Rooms are deleted with their site.

POST   /api/rooms             new room: {"id": "<uuid>"}
GET    /api/rooms/<id>        all keys as one JSON object
GET    /api/rooms/<id>/<key>  one value, raw bytes
PUT    /api/rooms/<id>/<key>  write; body is the value
DELETE /api/rooms/<id>/<key>  remove

In whole-room reads a value that parses as JSON nests as JSON; any other value is a string. 256 KiB and 256 keys per room, 64 MiB per app.

WEBSOCKETS

GET /api/rooms/<id>/ws       {"type":"snapshot","seq","state"}, then
                             {"type":"put","seq","key","value"} and
                             {"type":"delete","seq","key"}
your frames                  relayed verbatim to the other clients; not
                             echoed, not stored, so treat them as untrusted
{"type":"ping"}              every 20 s; answered with pong
close 4001                   dropped for a newcomer after 2 min without
                             ping; reconnect

64 sockets per room; frames up to 32 KiB.

WEBRTC

Peers connect browser to browser: data channels, audio, video, screen share. Signal over the room socket: send offers, answers and ICE candidates as your own frames, addressed with a per-tab id since every peer receives every frame. Pages you upload may call getUserMedia and getDisplayMedia; the browser still asks the visitor.

GET /api/rooms/<id>/ice      {"iceServers": [...], "ttl": 3600}
                             pass iceServers to new RTCPeerConnection; STUN
                             always, a TURN credential when the operator set
                             one up and its monthly budget allows; ttl only
                             with TURN: fetch again before it runs out

PUSH

GET        /api/push/key                       VAPID public key
PUT|DELETE /api/rooms/<id>/push/subscriptions  add or remove a PushSubscription
GET|PUT    /api/rooms/<id>/push/schedule       {"tz", "items": [{"id", "at": "HH:MM",
                                               "days": [0-6, 0 = Sunday], "title",
                                               "body" | "bodyKey", "url", "tag"}]}
POST       /api/rooms/<id>/push/test           send now

"when" (RFC 3339) fires once instead of at/days. bodyKey reads a room key at send time. 16 devices and 16 items per room, 8 sends per device per day, one test a minute. push and push/* are reserved keys.

PODS

Keep the bytes of your uploads in your own Solid pod.

pod link <webid>             prints a URL valid for 15 minutes and returns. A
                             person opens it, signs in to the pod provider and
                             approves (an agent cannot); pod status then shows it
pod status [-o json]         the linked folder, <pod>/hostthis/, or "no pod linked."
pod unlink                   new uploads are stored by hostthis again

The WebID is the profile URL your provider shows, e.g. https://<you>.solidcommunity.net/profile/card#me. Only bytes move: slugs, versions, URLs and quota stay on hostthis and work the same, delete included. If the profile lists several pods, the link page asks which one; to switch, run pod link again. Every upload made while linked, a new version of an existing slug included, is stored in the pod, except files a redeploy keeps unchanged, which stay where they were. Earlier versions stay where they were, and pod versions stay in the pod after unlink. hostthis can read and write <pod>/hostthis/ only. Unsharing that folder revokes it, and the versions stored there then fail to load.

LIMITS

quota    1 GiB per key, after compression
paste    10 MiB after compression
site     1 GiB unpacked

EXIT STATUS

0  ok              3  no ssh key
1  error           4  not found
2  usage           6  rate limited

ENVIRONMENT

NO_COLOR or TERM=dumb disables color.

LICENSE

MIT - see LICENSE.

About

Pipe HTML or Markdown to ssh, get a URL.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages