# Sites Upload a static site or a built single-page app as a zip. It is served at its own address behind your company login, keeps every version and rolls back in one click. URL: https://docs.qaldy.com/guides/sites/ A **site** is a static website or a built single-page app that your company shares like an app. You upload a zip; Qaldy serves it at its own address behind the same login and sharing as an app, keeps every version and lets you go back in one click. :::preview Preview Everyone who opens a site signs in first. Custom domains, sites without a login and deploy previews are [[Planned]]. A site's files are stored in the pilot's database, sized for the pilot. ::: A site is an app of its own kind. It has a building on the island, an owner, sharing and an audit trail. Its permissions are written by the platform: it can read nothing, call nothing and reach nothing, and it has no run. ## Publish one Open **Sites** in the console and upload a zip of the folder your build made (`dist/`, `build/`, `out/`). Name it, choose how it should treat unknown paths, and make it live. - **Single-page app (SPA) switch.** *Auto* treats one HTML file as a single-page app. *Single-page app* answers any path that looks like a page with `index.html`. *Several pages* does not. A missing script, style or image stays a 404 either way. - **Every upload is a new version**, with an optional note. Uploading the same files again answers "unchanged" and stores nothing, so a CI job can run twice safely. - **Make live** switches the address to a version. An older version rolls back the same way. ## What a zip may contain The upload is read strictly, in memory. Nothing is unpacked onto a disk. - **Paths:** `..`, a leading `/` or a drive letter refuses the whole upload. Names are NFC; two names that differ only by case are refused. A single top-level folder around everything (what "Compress this folder" makes) is lifted out. - **Left out, and listed** (never silently dropped): hidden files and folders (`.env`, `.git/`; only `.well-known/` is kept), `__MACOSX/`, `node_modules/`, `Thumbs.db`, `_redirects`, `_headers`, symbolic links and devices. - **Types:** pages, styles, scripts, JSON, source maps, images, fonts, audio, video, PDF, CSV, XML, WebAssembly and office documents. Anything else (`.php`, `.exe`, `.sh`, `.zip`, a file with no extension) refuses the upload and names the files. - **Refused:** encrypted zips, anything but stored and deflate entries, Zip64, entries that overlap, a size that lies, and a decompression ratio that looks like a bomb. ## Limits | Limit | Value | When it is passed | |---|---|---| | The zip as uploaded | 50 MiB | 413 `zip_too_large` | | Entries in the zip, folders included | 10,000 | `too_many_entries`, before any file is read | | Files in one version | 2,000 | `too_many_files` | | One file, unpacked | 25 MiB | `file_too_large` | | All files of a version, unpacked | 150 MiB | `site_too_large` | | A path | 200 characters, 12 folders deep, 100 per part | `bad_path` | | Versions kept per site | 20 | `versions_full`: delete an old one | | Sites in a workspace | 20 | `sites_full` | | Unique file bytes in a workspace (identical files count once) | 256 MiB | `storage_full` | | A note on a version | 200 characters | | ## How a visitor is answered - Only `GET` and `HEAD`. `/` and a folder open their `index.html`; `/about` finds `about.html`. A missing path shows the site's own `404.html`. - Pages are `private`, `no-cache` with a strong ETag, because a site sits behind a login and must never be stored by a shared cache. Fingerprinted files under `assets/`, `static/`, `_next/static/` and `_app/immutable/` are cached for a year. - Every answer carries `X-Content-Type-Options: nosniff`, `Referrer-Policy`, `Cross-Origin-Resource-Policy: same-origin` and `X-Robots-Tag: noindex, nofollow`. A site's own pages are not given a content security policy: a site loads its own scripts, fonts and APIs. - The site's JavaScript runs on the site's own origin, not the console's, and cannot read the login cookie. ## Share it Sharing is the same Share dialog as for an app: people, teams or the workspace. A public link is not offered for a site. See [Share it with your team](https://docs.qaldy.com/getting-started/share/). ## From CI A personal access token with the `write` scope may upload a new site or a new version, and read sites. Making a version live, deleting a version and deleting a site stay with a person in the console. ```sh curl -X POST "https://cloud-api.qaldy.com/v1/workspaces/$WS/sites?name=Staff%20handbook" \ -H "Authorization: Bearer $QALDY_TOKEN" -H "Content-Type: application/zip" \ --data-binary @site.zip ``` The routes are in the [Sites reference](https://docs.qaldy.com/reference/api/sites/). The two upload routes take a raw zip body, so they are listed there but not in the OpenAPI document. ## Traffic and the record The console shows page views, requests, data served and distinct people for 14 days, labelled approximate: a host that restarts loses what it had not yet reported. A person is counted by a short hash, never an id. Nothing is billed from it. Creating, publishing, making live, rolling back and deleting are [audit rows](https://docs.qaldy.com/concepts/audit/); file names and contents are never written to the log. ## Not built yet - Custom domains and certificates, sites without a login, deploy previews. - Server functions next to the files, redirect and header files, basic auth. - Per-site header settings, image resizing, building from Git.