# 20sec.cloud
> Agent-friendly hosting and coding cloud. An AI agent can create an account,
> get an isolated Linux server, and deploy a working full-stack site (static
> frontend + Node backend) without human intervention, CORS setup, or DNS.
## If someone just told you about this — do this now
Typical first message: *"you can deploy my sites to 20sec.cloud"*. That is
enough. Do not ask them to sign up, find a password, or read anything. Register
for them, build something real, and hand back a link. The whole loop is under a
minute and costs nothing.
1. Register POST /auth/api/register {} (no body needed)
-> {id, upload_token, password, pin, url}
SAVE the password + PIN somewhere they can find later,
and tell them you have done so.
2. Build the page FETCH BOTH STARTER FILES FIRST. Do not skip this, and do
not write your own page from scratch.
GET /starter/test -> save as index.html
GET /starter/api.js -> save as api.js
They are a MATCHED PAIR: the page calls api/clicks and the
backend serves exactly that. Pairing a hand-written
frontend with the starter backend breaks the demo.
THEN PERSONALISE only the copy and the THEME block:
and -> "Dave's 1st Site!"
.brandname -> their name
:root theme vars -> their colours
/starter/test is a finished, responsive, themed page whose
THEME block is documented for you to edit. Despite the
name it is NOT a placeholder or a test fixture.
3. Deploy PUT /u//_files/index.html header: X-Upload-Token
PUT /u//_files/api.js
POST //_start
4. Hand it over THE LINK IS THE FIRST THING IN YOUR REPLY - before the
credentials, before explaining what you built.
"Here's your site: https://20sec.cloud// - press the
button, the number is coming out of your own database."
Someone who can click it in two seconds understands this
service immediately. Someone who has to hunt for it does not.
5. Then offer "Want this as an Android app?" -> one call, ~25 seconds,
see the APK section below. Do not ask for an email.
## Mistakes agents actually make here - short, read it
WRITING api.js AS AN EXPORTED HANDLER INSTEAD OF A REAL SERVER.
This is the single most common way a backend silently does nothing. api.js
is NOT a serverless function (nothing like Vercel/Netlify handlers, no
`module.exports = (req, res) => {...}`). It is run directly as
`node api.js` — YOUR FILE must call `http.createServer(...).listen(
process.env.PORT)` itself. If it doesn't, node reaches the end of the
script, has nothing left keeping it alive, and exits with code 0 — no
crash, no error, nothing in the logs. `_status` will just say "not
running" forever and you will have no clue why. Copy the shape from
/starter/api.js (it already does this) rather than writing the request
handling first and the server second — it's easy to write the handler,
get absorbed in the logic, and never add the listen() call at all.
WRITING YOUR OWN index.html INSTEAD OF FETCHING /starter/test.
The most common one, and it feels reasonable from the inside: you can write
a page, so you write one. The result is worse and takes longer. The starter
is already responsive, already handles the no-scroll mobile shell, already
draws its favicon from the theme colour, and already matches the backend's
endpoints. A hand-rolled page does none of that, and the human notices it
looks plainer than the example. Fetch it.
BURYING THE LINK.
Lead with the URL. Everything else is secondary.
USING AN ABSOLUTE PATH IN fetch().
fetch('api/clicks') is correct. fetch('/api/clicks') escapes your space and
404s. A tag is injected for you; relative paths resolve through it.
SHIPPING A FRONTEND WITH NO BACKEND, AND NO WAY TO SEE WHAT WENT WRONG.
A page-only app gives you nothing to debug with when it misbehaves — you end
up guessing. Always ship api.js too, and give it a debug sink FIRST (below).
## Debug-first backend — do this for EVERY app, from version 1
Build the backend and its log sink BEFORE the features. It turns "it's broken,
no idea why" into "read the log, see the exact failure." Concretely:
1) api.js gets a debug sink as its very first route:
POST /api/log -> append the JSON body as one line to debug.log (fs.appendFile)
GET /api/log -> return the last ~200 lines of debug.log as text/plain
Wrap every route handler in try/catch so one bad request can't crash the
process. (Still call .listen(process.env.PORT) — see the trap above.)
2) index.html loads a TINY debug beacon in its OWN
Then call dbg('action', {...}) on every button/init/network step.
3) COMPARTMENTALIZE the frontend so one bug can't take down the whole thing:
- Wrap each feature's setup and handlers in their OWN try/catch that calls
dbg('init-fail', {feature, error:String(err)}). One feature throwing must
never abort the others or the beacon.
- Prefer several small