Host a public website
A static website (marketing page, documentation, single-page app, portfolio) can run entirely on Filebase: upload the build artifacts to a public bucket, set sensible Cache-Control headers, and the Filebase CDN serves them globally with edge caching.
Step 1 — Create a public bucket
aws --endpoint https://s3.filebase.io s3api create-bucket \
--bucket my-marketing-site \
--acl public-read
Step 2 — Upload the build
For most static-site generators (Vite, webpack, Astro, Next.js export, Hugo, etc.), build into a dist/ directory and sync:
# Long-cache hashed assets
aws --endpoint https://s3.filebase.io s3 sync ./dist/ s3://my-marketing-site/ \
--acl public-read \
--cache-control "public, max-age=31536000, immutable" \
--exclude "*.html" \
--exclude "*.xml"
# Short-cache HTML and feeds
aws --endpoint https://s3.filebase.io s3 sync ./dist/ s3://my-marketing-site/ \
--acl public-read \
--cache-control "public, max-age=300, must-revalidate" \
--exclude "*" \
--include "*.html" \
--include "*.xml"
The two-pass sync gives hashed assets aggressive caching while keeping HTML responsive to deploys.
Step 3 — Serve from the bucket URL
Your site is now live at:
https://my-marketing-site.s3.filebase.io/index.html
The Filebase CDN is in front automatically — popular pages serve from edge points-of-presence.
Step 4 — Custom domain
To serve via your own domain (e.g. example.com):
- Create a CNAME record at your DNS provider:
www.example.com. CNAME my-marketing-site.s3.filebase.io.
- The Filebase CDN auto-provisions a TLS certificate for the CNAME.
- Visit
https://www.example.com/— your site loads via the custom domain.
For root domains (example.com), an ALIAS / ANAME record is required, which depends on your DNS provider's capabilities. Cloudflare, Route 53, and most modern DNS providers support root-domain CNAMEs.
Step 5 — Index and 404 fallback
The Filebase CDN serves index.html as the directory index. Requests to https://example.com/ return https://example.com/index.html.
For 404s, upload a 404.html to the bucket and the CDN serves it for unmatched paths.
For SPAs that use client-side routing, upload your index.html as 404.html so unmatched paths fall through to your SPA bootstrap.
CI/CD example (GitHub Actions)
name: Deploy site
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run build
- uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.FILEBASE_KEY }}
aws-secret-access-key: ${{ secrets.FILEBASE_SECRET }}
aws-region: auto
- name: Sync to Filebase
run: |
aws --endpoint https://s3.filebase.io s3 sync ./dist/ s3://my-marketing-site/ \
--acl public-read \
--cache-control "public, max-age=31536000, immutable" \
--exclude "*.html"
aws --endpoint https://s3.filebase.io s3 sync ./dist/ s3://my-marketing-site/ \
--acl public-read \
--cache-control "public, max-age=300, must-revalidate" \
--exclude "*" --include "*.html"
Add FILEBASE_KEY and FILEBASE_SECRET to the repo's GitHub Actions secrets.
Atomic deploys via content-hashed filenames
Modern bundlers (Vite, webpack 5+, Rollup) emit hashed filenames like app.a3f9d2.js. Combined with the long Cache-Control above:
- New deploys upload new hashed files (no overwrite).
- Old hashed files keep working until cache expiry.
- The HTML (short cache) updates within minutes.
This gives you instant rollback (re-deploy the old commit), zero-downtime deploys, and aggressive edge caching with no invalidation needed.
What's next
- CDN and caching
- webpack-s3-plugin — bake the deploy into your webpack config
- AWS CLI guide
- Public vs. private buckets