At Swiftmade, we recently migrated our Statamic-powered website to Cloudflare Pages for improved performance and simplified hosting. Here's how we set up our deployment workflow to make it seamless and secure.
How Everything Connects: The Big Picture
Our setup works like this:
- We develop our website locally using Statamic, a flat-file CMS built on Laravel
- When we're ready to deploy, we push changes to our GitHub repository's main branch
- A GitHub Action automatically runs Statamic's static site generator (ssg:generate)
- The generated static files are committed to a separate live branch
- Cloudflare Pages watches this live branch and deploys the static content to its global CDN
This workflow allows us to maintain a dynamic CMS for content management while serving blazing-fast static pages to our visitors—without managing any server infrastructure.
Automating Deployments with GitHub Actions
Our solution was to use Statamic's static site generation capabilities along with GitHub Actions to automate deployments. This way, we can keep our build workflow & configuration in our repository, and don't have to worry about internal changes to Cloudflare's own build system.
Here's how our Github Actions yaml looks:
# .github/workflows/cloudflare.yaml
name: Deploy to Cloudflare Pages
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v2
with:
node-version: 20
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Install Dependencies
run: composer install --no-dev --optimize-autoloader
- name: Generate Static Site
run: |
npm ci
npm run production
php please ssg:generate
rm storage/app/static/css/.gitignore
cp resources/cloudflare/_headers storage/app/static/_headers
- name: Setup Git Config
run: |
git config user.name "GitHub Actions Bot"
git config user.email "<[email protected]>"
- name: Push
uses: s0/git-publish-subdir-action@develop
env:
REPO: self
BRANCH: live
FOLDER: storage/app/static
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MESSAGE: "Build: ({sha}) {msg}"
This workflow runs whenever we push to the main
branch. It generates a static version of our site using Statamic's ssg:generate
command and then pushes the compiled files to a live
branch. Our Cloudflare Pages project is configured to watch this branch for changes, triggering a new deployment whenever updates occur.
Obtaining GITHUB_TOKEN for Your Deployment Workflow
Good news! You don't need to manually create a token for your GitHub Actions workflow. GitHub automatically provides a GITHUB_TOKEN secret that has permissions to push to branches within the same repository.
You can learn more about this built-in secret here.
Security Headers
Turns out, Cloudflare Pages allows us to add custom headers through a simple _headers
file at the root of our deployment. Here's what our configuration looks like:
https://swiftmade.co/*
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Permissions-Policy: document-domain=()
Strict-Transport-Security: max-age=31536000; includeSubDomains
https://swiftmade.pages.dev/*
X-Robots-Tag: noindex
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Permissions-Policy: document-domain=()
Strict-Transport-Security: max-age=31536000; includeSubDomains
We stored this file under resources/cloudflare/_headers
and in our Github actions, we copy it to the root of our static output folder.
The Results
This setup has given us the best of both worlds: the user-friendly experience of Statamic's CMS with the performance of Cloudflare's global edge network.
This approach won't suit websites that have dynamic content, or sites that have features like login. If you're running a Statamic site and use Static Site Generator before hosting it, then moving to Cloudflare might make sense.
At the time of writing, Cloudflare Pages has a very generous free tier, so it also means that not paying for a server and not worrying about things like server maintenance / security updates / weak passwords.
If you need support with taking your Statamic project live, you can always contact us at [email protected].