This guide provides step-by-step instructions for migrating from the current ephemeral SQLite setup to persistent PostgreSQL database.
- Problem: Data loss occurs on every ECS deployment
- Cause: SQLite database stored in ephemeral container storage
- Impact: Users, workspaces, and settings are lost during updates
The solution implements:
- RDS PostgreSQL instance for persistent storage
- AWS Secrets Manager for secure credential management
- Updated ECS task definition with database connection
- Terraform infrastructure for automated deployment
If you have existing data that needs to be preserved:
# Connect to running container
TASK_ARN=$(aws ecs list-tasks --cluster coder-cluster --service-name coder-service --region us-east-1 --query 'taskArns[0]' --output text)
# Get container ID (if you have ECS Exec enabled)
aws ecs execute-command \
--cluster coder-cluster \
--task $TASK_ARN \
--container coder \
--command "/bin/bash" \
--interactive# Clone/update the infrastructure files
# Ensure you have: aws-rds.tf, aws-secrets.tf, coder-task-definition.json
# Set database password
export TF_VAR_db_password="your-secure-password"
# Deploy infrastructure
terraform init
terraform plan
terraform applyThe task definition has been updated to include:
- Database connection: Via
CODER_POSTGRES_URLsecret - IAM permissions: For Secrets Manager access
- Security groups: For ECS-to-RDS communication
# Use the deployment script
./deploy-with-database.sh
# Or manually:
# 1. Build and push new image
# 2. Register updated task definition
# 3. Update ECS serviceAfter deployment, check the logs:
# Check container logs
aws logs tail /ecs/coder --follow --region us-east-1Look for successful database connection messages.
- Instance:
db.t3.micro(suitable for development) - Storage: 20GB, auto-scaling to 100GB
- Backup: 7-day retention
- Security: Encrypted storage, VPC-only access
- Secret:
coder-postgres-url - Access: Limited to ECS task execution role
- Format: PostgreSQL connection string
- ECS Security Group: Allows inbound on port 3000
- RDS Security Group: Allows inbound on port 5432 from ECS
# 1. Create a test user/workspace
# 2. Deploy a new version
# 3. Verify data survives deployment# Connect to RDS instance
psql -h <rds-endpoint> -U coder -d coder- Check Coder web interface loads
- Verify user authentication works
- Test workspace creation
If issues occur, you can rollback to the previous SQLite setup:
# 1. Remove secrets section from task definition
# 2. Revert to original executionRoleArn
# 3. Deploy previous task definition- db.t3.micro: ~$13/month
- Storage: ~$2/month for 20GB
- Backup: Included in storage cost
- Approximately $15-20/month for persistent database
- Use strong database passwords (stored in Secrets Manager)
- Enable VPC-only access for RDS instance
- Use IAM roles instead of hardcoded credentials
- Enable encryption for database storage
- Monitor access logs via CloudWatch
-
"Connection refused" errors
- Check security group rules
- Verify RDS instance is running
- Confirm subnet group configuration
-
"Authentication failed" errors
- Verify secret value in Secrets Manager
- Check IAM role permissions
- Confirm database user exists
-
"Database does not exist" errors
- Verify database name in connection string
- Check if database was created during RDS setup
# Check RDS status
aws rds describe-db-instances --db-instance-identifier coder-postgres
# Check secret value
aws secretsmanager get-secret-value --secret-id coder-postgres-url
# Check ECS task logs
aws logs tail /ecs/coder --follow
# Test database connection
psql -h <endpoint> -U coder -d coder -c "SELECT version();"- Backup existing data (if any)
- Deploy RDS infrastructure with Terraform
- Update IAM roles and permissions
- Deploy updated task definition
- Verify database connection in logs
- Test data persistence across deployments
- Monitor application performance
- Update monitoring/alerting for database
After successful migration:
- Set up monitoring for database performance
- Configure automated backups if needed
- Implement SSL/TLS for database connections
- Set up database maintenance windows
- Create disaster recovery procedures
If you encounter issues:
- Check CloudWatch logs for error messages
- Verify security group configurations
- Test database connectivity manually
- Review Terraform outputs for correct values