Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Portal Deployment

Building

cd /development/rockfish/ndr

# Build Docker image
./scripts/build-portal.sh

# Push to DigitalOcean Container Registry
./scripts/build-portal.sh --push

# Build local binary
./scripts/build-portal.sh --install

Environment Variables

All configuration is via environment variables (.env file or platform settings).

Required

VariableDescription
PORTAL_DOMAINPublic URL (e.g., https://portal.rockfishndr.com)
STRIPE_SECRET_KEYStripe API secret key (sk_test_... or sk_live_...)
STRIPE_WEBHOOK_SECRETStripe webhook signing secret (whsec_...)
STRIPE_PRICE_BASICStripe Product or Price ID for Basic tier
STRIPE_PRICE_PROFESSIONALStripe Product or Price ID for Professional tier
STRIPE_PRICE_ENTERPRISEStripe Product or Price ID for Enterprise tier
LICENSE_SERVER_TOKENBearer token for the license server

Optional

VariableDefaultDescription
BIND_ADDR0.0.0.0:8080Server bind address
DATABASE_PATH/var/lib/rockfish/portal.dbDuckDB file path
LICENSE_SERVER_HOSThttp://127.0.0.1:8080License server URL
SMTP_HOSTSMTP server (emails logged if unset)
SMTP_PORT587SMTP port (587=STARTTLS, 465=TLS, 25/1025=plain)
SMTP_USERSMTP username
SMTP_PASSWORDSMTP password
SMTP_FROM[email protected]From address
S3_BUCKETS3 bucket for data persistence
S3_REGIONS3 region
S3_ENDPOINTS3 endpoint (for DigitalOcean Spaces, MinIO)
S3_ACCESS_KEY_IDS3 access key
S3_SECRET_ACCESS_KEYS3 secret key
S3_PORTAL_PREFIXportalS3 key prefix
S3_FORCE_PATH_STYLEfalseUse path-style S3 URLs
MAGIC_LINK_TTL_MINUTES15Magic link expiry
PORTAL_DISABLEDfalseShow “Coming Soon” page, disable purchasing

DigitalOcean App Platform

1. Push Docker image

./scripts/build-portal.sh
./scripts/build-portal.sh --push

2. Create App

DigitalOcean Dashboard → Apps → Create App:

  • Source: Container Registry → rockfishnetworks/rockfish-portal:latest
  • HTTP Port: 8080
  • Instance size: Basic ($5/mo)

3. Set environment variables

Add all required variables in the App Settings → Environment Variables.

4. Custom domain

App Settings → Domains → Add portal.rockfishndr.com

DNS: Add CNAME record pointing to your-app.ondigitalocean.app

5. Stripe webhook

Stripe Dashboard → Developers → Webhooks → Add:

  • URL: https://portal.rockfishndr.com/webhook/stripe
  • Events: checkout.session.completed

Docker (self-hosted)

docker run -d \
    --name rockfish-portal \
    --env-file .env \
    -e BIND_ADDR=0.0.0.0:8080 \
    -p 8080:8080 \
    rockfish-portal

Startup Connectivity Checks

On startup, the portal tests:

  1. License serverGET {LICENSE_SERVER_HOST}/api/v1/health
  2. S3 — attempts to list objects under the configured prefix

Results are logged to help diagnose configuration issues.

S3 Data Layout

s3://{bucket}/{prefix}/
├── users.parquet
├── licenses.parquet
├── pending_licenses.parquet
├── magic_links.parquet
└── reminders.parquet

Retry Logic

If the license server is unavailable when a payment is confirmed:

  1. License request is queued in pending_licenses table
  2. Background task retries every 60 seconds
  3. Up to 100 retries (~100 minutes)
  4. On success, license is moved to licenses table and synced to S3