GitHub + Cloudflare — Full Developer Workflow
The Big Picture
you write code
↓
git push → GitHub repo
↓
GitHub Actions (optional CI/CD)
↓
Cloudflare Pages (build + host)
↓
Cloudflare CDN (cache + serve globally)
↓
Cloudflare DNS (routes domain → CDN)
↓
visitor types your domain → gets your site in <50ms
Every piece has one job. GitHub stores and versions your code. Cloudflare Pages builds and hosts it. Cloudflare CDN serves it fast globally. Cloudflare DNS connects your domain to all of it.
Part 1 — GitHub
What GitHub Actually Is
GitHub is three things in one:
1. Remote git storage → your code lives here, backed up, versioned
2. Collaboration layer → PRs, issues, reviews, forks
3. Automation platform → GitHub Actions runs your CI/CD pipelines
Repository Structure
my-project/
├── .github/
│ └── workflows/
│ └── deploy.yml ← GitHub Actions config
├── src/ ← your source code
├── public/ ← static assets
├── package.json
└── README.md
GitHub Actions — Automated Pipelines
When you push code, GitHub Actions can automatically: - run tests - build your project - deploy to Cloudflare Pages - send notifications
# .github/workflows/deploy.yml
name: Deploy to Cloudflare Pages
on:
push:
branches: [main] # triggers on every push to main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: npm install
- name: Build
run: npm run build
- name: Deploy to Cloudflare Pages
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: my-project
directory: dist # output folder after buildGitHub Secrets
Never hardcode API keys. Store them in GitHub Secrets:
repo → Settings → Secrets and variables → Actions → New repository secret
Then access in workflows as
${{ secrets.SECRET_NAME }}.
Part 2 — Cloudflare Pages
What Cloudflare Pages Is
Cloudflare Pages is a hosting platform for static sites and frontend apps. You connect your GitHub repo, Cloudflare builds it on every push, and deploys it globally on their network.
GitHub repo → Cloudflare Pages → 300+ edge locations worldwide
Free tier gives you: - unlimited sites - 500 builds/month - unlimited bandwidth - custom domains with free SSL - preview deployments for every branch
How to Connect GitHub → Cloudflare Pages
1. cloudflare.com → Workers & Pages → Pages → Create a project
2. Connect to Git → authorize GitHub → select your repo
3. Set build settings:
Framework preset: (pick your framework or None)
Build command: npm run build (or bash build.sh for static)
Build output dir: dist (or output, public, etc.)
Root directory: / (leave blank usually)
4. Click Save and Deploy
Cloudflare Pages then: - clones your repo - runs the build command - takes the output directory - deploys it globally
Build Settings by Project Type
Static HTML (no build step)
Build command: (leave empty)
Output directory: / or public
Bash build script (like your notes-site)
Build command: bash build.sh
Output directory: output
React / Vite
Build command: npm run build
Output directory: dist
Next.js
Build command: npm run build
Output directory: .next
SvelteKit
Build command: npm run build
Output directory: build
Preview Deployments
Every branch and PR gets its own preview URL automatically:
main branch → my-project.pages.dev (production)
feature/navbar → abc123.my-project.pages.dev (preview)
fix/bug → def456.my-project.pages.dev (preview)
This means you can share a preview link with anyone before merging. No extra config needed — it just works.
Environment Variables in Pages
Pages project → Settings → Environment variables
Key: API_BASE_URL
Value: https://api.myapp.com
Environment: Production / Preview / Both
Access in your code:
const apiUrl = process.env.API_BASE_URLPart 3 — Cloudflare DNS
What DNS Does
DNS translates your domain name into an IP address. Without DNS:
visitor types: abhishekkumar.xyz
without DNS: visitor has no idea where to go
with DNS: abhishekkumar.xyz → 104.21.x.x (Cloudflare's IP)
Cloudflare knows to serve your Pages project
Adding Your Domain to Cloudflare
1. cloudflare.com → Add a site → enter your domain
2. Pick free plan
3. Cloudflare scans your existing DNS records
4. Cloudflare gives you 2 nameservers:
e.g. ava.ns.cloudflare.com
bob.ns.cloudflare.com
5. Go to your domain registrar (GoDaddy, Namecheap, etc.)
→ change nameservers to the ones Cloudflare gave you
6. Wait 5–30 minutes for propagation
7. Done — Cloudflare now controls your DNS
DNS Record Types
A domain → IPv4 address
example.com → 76.76.21.21
AAAA domain → IPv6 address
CNAME domain → another domain (alias)
www → example.com
blog → username.github.io
MX mail server
@ → mail.example.com (handles email)
TXT text records (verification, SPF, DKIM)
@ → "v=spf1 include:_spf.google.com ~all"
NS nameserver records (set by Cloudflare automatically)
The Orange Cloud — Proxied vs DNS Only
This is the most important concept in Cloudflare DNS:
Orange cloud (proxied) ☁️ → traffic goes through Cloudflare
get CDN, DDoS protection, firewall, SSL
visitor sees Cloudflare's IP, not yours
Grey cloud (DNS only) ☁️ → just DNS, no Cloudflare features
visitor connects directly to your server
use for: mail, FTP, SSH, non-HTTP services
Always use orange cloud for web traffic.
Setting Up DNS for Cloudflare Pages
When you add a custom domain in Pages, Cloudflare creates the DNS record automatically. But if you do it manually:
Type: CNAME
Name: @ (or www, or blog, or visual)
Target: your-project.pages.dev
Proxy: ON (orange cloud)
# examples for your projects
Type Name Target Proxy
CNAME @ notes-site.pages.dev ON
CNAME visual mirage.pages.dev ON
CNAME www abhishekkumar.xyz ON
Subdomains
# app.abhishekkumar.xyz → notes-site
Type: CNAME Name: app Target: notes-site.pages.dev
# visual.abhishekkumar.xyz → mirage
Type: CNAME Name: visual Target: mirage.pages.dev
# api.abhishekkumar.xyz → your backend server
Type: A Name: api Target: 1.2.3.4 (your server IP)Part 4 — Cloudflare CDN
What the CDN Does
CDN = Content Delivery Network. Cloudflare has 300+ data centers worldwide. When a visitor requests your site:
without CDN:
visitor in Tokyo → request travels to your server in Frankfurt → 200ms
with Cloudflare CDN:
visitor in Tokyo → Cloudflare Tokyo edge → cached copy served → 20ms
The first request hits your origin (Pages). Cloudflare caches the response. Every request after that is served from the nearest edge — fast.
What Gets Cached by Default
Cached automatically:
images .jpg .png .gif .webp .svg .ico
styles .css
scripts .js
fonts .woff .woff2 .ttf
documents .pdf
NOT cached by default:
HTML .html (because it can be dynamic)
API routes /api/*
anything with Cache-Control: no-cache header
Cache Rules — Control What Gets Cached
Go to: Cloudflare Dashboard → Rules → Cache Rules
# Cache everything (for fully static sites like mirage)
If: hostname equals visual.abhishekkumar.xyz
Then: Cache Level = Cache Everything
Edge TTL = 1 day
# Cache HTML too for static site
If: URI path ends with .html
Then: Cache Level = Cache Everything
Edge TTL = 4 hours
# Never cache admin or API
If: URI path starts with /api
Then: Cache Level = Bypass
Cache TTL (Time To Live)
How long Cloudflare keeps a cached copy before fetching fresh from origin:
Browser TTL how long visitor's browser caches it
Edge TTL how long Cloudflare's servers cache it
Recommended for static sites:
HTML files: Edge TTL = 4 hours (changes sometimes)
CSS/JS: Edge TTL = 1 week (versioned, rarely changes)
Images: Edge TTL = 1 month (almost never changes)
Fonts: Edge TTL = 1 year (never changes)
Purging Cache After a Deploy
After you push new code and it deploys, Cloudflare might still serve the old cached version to visitors. Purge it:
# Option 1: Dashboard
# Cloudflare → Caching → Configuration → Purge Everything
# Option 2: CLI via API (good for CI/CD)
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
--data '{"purge_everything":true}'
# Option 3: Purge specific files only
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
--data '{"files":["https://yourdomain.com/index.html","https://yourdomain.com/style.css"]}'Cloudflare Pages Auto-Purges Cache
Good news — when you deploy via Cloudflare Pages, it automatically purges the CDN cache for you. You only need to manually purge if you’re using a separate origin server.
Part 5 — SSL / HTTPS
Cloudflare handles SSL automatically. Zero config.
visitor → HTTPS → Cloudflare edge (valid SSL cert)
↓
Cloudflare → your origin (SSL or not)
SSL Modes
Off HTTP only — never use this
Flexible HTTPS to visitor, HTTP to origin — avoid (insecure)
Full HTTPS to both, self-signed cert OK on origin
Full (Strict) HTTPS to both, valid cert required on origin — best
For Cloudflare Pages: always use Full (Strict) — Pages provides a valid cert automatically.
SSL/TLS → Overview → Full (Strict)
SSL/TLS → Edge Certificates → Always Use HTTPS → ON
SSL/TLS → Edge Certificates → Minimum TLS Version → TLS 1.2
Part 6 — Full Deployment Architecture
Static Site (notes-site / mirage)
┌─────────────────────────────────────────────────────────┐
│ YOUR MACHINE │
│ write markdown/HTML → git push │
└─────────────────────────┬───────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ GITHUB │
│ stores code, triggers Pages build on push │
└─────────────────────────┬───────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ CLOUDFLARE PAGES │
│ runs build command → outputs static files │
│ deploys to 300+ edge locations │
└─────────────────────────┬───────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ CLOUDFLARE CDN + DNS │
│ DNS: app.abhishekkumar.xyz → pages.dev │
│ CDN: serves cached files from nearest edge │
│ SSL: HTTPS auto-provisioned │
│ DDoS: protected automatically │
└─────────────────────────┬───────────────────────────────┘
↓
VISITOR
gets your site in <50ms
from nearest edge globally
Full-Stack App (frontend + backend)
┌──────────────────────────────────────────────┐
│ GitHub repo │
│ ├── frontend/ → Cloudflare Pages │
│ └── backend/ → your VPS / Railway / Fly │
└──────────────────────────────────────────────┘
DNS setup:
app.yourdomain.com CNAME → pages project (frontend)
api.yourdomain.com A → VPS IP (backend)
Cloudflare proxy:
app subdomain → ON (CDN + DDoS for frontend)
api subdomain → ON (DDoS protection for API)
Part 7 — Complete Setup Walkthrough
Step 1 — Create repo and push code
mkdir my-site && cd my-site
echo "<h1>Hello</h1>" > index.html
git init && git add -A && git commit -m "init"
gh repo create my-site --public --source=. --pushStep 2 — Connect to Cloudflare Pages
Cloudflare Dashboard
→ Workers & Pages
→ Pages → Create a project
→ Connect to Git → select GitHub → select my-site repo
→ Build settings:
Build command: (empty for plain HTML)
Output dir: /
→ Save and Deploy
Your site is now live at my-site.pages.dev.
Step 3 — Add your domain to Cloudflare
Cloudflare Dashboard → Add a site → yourdomain.com
→ Free plan
→ Copy the 2 nameservers Cloudflare gives you
→ Go to your registrar → update nameservers
→ Wait for propagation (usually 15 min)
Step 4 — Add custom domain to Pages
Pages project → Custom domains → Set up a custom domain
→ Enter: yourdomain.com (or app.yourdomain.com)
→ Cloudflare automatically creates DNS record
→ SSL certificate provisioned in ~1 min
Step 5 — Configure SSL
SSL/TLS → Overview → Full (Strict)
SSL/TLS → Edge Certificates → Always Use HTTPS → ON
Step 6 — Set up cache rules (optional but good)
Rules → Cache Rules → Create rule
Name: Cache static assets
If: hostname = yourdomain.com
Then: Cache Everything
Edge TTL: 1 day
Step 7 — Push to deploy
From now on, every push to main:
git add -A
git commit -m "update content"
git push
# → GitHub notifies Cloudflare Pages
# → Pages rebuilds
# → deploys globally
# → cache purged automatically
# → visitors get new versionFor Your Projects
notes-site → app.abhishekkumar.xyz
Repo: github.com/you/notes-site
Pages project: notes-site
Build command: bash build.sh
Output dir: output
Domain: app.abhishekkumar.xyz
DNS record (auto-created by Pages):
CNAME app → notes-site.pages.dev (proxied)
mirage → visual.abhishekkumar.xyz
Repo: github.com/you/mirage
Pages project: mirage
Build command: (empty — pure static HTML)
Output dir: /
Domain: visual.abhishekkumar.xyz
DNS record (auto-created by Pages):
CNAME visual → mirage.pages.dev (proxied)
Quick Reference
── github ─────────────────────────────────────────
git push origin main triggers Pages build
.github/workflows/deploy.yml CI/CD pipeline config
Settings → Secrets store API tokens safely
gh run list see build status
── cloudflare pages ───────────────────────────────
Workers & Pages → Pages create/manage projects
Settings → Builds build command + output dir
Settings → Environment vars API keys for build
Custom domains connect your domain
Deployments see all deploy history
branch-name.project.pages.dev preview URL per branch
── cloudflare dns ─────────────────────────────────
DNS → Records manage all DNS records
Orange cloud = ON proxied (CDN + protection)
Grey cloud = OFF DNS only (mail, SSH, FTP)
CNAME @ → project.pages.dev point domain to Pages
── cloudflare cdn ─────────────────────────────────
Caching → Configuration cache settings
Rules → Cache Rules custom cache per path
Purge Everything clear cache after deploy
Edge TTL how long CF caches files
── ssl ────────────────────────────────────────────
SSL/TLS → Full (Strict) correct mode for Pages
Always Use HTTPS → ON force HTTPS everywhere