Deploy and Go Live
This is a member-only chapter. Log in with your Signal Over Noise membership email to continue.
Log in to readModule 5: Deploy and Go Live
You have a site that builds. Now you need it somewhere that isn’t your laptop. This module covers the two paths I use across my own sites: Cloudflare Pages for sites that don’t need server-side logic, and an IONOS VPS for sites that need more control.
Both paths end at the same place: a live domain with SSL, serving fast static HTML.
Path A: Cloudflare Pages
Cloudflare Pages is free for most use cases, globally distributed, and has zero configuration for SSL. It connects directly to a Git repository and deploys on push. For content sites with no server-side logic, it’s the right choice.
What it’s right for: Anything fully static. A personal site, blog, portfolio, documentation, landing page. Anything that doesn’t need Edge Functions or specific server behaviour.
What I deploy here: sketchscript.app and definitelyrealproducts.com both run on Cloudflare Pages.
Setup
- Push your site to a GitHub repository.
- Log into the Cloudflare dashboard and go to Workers & Pages > Create > Pages.
- Connect your GitHub account and select the repository.
- Set the build settings:
- Framework preset: Astro
- Build command:
npm run build - Build output directory:
dist
- Deploy.
That’s it. Cloudflare gives you a *.pages.dev subdomain immediately. You can add a custom domain in the Pages settings once the deploy succeeds.
Custom Domain
In Cloudflare Pages > Custom Domains, add your domain. If your DNS is already on Cloudflare (recommended), the DNS record is created automatically. If your DNS is elsewhere, you’ll add a CNAME pointing to your *.pages.dev subdomain.
SSL is automatic. There’s nothing to configure.
Environment Variables
If your Astro site uses environment variables at build time, add them in Pages > Settings > Environment Variables. Prefix anything you want available in client-side code with PUBLIC_.
Path B: VPS With rsync
For sites that need more control — a custom nginx configuration, server-side auth, or tools that don’t fit neatly into a serverless model — a VPS is the right call.
I deploy jimchristian.net, signalovernoise.at, sbc.jimchristian.net, howtocodeinminecraft.com, and thinklikeacoder.org to an IONOS VPS. The deploy workflow is rsync over SSH.
What it’s right for: Sites that need custom server config, sites with dynamic server-side logic, situations where you want full control over the environment.
The Deploy Workflow
Build the site locally:
npm run build
Then rsync the dist/ directory to the server:
rsync -avz --delete dist/ deploy@your-vps-ip:/var/www/your-site/
The --delete flag removes files from the server that no longer exist locally — important for keeping the live site in sync with the build output.
A deploy script makes this repeatable:
#!/usr/bin/env bash
set -e
echo "Building..."
npm run build
echo "Deploying..."
rsync -avz --delete dist/ deploy@your-vps-ip:/var/www/your-site/
echo "Done."
Save as deploy.sh, make it executable (chmod +x deploy.sh), and deploy with ./deploy.sh.
nginx Configuration
On the server, nginx serves the static files. A basic config:
server {
listen 80;
server_name your-domain.com;
root /var/www/your-site;
index index.html;
location / {
try_files $uri $uri/ $uri.html =404;
}
}
The try_files directive handles Astro’s clean URLs — it tries the exact path, then a directory index, then the same path with .html appended. This means /about resolves correctly even though the file is about.html.
For SSL, use Certbot with the nginx plugin:
sudo certbot --nginx -d your-domain.com
Certbot modifies the nginx config to add HTTPS and set up automatic renewal. After running it, your site serves on HTTPS.
SSH Key Setup
For the rsync to work, your local SSH key needs to be authorised on the server. Add your public key to ~/.ssh/authorized_keys on the server, or use ssh-copy-id:
ssh-copy-id deploy@your-vps-ip
Store the connection details in your local ~/.ssh/config so you’re not typing IPs:
Host my-vps
HostName your-vps-ip
User deploy
IdentityFile ~/.ssh/id_ed25519
Then your rsync command becomes:
rsync -avz --delete dist/ my-vps:/var/www/your-site/
R2 for Assets
For both deployment paths, large assets (images, fonts, downloadable files) are better served from a CDN than from your site’s own hosting.
All eight of my sites use Cloudflare R2 for this. Assets live at assets.jimchristian.net — served from R2 with a cache rule that sets Cache-Control: max-age=31536000, immutable on images. They load fast and don’t count against VPS bandwidth.
The pattern: upload assets to R2, reference them by their CDN URL in your Markdown and components, never commit large binary files to the repository.
R2 has a generous free tier (10 GB storage, zero egress fees). It’s the first thing I’d set up for any site with more than a handful of images.
Which Path to Choose
Start with Cloudflare Pages unless you have a specific reason not to:
- Free
- No server to maintain
- Global CDN built in
- SSL automated
- Deploys on every git push
Move to VPS when:
- You need custom server-side logic that Edge Functions don’t cover
- You’re consolidating multiple sites behind one nginx instance
- You have specific security or compliance needs
- You want to run additional server processes alongside the site
Your site is live. Module 6 is about the workflow that makes building the next one faster.
Check Your Understanding
Answer all questions correctly to complete this module.
1. When should you choose Cloudflare Pages over a VPS?
2. What does the --delete flag do in rsync deploy?
3. Why use R2 for large assets instead of the site's own hosting?
Pass the quiz above to unlock
Save failed. Please try again.