One command, or by hand
The Bunny CLI does all of the below for you, and adds what a storage zone cannot do on its own:404.html that answers a missing path, a _redirects file, and a _headers file. See bunny sites.
The rest of this page is the same deployment done by hand.
How It Works
Bunny Storage combined with a Pull Zone provides a simple, fast way to host static frontends:- Build your application locally
- Upload the build output to a Storage Zone
- Connect a Pull Zone for global CDN delivery
- Configure error handling for SPA routing (if needed)
Single-Page Application Routing
Single-page applications (React, Vue, Angular, etc.) handle routing client-side. When a user navigates directly to a route like/dashboard or refreshes the page, the server needs to serve index.html instead of returning a 404.
Why SPAs need special configuration
Why SPAs need special configuration
When your SPA loads, the JavaScript router takes over navigation. But if a
user: - Bookmarks a deep link like
/products/123 - Refreshes the page on
/settings - Shares a URL like /about The browser requests that exact path
from the server. Since no file exists at that path (only index.html and your
assets exist), the server returns a 404. The solution is to configure your
Storage Zone’s error handling to serve index.html for missing paths,
allowing your client-side router to handle the URL.Configure SPA Fallback
To enable client-side routing, configure the error handling settings on your Storage Zone:1
Navigate to your storage zone
Log in to your Bunny dashboard, go to Storage in the left navigation,
and select your storage zone.
2
Open Error handling settings
Open the Error handling page.
3
Set the 404 file path
Enter
/index.html in the 404 File path field.4
Enable 404 to 200 rewrite
Check the box for Rewrite 404 to 200 status code and click Save.
index.html for all missing paths, and your client-side router will handle the URL. Requests for files with extensions (like .js, .css, or images) that don’t exist will still return a 404.
See the Storage Zone Settings page for more details on
error handling configuration.
Framework Guides
Vite
Deploy a Vite-built static site with optimal configuration.
React
Deploy Create React App and other React builds.
Vue
Deploy Vue CLI and Vite-based Vue applications.
Does your site also need API routes or per-visitor responses? Put an Edge
Script in front of the storage zone instead of a plain
pull zone.
Redirects and Headers
A storage zone holds objects, and nothing else. It cannot answer a missing path with your own page, send a redirect, or add a response header. Three ways to get those:bunny sites
Deploy with the CLI, and its router reads
404.html, _redirects, and
_headers out of your build. The same file names Cloudflare Pages and
Netlify readEdge Rules
Redirect, rewrite, and set headers on the pull zone itself, one rule at a
time, in the dashboard or the API
A custom 404 page
Upload
bunnycdn_errors/404.html to the root of the storage zone. One page
per zone, and it needs no scriptAn Edge Script
Write the routing yourself, when your site needs a rule no list of rules can
express
Common Configuration
Custom Domains
Add your own domain to any frontend deployment:- In your Pull Zone, go to Hostnames
- Click Add Hostname and enter your domain
- Add a CNAME record pointing to
your-pullzone.b-cdn.net - Enable Free SSL for automatic HTTPS
Cache Configuration
Static frontends benefit from aggressive caching. Consider these settings in your Pull Zone:Modern build tools like Vite add content hashes to filenames (e.g.,
main.a1b2c3.js), making it safe to cache these files indefinitely.Cache-Control header of its own. So the pull zone’s cache expiration decides how long a file is kept, at the edge and in the browser. That one expiration covers every file in the zone. HTML therefore wants the short end of the table above, and a hashed file wants the long one.
To give each of the two its own lifetime, the response has to carry the header. bunny sites does that per file: a page gets a minute, and a directory named in _headers gets a year. By hand, there are two ways. Write an Edge Rule per path, or turn the zone’s cache override off and set the header from an Edge Script. While the override is on, it replaces whatever the origin or the script returns.