How to Deploy Your Static Astro Website to Bunny.net

Learn how to deploy your Astro static website to Bunny.net CDN with edge storage. Includes a deploy script, GitHub Actions CI/CD, caching setup, and Bunny Shield WAF configuration.

How to Deploy Your Static Astro Website to Bunny.net

You built an Astro site. It’s fast, it’s static, and now you need somewhere to host it that won’t cost a fortune or require you to maintain a server.

I run my own Astro site on Bunny.net, and after months of using it in production I can say the setup is straightforward once you know the steps. Bunny gives you edge storage with global replication and a CDN with 119+ points of presence. You upload your built files, Bunny serves them from the nearest edge location to every visitor. No VPS to patch, no Nginx config to debug, no Docker container to babysit.

I wrote a full Bunny.net review covering pricing and features in detail. This guide does one thing: walk you through getting your Astro static site deployed and live on Bunny.net.

If you don’t have an Astro site yet, I covered how to build a free blog with Astro using the Bitdoze Astro Theme. The same setup applies here, just swap Cloudflare Pages for Bunny.net hosting.

Try Bunny.net free for 14 days

You can follow along with this guide without spending anything. Sign up at Bunny.net with no credit card required and get a full 14-day free trial.

What you need before starting

  • An Astro site configured for static output (or fork the Bitdoze Astro Theme to follow along)
  • A Bunny.net account (free 14-day trial, no credit card)
  • Node.js installed on your machine
  • A domain name (optional, but recommended for production)

Why Bunny.net for static sites

A quick aside on why this is worth doing before we get into the setup.

  • No server maintenance. Upload files, Bunny serves them. No OS updates, no security patches.
  • Edge storage replication. Your site files live in multiple regions worldwide, not a single data center.
  • Perma-Cache stores content permanently on edge servers so visitors almost always get a cache hit.
  • Storage starts at $0.01/GB, bandwidth at $0.01/GB in EU/NA. Most blogs run for under $1/month.
  • Let’s Encrypt certificates are provisioned automatically. No certbot, no renewal cron jobs.
  • Custom domains with full DNS control. Bring your own domain and Bunny handles the rest.

Here’s how Bunny.net stacks up against other popular static hosting options:

FeatureBunny.netCloudflare PagesNetlifyVercel
Bandwidth price (EU/NA)$0.01/GBFree (limited)$0.10/GB$0.15/GB
Storage price$0.01/GBFree (limited)IncludedIncluded
Edge locations119+300+~100~100
Custom domainFreeFreeFreeFree
Free tier14-day trialYes (generous)100GB/mo100GB/mo
WAF / DDoS protectionBunny Shield (free tier)IncludedAdd-onAdd-on
Min. monthly cost$1$0$0$0

Cloudflare Pages has the better free tier if cost is your only concern. But if you want edge storage replication, predictable pricing at scale, or you already use Bunny for CDN or video, hosting your Astro site there keeps everything in one dashboard. I switched from Cloudflare Pages to Bunny for exactly that reason.

Step 1: Build your Astro site

Make sure your Astro project is configured for static output. Open astro.config.mjs and confirm it looks something like this:

import { defineConfig } from 'astro/config';

export default defineConfig({
  site: 'https://yourdomain.com',
  // output: 'static' is the default, so you may not see this line at all
});

Astro uses static output by default, so unless you explicitly changed it to server or hybrid, you’re already set.

Build the site:

npm run build

This generates a dist/ folder containing your complete static site — HTML files, CSS, JavaScript, images, everything. You can preview it locally to verify everything looks right:

npm run preview

The dist/ folder is what we’ll deploy to Bunny.net.

Step 2: Set up Bunny.net infrastructure

You need two things on the Bunny.net side: a storage zone (where your files live) and a pull zone (the CDN layer that serves them to visitors). Neither takes more than a couple of minutes.

Create a storage zone

Bunny.net add storage zone interface

  1. Log into your Bunny.net dashboard
  2. Go to Storage in the left sidebar
  3. Click Add Storage Zone
  4. Fill in the details:
    • Name: Something like my-astro-site (this becomes part of the storage URL)
    • Main Region: Pick the region closest to your primary audience (e.g., DE for Europe, NY for US East)
    • Replication Regions: Add regions where you want copies of your files (e.g., add NY and SYD if you have visitors in the US and Australia)
    • Tier: Edge tier (SSD storage) is worth the tiny price difference for better performance

Choose regions carefully

You cannot change the main region or remove replication regions after creating a storage zone. You can add replication regions later, but start with your primary audience’s region and add more as needed.

Create a pull zone

Bunny.net add pull zone interface

The pull zone is the CDN configuration that sits in front of your storage zone and serves files to visitors.

  1. In your newly created storage zone, go to Connected Pull Zones
  2. Click Connect Pull Zone
  3. Configure it:
    • Name: Something like my-astro-site (this becomes my-astro-site.b-cdn.net)
    • Zones: Select the geographic zones you want to serve traffic from (EU, NA, Asia, etc.)

That’s the basic infrastructure. Your pull zone hostname (my-astro-site.b-cdn.net) is already live and will serve whatever is in your storage zone. Right now that’s nothing, so let’s fix that.

Step 3: Deploy your site

The deployment uploads files from your dist/ folder to Bunny Storage via the Bunny API, then purges the CDN cache. You can do this from your local machine or automate it with GitHub Actions.

Get your credentials

You need four values from the Bunny dashboard:

  1. Storage Zone Name: The name you chose when creating the storage zone (e.g., my-astro-site)
  2. Storage Password: Go to Storage → your storage zone → FTP & API Access → copy the Password
  3. Pull Zone ID: Go to Pull Zones → your pull zone → check the URL, it contains the pull zone ID (or find it in the pull zone settings)
  4. Account API Key: Go to Account Settings → copy the API Key

Bunny.net API key location

Step 4: Configure your custom domain

Your site is already accessible at your-pull-zone.b-cdn.net, but you probably want your own domain. Here’s how.

Add the hostname in Bunny

  1. Go to Pull Zones → your pull zone → General
  2. Scroll to Hostnames
  3. Click Add Custom Hostname
  4. Enter your domain (e.g., www.yourdomain.com or yourdomain.com)
  5. Click Add

Bunny generates an SSL certificate automatically (usually within a few minutes).

Configure DNS at your registrar

How you configure DNS depends on whether you’re using a subdomain or the root domain.

For a subdomain (e.g., www.yourdomain.com):

Add a CNAME record:

TypeNameValue
CNAMEwwwyour-pull-zone.b-cdn.net

CNAME records are the standard approach. They route traffic through Bunny’s Anycast network efficiently.

For a root domain (e.g., yourdomain.com):

Add an ANAME (also called ALIAS) record:

TypeNameValue
ANAME / ALIAS@your-pull-zone.b-cdn.net

Not all DNS providers support ANAME records. Cloudflare, DNSMadeEasy, and Bunny’s own DNS do. If yours doesn’t, use a subdomain like www with a CNAME instead, then set up a redirect from the root domain to www.

CNAME vs ANAME for root domains

ANAME records resolve to an IP address at the DNS level, which can slightly reduce routing optimization compared to CNAME. If performance matters more than a clean root domain URL, use www with a CNAME record instead. Bunny has a detailed writeup on how ANAME records affect CDN routing if you want the technical details.

Verify and enforce SSL

  1. Wait for the SSL certificate status to change to Active (check the Hostnames section in your pull zone)
  2. Toggle Force SSL to redirect all HTTP traffic to HTTPS
  3. Verify by visiting https://yourdomain.com in a browser

DNS propagation

DNS changes can take anywhere from a few minutes to 48 hours to propagate globally, though most updates show up within 15-30 minutes. You can check propagation status with tools like dig or online DNS checkers.

Step 5: Configure caching

Bunny has three caching features worth understanding for a static Astro site. They work together in layers.

Smart Cache

Smart Cache is enabled by default on pull zones accelerated by Bunny DNS. It decides what gets cached and what passes through to the origin on every request.

For static sites, Smart Cache caches everything with a recognized static file extension (images, fonts, CSS, JS, PDFs, etc.) and never caches text/html, application/json, or application/xml MIME types. This is the right behavior for most Astro sites since your HTML pages will be fetched fresh while assets get cached.

If you need to cache HTML pages (Bunny excludes them by default), create an Edge Rule with the Override Cache Time action targeting your HTML files.

Vary Cache

Vary Cache lets Bunny store different versions of the same URL based on factors like browser capabilities, device type, or location. The relevant options for a static Astro site:

SettingWhat it does
WebP supportServes WebP images to browsers that support them, original format to the rest
AVIF supportSame idea, but for the AVIF format
URL Query StringTreats different query strings as separate cached files

Watch your cache cardinality

Each Vary setting multiplies the number of cached versions per URL. WebP + AVIF + Mobile/Desktop creates 2 x 2 x 2 = 8 cached versions of each file. Only enable settings you actually need, or your cache hit rate drops.

Perma-Cache

Perma-Cache is a secondary permanent cache layer between the CDN and your origin. When a cache miss occurs on the CDN edge, Bunny checks Perma-Cache storage first before hitting your origin. Files that get fetched from the origin are stored permanently in Perma-Cache in the background.

This is different from regular CDN caching, which expires based on time or available space. Perma-Cache files stick around indefinitely.

Perma-Cache vs Storage Zone origin

If your pull zone is directly connected to a storage zone as its origin (which is the setup in this guide), Perma-Cache is not available because your content is already hosted on Bunny storage. Perma-Cache is useful when your origin is an external server (a VPS, for example) and you want Bunny to cache origin responses permanently.

To enable Perma-Cache:

  1. Create a separate storage zone (different from the one holding your site files)
  2. Go to Pull Zones → your pull zone → CachingPerma-Cache
  3. Select the storage zone from the dropdown
  4. Save configuration

Step 6: Add security with Bunny Shield

Bunny Shield is Bunny’s WAF (Web Application Firewall) and DDoS protection service. It sits in front of your pull zone and filters malicious traffic before it reaches your site. There’s a free tier that covers the basics.

What the free tier gives you

The free Shield tier includes 71 built-in WAF rules and DDoS protection. It blocks common attacks automatically:

  • SQL injection attempts in query parameters and forms
  • Cross-site scripting (XSS) payloads
  • Remote file inclusion (RFI) attacks
  • Other OWASP Top 10 threats

For a static Astro site, Shield is mostly defense against DDoS and bot traffic since there’s no server-side code to exploit. But it still reduces noise in your logs and can block scrapers or abuse patterns.

Enable Shield

  1. Go to Shield in the Bunny dashboard
  2. Create a new Shield Zone
  3. Connect it to your pull zone
  4. The free tier activates automatically

Optional: rate limiting and custom WAF rules

The paid tiers ($9.50/month for Advanced, $99/month for Business) add:

  • Custom WAF rules (10 on Advanced, 25 on Business)
  • Advanced bot detection
  • Rate limiting per IP or path

For a static blog, the free tier is usually enough. Rate limiting becomes relevant if you notice specific IPs hammering your site or if you want to block traffic from certain countries.

Set up Edge Rules for security headers

Edge Rules let you add custom headers to responses. Adding security headers is a quick win regardless of whether you use Shield:

  1. Go to Pull Zones → your pull zone → Edge Rules
  2. Create rules to add headers:
HeaderValue
X-Content-Type-Optionsnosniff
X-Frame-OptionsSAMEORIGIN
X-XSS-Protection1; mode=block
Referrer-Policystrict-origin-when-cross-origin

Cost breakdown

What does this actually cost? Here’s a realistic scenario for a typical Astro blog:

ResourceMonthly usageCost
Edge storage500 MB~$0.01
CDN bandwidth (EU/NA)25 GB~$0.25
Shield (free tier)-$0.00
Total~$0.26/month

Under $4/year for a blog with moderate traffic, including DDoS protection and WAF. Even at 100 GB of monthly bandwidth you’re looking at roughly $1/month.

Bunny has a $1 monthly minimum, so very low-traffic sites still pay $1. But that $1 covers up to 100 GB of EU/NA bandwidth, which is more than most blogs use in a month.

Troubleshooting

Site returns 404 errors

Check that your files are uploaded to the root of your storage zone, not inside a subfolder. The dist/ folder contents (not the folder itself) should be at the top level. With the deploy script, this is handled by the path stripping logic (remote_path="${file#$DIST_DIR/}"). If you uploaded manually, make sure you uploaded the contents of dist/, not the dist/ directory itself.

Also verify your pull zone is connected to the correct storage zone (Pull Zones → your zone → General → Origin Type should show “StorageZone” with the right zone selected).

CSS and JavaScript not loading

This is usually a MIME type issue. Bunny.net should detect and serve correct MIME types automatically, but if something is off:

  1. Check the pull zone’s Routing settings
  2. Make sure the Enable Static File Processing option is enabled if available
  3. Verify that your dist/ folder contains the referenced assets with correct file extensions

If you’re using Astro’s default build output, CSS and JS files are placed in dist/_astro/ with hashed filenames. As long as the full dist/ folder was uploaded, these should work.

Changes not visible after deployment

The CDN is serving cached content. Purge the cache:

  • From the dashboard: Pull Zones → your zone → Purge Cache → Purge All Files
  • The deploy script handles this automatically after each upload

Cache purges propagate within seconds on Bunny’s network. If you’re using Perma-Cache, note that a full pull zone purge doesn’t delete Perma-Cache files. It switches to a new directory structure instead.

SSL certificate not provisioning

SSL certificates are provisioned automatically when you add a custom hostname, but they require the DNS record to be pointing to Bunny first. Verify:

  1. Your CNAME or ANAME record is correctly configured at your DNS provider
  2. DNS has propagated (use dig yourdomain.com to check)
  3. Wait a few minutes after DNS propagation for the certificate to be issued

If it’s been over 30 minutes and the certificate is still pending, remove the hostname from Bunny and re-add it.

Deploy script fails with authentication errors

Double-check your credentials:

  • Storage Password: This is the password from the storage zone’s FTP & API Access page, not your account password
  • API Key: This is the key from Account Settings, not the storage password
  • Pull Zone ID: This is a numeric ID, not the pull zone name. You can find it in the pull zone settings or the dashboard URL

Also make sure your .env file doesn’t have trailing whitespace or quotes around the values.

Frequently asked questions

Can I use this with other static site generators?

Yes. The same setup works with Hugo, Next.js (static export), Gatsby, 11ty, Jekyll, or any tool that outputs a folder of static files. The only Astro-specific step is the build command (npm run build producing a dist/ folder). Replace that with your generator’s build command and output directory, and everything else stays the same.

Why use the deploy script instead of Bunny Launcher?

Bunny Launcher is a third-party tool that abstracts away the Bunny API. The deploy script in this guide calls the Bunny Storage and CDN APIs directly with curl, so you can see exactly what’s happening and adapt it to any environment. It works in GitHub Actions, GitLab CI, or a local terminal without installing extra npm packages.

What about server-side rendering (SSR)?

This guide covers static sites only. Bunny.net’s edge storage and CDN serve pre-built files with no server-side runtime. If your Astro site uses SSR mode (output: 'server'), you need a hosting platform that runs Node.js (Vercel, Netlify, or a VPS). You can still put Bunny CDN in front of your SSR server for caching, but that’s a different setup.

Do I need Bunny Optimizer?

Not necessarily. Astro handles image optimization, CSS minification, and JavaScript bundling during the build process. Your dist/ folder is already optimized. Bunny Optimizer is worth considering if you serve images that weren’t processed during build (user uploads, dynamically referenced assets) or want on-the-fly WebP/AVIF conversion. For a standard Astro blog, it’s redundant.

How do I handle redirects?

Use Bunny’s Edge Rules to set up redirects. Go to Pull Zones → your zone → Edge Rules and create a redirect rule. Common patterns include redirecting yourdomain.com to www.yourdomain.com, redirecting old URLs after a site migration, or enforcing trailing slash consistency.

For Astro’s built-in redirects (configured in astro.config.mjs), those generate a _redirects file in the dist/ folder during build. Bunny doesn’t process this file, so you’d need to replicate those rules as Edge Rules in the Bunny dashboard.

Wrapping up

Your Astro site is now running on Bunny.net’s global CDN with edge storage, caching, and DDoS protection via Shield. Storage, CDN, SSL, WAF, and global delivery for under $1/month for most blogs.

If you run into issues, the troubleshooting section above covers the common ones. The GitHub Actions workflow from Step 3 is the logical next step if you want automatic deploys on every push to main.

Get Started with Bunny.net