Skip to main content

Deployment Guide — PhotoSwipe Pro with AI SEO

This guide explains how to deploy the complete revenue-generating system: payment checkout, license validation, and documentation site.

Architecture Overview

┌─────────────────────────────────────────────────┐
│ Frontend (Docusaurus) │
│ - Marketing pages (/pro, /checkout) │
│ - Documentation │
│ - Customer portal │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│ Backend API (Express) │
│ - /api/payment/* (checkout, products) │
│ - /api/license/* (activate, validate) │
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│ LemonSqueezy │
│ - Payment processing │
│ - License key generation │
│ - Customer management │
└─────────────────────────────────────────────────┘

Prerequisites

  1. LemonSqueezy Account — Sign up at https://lemonsqueezy.com
  2. Products Created — Site and Agency licenses configured with license keys
  3. Environment Variables — See Environment Configuration

Vercel provides seamless deployment for both frontend and backend.

Step 1: Install Vercel CLI

npm i -g vercel
vercel link

Step 3: Set Environment Variables

vercel env add LEMON_SQUEEZY_API_KEY production
vercel env add LEMON_SQUEEZY_STORE_ID production
vercel env add LEMON_SQUEEZY_VARIANT_ID_SITE production
vercel env add LEMON_SQUEEZY_VARIANT_ID_AGENCY production
vercel env add LEMON_SQUEEZY_PRODUCT_ID production

Or via Vercel dashboard:

  1. Go to Project → Settings → Environment Variables
  2. Add all required variables for Production
  3. Redeploy

Step 4: Deploy

vercel --prod

Your site will be live at https://your-project.vercel.app

Step 5: Test

# Health checks
curl https://your-project.vercel.app/health
curl https://your-project.vercel.app/api/payment/health
curl https://your-project.vercel.app/api/license/health

Option 2: Deploy to Railway

Railway is great for full-stack apps with persistent backends.

Step 1: Install Railway CLI

npm i -g @railway/cli
railway login

Step 2: Initialize Project

railway init

Step 3: Set Environment Variables

railway variables set LEMON_SQUEEZY_API_KEY=your_key
railway variables set LEMON_SQUEEZY_STORE_ID=12345
railway variables set LEMON_SQUEEZY_VARIANT_ID_SITE=67890
railway variables set LEMON_SQUEEZY_VARIANT_ID_AGENCY=67891
railway variables set LEMON_SQUEEZY_PRODUCT_ID=your_product_id

Step 4: Deploy

railway up

Step 5: Get URL

railway domain

Option 3: Deploy to Fly.io

Fly.io offers global edge deployment with low latency.

Step 1: Install Fly CLI

curl -L https://fly.io/install.sh | sh
fly auth login

Step 2: Create App

fly launch

Step 3: Set Secrets

fly secrets set LEMON_SQUEEZY_API_KEY=your_key
fly secrets set LEMON_SQUEEZY_STORE_ID=12345
fly secrets set LEMON_SQUEEZY_VARIANT_ID_SITE=67890
fly secrets set LEMON_SQUEEZY_VARIANT_ID_AGENCY=67891
fly secrets set LEMON_SQUEEZY_PRODUCT_ID=your_product_id

Step 4: Deploy

fly deploy

Option 4: Self-Hosted (VPS/Cloud)

For full control, deploy to your own server.

Step 1: Install Dependencies

# On your server
git clone https://github.com/your-org/photoswipe-pro.git
cd photoswipe-pro

# Install backend deps
cd server
npm install

# Install frontend deps
cd ../demo-docs-website
npm install
npm run build

Step 2: Configure Environment

# Create .env in server/
cp .env.example .env
nano .env
# Add all required variables

Step 3: Set Up Process Manager

# Install PM2
npm i -g pm2

# Start backend
cd server
pm2 start index.js --name photoswipe-pro-api

# Serve frontend (use Nginx/Caddy)

Step 4: Configure Web Server

Nginx example:

server {
listen 80;
server_name photoflowseo.com;

# Frontend (static files)
root /var/www/photoswipe-pro/demo-docs-website/build;
index index.html;

# API proxy
location /api/ {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}

# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
}

Step 5: Set Up SSL

# Install Certbot
sudo apt install certbot python3-certbot-nginx

# Get certificate
sudo certbot --nginx -d photoflowseo.com

Post-Deployment Checklist

1. Test Payment Flow

  • Visit /checkout
  • Click "Buy Now" on Site tier
  • Complete test purchase (use LemonSqueezy test mode)
  • Verify redirect to success page
  • Check license key in email

2. Test License Validation

  • Go to /customer-portal
  • Enter test order ID
  • Verify license key appears
  • Copy key and test in demo /pro page
  • Verify AI SEO features unlock

3. Test API Endpoints

# Health checks
curl https://your-domain.com/health
curl https://your-domain.com/api/payment/health
curl https://your-domain.com/api/license/health

# Get products
curl https://your-domain.com/api/payment/products

# Create checkout (should return checkoutUrl)
curl -X POST https://your-domain.com/api/payment/checkout \
-H "Content-Type: application/json" \
-d '{"productId":"site"}'

4. Configure Monitoring

Set up error tracking and monitoring:

Sentry (recommended):

npm install @sentry/node

Add to server/index.js:

import * as Sentry from '@sentry/node';

Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
});

app.use(Sentry.Handlers.errorHandler());

Uptime monitoring:

  • Use UptimeRobot, Pingdom, or Better Uptime
  • Monitor /health endpoint every 5 minutes

5. Configure Analytics

Track conversions:

Google Analytics:

  • Add GA4 to Docusaurus config
  • Track /checkout page views
  • Set up purchase event tracking

Plausible (privacy-friendly):

// In docusaurus.config.js
scripts: [
{
src: 'https://plausible.io/js/script.js',
'data-domain': 'photoflowseo.com',
defer: true,
},
],

6. Set Up Backups

Database backups (if using):

  • Automated daily backups
  • Store in S3/R2

Code backups:

  • Git repository (already backed up)
  • Tag releases: git tag v1.0.0 && git push --tags

Troubleshooting

"Payment system not configured"

Problem: Backend can't connect to LemonSqueezy

Solution:

  1. Check environment variables are set
  2. Verify API key has correct permissions
  3. Test API key manually:
    curl https://api.lemonsqueezy.com/v1/stores \
    -H "Authorization: Bearer YOUR_API_KEY"

Checkout button does nothing

Problem: Frontend can't reach backend

Solution:

  1. Check browser console for errors
  2. Verify CORS is configured correctly
  3. Test backend endpoint directly:
    curl -X POST https://your-domain.com/api/payment/checkout \
    -H "Content-Type: application/json" \
    -d '{"productId":"site"}'

License validation fails

Problem: License key format or validation logic issue

Solution:

  1. Verify license key format matches: pswp_paid_XXXX
  2. Check /api/license/validate endpoint works
  3. Test with a real key from LemonSqueezy

500 errors in production

Problem: Server error not caught properly

Solution:

  1. Check server logs: pm2 logs or vercel logs
  2. Enable debug mode temporarily: DEBUG=* node server/index.js
  3. Check all environment variables are set in production

Security Best Practices

  1. Never commit secrets — Use environment variables only
  2. Rotate API keys — Quarterly or if compromised
  3. Rate limit APIs — Prevent abuse (use express-rate-limit)
  4. Validate inputs — Never trust client data
  5. Use HTTPS — Always (free with Vercel/Certbot)
  6. Monitor logs — Set up alerts for unusual activity

Scaling Considerations

Current Setup (up to 1,000 customers)

  • ✅ Serverless functions (Vercel/Railway)
  • ✅ No database needed (LemonSqueezy stores everything)
  • ✅ Simple deployment

Medium Scale (1,000–10,000 customers)

  • Add Redis for caching product data
  • Implement rate limiting
  • Use CDN for static assets (Cloudflare)

Large Scale (10,000+ customers)

  • Dedicated backend server (not serverless)
  • Database for analytics
  • Load balancer
  • Separate license validation service

Next Steps

  1. ✅ Deploy to your chosen platform
  2. ✅ Test complete purchase flow
  3. ✅ Configure monitoring and analytics
  4. ✅ Set up custom domain
  5. ✅ Launch! 🚀

See also: