Docs
Sites
Static hosting for anything you can build to a folder — a marketing page, a docs site, a Vue or React app. You publish a directory of files and get a TLS address that serves it. There is no server to keep alive, no container to patch, and nothing to scale.
Publish your first site
Open Infrastructure → Sites and create one. You pick two things and only one of them is permanent:
- The name is yours and you can change it whenever you like.
- The address becomes
<address>under the platform's site domain and cannot be changed later — people paste it into other places, and renaming it would break every one of them. To move, create a second site.
Then drag your build output onto the page. Drop the dist/ or build/ directory, not the project folder — .env, .git and node_modules are skipped either way, but publishing your source tree is rarely what you meant.
Deploy from CI
The CLI does the same thing without a browser. Link a directory once, then deploy from anywhere:
subnomic sites link blog --dir dist subnomic sites deploy --prod # prints the live URL subnomic sites deploy # a preview URL, nothing goes live
In CI, authenticate with an API key in SUBNOMIC_TOKEN instead of a login. Give it only the sites.deploy scope: that token can publish and roll back, and deliberately cannot delete the site it publishes to or move its address.
Every deploy is kept, so rollback is instant
A deployment is immutable. Publishing does not overwrite the previous build — it uploads a new one alongside it and then moves a single pointer. Rolling back moves that pointer again, so it is as fast as a page load and copies nothing.
Every deployment also has its own address of its own, whether or not it is live. That is what a preview is: a build you can open and share before you promote it. Previews are served with X-Robots-Tag: noindex so search engines do not index a copy of your site.
Single-page apps and 404s
A React or Vue app routes in the browser, so a request for /settings has no file behind it. Turn on Single-page app and those requests are answered with index.html and a 200, which lets the app take over the route.
A missing file still returns 404 even with that on — a request for a script or a stylesheet that is not there gets a real 404 rather than your HTML. That is on purpose: a broken build then reports itself instead of filling the browser console with Unexpected token '<'.
For a multi-page site, leave it off and set an error page such as /404.html instead. It is served with a 404 status — an error page returned as 200 makes every uptime monitor report a broken site as healthy.
Redirects and headers
Put a _redirects or _headers file at the root of your build output and it takes effect on the next deploy. They belong to the deployment, so a rollback takes the old rules back with it.
# _redirects — first match wins /old-post /blog/new-post 301 /blog/* /posts/:splat 302 /beta https://beta.example.com /retired / 410
A rule wins over a file at the same path, which is how you retire a page before you delete it. Allowed statuses are 301, 302, 303, 307, 308 and — for a page that is deliberately gone — 404 and 410, which still serve your own error page. A line that does not parse is skipped rather than taking the rest of the file down with it.
# _headers — every matching group applies /* X-Frame-Options: DENY Content-Security-Policy: default-src 'self' /assets/* Cache-Control: public, max-age=31536000, immutable
Strict-Transport-Security and X-Content-Type-Options cannot be changed from a _headers file. HSTS is scoped to a whole domain, so one site turning it off would weaken every other site sharing that domain in the same browser.There is no 200 rewrite rule. Use the Single-page app switch instead — one behaviour with two controls is one behaviour that can disagree with itself.
Your own domain
Add a hostname you own on the site's page and you get two DNS records to create: a CNAME that points the domain at the site, and a TXT that proves the domain is yours so a certificate can be issued. The certificate is issued and renewed for you; there is nothing to install and nothing to remember to rotate.
For a bare domain — example.com with no www — DNS does not allow a CNAME at the root. Most providers offer a flattened record for exactly this case (Cloudflare calls it CNAME flattening, others call it ALIAS or ANAME) and it works here unchanged. If yours does not, point www.example.com at the site and have your registrar redirect the bare domain to it.
The panel shows Waiting for DNS until both records are live and the certificate exists, then flips to Active on its own — usually a few minutes. Until then the domain does not route, which is the point: a hostname nobody has proven they own is never served.
Keeping a site private
A hosted site is public by default. Two ways to change that, on the site's page:
- Anyone with the password — one shared password, asked for once and remembered for 12 hours. Use this for a staging site you are showing a client who has no account here.
- Workspace members only — a signed-in member of this workspace. Visitors are sent to Subnomic to sign in and come straight back. Nobody outside the workspace gets in, and there is no password to leak.
Protection is on the site, so every preview address is covered too. A protected page is never cached by anything in front of it and is never indexed, whatever your _headers file asks for.
Traffic
Every site has a traffic section: requests and data served over the last day, week, month or quarter, with breakdowns by page, response status, referring site, browser, operating system and device.
It needs no script on your pages and sets no cookie, because it is counted where the site is served rather than in the visitor's browser. Nothing that identifies a visitor is stored — no IP addresses, no full User-Agent strings, no full referrer URLs (only the referring site's domain), and nothing that joins two visits together. Numbers are kept for 90 days.
Limits
Two things are counted: how much storage your deployments hold, and how many bytes your sites serve in a calendar month. Storage is checked when you open a deploy, before anything is uploaded, so a deploy that cannot fit is refused up front rather than halfway through.
Go past the monthly traffic your plan allows and sites can be paused until the month rolls over or the plan is upgraded. The site itself is untouched: nothing is deleted, and the same deployment starts serving again the moment the allowance is back.
Old deployments are tidied up on their own. The live one is always kept, along with the last ten builds and anything published in the past couple of hours, so a rollback target is always there.
Deleting a site
Delete is at the bottom of a site's settings and asks you to type the address back. It erases the site, every deployment and all of their files, stops any custom domains from answering, and releases the address for anyone else to claim. There is no undo and no grace period.
Who can do what
| Permission | Allows |
|---|---|
sites.read | See sites, deployments and domains |
sites.write | Create and delete sites, change settings, add and remove custom domains |
sites.deploy | Upload a deployment, promote it, roll back — the scope a CI token wants |