Monorepo for Aesthetic.Computer aesthetic.computer
core grab docs DEPLOYMENT.md
14 kB

Grab Worker Deployment Guide #

Comprehensive deployment guide for the Aesthetic Computer screenshot/preview generation service.


โœ… Current Status #

Deployed Version: 511d31bc-c2e8-4f00-aea7-9b9d95e08733
Worker URL: https://aesthetic-grab.aesthetic-computer.workers.dev
Custom Domain: grab.aesthetic.computer (โš ๏ธ pending manual setup)

Test Commands:

# Test icon endpoint
curl -I "https://aesthetic-grab.aesthetic-computer.workers.dev/icon/128x128/prompt.png"

# Test preview endpoint  
curl -I "https://aesthetic-grab.aesthetic-computer.workers.dev/preview/1200x630/prompt.png"

๐Ÿš€ Quick Deploy with Automatic DNS #

Recommended: One-command deployment with automatic DNS configuration

cd /workspaces/aesthetic-computer/grab
./scripts/deploy-with-dns.fish

This will:

  1. โœ… Deploy worker to Cloudflare
  2. โœ… Automatically create/update CNAME record via API
  3. โœ… Wait for DNS propagation
  4. โœ… Verify deployment is accessible

Requirements:

  • CLOUDFLARE_EMAIL in vault/.env
  • CLOUDFLARE_API_TOKEN in vault/.env (with Zone.DNS Edit permission)

See vault README for how to get API token: /aesthetic-computer-vault/grab/README.md


๐ŸŒ Custom Domain Setup #

Automated via deploy script (recommended): The deploy-with-dns.fish script handles this automatically.

Manual methods if needed:

Method 1: Direct DNS Configuration (2 minutes) โšก #

Quick link: https://dash.cloudflare.com/a23b54e8877a833a1cf8db7765bce3ca/aesthetic.computer/dns/records

  1. Open DNS Settings

    • Navigate to: Cloudflare Dashboard โ†’ aesthetic.computer โ†’ DNS โ†’ Records
  2. Add CNAME Record

    • Click: "Add record"
    • Type: CNAME
    • Name: grab
    • Target: aesthetic-grab.aesthetic-computer.workers.dev
    • Proxy status: Proxied (orange cloud โ˜๏ธ)
    • Click: Save
  3. Wait ~30 seconds for DNS propagation

  4. Verify Setup

    curl -I "https://grab.aesthetic.computer/icon/128x128/prompt.png"
    

    Should return:

    HTTP/2 200
    content-type: image/png
    cache-control: public, max-age=3600
    

โœ… Done! Total time: ~2 minutes

Method 2: Workers Dashboard (Alternative) #

  1. Navigate to: https://dash.cloudflare.com/
  2. Go to: Workers & Pages โ†’ aesthetic-grab โ†’ Settings โ†’ Domains & Routes
  3. Click: "Add Custom Domain"
  4. Enter: grab.aesthetic.computer
  5. Save and wait 2-5 minutes

This automatically creates the same CNAME record as Method 1.

DNS Record Created #

Either method creates:

grab.aesthetic.computer โ†’ aesthetic-grab.aesthetic-computer.workers.dev (CNAME, Proxied)

Cloudflare automatically handles:

  • โœ… SSL/TLS certificates
  • โœ… Edge routing
  • โœ… DDoS protection
  • โœ… CDN caching

๐Ÿ“‹ Prerequisites #

  • Cloudflare account with Workers enabled
  • Browser Rendering enabled in your Cloudflare account
  • Wrangler CLI installed globally (npm i -g wrangler)
  • Access to /aesthetic-computer-vault/grab/ secrets
  • Node.js 20+ installed

๐Ÿ” Initial Setup #

1. Clone and Install #

cd /workspaces/aesthetic-computer/grab
npm install

2. Authenticate with Cloudflare #

wrangler login

This will open a browser to authenticate your Cloudflare account.

3. Verify Account Access #

wrangler whoami

Ensure:

  • Account ID is correct
  • Browser Rendering is in enabled features
  • Workers permission is active

4. Enable Browser Rendering #

If not already enabled:

# Enable via Cloudflare Dashboard
# Workers & Pages > Browser Rendering > Enable

Or via API:

curl -X POST "https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/browser" \
  -H "X-Auth-Email: me@jas.life" \
  -H "X-Auth-Key: <API_KEY>" \
  -H "Content-Type: application/json"

๐Ÿš€ Deployment Steps #

Phase 1: Create Infrastructure #

1.1 Create Browser Binding #

cd /workspaces/aesthetic-computer/grab
./scripts/setup-browser-binding.fish

This script will:

  • Create the browser binding named BROWSER
  • Output the binding configuration
  • Update the vault .env file

Alternatively, manually:

wrangler browser create BROWSER

1.2 Create Durable Object Namespace #

wrangler dispatch-namespace create SCREENSHOT_DO

Copy the output ID and update /aesthetic-computer-vault/grab/.env:

DO_NAMESPACE_ID=<paste-id-here>

1.3 Create R2 Bucket (Optional) #

For long-term caching:

wrangler r2 bucket create aesthetic-screenshots

Note the bucket name/ID for configuration.

Phase 2: Configure Wrangler #

2.1 Copy Production Config #

# Copy template from vault to working directory
cp /workspaces/aesthetic-computer/aesthetic-computer-vault/grab/wrangler.production.toml \
   /workspaces/aesthetic-computer/grab/wrangler.toml

2.2 Update IDs in wrangler.toml #

Edit /workspaces/aesthetic-computer/grab/wrangler.toml:

# Update these with actual IDs from previous steps
[[durable_objects.bindings]]
name = "SCREENSHOT_DO"
class_name = "ScreenshotDO"
script_name = "aesthetic-grab"
# namespace_id = "<from step 1.2>"  # If needed

[[r2_buckets]]
binding = "SCREENSHOTS"
bucket_name = "aesthetic-screenshots"  # From step 1.3

โš ๏ธ Important: Add wrangler.toml to .gitignore (it's environment-specific)

Phase 3: Set Secrets #

If you have additional secrets (optional):

cd /workspaces/aesthetic-computer/grab
wrangler secret put BROWSER_API_KEY
# Enter secret when prompted

Phase 4: Test Locally #

4.1 Start Dev Server #

npm run dev

4.2 Test Endpoints #

# Test icon
curl http://localhost:8787/icon/128x128/welcome.png -o test-icon.png
open test-icon.png

# Test preview
curl http://localhost:8787/preview/1200x630/prompt~wipe.png -o test-preview.png
open test-preview.png

# Test caching with ETag
curl -I http://localhost:8787/icon/128x128/welcome.png
# Note the ETag header

curl -H "If-None-Match: <etag-from-above>" \
     http://localhost:8787/icon/128x128/welcome.png
# Should return 304 Not Modified

Phase 5: Deploy to Production #

5.1 Type Check #

npm run type-check

Fix any TypeScript errors before deploying.

5.2 Deploy #

npm run deploy:production

Or manually:

wrangler deploy --config wrangler.toml

5.3 Verify Deployment #

# Check worker is live
curl -I https://aesthetic-grab.<account>.workers.dev/icon/128x128/welcome.png

# View logs
npm run logs

Phase 6: Configure Custom Domain #

  1. Go to https://dash.cloudflare.com/
  2. Select your account
  3. Navigate to Workers & Pages
  4. Click on aesthetic-grab
  5. Go to Settings > Domains & Routes
  6. Click Add Custom Domain
  7. Enter: grab.aesthetic.computer
  8. Click Add Domain

Cloudflare will automatically:

  • Create DNS CNAME record
  • Set up SSL/TLS
  • Route traffic to worker

Via Wrangler (Alternative) #

wrangler route add grab.aesthetic.computer/* aesthetic-grab

Verify Domain #

# Test custom domain
curl -I https://grab.aesthetic.computer/icon/128x128/welcome.png

# Should return 200 with your screenshot

๐Ÿ”„ Migration from Netlify #

Step 1: Verify Worker is Working #

Test all resolutions:

# Icon (128x128)
curl https://grab.aesthetic.computer/icon/128x128/welcome.png -o test-icon.png

# OG Image (1200x630)
curl https://grab.aesthetic.computer/preview/1200x630/prompt~wipe.png -o test-og.png

# Twitter Card (1800x900)
curl https://grab.aesthetic.computer/preview/1800x900/prompt~wipe.png -o test-twitter.png

Step 2: Update index.mjs #

Edit /workspaces/aesthetic-computer/system/netlify/functions/index.mjs:

Find the icon and ogImage generation (around line 360-380):

Before:

const icon = pixelPerfect(
  baseURL,
  parsed?.host,
  `/icon/128x128/${location}.png`,
  meta,
  "https:",
);

const ogImage = pixelPerfect(
  baseURL,
  parsed?.host,
  `/preview/1200x630/${location}.png`,
  meta,
  "https:",
);

const twitterImage = pixelPerfect(
  baseURL,
  parsed?.host,
  `/preview/1800x900/${location}.png`,
  meta,
  "https:",
);

After:

// Direct URLs to grab worker
const icon = `https://grab.aesthetic.computer/icon/128x128/${location}.png`;
const ogImage = `https://grab.aesthetic.computer/preview/1200x630/${location}.png`;
const twitterImage = `https://grab.aesthetic.computer/preview/1800x900/${location}.png`;

Step 3: Add Redirects (Optional) #

Edit /workspaces/aesthetic-computer/system/netlify.toml:

# Redirect legacy paths to grab worker
[[redirects]]
  from = "/icon/*"
  to = "https://grab.aesthetic.computer/icon/:splat"
  status = 200
  force = true

[[redirects]]
  from = "/preview/*"
  to = "https://grab.aesthetic.computer/preview/:splat"
  status = 200
  force = true

Step 4: Deploy and Test #

# Commit changes
git add system/netlify/functions/index.mjs
git commit -m "Switch to grab worker for screenshots"
git push

# Test on live site
curl -I https://aesthetic.computer/icon/128x128/welcome.png
# Should redirect to grab.aesthetic.computer

# Check HTML meta tags
curl https://aesthetic.computer/welcome | grep "og:image"
# Should show grab.aesthetic.computer URLs

Step 5: Monitor #

# Watch grab worker logs
npm run logs:production

# Check for errors
# Monitor traffic in Cloudflare Dashboard

Step 6: Clean Up (After 1 Week) #

Once confirmed working:

# Remove old screenshot function
rm /workspaces/aesthetic-computer/system/netlify/functions/screenshot.js

# Remove Puppeteer dependencies
cd /workspaces/aesthetic-computer/system
npm uninstall puppeteer-core @sparticuz/chromium

# Clean dev cache
rm -rf /workspaces/aesthetic-computer/.netlify/cache/screenshots

๐Ÿ“Š Post-Deployment Monitoring #

Check Metrics #

In Cloudflare Dashboard:

  • Workers & Pages > aesthetic-grab > Metrics
  • Look for:
    • Request rate
    • Error rate
    • P95 latency
    • Cache hit rate

Set Up Alerts #

Configure notifications for:

  • Error rate > 5%
  • P95 latency > 10s
  • Browser session failures

View Logs #

# Real-time logs
wrangler tail aesthetic-grab --env production

# Filter for errors
wrangler tail aesthetic-grab --env production --status error

Test Cache Performance #

# First request (cache miss)
time curl https://grab.aesthetic.computer/icon/128x128/welcome.png -o /dev/null

# Second request (cache hit)
time curl https://grab.aesthetic.computer/icon/128x128/welcome.png -o /dev/null

# Second should be much faster

๐Ÿ› Troubleshooting #

Deployment Fails #

Error: Browser rendering not enabled

Solution:

# Enable in dashboard or via API
curl -X POST "https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/browser" \
  -H "X-Auth-Email: me@jas.life" \
  -H "X-Auth-Key: <API_KEY>"

Error: Durable Object namespace not found

Solution:

# Recreate namespace
wrangler dispatch-namespace create SCREENSHOT_DO

# Update ID in wrangler.toml

Error: R2 bucket not found

Solution:

# Create bucket
wrangler r2 bucket create aesthetic-screenshots

# Or remove R2 binding from wrangler.toml if not using

Runtime Errors #

Error: Browser timeout

Solution:

  • Increase BROWSER_TIMEOUT_MS in wrangler.toml
  • Check network connectivity
  • Verify aesthetic.computer is accessible

Error: Durable Object not found

Solution:

  • Check namespace ID is correct
  • Verify migration ran successfully
  • Check worker name matches in binding

Error: Rate limit exceeded

Solution:

  • Increase MAX_REQUESTS_PER_MINUTE
  • Implement IP-based throttling
  • Check for abuse/spam

Performance Issues #

Problem: Slow screenshot generation

Solutions:

  • Check browser rendering time in logs
  • Optimize page load (reduce assets)
  • Increase viewport/timeout limits
  • Pre-warm Durable Objects

Problem: High costs

Solutions:

  • Review cache hit rate
  • Increase cache TTL
  • Implement R2 long-term cache
  • Reduce browser timeout
  • Monitor usage dashboard

๐Ÿ”„ Rollback Procedure #

If issues occur:

1. Quick Rollback (Domain) #

In Cloudflare Dashboard:

  • Workers & Pages > aesthetic-grab
  • Domains & Routes
  • Remove custom domain temporarily
  • Update index.mjs to point back to Netlify

2. Full Rollback #

# Revert index.mjs changes
git revert <commit-hash>
git push

# Remove redirects from netlify.toml

# Keep grab worker for testing/debugging

3. Emergency Fallback #

Add to index.mjs:

const useGrabWorker = false; // Emergency kill switch

const icon = useGrabWorker
  ? `https://grab.aesthetic.computer/icon/128x128/${location}.png`
  : pixelPerfect(baseURL, parsed?.host, `/icon/128x128/${location}.png`, meta, "https:");

๐Ÿ“ Deployment Checklist #


๐ŸŽฏ Success Criteria #

After deployment, verify:

โœ… All three resolutions work โœ… Cache hit rate > 80% โœ… P95 latency < 5s โœ… Error rate < 1% โœ… Browser rendering cost reasonable โœ… No 500 errors in logs โœ… Custom domain works โœ… ETag caching works โœ… CDN caching works


๐Ÿ“ž Support #

For issues:

  1. Check logs: npm run logs:production
  2. Review Cloudflare Dashboard metrics
  3. Check GitHub issues
  4. Contact Cloudflare support if infrastructure issues

Status: ๐Ÿ“ Ready for Deployment
Last Updated: 2025-01-09