Skip to content

Static sites

WebShield can host static sites without a separate origin server: files are stored in the WebShield infrastructure and served through the same protection layer as proxied sites — with CDN caching, WAF, and bot protection.

  • Static site hosting must be available on the domain plan. Storage size and the maximum file size depend on the plan.
  • A site is bound to the domain apex or to an existing A, AAAA, or CNAME record. For a subdomain, create the DNS record first.
  • Proxying must be disabled for the name. One hostname is either proxied or hosts a static site.
  1. Open the Sites section.
  2. Click Create and select a hostname from the list. Names that are already proxied or taken are marked and unavailable.
  3. The site is created in the Disabled state — it is not visible to visitors until you publish it.

index.html in the site root serves as the start page. Files can be uploaded in several ways:

  • Drag and drop — drag files or folders into the upload area. The subdirectory structure is preserved.
  • Pick files / Pick folder — upload via the selection dialog. When a folder is selected, relative paths are preserved.
  • Into a specific folder — the upload button on a folder row in the file list adds the selected files directly to it.
  • ZIP archive — uploading an archive completely replaces the current site content. The other methods work in merge mode: new files are added and matching paths are overwritten.

Files are displayed as a tree with subdirectories. Folders show the total size of their content.

  • Download: a file is downloaded as is; a folder or the whole site (the ZIP button in the list header) is downloaded as a ZIP archive.
  • View: text files (HTML, CSS, JS, JSON, and others, up to 512 KB) open in a preview window.
  • Delete: select files and folders and click Delete selected. A folder is deleted together with its content. A single item can be deleted with the button in its row.
  • Updating a file: upload a file with the same path — it overwrites the old one.

Uploaded files go into a draft (the working area) shown in the file manager. Visitors see the last published version, not the draft.

The Publish button:

  1. Takes an immutable snapshot of the draft as a new version (atomically — visitors never see a half-updated site).
  2. Switches the host DNS record to the WebShield infrastructure. The original record is saved and will be restored when the site is disabled.
  3. Issues a TLS certificate (if HTTPS is enabled and the domain is delegated).
  4. Makes the new version available to visitors.

Disable unpublishes the site and restores the original DNS record; the files are kept. Deleting the site removes the files and fully releases the hostname.

Content is cached on edge nodes. Every publish is a new version, so the cache is invalidated automatically: visitors receive the new content immediately after publishing, with no manual purge. If you changed draft files and want visitors to see them, click Publish.

  • Site generator — pick a preset (Hugo, Jekyll, Astro, Gatsby, Next.js export, SPA, plain HTML). The preset sets sensible defaults for the other options, which you can still tweak.
  • Clean URLs — how pretty paths resolve to files, matching your generator:
    • Directory index/about/about/index.html (Hugo, Jekyll, Astro, Eleventy, Gatsby);
    • HTML extension/about/about.html, then /about/index.html (Next.js export);
    • Exact path only — no guessing.
  • 404 page — document served for missing paths (e.g. 404.html), returned with a 404 status. Empty — pass the origin response through.
  • SPA mode — serve index.html (with a 200 status) for unknown paths. Enable it for single-page applications with client-side routing.
  • Serve over HTTPS — issue a certificate and serve the site over HTTPS with a redirect from HTTP.
  • Bot protectionOff, Browser check, or Captcha check. Works the same way as for proxied sites.

Settings changes for a published site are applied automatically.

To build and publish automatically, create a deploy token in the site card (the “Deploy tokens” section). The token is scoped to that one site; the full token is shown once — store it in your repository secrets.

Pass the token in the Authorization: Bearer <token> header. Archive upload and publish are available:

.github/workflows/deploy.yml
name: Deploy site
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
env:
SITE_ID: "123" # site id (from the card URL)
WSP_TOKEN: ${{ secrets.WEBSHIELD_DEPLOY_TOKEN }}
API: https://webshield.pro/api
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build # your build → ./dist
- name: Pack
run: cd dist && zip -r ../site.zip . && cd ..
- name: Upload (replaces site content)
run: |
curl -fsS -X POST "$API/static-sites/$SITE_ID/archive" \
-H "Authorization: Bearer $WSP_TOKEN" \
-F "archive=@site.zip"
- name: Publish
run: |
curl -fsS -X POST "$API/static-sites/$SITE_ID/publish" \
-H "Authorization: Bearer $WSP_TOKEN"

A deploy token can only upload files and publish this site — it cannot manage the site, the domain, or other sites. Revoke it from the same card.

For large sites (thousands of files) re-uploading a full archive every time is slow. You can upload only the changed files: GET /static-sites/<id>/files returns the file list with an etag field (the content MD5). Compare it with the MD5 of your local files, then:

  • upload new/changed files via POST /static-sites/<id>/upload (fields files and paths; appends to the draft, does not replace the whole site);
  • remove deleted files via POST /static-sites/<id>/delete-files (JSON {"paths": [...]});
  • publish: POST /static-sites/<id>/publish.

The draft persists between publishes, so only the delta needs uploading. A ready-to-use, dependency-free script ships with WebShield — tools/publish_static_site.py:

Terminal window
WS_PUBLISH_TOKEN=<token> python3 tools/publish_static_site.py \
--site-id 123 --dir ./dist --api-base https://webshield.pro

If you use object storage, you can publish a site straight from one of your own buckets — the content is not uploaded through WebShield. Upload the built site to any of your buckets, into any folder, with any S3 tool (rclone, aws s3, s3cmd, CI artifacts), then publish it from there.

  • In the dashboard: open the site card, find Publish from an S3 bucket, pick the bucket, enter the prefix (folder), and click Publish from bucket.

  • In the CLI:

    Terminal window
    webshield sites publish-from-bucket www.example.com --bucket web --path public/
  • Over the API: POST /static-sites/<id>/publish-from-bucket with {"bucket": "<name>", "path": "<prefix>"} (works with a sites:publish token). It runs asynchronously — the response is 202 with status publishing; poll the site until the status becomes active (or publish_error is set on failure).

The contents of the chosen prefix replace the site and are published as a new immutable version. Plan size limits are enforced at publish time. The source keeps living in your bucket (billed as object storage); only the served copy is part of static hosting — you may delete the source bucket afterwards, the published snapshot survives.

  • Storage size and the maximum size of a single file are limited by the plan.
  • Uploading executable files and installers (.exe, .msi, .apk, .bat, and similar) is not allowed — this protects against malware distribution through the hosting.
  • ZIP archive: no more than 5000 files; archives with an abnormally high compression ratio are rejected.