Production quick wins for improved observability and scalability: Sentry Error Tracking: - Add sentry-sdk[fastapi] dependency - Initialize Sentry in main.py with FastAPI/SQLAlchemy integrations - Add Celery integration for background task error tracking - Feature-flagged via SENTRY_DSN (disabled when empty) Cloudflare R2 Storage: - Add boto3 dependency for S3-compatible API - Create storage_service.py with StorageBackend abstraction - LocalStorageBackend for development (default) - R2StorageBackend for production cloud storage - Feature-flagged via STORAGE_BACKEND setting CloudFlare CDN/Proxy: - Create middleware/cloudflare.py for CF header handling - Extract real client IP from CF-Connecting-IP - Support CF-IPCountry for geo features - Feature-flagged via CLOUDFLARE_ENABLED setting Documentation: - Add docs/deployment/cloudflare.md setup guide - Update infrastructure.md with dev vs prod requirements - Add enterprise upgrade checklist for scaling beyond 1000 users - Update installation.md with new environment variables All features are optional and disabled by default for development. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
300 lines
6.8 KiB
Markdown
300 lines
6.8 KiB
Markdown
# CloudFlare Setup Guide
|
|
|
|
This guide covers setting up CloudFlare for Wizamart, including CDN, proxy, WAF, and R2 storage.
|
|
|
|
## Overview
|
|
|
|
CloudFlare provides:
|
|
|
|
| Feature | Benefit |
|
|
|---------|---------|
|
|
| **CDN** | Global edge caching for static assets |
|
|
| **Proxy** | Hide origin IP, DDoS protection |
|
|
| **WAF** | Web Application Firewall (basic rules free) |
|
|
| **R2** | S3-compatible object storage (~$5/mo) |
|
|
| **SSL** | Free SSL certificates |
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### 1. Add Your Domain to CloudFlare
|
|
|
|
1. Create a CloudFlare account at [cloudflare.com](https://cloudflare.com)
|
|
2. Add your domain and follow the setup wizard
|
|
3. Update your domain's nameservers to CloudFlare's
|
|
|
|
### 2. Configure DNS Records
|
|
|
|
Create these DNS records (with proxy enabled - orange cloud):
|
|
|
|
| Type | Name | Content | Proxy |
|
|
|------|------|---------|-------|
|
|
| A | @ | Your server IP | ✅ Proxied |
|
|
| A | www | Your server IP | ✅ Proxied |
|
|
| A | api | Your server IP | ✅ Proxied |
|
|
| CNAME | media | your-bucket.r2.dev | ✅ Proxied |
|
|
|
|
### 3. Enable CloudFlare in Wizamart
|
|
|
|
```env
|
|
# .env
|
|
CLOUDFLARE_ENABLED=true
|
|
```
|
|
|
|
This enables the CloudFlare middleware to:
|
|
- Extract real client IPs from `CF-Connecting-IP`
|
|
- Read client country from `CF-IPCountry`
|
|
- Track requests via `CF-Ray` header
|
|
|
|
---
|
|
|
|
## SSL/TLS Configuration
|
|
|
|
### Recommended: Full (Strict) Mode
|
|
|
|
1. Go to **SSL/TLS** > **Overview**
|
|
2. Select **Full (strict)**
|
|
3. This requires a valid SSL certificate on your origin server
|
|
|
|
### Origin Certificates
|
|
|
|
For the origin server, you can use:
|
|
|
|
1. **Let's Encrypt** (recommended for VPS):
|
|
```bash
|
|
sudo certbot --nginx -d yourdomain.com
|
|
```
|
|
|
|
2. **CloudFlare Origin Certificate** (15-year free cert):
|
|
- Go to **SSL/TLS** > **Origin Server**
|
|
- Create Certificate
|
|
- Install on your server
|
|
|
|
---
|
|
|
|
## Caching Configuration
|
|
|
|
### Page Rules for Static Assets
|
|
|
|
Create page rules for optimal caching:
|
|
|
|
**Rule 1: Static Assets**
|
|
- URL: `*yourdomain.com/static/*`
|
|
- Setting: Cache Level → Cache Everything
|
|
- Setting: Edge Cache TTL → 1 month
|
|
|
|
**Rule 2: Uploads**
|
|
- URL: `*yourdomain.com/uploads/*`
|
|
- Setting: Cache Level → Cache Everything
|
|
- Setting: Edge Cache TTL → 1 week
|
|
|
|
**Rule 3: API (No Cache)**
|
|
- URL: `*yourdomain.com/api/*`
|
|
- Setting: Cache Level → Bypass
|
|
|
|
### Cache Rules (New Interface)
|
|
|
|
Or use the newer Cache Rules:
|
|
|
|
```
|
|
Expression: (http.request.uri.path starts with "/static/")
|
|
Action: Cache eligible → Override → 30 days
|
|
```
|
|
|
|
---
|
|
|
|
## Cloudflare R2 Storage
|
|
|
|
### Create R2 Bucket
|
|
|
|
1. Go to **R2** in CloudFlare dashboard
|
|
2. Click **Create bucket**
|
|
3. Name: `wizamart-media`
|
|
4. Location: Choose region closest to your users
|
|
|
|
### Create API Token
|
|
|
|
1. Go to **R2** > **Manage R2 API Tokens**
|
|
2. Create new token with:
|
|
- Permission: Object Read & Write
|
|
- Bucket: Select your bucket
|
|
3. Save the **Access Key ID** and **Secret Access Key**
|
|
|
|
### Configure Wizamart
|
|
|
|
```env
|
|
# .env
|
|
STORAGE_BACKEND=r2
|
|
R2_ACCOUNT_ID=your_account_id
|
|
R2_ACCESS_KEY_ID=your_access_key
|
|
R2_SECRET_ACCESS_KEY=your_secret_key
|
|
R2_BUCKET_NAME=wizamart-media
|
|
```
|
|
|
|
### Enable Public Access (Optional)
|
|
|
|
For direct public access to uploaded files:
|
|
|
|
1. Go to **R2** > Your bucket > **Settings**
|
|
2. Enable **Public Access**
|
|
3. Note the public URL: `https://your-bucket.account-id.r2.dev`
|
|
|
|
Or use a custom domain:
|
|
|
|
1. Go to **R2** > Your bucket > **Settings** > **Custom Domains**
|
|
2. Add `media.yourdomain.com`
|
|
3. Update `.env`:
|
|
```env
|
|
R2_PUBLIC_URL=https://media.yourdomain.com
|
|
```
|
|
|
|
---
|
|
|
|
## Security Settings
|
|
|
|
### WAF Rules (Free Tier)
|
|
|
|
Enable these managed rules:
|
|
|
|
1. **CloudFlare Managed Ruleset** - Basic protection
|
|
2. **OWASP Core Ruleset** - SQL injection, XSS protection
|
|
|
|
### Rate Limiting
|
|
|
|
Create rate limiting rules for the API:
|
|
|
|
- URL: `/api/*`
|
|
- Rate: 100 requests per minute
|
|
- Action: Challenge or Block
|
|
|
|
### Bot Fight Mode
|
|
|
|
1. Go to **Security** > **Bots**
|
|
2. Enable **Bot Fight Mode**
|
|
|
|
---
|
|
|
|
## Nginx Configuration for CloudFlare
|
|
|
|
When using CloudFlare proxy, update Nginx to trust CloudFlare IPs:
|
|
|
|
```nginx
|
|
# /etc/nginx/conf.d/cloudflare.conf
|
|
|
|
# CloudFlare IP ranges
|
|
set_real_ip_from 103.21.244.0/22;
|
|
set_real_ip_from 103.22.200.0/22;
|
|
set_real_ip_from 103.31.4.0/22;
|
|
set_real_ip_from 104.16.0.0/13;
|
|
set_real_ip_from 104.24.0.0/14;
|
|
set_real_ip_from 108.162.192.0/18;
|
|
set_real_ip_from 131.0.72.0/22;
|
|
set_real_ip_from 141.101.64.0/18;
|
|
set_real_ip_from 162.158.0.0/15;
|
|
set_real_ip_from 172.64.0.0/13;
|
|
set_real_ip_from 173.245.48.0/20;
|
|
set_real_ip_from 188.114.96.0/20;
|
|
set_real_ip_from 190.93.240.0/20;
|
|
set_real_ip_from 197.234.240.0/22;
|
|
set_real_ip_from 198.41.128.0/17;
|
|
|
|
# IPv6
|
|
set_real_ip_from 2400:cb00::/32;
|
|
set_real_ip_from 2606:4700::/32;
|
|
set_real_ip_from 2803:f800::/32;
|
|
set_real_ip_from 2405:b500::/32;
|
|
set_real_ip_from 2405:8100::/32;
|
|
set_real_ip_from 2a06:98c0::/29;
|
|
set_real_ip_from 2c0f:f248::/32;
|
|
|
|
real_ip_header CF-Connecting-IP;
|
|
```
|
|
|
|
---
|
|
|
|
## Environment Variables Reference
|
|
|
|
| Variable | Description | Default |
|
|
|----------|-------------|---------|
|
|
| `CLOUDFLARE_ENABLED` | Enable CF header processing | `false` |
|
|
| `STORAGE_BACKEND` | Storage backend (`local` or `r2`) | `local` |
|
|
| `R2_ACCOUNT_ID` | CloudFlare account ID | - |
|
|
| `R2_ACCESS_KEY_ID` | R2 API access key | - |
|
|
| `R2_SECRET_ACCESS_KEY` | R2 API secret key | - |
|
|
| `R2_BUCKET_NAME` | R2 bucket name | `wizamart-media` |
|
|
| `R2_PUBLIC_URL` | Custom public URL for R2 | - |
|
|
|
|
---
|
|
|
|
## Verification
|
|
|
|
### Check CloudFlare is Working
|
|
|
|
1. **Check headers** in browser DevTools:
|
|
- `CF-Ray` header should be present
|
|
- `CF-Cache-Status` shows caching status
|
|
|
|
2. **Test from command line**:
|
|
```bash
|
|
curl -I https://yourdomain.com/static/css/main.css
|
|
# Should see CF-Ray and CF-Cache-Status headers
|
|
```
|
|
|
|
### Check R2 is Working
|
|
|
|
1. **Upload a test file** via the admin media library
|
|
2. **Check the URL** - should point to R2 or your custom domain
|
|
3. **Verify in CloudFlare dashboard** - file should appear in bucket
|
|
|
|
### Check Real IP Logging
|
|
|
|
With `CLOUDFLARE_ENABLED=true`:
|
|
|
|
```bash
|
|
# Check application logs
|
|
journalctl -u wizamart | grep "real_ip"
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### 521 Error (Web Server Down)
|
|
|
|
- Ensure your origin server is running
|
|
- Check firewall allows CloudFlare IPs
|
|
- Verify SSL certificate is valid
|
|
|
|
### 522 Error (Connection Timed Out)
|
|
|
|
- Check origin server is responding
|
|
- Verify port 443 is open
|
|
- Check server isn't overloaded
|
|
|
|
### 525 Error (SSL Handshake Failed)
|
|
|
|
- Ensure origin has valid SSL certificate
|
|
- Try CloudFlare Origin Certificate
|
|
- Check SSL mode is correct (Full vs Full Strict)
|
|
|
|
### R2 Access Denied
|
|
|
|
- Verify API token has correct permissions
|
|
- Check bucket name is correct
|
|
- Ensure bucket policy allows the operation
|
|
|
|
---
|
|
|
|
## Cost Estimate
|
|
|
|
| Service | Free Tier | Paid Usage |
|
|
|---------|-----------|------------|
|
|
| CDN | Unlimited | Free |
|
|
| WAF | Basic rules | $20/mo for advanced |
|
|
| R2 Storage | 10 GB/mo | $0.015/GB |
|
|
| R2 Requests | 10M Class A, 10M Class B | $0.36/M, $0.0036/M |
|
|
| SSL | Free | Free |
|
|
|
|
**Typical monthly cost for small-medium site: ~$5-15**
|