A static site serves HTML, CSS, JavaScript, and other files from object storage through Bex's shared static server. It does not run a dedicated application server. Use a web service if your application requires server-side rendering, API handlers, or runtime computation per request.
Self-hosted installations need a configured object store, publishing pipeline, static server, and public routing. An operator-only local installation is not a complete static hosting setup.
Publish files without a build
This example publishes the repository's sample site as-is:
services:
- name: static-site
type: web
runtime: static
repo: https://github.com/bex-co/bex
rootDir: examples/static-site
branch: main
staticPublishPath: .staticPublishPath selects the directory to publish. Here, . refers to the
selected root directory. Check that it contains the intended index.html and
assets. Follow the Blueprint guide to authenticate, validate,
and deploy the manifest.
Build a site before publishing
For a Node-based static project with a committed lockfile and a build script
that writes to dist, configure:
services:
- name: frontend
type: web
runtime: static
repo: https://github.com/your-org/frontend
branch: main
buildCommand: npm ci && npm run build
staticPublishPath: distReplace the repository and commands with your project's values. A static build needs no start command: Bex extracts and publishes the output files. Confirm that your framework is producing a static export rather than a server bundle. Configuration embedded into browser assets is public; do not put server credentials into frontend build variables.
Redirects, rewrites, and response headers
A redirect tells the browser to request another URL. A rewrite serves a different file without changing the browser's URL. Rules are ordered, so place specific redirects before a catch-all rewrite.
For API examples, set BEX_API_URL to your API origin, BEX_TOKEN to an
authorized token, and SERVICE_ID to the static site's id. The following
requests replace the complete list. Read the current list with GET and
include any rules you want to keep before sending PUT.
curl --fail-with-body -X PUT "$BEX_API_URL/v1/services/$SERVICE_ID/routes" \
-H "Authorization: Bearer $BEX_TOKEN" \
-H "Content-Type: application/json" \
-d '[{"type":"redirect","source":"/old/*","destination":"/new/:splat"},{"type":"rewrite","source":"/*","destination":"/index.html"}]'
curl --fail-with-body -X PUT "$BEX_API_URL/v1/services/$SERVICE_ID/headers" \
-H "Authorization: Bearer $BEX_TOKEN" \
-H "Content-Type: application/json" \
-d '[{"path":"/*","name":"X-Frame-Options","value":"DENY"}]'Both endpoints accept a JSON array, not a routes or headers wrapper.
Redirects return 301. Rewrites serve the destination object when it exists.
The /* to /index.html rewrite is useful for a client-side router; include it
only when your app should handle those paths. These rule changes do not require
rebuilding the site, but allow time for the configuration to propagate.
Verify and troubleshoot
Open the site's URL after deployment, then test an asset and a nested page by navigating directly to their URLs.
- Build fails: check the build command, lockfile, root directory, and build logs.
- Publish fails: verify that the output directory exists and contains files; on a self-hosted instance, inspect publishing and object-store configuration.
- Homepage returns 404: check the publish path and
index.htmllocation. - Nested client routes return 404: add an appropriate rewrite if the app uses client-side routing.
- Missing assets: check base paths, filename capitalization, and whether the build included the referenced files.
See Custom domains, TLS, and How deploys work for routing and release details.