9.9 KiB
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.exampleinit.sqlkong.yml.templatesetup.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.ymlfrom 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
.envvalues 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
-
Secure your .env file
chmod 600 .env -
Protect Supabase Studio with auth
# Generate password file for nginx htpasswd -c /etc/nginx/.htpasswd admin -
Regular updates
- Keep Docker and host OS updated
- Regularly pull latest portal images
-
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