12 KiB
RYS Premium Server Deployment Guide
Complete guide to deploying the premium subscription server and testing the monetization flow.
Server URL: https://server.lawrencehook.com/rys/
Table of Contents
- Prerequisites
- Stripe Setup
- AWS SES Setup
- Server Deployment
- Apache Configuration
- Extension Setup
- Testing
- Troubleshooting
- Maintenance
Prerequisites
- AWS Lightsail instance (Bitnami stack)
- Node.js v20+
- Stripe account (test mode for development)
- AWS SES configured for sending emails
Stripe Setup
Create Products
- Go to https://dashboard.stripe.com/test/products
- Click "+ Add product"
Monthly Plan:
- Name:
RYS Premium Monthly - Pricing:
$3.00 USD/month/recurring - Save and copy the Price ID (starts with
price_...)
Yearly Plan:
- Name:
RYS Premium Yearly - Pricing:
$24.00 USD/year/recurring - Save and copy the Price ID
Get API Keys
- Go to https://dashboard.stripe.com/test/apikeys
- Copy the Secret key (starts with
sk_test_...)
Configure Billing Portal
- Go to Settings → Billing → Customer portal
- Enable the customer portal
- Configure allowed actions:
- Update payment methods
- View invoice history
- Cancel subscriptions
- Save changes
Create Webhook Endpoint
- Go to https://dashboard.stripe.com/test/webhooks
- Click "+ Add endpoint"
- Endpoint URL:
https://server.lawrencehook.com/rys/webhook/stripe - Select events:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_failedinvoice.payment_succeeded
- Click "Add endpoint"
- Copy the Signing secret (starts with
whsec_...)
AWS SES Setup
Verify Sender Email/Domain
- In AWS Console → SES → Verified identities
- Click "Create identity"
- For email: click the verification link sent to you
- For domain: add the DNS records provided
Request Production Access
SES starts in sandbox mode (can only send to verified emails).
- Go to SES → Account dashboard
- Click "Request production access"
- Fill out the form explaining your use case
- Wait for approval (usually 24-48 hours)
IAM Credentials
If not using instance roles, create IAM credentials:
- Create a new user (e.g.,
rys-premium-ses) - Attach policy:
AmazonSESFullAccess - Create access keys
- Copy the Access Key ID and Secret Access Key
Server Deployment
SSH to Lightsail Instance
ssh bitnami@your-instance-ip
Install Node.js 20+ (if needed)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
node --version # Should show v20.x.x
Install PM2
sudo npm install -g pm2
Clone and Setup Repository
cd ~/github
git clone https://github.com/lawrencehook/remove-youtube-suggestions.git
cd remove-youtube-suggestions
git checkout feature/monetize
cd server
npm install
Create Environment File
nano .env
Paste the following (fill in your values):
# Server
PORT=3005
BASE_URL=https://server.lawrencehook.com/rys
# JWT (generate with: openssl rand -base64 32)
JWT_SECRET=your-random-secret-at-least-32-characters-long
# Stripe
STRIPE_SECRET_KEY=sk_test_YOUR_KEY
STRIPE_PRICE_MONTHLY=price_YOUR_MONTHLY_ID
STRIPE_PRICE_YEARLY=price_YOUR_YEARLY_ID
STRIPE_WEBHOOK_SECRET=whsec_YOUR_WEBHOOK_SECRET
# AWS SES (uses instance role, no explicit credentials needed)
AWS_REGION=us-east-1
EMAIL_FROM=noreply@lawrencehook.com
Save: Ctrl+O, Enter, Ctrl+X
Create Data Directory
mkdir -p data
echo '[]' > data/grandfathered.json
To add grandfathered users (past donors with lifetime access):
echo '["donor1@example.com", "donor2@example.com"]' > data/grandfathered.json
Test Server Starts
npm start
Expected output:
Loaded X grandfathered emails
RYS Premium Server running on port 3005
Base URL: https://server.lawrencehook.com/rys
Press Ctrl+C to stop.
Start with PM2
pm2 start src/index.js --name rys-premium
pm2 save
Configure PM2 Auto-Start on Reboot
pm2 startup
# Run the command it outputs (starts with: sudo env PATH=...)
pm2 save
Apache Configuration
Your Lightsail instance uses Bitnami's Apache with path-based proxying.
Edit SSL Config
Edit your local deployments repo:
nano ~/github/deployments/opt/bitnami/apache/conf/bitnami/bitnami-ssl.conf
Add these lines inside the <VirtualHost _default_:443> block:
ProxyPass /rys/ http://localhost:3005/
ProxyPassReverse /rys/ http://localhost:3005/
Deploy Apache Config
# Local machine
cd ~/github/deployments
git add -A && git commit -m "Add RYS Premium server proxy config" && git push
# On server
cd ~/github/deployments && git pull
./update_apache_conf.sh
Extension Setup
Verify Config Points to Production
Check src/shared/config.js:
const PREMIUM_CONFIG = {
SERVER_URL: 'https://server.lawrencehook.com/rys',
// ...
};
Build the Extension
For Chrome:
./make_chrome.sh
For Firefox:
./make_firefox.sh
Load in Chrome
- Navigate to
chrome://extensions/ - Enable "Developer mode" (toggle in top-right)
- Click "Load unpacked"
- Select:
chrome_extension/
Load in Firefox
- Navigate to
about:debugging#/runtime/this-firefox - Click "Load Temporary Add-on..."
- Select:
src/firefox_manifest.json
Testing
Automated Tests
cd server
npm test
All tests should pass (currently 46).
Health Check
curl https://server.lawrencehook.com/rys/health
# Expected: {"status":"ok","timestamp":"..."}
Magic Link Flow
Via curl:
curl -X POST https://server.lawrencehook.com/rys/auth/send-magic-link \
-H "Content-Type: application/json" \
-d '{"email":"your-email@example.com"}'
# Expected: {"request_id":"abc123-..."}
Via extension:
- Go to any YouTube page
- Click the RYS extension icon
- Click the gear icon (settings menu)
- Click "Sign In"
- Enter your email and click "Send Sign-In Link"
- Check your email and click the magic link
- Return to extension — should show "Signed in successfully"
License Check
After signing in:
- Click gear icon → "Account"
- Should show your email and status: "Free"
For grandfathered users:
- Add email to
data/grandfathered.jsonon server - Restart:
pm2 restart rys-premium - Sign out and sign back in
- Status should show: "Premium (Lifetime)"
Checkout Flow
- Open Account modal
- Click "Upgrade to Premium"
- Select a plan (Monthly or Yearly)
- Click "Continue to Checkout"
- Complete payment with test card:
- Card:
4242 4242 4242 4242 - Expiry: Any future date (e.g.,
12/34) - CVC: Any 3 digits (e.g.,
123) - ZIP: Any valid ZIP (e.g.,
12345)
- Card:
- After success page, return to extension
- Open Account — status should show "Premium Active"
Billing Portal
- With an active subscription, open Account modal
- Click "Manage Subscription"
- Stripe billing portal opens in new tab
- Can cancel subscription here for testing
Webhook Verification
- Go to Stripe Dashboard → Webhooks → your endpoint
- Click "Send test webhook"
- Select
checkout.session.completed - Check server logs:
pm2 logs rys-premium
Extension Smoke Tests
- Sign-in flow: Send magic link → click link → see "Signed in successfully"
- Poll cancel: Start sign-in → hit Cancel → spinner stops, no sign-in after cancel
- Premium gate: Mark option as premium → non-premium click opens upgrade modal
- License refresh: Open Account → premium label reflects correct status
- Upgrade flow: Choose plan → click checkout → Stripe checkout opens
- Billing portal: With subscription → click "Manage Subscription" → portal opens
Pre-Launch Checklist
- All automated tests pass
- Server starts without errors
/healthendpoint returns OK- Magic link emails are received
- Magic link verification works
- Grandfathered users show as premium
- Stripe checkout creates a session
- Stripe webhook is configured and verified
- Billing portal is accessible
- SSL certificate is valid
- CORS works from extension origins
Test Cards Reference
| Card | Result |
|---|---|
4242 4242 4242 4242 |
Success |
4000 0000 0000 0002 |
Declined |
4000 0025 0000 3155 |
Requires authentication |
Troubleshooting
Server won't start
pm2 logs rys-premium --lines 50
Common issues:
- Missing .env variables
- JWT_SECRET too short (needs 32+ chars)
- Port already in use
Magic link emails not sending
- Check SES is configured
- Verify EMAIL_FROM domain is verified in SES
- If in SES sandbox, recipient must also be verified
CORS errors in extension
# Verify server is running
curl http://localhost:3005/health
SSL certificate issues
sudo /opt/bitnami/bncert-tool # regenerate if needed
Extension can't connect
# Test endpoint
curl https://server.lawrencehook.com/rys/health
# Check Apache config
sudo apachectl configtest
Maintenance
Update Server Code
cd ~/github/remove-youtube-suggestions
git pull
git checkout feature/monetize
cd server
npm install
pm2 restart rys-premium
View Logs
pm2 logs rys-premium # Tail logs
pm2 logs rys-premium --lines 100 # Last 100 lines
Server Commands
pm2 restart rys-premium # Restart
pm2 stop rys-premium # Stop
pm2 status # Check status
Add to Deployment Script
Add to ~/github/deployments/run:
# RYS Premium Server (pm2)
cd /home/bitnami/github/remove-youtube-suggestions && git checkout -- . && git pull && git checkout feature/monetize;
cd server && npm install && npm audit fix;
pm2 restart rys-premium || pm2 start src/index.js --name rys-premium;
Updating Grandfathered List
- Edit
data/grandfathered.json - Restart:
pm2 restart rys-premium
Environment Variables Reference
| Variable | Description | Example |
|---|---|---|
PORT |
Server port | 3005 |
BASE_URL |
Public URL | https://server.lawrencehook.com/rys |
JWT_SECRET |
32+ char secret | (generate with openssl rand -base64 32) |
STRIPE_SECRET_KEY |
Stripe API secret | sk_test_... |
STRIPE_PRICE_MONTHLY |
Monthly plan price ID | price_... |
STRIPE_PRICE_YEARLY |
Yearly plan price ID | price_... |
STRIPE_WEBHOOK_SECRET |
Webhook signing secret | whsec_... |
AWS_REGION |
AWS region for SES | us-east-1 |
EMAIL_FROM |
Sender email address | noreply@lawrencehook.com |
API Endpoints Reference
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/health |
GET | No | Health check |
/auth/send-magic-link |
POST | No | Send magic link email |
/auth/verify |
GET | No | Magic link target (HTML) |
/auth/poll |
GET | No | Poll for auth status |
/license/check |
GET | Yes | Check premium status |
/checkout/create |
POST | Yes | Create Stripe checkout |
/checkout/success |
GET | No | Success page (HTML) |
/checkout/cancel |
GET | No | Cancel page (HTML) |
/billing/portal |
POST | Yes | Create billing portal session |
/billing/return |
GET | No | Return page (HTML) |
/webhook/stripe |
POST | No* | Stripe webhook |
*Authenticated via Stripe signature