Skip to content

Database Setup

Rack Gateway requires PostgreSQL 14+ for storing users, API tokens, audit logs, and session data.

RequirementMinimumRecommended
PostgreSQL version1416
Storage10GB50GB+ (scales with audit logs)
Memory256MB1GB+
Connections2550+

Set the DATABASE_URL environment variable:

Terminal window
DATABASE_URL=postgres://user:password@host:5432/rack_gateway

Use PostgreSQL standard environment variables:

Terminal window
PGHOST=database.example.com
PGPORT=5432
PGUSER=rack_gateway
PGPASSWORD=your-password
PGDATABASE=rack_gateway

Configure the connection pool for your workload:

VariableDefaultDescription
DB_MAX_OPEN_CONNS25Maximum concurrent connections
DB_MAX_IDLE_CONNS5Idle connections to keep warm
DB_CONN_MAX_LIFETIME30mConnection lifetime before recycling
DB_CONN_MAX_IDLE_TIME10mIdle time before closing
WorkloadMax OpenMax IdleNotes
Small (<100 users)103Conservative for shared DB
Medium (<1000 users)255Default settings
Large (>1000 users)5010Increase with load

Create a PostgreSQL resource in your Convox rack:

Terminal window
# Create database
convox resources create postgres --name gateway-db
# Link to application
convox resources link gateway-db -a rack-gateway
# View connection info
convox resources info gateway-db

Convox automatically sets DATABASE_URL for linked apps.

Migrations run automatically when the gateway starts. The gateway:

  1. Checks current schema version in schema_migrations
  2. Applies any pending migrations
  3. Continues to API server startup

Run migrations manually:

Terminal window
# Via Docker
docker exec rack-gateway rack-gateway-api migrate
# Via Convox
convox run gateway -- rack-gateway-api migrate -a rack-gateway
  • Migrations are idempotent - safe to run multiple times
  • Each migration runs in a transaction
  • Failures abort startup with clear error messages
Terminal window
export RESET_RACK_GATEWAY_DATABASE=DELETE_ALL_DATA
export DEV_MODE=true
rack-gateway-api reset-db
Terminal window
export RESET_RACK_GATEWAY_DATABASE=DELETE_ALL_DATA
export DISABLE_DATABASE_ENVIRONMENT_CHECK=1
rack-gateway-api reset-db

The reset command enforces safety checks:

CheckPurposeOverride
RESET_RACK_GATEWAY_DATABASE=DELETE_ALL_DATAExplicit confirmationRequired
Development mode or environment checkPrevent accidental prod resetDISABLE_DATABASE_ENVIRONMENT_CHECK=1

The gateway creates these tables:

TablePurpose
usersUser accounts and roles
user_sessionsActive user sessions
api_tokensAPI tokens for CI/CD
mfa_methodsMFA registrations (TOTP, WebAuthn)
mfa_backup_codesMFA recovery codes
trusted_devicesRemembered MFA devices
audit.audit_eventComplete audit trail
deploy_approval_requestsDeploy workflow state
settingsConfiguration settings
user_resourcesUser ↔ resource audit links
cli_login_statesCLI OAuth state tracking
rgw_internal_metadataEnvironment markers
slack_integrationSlack OAuth tokens
schema_migrationsMigration tracking

For production, implement regular backups:

FrequencyRetentionPurpose
Hourly24 hoursPoint-in-time recovery
Daily30 daysOperational recovery
Weekly1 yearCompliance/audit
resource "aws_db_instance" "gateway" {
# ... other config
backup_retention_period = 30 # days
backup_window = "03:00-04:00" # UTC
# Enable PITR
delete_automated_backups = false
}
Terminal window
# Export full database
pg_dump -h $PGHOST -U $PGUSER $PGDATABASE | gzip > backup-$(date +%Y%m%d).sql.gz
# Export specific tables
pg_dump -h $PGHOST -U $PGUSER -t audit.audit_event $PGDATABASE > audit-backup.sql
Terminal window
# Restore full backup
gunzip -c backup-20240115.sql.gz | psql -h $PGHOST -U $PGUSER $PGDATABASE
# Restore from RDS snapshot
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier rack-gateway-restored \
--db-snapshot-identifier rds:rack-gateway-2024-01-15-03-00

Audit logs grow continuously. Estimate storage needs:

Events/DayAnnual StorageNotes
1,000~5 GBSmall team
10,000~50 GBMedium team
100,000~500 GBLarge/busy

For compliance, set appropriate retention:

Terminal window
# 400 days (annual audit + buffer)
convox env set LOG_RETENTION_DAYS=400
# 7 years (SOX/FINRA compliance)
convox env set LOG_RETENTION_DAYS=2557

For tamper-evident logs, enable S3 WORM anchoring:

Terminal window
convox env set \
AUDIT_ANCHOR_BUCKET=audit-anchors-prod \
AUDIT_ANCHOR_CHAIN_ID=production

See S3 WORM Storage for setup details.

For dedicated gateway databases:

-- Connection limits
ALTER SYSTEM SET max_connections = 100;
-- Memory settings
ALTER SYSTEM SET shared_buffers = '256MB';
ALTER SYSTEM SET work_mem = '16MB';
ALTER SYSTEM SET maintenance_work_mem = '64MB';
-- Write performance
ALTER SYSTEM SET wal_buffers = '16MB';
ALTER SYSTEM SET checkpoint_completion_target = 0.9;
-- Query optimization
ALTER SYSTEM SET effective_cache_size = '768MB';
ALTER SYSTEM SET random_page_cost = 1.1; -- For SSD
SELECT pg_reload_conf();

The gateway creates necessary indexes automatically. For high-volume deployments, monitor and maintain:

-- Check index usage
SELECT
relname AS table,
indexrelname AS index,
idx_scan AS scans,
idx_tup_read AS tuples_read,
idx_tup_fetch AS tuples_fetched
FROM pg_stat_user_indexes
ORDER BY idx_scan DESC;
-- Reindex if needed
REINDEX TABLE audit_events;

Monitor these PostgreSQL metrics:

MetricWarning ThresholdCritical Threshold
Connection usage70%90%
Replication lag1s10s
Transaction rate-Baseline + 200%
Disk usage70%85%
resource "aws_cloudwatch_metric_alarm" "db_connections" {
alarm_name = "rack-gateway-db-connections"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 2
metric_name = "DatabaseConnections"
namespace = "AWS/RDS"
period = 300
statistic = "Average"
threshold = 40
dimensions = {
DBInstanceIdentifier = aws_db_instance.gateway.identifier
}
}

Enable slow query logging:

ALTER SYSTEM SET log_min_duration_statement = 1000; -- Log queries > 1s
SELECT pg_reload_conf();
  • Place database in private subnet
  • Use security groups to restrict access
  • Enable SSL for connections
resource "aws_security_group" "rds" {
name = "rack-gateway-rds"
vpc_id = var.vpc_id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.gateway.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
  • Enable encryption at rest (RDS default)
  • Use SSL for connections in transit
  • Consider KMS for key management
Terminal window
# Force SSL connections
DATABASE_URL=postgres://user:pass@host:5432/db?sslmode=require

Create a dedicated database user:

-- Create role with minimal privileges
CREATE ROLE rack_gateway_app WITH LOGIN PASSWORD 'secure-password';
-- Grant necessary permissions
GRANT CONNECT ON DATABASE rack_gateway TO rack_gateway_app;
GRANT USAGE ON SCHEMA public TO rack_gateway_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO rack_gateway_app;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO rack_gateway_app;
-- For migrations (separate admin user)
CREATE ROLE rack_gateway_admin WITH LOGIN PASSWORD 'admin-password';
GRANT ALL PRIVILEGES ON DATABASE rack_gateway TO rack_gateway_admin;
Terminal window
# Test connection
psql $DATABASE_URL -c "SELECT 1"
# Check connection count
psql $DATABASE_URL -c "SELECT count(*) FROM pg_stat_activity"
# View active connections
psql $DATABASE_URL -c "SELECT * FROM pg_stat_activity WHERE datname = 'rack_gateway'"
Terminal window
# Check migration status
psql $DATABASE_URL -c "SELECT * FROM schema_migrations ORDER BY version"
# View gateway logs for migration errors
convox logs -a rack-gateway --filter migration
-- Find slow queries
SELECT query, calls, mean_time, total_time
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 10;
-- Check table sizes
SELECT relname, pg_size_pretty(pg_total_relation_size(relid))
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC;