web/README.md
croc web is a React/Vite client that sends and receives files with ordinary
croc CLI peers. Its production build and WebAssembly runtime are embedded in
the croc binary. croc serve serves the website, runtime configuration,
health check, and opaque WebSocket-to-TCP bridge from one HTTP address. File
metadata and contents remain encrypted between the browser and the other croc
client.
When the server is started with --store-dir, the UI also offers an explicit
Store for 24 hours mode. It encrypts file names, metadata, and 4 MiB chunks
in the browser, uploads only ciphertext, and produces both a browser link and a
CLI token. The transfer is deleted after one fully verified download or 24
hours, whichever comes first. The normal direct-transfer mode remains the
default.
The security-sensitive protocol operations are compiled from this repository's Go packages into WebAssembly:
Active sends and receives show total and per-file progress, measured bytes per
second, and an ETA calculated with arrival-time.
From this directory:
npm install
npm run dev:stack
This builds and embeds the complete client, then runs:
croc serve localhost:5173
The local shortcut binds directly to localhost:5173; both the website and
WebSocket relay are available there. For frontend hot reloading, run:
npm run dev:hot
Useful checks:
npm test
npm run test:e2e
npm run typecheck
npm run build
npm run embed
go test ./...
npm run embed builds the WASM and Vite client and copies the result into
src/webassets/dist, where Go's embed package includes it in every compiled
binary. A deployed binary does not need this source directory or any external
static files.
The Playwright suite builds a real croc binary, starts an isolated local croc
relay and unified embedded server on temporary ports, then verifies CLI → Web,
Web → CLI, Web → Web, CLI stored → Web, and Web stored → CLI transfers
byte-for-byte. Install its browser once with npx playwright install chromium.
Test processes use an isolated CROC_CONFIG_DIR and storage directory and do
not read or change remembered croc settings.
The server fixes one upstream host and allowlists every TCP port so /ws
cannot be used as an arbitrary network proxy:
croc --pass YOUR_RELAY_PASSWORD serve \
--bind 127.0.0.1:9014 \
--relay relay.example.com \
--ports 9009,9010,9011,9012,9013,9014,9015,9016,9017 \
files.example.com
The server injects the selected relay address and password as browser defaults
through /config.js. Users can still override them from the advanced settings
panel.
The unified server exposes:
GET / and embedded static client assets; curl and wget receive the
installer script at / while browsers receive the web clientGET /config.jsGET /healthzGET /ws?port=<allowlisted-port> upgraded to a binary WebSocket/api/v1/store/transfers and its descendants when --store-dir is setRun croc serve behind an HTTPS reverse proxy:
croc serve --bind 127.0.0.1:9014 getcroc.com
Proxy the complete origin—including WebSocket upgrades—to
127.0.0.1:9014, preserving the original Host header. The server returns the
site at / and the WebSocket bridge at /ws, so no split routing or external
static file deployment is required. TLS certificates remain at the reverse
proxy.
Temporary storage is disabled unless a directory is explicitly configured:
croc serve \
--bind 127.0.0.1:9014 \
--store-dir /var/lib/croc/store \
--store-max-transfer 1GiB \
--store-quota 5GiB \
--store-min-free 512MiB \
getcroc.com
The store directory is locked to one server process and should be persistent,
private, writable only by the croc service account, and excluded from backups.
If a trusted reverse proxy supplies X-Forwarded-For, identify its network
with repeatable --store-trusted-proxy CIDR flags; untrusted forwarding
headers are ignored. See
src/docs/STORED_TRANSFERS.md for all
limits and operational details.
--bind defaults to 127.0.0.1:9014. When an explicit loopback website
address with a port is used, such as localhost:5173, the local shortcut binds
there unless --bind is explicitly provided.