monacousa-portal/deploy
Matt f81da356cc
Build and Push Docker Image / build (push) Successful in 2m49s Details
Fix init.sql table grant ordering
Move GRANT statements for document_folders and user_notification_preferences
to after their respective CREATE TABLE statements. The grants were failing
because they referenced tables that hadn't been created yet.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 16:52:07 +01:00
..
.env.example Fix domain configuration for separate portal and API domains 2026-01-26 11:34:25 +01:00
README.md Complete database grants and update README 2026-01-26 15:44:25 +01:00
docker-compose.yml Add password setup script for Supabase roles 2026-01-26 13:57:35 +01:00
init.sql Fix init.sql table grant ordering 2026-01-26 16:52:07 +01:00
kong.yml.template Add standalone production deployment package 2026-01-26 11:15:56 +01:00
setup.sh Fix domain configuration for separate portal and API domains 2026-01-26 11:34:25 +01:00
zz-set-passwords.sh Add password setup script for Supabase roles 2026-01-26 13:57:35 +01:00

README.md

Monaco USA Portal - Standalone Production Deployment

This is a standalone deployment package for the Monaco USA Portal. No source code cloning required.

Prerequisites

  • Linux server (Ubuntu 22.04+ recommended)
  • Docker Engine 24.0+
  • Docker Compose v2.20+
  • Nginx installed and configured for SSL
  • Domain name with DNS pointing to your server

Quick Start

1. Download the deployment files

Create a directory and download the deployment files:

mkdir -p /opt/monacousa
cd /opt/monacousa

# Download files from your deployment source
# Example: copy from Gitea, scp, etc.

You need these files:

  • docker-compose.yml
  • .env.example
  • init.sql
  • kong.yml.template
  • setup.sh

2. Configure environment

# Copy the example environment file
cp .env.example .env

# Edit with your settings
nano .env

At minimum, configure:

  • DOMAIN - Your domain name (e.g., portal.monacousa.org)
  • SMTP settings (optional but recommended for emails)

3. Run setup script

# Make setup script executable
chmod +x setup.sh

# Run setup - this generates secrets and kong.yml
./setup.sh

The setup script will:

  • Generate secure random passwords and JWT tokens
  • Create kong.yml from the template with your API keys
  • Validate your configuration

4. Start the services

docker compose up -d

5. Configure Nginx

Add proxy configuration for your domain. Example:

# Portal - main site
server {
    listen 443 ssl http2;
    server_name portal.monacousa.org;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}

# API - Supabase services
server {
    listen 443 ssl http2;
    server_name api.portal.monacousa.org;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}

# Studio - Supabase dashboard (optional)
server {
    listen 443 ssl http2;
    server_name studio.portal.monacousa.org;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # Add basic auth for security
    auth_basic "Supabase Studio";
    auth_basic_user_file /etc/nginx/.htpasswd;

    location / {
        proxy_pass http://127.0.0.1:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}

Reload nginx:

nginx -t && systemctl reload nginx

6. Verify deployment

# Check all containers are running
docker compose ps

# Check database initialization
docker compose logs db

# Check for any errors
docker compose logs -f

7. Access the portal

Open https://portal.monacousa.org in your browser. On first visit, you'll be redirected to /setup to create the initial admin account.

Architecture

Internet
    │
    └─► Nginx (SSL/Reverse Proxy)
            │
            ├─► portal.domain.com:443 ──► localhost:3000 ──► Portal (SvelteKit)
            ├─► api.domain.com:443 ──► localhost:8000 ──► Kong ──► Auth/REST/Storage
            └─► studio.domain.com:443 ──► localhost:3001 ──► Studio (Dashboard)

Internal Docker Network
    │
    ├─► Kong API Gateway (port 8000)
    │       ├─► Auth (GoTrue)
    │       ├─► REST (PostgREST)
    │       ├─► Storage API
    │       └─► Realtime
    │
    └─► PostgreSQL Database

Exposed Ports

Service Port Purpose
Portal 127.0.0.1:3000 Main web application
Kong 127.0.0.1:8000 Supabase API gateway
Studio 127.0.0.1:3001 Supabase dashboard (optional)

All ports are bound to localhost only for security. Use nginx to expose them.

Files Description

File Purpose
docker-compose.yml All service definitions
.env Your configuration (from .env.example)
init.sql Database schema and migrations
kong.yml.template API gateway config template
kong.yml Generated API gateway config (created by setup.sh)
setup.sh Setup script for secrets and validation

Management Commands

# Start all services
docker compose up -d

# Stop all services
docker compose down

# View logs
docker compose logs -f

# View specific service logs
docker compose logs -f portal
docker compose logs -f db

# Restart a specific service
docker compose restart portal

# Check resource usage
docker stats

# Enter database shell
docker compose exec db psql -U postgres

Updating

To update the portal to a new version:

# Pull the latest image
docker compose pull portal

# Restart the portal service
docker compose up -d portal

Backup

Database backup

# Create backup
docker compose exec db pg_dump -U postgres postgres > backup_$(date +%Y%m%d).sql

# Restore backup
docker compose exec -T db psql -U postgres postgres < backup_YYYYMMDD.sql

Full backup (including storage)

# Stop services first for consistent backup
docker compose stop

# Backup volumes
docker run --rm -v monacousa_db-data:/data -v $(pwd):/backup alpine \
    tar czf /backup/db-data-backup.tar.gz -C /data .

docker run --rm -v monacousa_storage-data:/data -v $(pwd):/backup alpine \
    tar czf /backup/storage-data-backup.tar.gz -C /data .

# Start services
docker compose up -d

Important Notes

Environment Variables

The portal uses dynamic environment variables which are read at runtime. This means:

  • You can change .env values and restart containers without rebuilding
  • The pre-built Docker image works with any configuration
  • JWT tokens and API keys must be generated using ./setup.sh

First-Time Setup

On first access to the portal, you'll be redirected to /setup where you create the initial admin account. This only happens when the members table is empty.

Database Initialization

The init.sql file:

  • Creates all database schemas, tables, views, and functions
  • Sets up Row Level Security (RLS) policies
  • Grants appropriate permissions to database roles
  • Runs automatically on first container start

If you need to reset the database:

docker compose down -v  # WARNING: Deletes all data!
docker compose up -d

Rebuilding the Portal (If Needed)

If you're building from source instead of using the pre-built image, ensure environment variables are passed during build for static features. For most deployments, the pre-built image with runtime env vars is recommended.

Troubleshooting

Containers not starting

# Check logs for errors
docker compose logs

# Check if ports are in use
netstat -tlnp | grep -E ':(3000|3001|8000)'

Database connection errors

# Check database is healthy
docker compose ps db

# Check database logs
docker compose logs db

# Verify database is accepting connections
docker compose exec db pg_isready -U postgres

API 401 Unauthorized errors

This usually means the API keys don't match. Run setup again:

./setup.sh
docker compose restart kong

API 403 Forbidden errors

This means the database permissions (GRANTs) are missing. This is fixed in the init.sql, but if you see this on an existing deployment, run:

docker compose exec db psql -U postgres -c "
GRANT SELECT, INSERT, UPDATE ON public.members TO authenticated;
GRANT SELECT ON public.membership_statuses TO authenticated;
GRANT SELECT ON public.membership_types TO authenticated;
GRANT SELECT ON public.members_with_dues TO authenticated;
GRANT SELECT, INSERT ON public.dues_payments TO authenticated;
GRANT SELECT, INSERT, UPDATE, DELETE ON public.events TO authenticated;
GRANT SELECT, INSERT, UPDATE, DELETE ON public.event_rsvps TO authenticated;
GRANT SELECT ON public.events_with_counts TO authenticated;
"

"Your account is not properly configured" error

This occurs when a user can authenticate but can't query their member profile. Usually a database permission issue - see the 403 fix above.

Portal not loading

# Check portal logs
docker compose logs portal

# Verify kong is routing correctly
docker compose exec portal wget -qO- http://kong:8000/rest/v1/ || echo "Kong not reachable"

Nginx 502 Bad Gateway

Check if the Docker containers are running:

docker compose ps
curl http://127.0.0.1:3000  # Should return HTML
curl http://127.0.0.1:8000  # Should return JSON

Security Recommendations

  1. Secure your .env file

    chmod 600 .env
    
  2. Protect Supabase Studio with auth

    # Generate password file for nginx
    htpasswd -c /etc/nginx/.htpasswd admin
    
  3. Regular updates

    • Keep Docker and host OS updated
    • Regularly pull latest portal images
  4. Monitor logs

    • Set up log rotation (configured in docker-compose.yml)
    • Consider centralized logging

Support

For issues and questions: