Cloudflare Pages Setup Guide

This guide documents the migration from GitHub Pages to Cloudflare Pages and the configuration required.

Why Cloudflare Pages?

Gemfile Configuration

GitHub Pages uses a locked-down environment with Jekyll 3.x. Cloudflare Pages allows Jekyll 4.x but requires a separate Gemfile to avoid native compilation issues.

Gemfile.cloudflare

A separate Gemfile.cloudflare is used for Cloudflare builds:

source 'https://rubygems.org'

gem "jekyll", "~> 4.3"

# Pin sass converter to v2 to avoid sass-embedded native compilation issues
gem "jekyll-sass-converter", "~> 2.0"
gem "sassc", "~> 2.4"

group :jekyll_plugins do
    gem 'jekyll-seo-tag'
    gem 'jekyll-gist'
    gem 'jekyll-feed'
    gem 'jemoji'
    gem "jekyll-paginate-v2", "~> 3.0"
    gem "html-proofer"
    gem "jekyll-sitemap"
    gem 'jekyll-minifier'
    gem 'jekyll-include-cache'
end

gem "webrick", "~> 1.8"
gem "faraday-retry", "~> 2.2"
gem "csv"
gem "base64"

Key Differences from GitHub Pages Gemfile

SettingGitHub PagesCloudflare
Jekyll version3.10.x (locked)4.3.x
Sass compilersass-embeddedsassc (pinned)
PluginsLimitedFull control

Cloudflare Pages Build Configuration

Build Settings

In Cloudflare Dashboard > Pages > Your Project > Settings > Builds & deployments:

SettingValue
Framework presetNone
Build commandexport BUNDLE_GEMFILE=Gemfile.cloudflare && JEKYLL_ENV=production bundle install && bundle exec jekyll build
Build output directory_site
Root directory/

Environment Variables

VariableValueNotes
RUBY_VERSION3.2.2Required
JEKYLL_ENVproductionAlready in build command; optional here

DNS Configuration

For Domains on Cloudflare DNS

  1. Root domain (sameerbajaj.com):
  2. WWW subdomain:

Migration from GitHub Pages

  1. Remove old GitHub A records:
  2. Add CNAME pointing to <project-name>.pages.dev

  3. Wait for DNS propagation (usually 5-10 minutes with Cloudflare)

Custom Headers

Cache headers are configured via the _headers file in the project root:

/*
  X-Content-Type-Options: nosniff
  Referrer-Policy: no-referrer-when-downgrade

/*.html
  Cache-Control: public, max-age=3600

/assets/*
  Cache-Control: public, max-age=31536000, immutable

Important: Add _headers to Jekyll’s include list in _config.yml:

include:
  - _headers

Verifying the Migration

Check Server Headers

curl -sI https://yourdomain.com | grep -i server
# Should show: server: cloudflare

Check No GitHub Headers

curl -sI https://yourdomain.com | grep -i github
# Should return nothing

Check Cache Headers

curl -sI https://yourdomain.com/assets/js/some-file.js | grep -i cache-control
# Should show: cache-control: public, max-age=31536000, immutable

Troubleshooting

Build Fails: sass-embedded Compilation Error

Symptom: sass-embedded fails to compile native extensions

Fix: Use sassc instead by pinning versions in Gemfile.cloudflare:

gem "jekyll-sass-converter", "~> 2.0"
gem "sassc", "~> 2.4"

Build Fails: Incompatible Units in Sass

Symptom: Error like Incompatible units: 'ch' and 'px'

Fix: Wrap CSS min()/max()/clamp() in interpolation to pass through as literal CSS:

// Before (fails with sassc)
width: min(210px, 24ch);

// After (works)
width: #{"min(210px, 24ch)"};

WWW Subdomain Returns 522 Error

Symptom: www.yourdomain.com shows Cloudflare 522 error

Fix: Add www.yourdomain.com as a Custom Domain in Pages project, not just a DNS CNAME record.

Cache Headers Still Show 10m

Symptom: PageSpeed shows 10-minute cache despite _headers file

Causes:

  1. _headers not in Jekyll’s include list
  2. Stale PageSpeed cache - run a fresh analysis
  3. Cloudflare edge cache - purge via Dashboard > Caching > Purge Everything

Build Time Optimization

Cloudflare builds may be slower than GitHub Pages due to:

Current build time: ~7-8 minutes (vs ~2 minutes on GitHub Pages)

This is acceptable for a blog with infrequent updates.

Maintaining Both Environments

The main Gemfile still works with GitHub Pages if needed as a fallback. Keep both files in sync when adding new plugins.

EnvironmentGemfileCommand
Local devGemfilebundle exec jekyll serve
GitHub PagesGemfileAutomatic
CloudflareGemfile.cloudflareCustom build command