Add production deployment configuration
Torey Heinz
committed Aug 24, 2025
commit d1491daf7761abb52c975d1edc53a6c8c28a3a6e
Showing 3
changed files with
233 additions
and 0 deletions
DEPLOYMENT.md
+165
-0
| @@ | @@ -0,0 +1,165 @@ |
| + | # Deployment Guide for qrurl.us |
| + | |
| + | ## Prerequisites |
| + | |
| + | 1. **Cloudflare Account** with: |
| + | - Workers subscription (free tier works) |
| + | - R2 enabled |
| + | - Pages enabled |
| + | - Domain `qrurl.us` added to Cloudflare |
| + | |
| + | 2. **GitHub Repository**: https://github.com/toreyheinz/qrurl |
| + | |
| + | ## Setup Steps |
| + | |
| + | ### 1. Configure Cloudflare API Token |
| + | |
| + | Create a Cloudflare API token with these permissions: |
| + | - Account: Cloudflare Workers Scripts:Edit |
| + | - Account: Cloudflare Pages:Edit |
| + | - Account: D1:Edit |
| + | - Account: Workers R2 Storage:Edit |
| + | - Account: Workers KV Storage:Edit |
| + | - Zone: DNS:Edit (for qrurl.us) |
| + | |
| + | ### 2. Add GitHub Secrets |
| + | |
| + | Go to GitHub repo → Settings → Secrets → Actions and add: |
| + | |
| + | - `CLOUDFLARE_API_TOKEN`: Your Cloudflare API token |
| + | - `CLOUDFLARE_ACCOUNT_ID`: b253e6fbfd2f7757cadd0386de5bde3f |
| + | |
| + | ### 3. Configure Cloudflare Environment |
| + | |
| + | #### Workers Secrets (via Dashboard or CLI): |
| + | ```bash |
| + | # Set production secrets |
| + | npx wrangler secret put JWT_SECRET --env production |
| + | npx wrangler secret put EMAIL_API_KEY --env production |
| + | npx wrangler secret put AUTHORIZED_EMAILS --env production |
| + | ``` |
| + | |
| + | #### Initialize Production Database: |
| + | ```bash |
| + | # Run database migrations on production |
| + | npm run db:init:remote |
| + | ``` |
| + | |
| + | ### 4. Set Up Custom Domains |
| + | |
| + | #### For API (Workers): |
| + | 1. Go to Cloudflare Dashboard → Workers & Pages → qrurl |
| + | 2. Settings → Triggers → Custom Domains |
| + | 3. Add: `api.qrurl.us` |
| + | |
| + | #### For Frontend (Pages): |
| + | 1. Go to Cloudflare Dashboard → Workers & Pages → qrurl-frontend |
| + | 2. Custom domains → Add domain |
| + | 3. Add: `qrurl.us` and `www.qrurl.us` |
| + | |
| + | ### 5. Create Cloudflare Pages Project |
| + | |
| + | ```bash |
| + | # One-time setup for Pages project |
| + | npx wrangler pages project create qrurl-frontend --production-branch main |
| + | ``` |
| + | |
| + | ### 6. DNS Configuration |
| + | |
| + | Add these DNS records in Cloudflare: |
| + | |
| + | ``` |
| + | Type Name Content |
| + | A @ 192.0.2.1 (Proxied - placeholder for Pages) |
| + | CNAME www qrurl.us (Proxied) |
| + | CNAME api qrurl.workers.dev (Proxied - or use Workers custom domain) |
| + | ``` |
| + | |
| + | ## Deployment Process |
| + | |
| + | ### Automatic Deployment |
| + | |
| + | Push to `main` branch triggers automatic deployment: |
| + | |
| + | ```bash |
| + | git push origin main |
| + | ``` |
| + | |
| + | This will: |
| + | 1. Deploy backend to Cloudflare Workers |
| + | 2. Build and deploy frontend to Cloudflare Pages |
| + | 3. Update both production environments |
| + | |
| + | ### Manual Deployment |
| + | |
| + | #### Backend: |
| + | ```bash |
| + | npm run deploy |
| + | ``` |
| + | |
| + | #### Frontend: |
| + | ```bash |
| + | cd frontend |
| + | npm run build |
| + | npx wrangler pages deploy dist --project-name qrurl-frontend |
| + | ``` |
| + | |
| + | ## Environment Variables |
| + | |
| + | ### Backend (Workers): |
| + | - `JWT_SECRET`: Strong random secret for JWT signing |
| + | - `EMAIL_API_KEY`: Resend or SendGrid API key |
| + | - `AUTHORIZED_EMAILS`: Comma-separated list of authorized emails |
| + | - `FRONTEND_URL`: https://qrurl.us |
| + | - `BACKEND_URL`: https://qrurl.us |
| + | |
| + | ### Frontend (Build-time): |
| + | - `VITE_API_URL`: https://api.qrurl.us/api |
| + | - `VITE_SHORT_URL`: https://qrurl.us |
| + | |
| + | ## Post-Deployment Checklist |
| + | |
| + | - [ ] Verify Workers deployment at https://api.qrurl.us/health |
| + | - [ ] Verify Pages deployment at https://qrurl.us |
| + | - [ ] Test authentication flow |
| + | - [ ] Test URL creation and redirection |
| + | - [ ] Test logo upload to R2 |
| + | - [ ] Verify QR code generation with logos |
| + | - [ ] Check analytics tracking |
| + | - [ ] Test rate limiting |
| + | |
| + | ## Monitoring |
| + | |
| + | - **Workers Analytics**: Cloudflare Dashboard → Workers & Pages → qrurl → Analytics |
| + | - **Pages Analytics**: Cloudflare Dashboard → Workers & Pages → qrurl-frontend → Analytics |
| + | - **R2 Storage**: Cloudflare Dashboard → R2 → qrurl-storage |
| + | - **D1 Database**: Cloudflare Dashboard → D1 → qrurl-db |
| + | |
| + | ## Rollback |
| + | |
| + | If issues occur: |
| + | |
| + | 1. **Workers**: Deploy previous version via dashboard or: |
| + | ```bash |
| + | npx wrangler rollback |
| + | ``` |
| + | |
| + | 2. **Pages**: Rollback via dashboard to previous deployment |
| + | |
| + | ## Troubleshooting |
| + | |
| + | ### CORS Issues |
| + | - Verify `FRONTEND_URL` is set correctly in Workers environment |
| + | - Check custom domain configuration |
| + | |
| + | ### Database Issues |
| + | - Ensure D1 database ID matches in wrangler.toml |
| + | - Run migrations: `npm run db:init:remote` |
| + | |
| + | ### R2 Issues |
| + | - Verify R2 bucket exists: `qrurl-storage` |
| + | - Check bucket permissions |
| + | |
| + | ### Domain Issues |
| + | - Ensure DNS records are proxied through Cloudflare |
| + | - Wait for DNS propagation (up to 48 hours) |
| \ No newline at end of file | |
setup-secrets.sh
+28
-0
| @@ | @@ -0,0 +1,28 @@ |
| + | #!/bin/bash |
| + | |
| + | # Production secrets setup script |
| + | # Run this once to configure production secrets |
| + | |
| + | echo "Setting up Cloudflare Workers secrets for production..." |
| + | |
| + | # Generate a strong JWT secret |
| + | JWT_SECRET=$(openssl rand -base64 32) |
| + | echo "Generated JWT_SECRET" |
| + | |
| + | # Prompt for email API key |
| + | read -p "Enter your Email API Key (Resend/SendGrid): " EMAIL_API_KEY |
| + | |
| + | # Prompt for authorized emails |
| + | read -p "Enter authorized emails (comma-separated): " AUTHORIZED_EMAILS |
| + | |
| + | # Set the secrets |
| + | echo "$JWT_SECRET" | npx wrangler secret put JWT_SECRET |
| + | echo "$EMAIL_API_KEY" | npx wrangler secret put EMAIL_API_KEY |
| + | echo "$AUTHORIZED_EMAILS" | npx wrangler secret put AUTHORIZED_EMAILS |
| + | |
| + | echo "✅ Secrets configured successfully!" |
| + | echo "" |
| + | echo "Next steps:" |
| + | echo "1. Add GitHub secrets (CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID)" |
| + | echo "2. Configure custom domains in Cloudflare dashboard" |
| + | echo "3. Push to main branch to trigger deployment" |
| \ No newline at end of file | |
wrangler.production.toml
+40
-0
| @@ | @@ -0,0 +1,40 @@ |
| + | name = "qrurl" |
| + | main = "src/index.js" |
| + | compatibility_date = "2024-12-01" |
| + | compatibility_flags = ["nodejs_compat"] |
| + | account_id = "b253e6fbfd2f7757cadd0386de5bde3f" |
| + | |
| + | # Custom domain |
| + | route = { pattern = "api.qrurl.us/*", custom_domain = true } |
| + | |
| + | # D1 Database |
| + | [[d1_databases]] |
| + | binding = "DB" |
| + | database_name = "qrurl-db" |
| + | database_id = "17eb6fdb-19da-4ed7-931c-a4cdef281f8c" |
| + | |
| + | # R2 Storage |
| + | [[r2_buckets]] |
| + | binding = "STORAGE" |
| + | bucket_name = "qrurl-storage" |
| + | |
| + | # KV Namespace for caching |
| + | [[kv_namespaces]] |
| + | binding = "CACHE" |
| + | id = "1cacb0f1b44b4324b62c1bc010ff15f5" |
| + | |
| + | # Environment Variables (set in Cloudflare dashboard or via secrets) |
| + | [vars] |
| + | FRONTEND_URL = "https://qrurl.us" |
| + | BACKEND_URL = "https://qrurl.us" |
| + | |
| + | # Production settings |
| + | [env.production] |
| + | name = "qrurl-production" |
| + | |
| + | # Rate limiting |
| + | [[unsafe.bindings]] |
| + | name = "RATE_LIMITER" |
| + | type = "ratelimit" |
| + | namespace_id = "1" |
| + | simple = { limit = 60, period = 60 } |
| \ No newline at end of file | |