# 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: ```bash 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 ```bash # 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 ```bash # 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 ```bash docker compose up -d ``` ### 5. Configure Nginx Add proxy configuration for your domain. Example: ```nginx # 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: ```bash nginx -t && systemctl reload nginx ``` ### 6. Verify deployment ```bash # 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 ```bash # 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: ```bash # Pull the latest image docker compose pull portal # Restart the portal service docker compose up -d portal ``` ## Backup ### Database backup ```bash # 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) ```bash # 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: ```bash 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 ```bash # Check logs for errors docker compose logs # Check if ports are in use netstat -tlnp | grep -E ':(3000|3001|8000)' ``` ### Database connection errors ```bash # 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: ```bash ./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: ```bash 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 ```bash # 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: ```bash 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** ```bash chmod 600 .env ``` 2. **Protect Supabase Studio with auth** ```bash # 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: - Check logs: `docker compose logs -f` - GitHub/Gitea issues - Email: support@monacousa.org