CloudFlare-ImgBed
Image hosting service powered by CloudFlare-ImgBed, deployed on Cloudflare Pages with R2 storage.
Architecture
- Frontend + API: Cloudflare Pages (serverless, free tier)
- Storage: Cloudflare R2 (free tier: 10GB)
- Database: Cloudflare D1 (SQLite, free tier: 5M reads/day)
- Domain: img.emacsbliss.com (DNS-only, no Cloudflare proxy)
- GitHub: Forked from MarSeventh/CloudFlare-ImgBed
Prerequisites
- Cloudflare account with R2 enabled
- GitHub account (for Pages deployment)
- Custom domain on Cloudflare DNS
Setup Steps
1. Fork the Repository
- Go to https://github.com/MarSeventh/CloudFlare-ImgBed
- Click Fork to create a copy under your GitHub account
2. Create R2 Bucket
- Cloudflare Dashboard → R2 Object Storage → Create bucket
- Bucket name:
imgbed - Storage class: Standard (free tier eligible)
- Location: closest to your region
3. Create D1 Database
- Cloudflare Dashboard → Storage & Databases → D1
- Create database, name it
img_d1 - Go to Console tab and run the init SQL from
database/init.sqlin the repo (createsfiles,settings,index_operations,index_metadata,other_datatables + indexes + triggers)
4. Deploy to Cloudflare Pages
- Cloudflare Dashboard → Workers & Pages → Create
- Choose Pages (NOT Workers)
- “Connect to Git” → select the forked repo
- Settings:
- Framework preset: None
- Build command:
npm install - Build output directory:
frontend-dist - Root directory: leave blank
- Click Deploy
5. Bind D1 Database
- Pages project → Settings → Bindings
- Add → D1 database
- Variable name:
img_d1 - D1 database: select
img_d1
- Variable name:

- Save → Retry deployment (bindings only take effect after redeploy)
6. Bind R2 Bucket
- Pages project → Settings → Bindings
- Add → R2 bucket
- Variable name:
img_r2 - R2 bucket: select
imgbed
- Variable name:

- Save → Retry deployment
7. Configure Custom Domain
- Pages project → Custom domains → Add
- Enter
img.emacsbliss.com - Cloudflare DNS record can be proxied (orange cloud) — works fine with Pages
8. Admin Setup
- Visit https://img.emacsbliss.com
- On first visit, no login is required (admin not configured yet)
- Go to Admin Dashboard:
- Set admin username and password (Security Settings)
- Set user auth code if you want upload password protection
- Enable the R2_env channel in Upload Settings
- Set public URL to
https://img.emacsbliss.com
- Set default naming method to
short - Create an API token with upload permission (for programmatic use)
9. API Token Configuration
- Admin panel → Security Settings → API Tokens
- Create token with upload permission
- Store token in
~/.hermes/.envasIMG_BED_TOKEN
Upload API
curl -X POST 'https://img.emacsbliss.com/upload?uploadChannel=cfr2&uploadNameType=short&returnFormat=full' \
-H "Authorization: Bearer $IMG_BED_TOKEN" \
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36" \
-F "file=@/path/to/image.png"Response: [{"src": "https://img.emacsbliss.com/file/XXXXX.png"}]
Key Decisions
- Pages over Docker — zero server maintenance, edge-cached globally, all within Cloudflare ecosystem
- Pages over Workers — Pages wraps Workers with automatic static asset hosting; the
functions/directory IS Workers - R2 over Telegram — proper object storage with direct URLs, no proxying needed, already in Cloudflare ecosystem
- DNS-only domain — Cloudflare proxy (orange cloud) blocks API calls with 1010 bot error
- Short naming — clean URLs for programmatic use (
/file/XXXXX.png) - No WebP conversion — preserve original format for programmatic hosting
Troubleshooting
- 1010 bot error — Cloudflare Pages has built-in bot protection. All API calls must include a browser
User-Agentheader (e.g.,Mozilla/5.0 ...). Without it, requests return 403 with error code 1010. - “Database not configured” — D1 binding variable name must be exactly
img_d1. Check Settings → Bindings and retry deployment. - Login loop on fresh install — D1 tables not initialized. Run the
init.sqlfrom the repo in the D1 console. - 403 Forbidden on upload — API token lacks upload permission. Recreate the token with upload permission enabled.
- DNS record — proxied (orange cloud) works fine. Pages has its own CDN/SSL, but the Cloudflare proxy adds an extra layer of caching without causing issues.