Skip to content

Docker Cluster

The Docker Cluster deployment runs RAMP in a high-availability configuration with multiple API instances, load balancing, centralized file storage, and a Redis backplane for real-time messaging. This is the recommended setup for production environments with more than 10 users.

ComponentInstancesPurpose
API3 (load balanced)Backend application servers
Web UI2 (load balanced)Frontend static file servers
Nginx1Load balancer and reverse proxy
PostgreSQL1Relational database
Redis1Cache + SignalR backplane
MinIO1S3-compatible file storage
LDAP1Enterprise authentication

  • Docker Desktop 4.0+ (Windows/Mac) or Docker Engine 20.10+ (Linux)
  • Docker Compose 2.0+
  • Available RAM: 8 GB minimum (16 GB recommended)
  • Disk Space: 20 GB minimum
Terminal window
# Verify installation
docker --version # 24.0.0 or higher
docker-compose --version # 2.0.0 or higher

  1. Navigate to the RAMP directory:

    Terminal window
    cd /path/to/RAMP
  2. Create a .env file with secure passwords:

    Terminal window
    DB_PASSWORD=YourSecureDbPassword123!
    LDAP_ADMIN_PASSWORD=YourLdapPassword123!
    LDAP_JWT_SECRET=your_jwt_secret_min_32_chars_long!
    JWT_SECRET=YourApiJwtSecretAtLeast32CharsLong!
    MINIO_ROOT_USER=admin
    MINIO_ROOT_PASSWORD=YourMinioPassword123!
  3. Start the cluster (first run takes 5—10 minutes to build images):

    Terminal window
    docker-compose -f docker-compose.cluster.yml up -d --build
  4. Monitor startup progress:

    Terminal window
    docker-compose -f docker-compose.cluster.yml ps

    Wait for all services to show Up (healthy). Typical startup times:

    • Infrastructure (Redis, PostgreSQL, LDAP, MinIO): 30—60 seconds
    • API instances: 60—90 seconds (includes database migrations)
    • Web UI + load balancer: 10—20 seconds after APIs are healthy
  5. Open your browser at http://localhost.


FieldValue
Emailadmin@ramp.local
PasswordAdmin123!
FieldValue
URLhttp://localhost:9001
Usernameadmin
Passwordminio_secure_password_change_me

Use the MinIO console to view uploaded files, create buckets, monitor storage usage, and configure access policies.

FieldValue
URLhttp://localhost:17170
Usernameadmin
PasswordLdapAdmin123!
FieldValue
Hostlocalhost
Port5432
Databaseramp
Usernameramp
PasswordRampDbPassword123!

Connection string: postgresql://ramp:RampDbPassword123!@localhost:5432/ramp

FieldValue
Hostlocalhost
Port6379
PasswordNone (no authentication by default)
Terminal window
# Connect to Redis
docker exec -it ramp-redis redis-cli
> PING
PONG
> KEYS RAMP:*

After startup, verify the cluster is working correctly:

Terminal window
docker-compose -f docker-compose.cluster.yml ps

Expected output: all 10 containers running, with API, database, Redis, MinIO, and LDAP showing (healthy).

Terminal window
curl http://localhost/_health
Terminal window
curl http://localhost/_api/signalrmonitoring/health

Expected response includes:

{
"status": "healthy",
"signalr": {
"hubsInitialized": true,
"redisBackplaneEnabled": true,
"redisConnected": true
}
}
  1. Open two browser windows (use different browsers or incognito mode).
  2. Log in to RAMP in both windows.
  3. Navigate to the same template in both windows.
  4. In Window 1, lock a field by clicking on it.
  5. Window 2 should immediately show the field is locked.

This works because the two windows connect to different API instances, and the lock event is broadcast through the Redis backplane.

  1. Open RAMP in your browser and navigate around.

  2. Stop one API instance:

    Terminal window
    docker stop ramp-api-1
  3. Refresh the page. The application continues working because requests are routed to the remaining instances.

  4. Restart the instance:

    Terminal window
    docker start ramp-api-1
  1. Log in to RAMP and upload an attachment to an instance.
  2. Open the MinIO console at http://localhost:9001.
  3. Verify the file appears in the ramp-uploads bucket.
  4. Download the file from RAMP to confirm the round trip.

Terminal window
# All containers
docker-compose -f docker-compose.cluster.yml logs -f
# Specific service
docker-compose -f docker-compose.cluster.yml logs -f ramp-api-1
# Last 100 lines
docker-compose -f docker-compose.cluster.yml logs --tail=100 ramp-api-1
Terminal window
# Restart a single instance
docker-compose -f docker-compose.cluster.yml restart ramp-api-1
# Restart all API instances
docker-compose -f docker-compose.cluster.yml restart ramp-api-1 ramp-api-2 ramp-api-3
Terminal window
docker-compose -f docker-compose.cluster.yml stop

Terminal window
# Plain SQL
docker exec ramp-db pg_dump -U ramp -d ramp > ramp_backup_$(date +%Y%m%d).sql
# Compressed
docker exec ramp-db pg_dump -U ramp -d ramp | gzip > ramp_backup_$(date +%Y%m%d).sql.gz
Terminal window
# Backup MinIO data
docker exec ramp-minio tar czf - /data | cat > minio_backup_$(date +%Y%m%d).tar.gz

Terminal window
docker-compose -f docker-compose.cluster.yml logs

Common causes:

  • Ports already in use (80, 443, 5432, 6379, 9000, 17170)
  • Insufficient memory (need 8 GB+ RAM)
  • Docker Desktop not running
Terminal window
# Check port conflicts
lsof -i :80,5432,6379 # Linux/Mac
netstat -ano | findstr "80 5432 6379" # Windows
Terminal window
docker-compose -f docker-compose.cluster.yml logs ramp-api-1 | grep ERROR

Common causes: database migration errors, Redis connection failure, MinIO connection failure.

Solution:

Terminal window
# Restart infrastructure first
docker-compose -f docker-compose.cluster.yml restart ramp-db ramp-redis ramp-minio
# Wait 30 seconds, then restart API instances
docker-compose -f docker-compose.cluster.yml restart ramp-api-1 ramp-api-2 ramp-api-3
Terminal window
# Verify admin user exists
docker exec -it ramp-db psql -U ramp -d ramp \
-c "SELECT \"Email\", \"UserName\" FROM \"AspNetUsers\" WHERE \"Email\" = 'admin@ramp.local';"

If the admin user is missing, database migrations may not have run. Check the API logs for migration errors.

Terminal window
curl http://localhost/_api/signalrmonitoring/health

If redisConnected is false:

Terminal window
# Verify Redis is running
docker exec ramp-redis redis-cli PING
# Expected: PONG
# Restart API instances
docker-compose -f docker-compose.cluster.yml restart ramp-api-1 ramp-api-2 ramp-api-3

Open the MinIO console at http://localhost:9001 and check whether the ramp-uploads bucket exists. If it is missing, create it manually in the MinIO console.

Terminal window
# Test LDAP connection
docker exec ramp-ldap /app/lldap healthcheck
# View LDAP logs
docker logs ramp-ldap

Verify users exist in the LDAP admin panel at http://localhost:17170 under ou=people,dc=ramp,dc=local.


Terminal window
# All containers
docker stats
# API instances only
docker stats ramp-api-1 ramp-api-2 ramp-api-3
Terminal window
# Real-time operations
docker exec -it ramp-redis redis-cli monitor
# Memory usage
docker exec ramp-redis redis-cli INFO memory
Terminal window
docker exec -it ramp-db psql -U ramp -d ramp
-- Active connections
SELECT count(*) FROM pg_stat_activity;
-- Database size
SELECT pg_size_pretty(pg_database_size('ramp'));

Edit docker-compose.cluster.yml to add ramp-api-4, ramp-api-5, etc., then:

Terminal window
docker-compose -f docker-compose.cluster.yml up -d

Add to the ramp-db environment in docker-compose.cluster.yml:

- POSTGRES_MAX_CONNECTIONS=200

Edit the Redis command in docker-compose.cluster.yml:

ramp-redis:
command: redis-server --appendonly yes --maxmemory 4gb --maxmemory-policy allkeys-lru

Restart after making changes:

Terminal window
docker-compose -f docker-compose.cluster.yml restart ramp-redis

  • Change all default passwords (create .env file with secure values)
  • Configure SSL/TLS (add certificates to Nginx load balancer config)
  • Set up automated PostgreSQL backups
  • Configure external DNS (point your domain to the load balancer)
  • Enable authentication for Redis (if exposed to the network)
  • Review security headers in the Nginx config
  • Set up monitoring (Prometheus, Grafana, or similar)
  • Configure log aggregation (ELK stack, Splunk, or similar)
  • Test disaster recovery (restore from backup)
  • Document runbooks for your operations team