Publish static files to your own Cloudflare subdomain
A minimal workflow for throwing quick HTML pages and static demos onto a public URL you control, free, in seconds, with easy takedown later.
How to use this page: give the URL of this page (or its saved HTML) to your AI agent and say something like: "Follow this guide to set up static publishing on a subdomain of my domain. My domain is X, use subdomain Y." The guide is written so an agent can execute it end to end. The only step that needs a human is the browser login to Cloudflare.
What you end up with
- A subdomain like
tmp.yourdomain.comserved by Cloudflare's CDN. - One local folder on your machine that mirrors the whole subdomain. One subfolder per published thing; the subfolder name is the URL path.
- Publishing is: drop files in a subfolder, run one command. Live in a few seconds at
tmp.yourdomain.com/whatever. - Takedown is: delete the subfolder, run the same command.
- Zero cost. Static asset requests and bandwidth on Cloudflare Workers are free on every plan.
Prerequisites
- A domain whose DNS is managed by Cloudflare (the domain is in your Cloudflare dashboard as an active zone).
- Node.js 18 or newer with npm.
- Nothing else. No credit card, no paid plan.
Part 1: One time setup
1. Install and authenticate Wrangler
Wrangler is Cloudflare's CLI. Install it globally, then log in (this opens a browser window for OAuth; a human needs to click approve):
npm install -g wrangler
wrangler login
wrangler whoami
The login token is stored per machine, so this is done once. wrangler whoami should print your account email and account ID.
2. Create the mirror folder
Pick a permanent home for the project. Suggested layout (adjust paths for your OS):
tmp.yourdomain.com/
wrangler.jsonc <-- deploy config (below)
site/ <-- web root; ONLY this folder gets uploaded
404.html <-- custom not found page (optional but nice)
hello/
index.html <-- served at tmp.yourdomain.com/hello
3. Create wrangler.jsonc
In the project root, next to site. Replace the two placeholder values. The name is what the project is called inside your Cloudflare account (letters, numbers, and dashes only).
{
"name": "tmp-yourdomain-com",
"compatibility_date": "2026-08-21",
"assets": {
"directory": "./site",
"not_found_handling": "404-page"
},
"routes": [
{
"pattern": "tmp.yourdomain.com",
"custom_domain": true
}
]
}
Notes for the agent: this is a Workers static assets project with no worker script, so there is no main entry. not_found_handling: "404-page" serves site/404.html with status 404 for unknown paths; omit it if you skip the 404 page. custom_domain: true makes the first deploy create the DNS record for the subdomain automatically, so no manual DNS step is needed. The subdomain must not already have a conflicting DNS record in the zone.
4. Add a test page and deploy
Create site/hello/index.html with any content, then from the project root:
wrangler deploy
First deploy takes a few seconds and prints the custom domain it attached. Verify with an HTTP GET:
curl -i https://tmp.yourdomain.com/hello
Expect HTTP 200 immediately. Because the zone is already on Cloudflare, there is no DNS propagation wait. A request to a bogus path should return your 404 page with status 404.
Part 2: Everyday workflow
- Publish: create
site/<name>/, put anindex.html(plus any CSS, JS, images) inside, runwrangler deploy. Sharehttps://tmp.yourdomain.com/<name>. Folders with anindex.htmlresolve automatically, so URLs stay clean. - Update: edit the files, run
wrangler deployagain. - Take down: delete
site/<name>/, runwrangler deploy. The URL now 404s. - Never run
wrangler deleteto remove one page; that unpublishes the entire subdomain.
Deploys are not full reuploads. Wrangler hashes every file, asks Cloudflare which hashes it already has, and uploads only new or changed files. Adding one page to a folder with hundreds of old projects uploads exactly one file. Deploys are also atomic: the new file manifest swaps in all at once.
Part 3: Free tier limits
| Thing | Limit on the free plan |
|---|---|
| Requests and bandwidth for static assets | Free and unmetered on every plan; they do not count against Worker request quotas |
| Files per deployment | 20,000 |
| Size per individual file | 25 MiB |
| Deploys | 500 per day |
Figures current as of August 2026. For quick HTML pages and small demos you will never hit any of these.
Part 4: Optional, teach your agent a reusable skill
If your agent supports reusable skills or custom instructions (Claude Code skills, Cursor rules, and similar), save something like the following so "publish this" becomes a one liner. Adapt paths, the domain, and the format to your setup.
---
name: publish-cloudflare-subdomain
description: Publish an HTML file or static assets to my Cloudflare
subdomain by copying files into the local mirror folder and running
wrangler deploy. Use when I say "publish this" or "put this on tmp".
Also handles taking published paths down and listing what is live.
---
# Publish to tmp.yourdomain.com
Local mirror project: /path/to/tmp.yourdomain.com
Web root (only thing uploaded): /path/to/tmp.yourdomain.com/site
One subfolder per published thing; subfolder name = URL path.
site/404.html is the custom not found page, never a project.
## Hard rules
1. NEVER touch existing subfolders under site/ except the one being
published or taken down by name. They are live, shared URLs.
2. ALWAYS confirm the path name with me if I did not state one.
3. On a name collision, STOP and ask whether it is an intentional
redeploy.
4. NEVER run "wrangler delete". Takedown is always: delete the one
subfolder, then "wrangler deploy".
## Publish
1. Single HTML file: copy to site/<name>/index.html for a clean URL.
A folder of assets: copy into site/<name>/ preserving structure.
2. Run "wrangler deploy" from the project root.
3. Verify HTTP 200 at https://tmp.yourdomain.com/<name>.
4. End by printing the full URL.
## Take down
Delete site/<name>/, run "wrangler deploy", verify the URL is 404.
Troubleshooting
- Custom domain fails to attach: the zone is not on this Cloudflare account, or a DNS record for the subdomain already exists. Remove the conflicting record in the dashboard and redeploy.
- Auth errors on deploy: run
wrangler whoami; if logged out, rerunwrangler login(human step). - Page serves but assets 404: asset paths in the HTML should be relative (
./app.js) so they resolve under the subpath. - Stale content after deploy: rare, but a hard refresh handles browser cache; Cloudflare's edge cache is invalidated by the deploy itself.
Shared by Trevor. This page is itself published with the exact workflow it describes.