Guide for deploying the application to production on Render or other platforms.
- Render Deployment (Recommended)
- Manual Deployment
- Environment Variables
- Database Setup
- Post-Deployment
Render provides automatic deployments with a simple render.yaml configuration.
- GitHub/GitLab repository
- Render account (free tier available)
- Turso database (free tier available)
-
Push code to GitHub:
git add . git commit -m "Prepare for deployment" git push origin master
-
Verify
render.yamlexists in root
- Sign up at https://turso.tech
- Create database:
turso db create b2l-registration
- Get credentials:
turso db show b2l-registration --url turso db tokens create b2l-registration
- Save URL and token for later
-
Click "New +" → "Blueprint"
-
Connect your GitHub repository
-
Render detects
render.yamlautomatically -
Add environment variables:
TURSO_DATABASE_URL: Your Turso database URLTURSO_AUTH_TOKEN: Your Turso auth tokenFRONTEND_URL: Your frontend URL (will be provided after frontend deploys)CLERK_SECRET_KEY: Your Clerk secret key for authenticationTWILIO_ACCOUNT_SID: (Optional) Twilio account SID for WhatsAppTWILIO_AUTH_TOKEN: (Optional) Twilio auth token for WhatsAppTWILIO_WHATSAPP_NUMBER: (Optional) Twilio WhatsApp numberRESEND_API_KEY: (Optional) Resend API key for email notifications (get from https://resend.com/api-keys)RESEND_FROM_EMAIL: (Optional) Email sender address (default: onboarding@resend.dev)
-
Click "Apply"
-
Wait for deployment (5-10 minutes)
- After deployment, Render provides URLs
- Copy backend URL (e.g.,
https://your-app.onrender.com) - Update frontend
.env:VITE_API_URL=https://your-app.onrender.com
- Update backend
FRONTEND_URLenv var to frontend URL - Redeploy if needed
Create Dockerfile in backend/:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]Build and run:
docker build -t b2l-backend .
docker run -p 8000:8000 --env-file .env b2l-backendInstall dependencies:
pip install -r requirements.txtRun with Gunicorn (production ASGI server):
pip install gunicorn uvicorn[standard]
gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000Systemd service (/etc/systemd/system/b2l-backend.service):
[Unit]
Description=MagPie Backend
After=network.target
[Service]
Type=notify
User=www-data
WorkingDirectory=/var/www/b2l_registration/backend
Environment="PATH=/var/www/b2l_registration/backend/venv/bin"
ExecStart=/var/www/b2l_registration/backend/venv/bin/gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
Restart=always
[Install]
WantedBy=multi-user.targetcd frontend
npm run buildThis creates dist/ folder with optimized static files.
Netlify:
npm install -g netlify-cli
netlify deploy --prod --dir=distVercel:
npm install -g vercel
vercel --prodAWS S3 + CloudFront:
aws s3 sync dist/ s3://your-bucket-name/Nginx:
server {
listen 80;
server_name your-domain.com;
root /var/www/b2l_registration/frontend/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Required:
TURSO_DATABASE_URL=libsql://your-database.turso.io
TURSO_AUTH_TOKEN=your_auth_token
FRONTEND_URL=https://your-frontend-domain.com
CLERK_SECRET_KEY=sk_test_...Optional (WhatsApp):
TWILIO_ACCOUNT_SID=AC...
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_WHATSAPP_NUMBER=whatsapp:+14155238886Optional (Email):
RESEND_API_KEY=re_...
RESEND_FROM_EMAIL=onboarding@resend.dev # For testing only
# RESEND_FROM_EMAIL=noreply@yourdomain.com # For production with custom domainVITE_API_URL=https://your-backend-domain.com
VITE_CLERK_PUBLISHABLE_KEY=pk_live_... # Your production Clerk key- Sign up at https://resend.com/signup
- Get API key from https://resend.com/api-keys
- Use test sender:
onboarding@resend.devRESEND_API_KEY=re_xxxxxxxxxxxxx RESEND_FROM_EMAIL=onboarding@resend.dev
- Test limits: 100 emails/day, 3,000/month
Follow: https://resend.com/docs/knowledge-base/introduction
- Go to https://resend.com/domains
- Click "Add Domain"
- Enter your domain (e.g.,
yourdomain.com)
Add these DNS records to your domain:
SPF Record (TXT):
Name: @
Value: v=spf1 include:_spf.resend.com ~all
DKIM Record (TXT):
Name: resend._domainkey
Value: [Provided by Resend - copy from dashboard]
DMARC Record (TXT) - Optional but recommended:
Name: _dmarc
Value: v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com
MX Record - Optional (only if receiving emails):
Priority: 10
Value: feedback-smtp.us-east-1.amazonses.com
- Wait 24-48 hours for DNS propagation
- Click "Verify" in Resend dashboard
- Check status - should show "Verified"
RESEND_API_KEY=re_xxxxxxxxxxxxx
RESEND_FROM_EMAIL=noreply@yourdomain.com
# Or use any email like: hello@yourdomain.com, support@yourdomain.comSend a test email from your dashboard to verify the custom domain works.
Free tier:
- 100 emails/day
- 3,000 emails/month
- No credit card required
Paid plans (if needed):
- Pro: $20/month - 50,000 emails
- Scale: Custom pricing - Unlimited
Domain not verifying?
- Check DNS records with:
dig TXT resend._domainkey.yourdomain.com - DNS can take 24-48 hours to propagate
- Ensure records are added to root domain, not subdomain
Emails going to spam?
- Add DMARC record
- Warm up domain by sending gradually
- Ensure SPF and DKIM records are correct
Rate limits?
- Free tier: 2 requests/second
- Upgrade plan if sending more frequently
Advantages:
- Free tier (500MB, 1B row reads/month)
- Global edge network
- Automatic backups
- Zero-downtime migrations
Setup:
# Install Turso CLI
curl -sSfL https://get.tur.so/install.sh | bash
# Create database
turso db create b2l-registration
# Get connection details
turso db show b2l-registration
# Create auth token
turso db tokens create b2l-registrationInstall psycopg2 and update database code:
pip install psycopg2-binaryConnection string:
DATABASE_URL=postgresql://user:password@host:port/databaseBackend:
curl https://your-backend-domain.com/healthFrontend:
- Visit
https://your-frontend-domain.com - Check browser console for errors
Point domain to Render:
Type: CNAME
Name: @
Value: your-app.onrender.com
Render provides automatic SSL certificates via Let's Encrypt.
For custom domains:
- Add custom domain in Render
- Update DNS records
- Wait for SSL provisioning (few minutes)
Render Dashboard:
- View logs
- Monitor resource usage
- Check deployment status
External Monitoring:
- UptimeRobot
- Pingdom
- StatusCake
Turso:
- Automatic backups enabled
- Point-in-time recovery
Manual Backups:
# Export database
turso db shell b2l-registration .dump > backup.sql
# Import database
turso db shell b2l-registration < backup.sqlCaching:
- Redis for session storage
- CDN for static assets
Database:
- Connection pooling
- Query optimization
- Index optimization
Build Optimization:
- Code splitting
- Tree shaking
- Minification (automatic with Vite)
CDN:
- Cloudflare
- AWS CloudFront
- Fastly
Image Optimization:
- WebP format
- Lazy loading
- Responsive images
- HTTPS enabled
- Environment variables secured
- CORS properly configured
- Rate limiting enabled
- Input validation active
- Database credentials rotated
- Backups tested
- Monitoring setup
- Error logging configured
- Security headers set
Check:
- Build logs in Render/platform dashboard
- Environment variables set correctly
- Dependencies in requirements.txt
- Python version matches (3.11+)
Check:
- Turso credentials correct
- Database URL format
- Network connectivity
- Token not expired
Check:
FRONTEND_URLmatches actual frontend domain- Include protocol (https://)
- No trailing slash
Check:
- Twilio credentials set
- Sandbox activated
- Recipients joined sandbox
- Account has credits
- Go to Deployments tab
- Click "Rollback" on previous deployment
- Confirm rollback
- Checkout previous commit:
git checkout <previous-commit-hash>
- Redeploy
- Update DNS if needed
- Render: Free (with cold starts)
- Turso: Free (500MB, 1B reads)
- Total: $0/month
- Render: $7/month (Starter plan)
- Turso: Free (within limits)
- Twilio: Pay-per-message (~₹0.75/msg)
- Total: ~$7/month + message costs
- Render: $25/month (Standard plan)
- Turso: $29/month (Scaler plan)
- CDN: $5/month
- Total: ~$60/month + message costs
Symptoms:
npm ERR! magpie-frontend@1.0.0 dev: `vite`
npm ERR! spawn ENOENT
npm WARN Local package.json exists, but node_modules missingSolution:
# Install dependencies first
cd frontend
npm install
# Then run dev server
npm run devRoot Cause: Dependencies not installed. Always run npm install before npm run dev or npm run build.
Symptoms:
npm WARN notsup Unsupported engine for @clerk/clerk-react@5.52.0
npm WARN notsup wanted: {"node":">=18.17.0"} (current: {"node":"10.19.0"})
npm ERR! notarget No matching version foundSolution:
# Upgrade to Node.js 18 LTS
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# Verify version
node --version # Should show v18.x.x
# Reinstall dependencies
cd frontend
rm -rf node_modules package-lock.json
npm installRoot Cause: Project requires Node.js 18.17.0+ for Clerk, Vite, and modern React features.
Symptoms:
Failed to load PostCSS config: [SyntaxError] Unexpected token 'export'
/home/MagPie/frontend/postcss.config.js:1
export default {
^^^^^^
SyntaxError: Unexpected token 'export'Solution Option A (Recommended):
# Add "type": "module" to package.json
cd frontend
npm pkg set type=module
# Restart dev server
npm run devSolution Option B (Alternative):
# Convert postcss.config.js to CommonJS
cd frontend
mv postcss.config.js postcss.config.cjs
# Update the file
cat > postcss.config.cjs << 'EOF'
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
EOF
# Restart dev server
npm run devRoot Cause: PostCSS config uses ES module syntax but Node treats it as CommonJS.
Symptoms:
npm ERR! Failed at the @clerk/shared@3.27.3 postinstall script.
npm ERR! errno 1Solution:
# Install with legacy peer deps flag
cd frontend
npm install --legacy-peer-deps
# Alternative: Skip postinstall scripts (if needed)
npm install --legacy-peer-deps --ignore-scriptsRoot Cause: Peer dependency conflicts or postinstall script compatibility issues.
Symptoms:
- Build completes successfully
- Browser shows blank white page
- Console shows errors about missing routes or API calls
Solution:
# 1. Check environment variables
cat frontend/.env
# Should have:
VITE_API_URL=https://your-backend-domain.com/api
VITE_CLERK_PUBLISHABLE_KEY=pk_live_your_key_here
# 2. Verify backend CORS settings allow your domain
# backend/.env should have:
FRONTEND_URL=https://your-frontend-domain.com
# 3. Rebuild with correct env vars
npm run build
# 4. Check browser console for specific errorsRoot Cause: Missing or incorrect environment variables.
Before deploying frontend, verify:
-
Node.js version >= 18.17.0
node --version
-
Dependencies installed
npm install
-
Environment variables set
cat .env # VITE_API_URL=https://api.yourdomain.com/api # VITE_CLERK_PUBLISHABLE_KEY=pk_live_xxx
-
Backend CORS configured
# backend/.env FRONTEND_URL=https://yourdomain.com -
Build succeeds
npm run build # Should create dist/ folder -
Clerk domain added
- Go to https://dashboard.clerk.com
- Settings → Domains
- Add your production domain
-
Test locally first
npm run preview # Test at http://localhost:4173
# Development
npm install # Install dependencies
npm run dev # Start dev server (http://localhost:3000)
# Production Build
npm run build # Build for production (creates dist/)
npm run preview # Preview production build locally
# Deployment
npx serve -s dist -l 3000 # Serve with 'serve' package
pm2 serve dist 3000 --name frontend --spa # Serve with PM2- Use
curl -fsSL https://deb.nodesource.com/setup_18.xfor Node.js - Python 3.8 is default (works fine for backend)
- May need
--legacy-peer-depsflag for npm install
- Node.js 18 available in default repos
- Python 3.10 is default (works great)
- Usually works without
--legacy-peer-deps
- Use
node:18-alpinebase image - Multi-stage build recommended
- See
PRODUCTION_DEPLOY_FRONTEND.mdfor Dockerfile
For deployment issues:
- Check Render documentation
- Review error logs
- Contact support
- Open GitHub issue