Docs

Web hosting (Sites)

Host static sites and single-page apps on <site>.sovaria.app and your own domains: deploys that upload only changed files, instant rollback, preview channels, redirects, rewrites to functions and SPA fallback.

Updated Oct 26, 2026

A site serves a build folder (Vite, React, Vue, Svelte, Astro, a Next.js static export, docs, a landing page) at https://<site>.sovaria.app — a domain of its own, separate from the console and the API, so a page can never read or set their cookies — and at any custom domain you connect. Every deploy is immutable; a release points the site at one deploy in a single step, so visitors see the old site or the new one, never a mix; rollback is the same step backwards.

cachedrewriteVisitor<site>.sovaria.appor your domainGatewayTLS, rate limitper IPForge Sitesrelease → deploy →file, rulesA functionrewritesPrivate storagefiles by sha256

#Deploy a site

  1. Create the site and its config

    sov hosting init --site my-app --public dist --spa      # writes the hosting section of sovaria.json
  2. Build and deploy

    Only files the project doesn't already have are uploaded; then the release switches the site.

    npm run build && sov hosting deploy -m "new pricing page"
    # ✓ Deployed 214 files (3 uploaded) → https://my-app.sovaria.app
  3. Roll back if needed

    sov hosting releases
    sov hosting rollback                 # the previous release, at once (or --to <deploy id>)

In the console (Hosting) you can also create sites, deploy a folder from the browser, roll back, manage preview channels, domains and deploy tokens. From code: sovaria.hosting.deployFiles(site, files) (JavaScript) or HostingClient(sov).deploy_directory(site, "dist") (Python). Sovariq can create a site and publish a page you write together.

#sovaria.json

{
  "hosting": {
    "site": "my-app",
    "public": "dist",
    "spa": true,
    "cleanUrls": true,
    "trailingSlash": false,
    "redirects": [{ "source": "/blog/:slug", "destination": "https://blog.example.com/:slug", "type": 301 }],
    "rewrites": [
      { "source": "/api/**", "function": "api" },
      { "source": "/app/**", "destination": "/app.html" }
    ],
    "headers": [{ "source": "**/*.@(js|css)", "headers": { "Cache-Control": "public, max-age=600" } }],
    "errorPage": "/404.html",
    "ignore": ["**/.*", "**/node_modules/**"]
  }
}
SettingWhat it does
spaRequests for pages that don't exist serve /index.html (client-side routing). Missing assets (/x.png) still get 404.
cleanUrls/about serves about.html; /about.html redirects to /about.
trailingSlashtrue: /docs → /docs/; false: /docs/ → /docs; omitted: both work.
redirectssource → destination with type 301/302/303/307/308. The query string is kept.
rewritesServe another file, or call a function (as an HTTP function request from the visitor; it may return HTML here).
headersExtra response headers for matching paths (CSP, CORS, caching). Set-Cookie, Content-Type and framing headers are set by Sovaria.
errorPageThe page sent with 404 (default /404.html when it exists).

Patterns: ** any depth, * one segment, ? one character, {a,b} and @(a|b) alternatives, :name one segment and :name* the rest, both usable in the destination. A request is answered by the first that applies: redirects → the exact file (with cleanUrls / trailingSlash) → rewrites → the SPA fallback → the 404 page.

#Caching, compression and paths

  • Content types come from the file extension (text/html; charset=utf-8, text/javascript, font/woff2, application/wasm…).
  • Fingerprinted assets (app-3f9a2b1c.js, the default for Vite and most bundlers) are cached for a year with immutable; pages are revalidated on every visit with an ETag (unchanged → 304), so a release shows at once; other files for an hour.
  • Pre-compressed files next to an asset (app.js.br, app.js.gz) are sent to browsers that accept them, with Vary: Accept-Encoding.
  • Paths are strict: .., backslashes and control characters are refused at deploy and at serve, and there are no directory listings — a path is a file in the deploy or it isn't.

#Preview channels

A channel serves its own deploy at https://<site>--<channel>.sovaria.app and expires on its own. Use one per pull request or for a stakeholder review.

sov hosting channels deploy pr-12 --expires 7d
sov hosting channels list
sov hosting channels delete pr-12

With a GitHub repository linked (console › Functions › GitHub, Site folder), every push to the branch deploys the folder live, and each pull request gets a pr-<number> channel that is deleted when it closes — for prebuilt or plain static folders. To build first, use the CI flow below.

#Deploy from CI

A deploy token deploys one site and nothing else; it needs no person's session. Create it in the console (Hosting › Deploy tokens) or with sov hosting tokens create --name "GitHub Actions", and store it as the secret SOVARIA_HOSTING_TOKEN.

on: { push: { branches: [main] }, pull_request: {} }
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build
      - run: pip install sovaria-cli
      - run: sov hosting deploy --site my-app ${{ github.event_name == 'pull_request' && format('--channel pr-{0} --expires 7d', github.event.number) || '' }}
        env:
          SOVARIA_HOSTING_TOKEN: ${{ secrets.SOVARIA_HOSTING_TOKEN }}

#Custom domains

  1. Add the domain

    sov hosting domains add www.example.com --site my-app
  2. Add the two DNS records it shows

    A TXT record proves you own the domain; a CNAME sends its traffic to Sovaria.

  3. Verify

    Console › Hosting › Domains › Check DNS, or sov hosting domains verify <id>. TLS is issued automatically once the domain is verified and points here; ownership is re-checked regularly.

#Limits and billing

FreeProUltraTeamEnterprise
Sites per project (web hosting)1102550200
Site files stored1 GB10 GB50 GB200 GB1 TB
Monthly site bandwidth2,147,483,648107,374,182,400536,870,912,0002,199,023,255,55210,995,116,277,760
Custom domains for sites11025100500
Preview channels per site1102550100
Longest preview channel lifetime (days)7 days30 days30 days90 days90 days
Largest file in a site deploy10 MB50 MB100 MB100 MB100 MB
Largest site deploy250 MB1 GB2 GB5 GB10 GB
Files per site deploy5,00020,00050,000100,000100,000
Releases kept per site for rollback1050100200500
  • Stored files count each distinct file once across your sites and the releases kept for rollback; older deploys are pruned past host.releases_kept.
  • Bandwidth on Free is a hard monthly cap: past it, sites answer 429 until the next month. Paid plans keep serving; site downloads count with the plan's bandwidth and are billed past it.
  • Sovaria may take down a site that hosts phishing, malware or other abuse; it then answers "Site unavailable" and you are told why.

#Coming from Firebase or Supabase?

PlatformWhat this is called there
FirebaseFirebase Hosting
SupabaseVercel / Netlify static hosting
SovariaWeb hosting (Sites)

Moving an existing app? Migrate from Supabase or Firebase imports users (with their passwords), data, files and rules.