# Deploy to Cloudflare The published site is static files, so it can be hosted anywhere that serves them. Cloudflare Pages is what the reference deployment uses, and everything described here fits inside Cloudflare's free tier. ## The straightforward part A build produces an `out/` directory. Deploying it is one command: ```sh wrangler pages deploy out --project-name my-archive --branch main ``` The editor can run this for you as part of a build-and-deploy action. Pass `--branch main` explicitly: wrangler otherwise infers the branch from git, and from anywhere that isn't the main branch it will quietly publish a *preview* URL instead of production — which looks like a successful deploy of a site nobody can see. ## The part that needs thought: bulk archives Each build can generate one transcript zip and one live-chat zip per channel, so that people can take the raw material rather than scraping the site. These are listed in a manifest that the Downloads page reads. Cloudflare Pages rejects any single file larger than **25 MB**, and real channels blow through that easily — a busy channel's live-chat archive can run to hundreds of megabytes. So archives are split by size: | Archive size | Served from | |---|---| | Up to 25 MB | Pages, shipped inside the site | | Over 25 MB, object storage configured | Cloudflare R2 | | Over 25 MB, nothing configured | Not served; shown as "too large to host" | Oversize archives are staged during the build and uploaded before the site deploy, so the links resolve the moment the site goes live. Note that only the editor's deploy actions upload them — that is where the storage credentials live. Building and deploying by hand from the command line stages the files without uploading them. ## Setting up object storage One bucket serves every site; objects are namespaced per site, so there is no need for one bucket each. Buckets are private by default, and the Downloads page links to plain URLs, so the bucket needs public read access. There are three ways to arrange that: - **A small worker on a free `workers.dev` subdomain** — recommended. It streams objects from the bucket and gives you edge caching *and* rate limiting you control in code. No domain purchase, no WHOIS record, and one worker serves every site. A ready-made one is included in the source. - **A custom domain** on your Cloudflare account, which routes downloads through the CDN and the dashboard's own rate-limiting rules. - **The built-in public subdomain**, which is fine for a smoke test but is throttled by Cloudflare and gives you no cache or rate-limit control of your own. ## Why the rate limiting matters Public download links to multi-hundred-megabyte files are, left unguarded, a way for someone to run up your bill on purpose. The worker option exists precisely because it puts a limiter in front of them that you control, at no cost, without owning a domain. Uploads go through the S3-compatible API rather than the wrangler CLI, because wrangler caps a single upload at 300 MiB and real archives exceed that. That is why archive uploads need a second set of credentials beyond the ones the site deploy already uses. ## If you host somewhere else Nothing in the published output is Cloudflare-specific. It is HTML, JSON, and static assets: any object store or web server will do. Two things to configure wherever you land: - **Serve the 404 page** for unmatched paths. - **Set a short cache lifetime on the downloads directory** if you publish archives, so a rebuilt archive isn't shadowed by a stale cached copy. Next: [Building several sites at once](/docs/deploy-docker/).