Generating Secrets for VPS Deployment¶
Guide to generate and deploy secrets for the Portugal Odyssey platform on VPS.
Overview¶
You need three environment files on your VPS:
.env.shared- Shared infrastructure (PostgreSQL, Redis, RabbitMQ, MinIO, Grafana).env.qual- Qualification environment services.env.prod- Production environment services (if using production)
Step 1: Generate Secrets Locally¶
Run the secrets generation script from your local development machine:
Or directly:
This will create:
- infrastructure/compose/.env.shared
- infrastructure/compose/.env.qualification
- infrastructure/compose/.env.production
Step 2: Copy Files to VPS¶
Option A: Using SCP (Recommended)¶
# Copy shared secrets
scp infrastructure/compose/.env.shared root@qual.portugalodyssey.pt:/opt/po-platform/infrastructure/compose/
# Copy qualification secrets (note: rename to .env.qual)
scp infrastructure/compose/.env.qualification root@qual.portugalodyssey.pt:/opt/po-platform/.env.qual
# Copy production secrets (if needed)
scp infrastructure/compose/.env.production root@qual.portugalodyssey.pt:/opt/po-platform/.env.prod
Option B: Using Git (If files are committed)¶
⚠️ WARNING: Never commit .env files with real secrets! Only commit templates.
If you're using a secure method to transfer secrets (e.g., encrypted files, secret management), you can:
Option C: Manual Creation on VPS¶
If you prefer to generate secrets directly on the VPS:
# SSH into VPS
ssh root@qual.portugalodyssey.pt
# On VPS
cd /opt/po-platform
# Generate secrets
make secrets
# Rename qualification file to match Makefile expectations
mv infrastructure/compose/.env.qualification .env.qual
Step 3: Verify Files on VPS¶
After copying, verify the files exist:
# On VPS
cd /opt/po-platform
# Check shared secrets
ls -la infrastructure/compose/.env.shared
# Check qualification secrets
ls -la .env.qual
# Verify they have content (don't show full content for security)
head -5 infrastructure/compose/.env.shared
head -5 .env.qual
Step 4: Fill in External API Keys¶
The generated secrets include placeholders for external services. Edit the files and fill in:
.env.qual - Required External Keys:¶
# Payment Service (Stripe)
STRIPE_SECRET_KEY_QUAL=sk_test_...
STRIPE_PUBLISHABLE_KEY_QUAL=pk_test_...
STRIPE_WEBHOOK_SECRET_QUAL=whsec_...
# Notification Service (SMTP)
SMTP_HOST_QUAL=smtp.example.com
SMTP_PORT_QUAL=587
SMTP_USER_QUAL=apikey
SMTP_PASSWORD_QUAL=your_smtp_password
EMAIL_FROM_QUAL=noreply@qual.portugalodyssey.pt
# Google Maps
GOOGLE_MAPS_API_KEY=your_google_maps_api_key
# Auth Service
OIDC_CONFIDENTIAL_CLIENT_SECRET_QUAL=your_keycloak_client_secret
.env.shared - Optional External Keys:¶
Step 5: Set Proper Permissions¶
Ensure the files have correct permissions:
# On VPS
cd /opt/po-platform
# Set restrictive permissions (readable only by root)
chmod 600 infrastructure/compose/.env.shared
chmod 600 .env.qual
chmod 600 .env.prod # if exists
File Structure on VPS¶
Your VPS should have this structure:
/opt/po-platform/
├── infrastructure/
│ └── compose/
│ └── .env.shared # Shared infrastructure secrets
├── .env.qual # Qualification environment secrets
└── .env.prod # Production environment secrets (if using)
Verification¶
After setting up secrets, verify they're being read correctly:
# On VPS
cd /opt/po-platform
# Check shared infrastructure can read secrets
docker compose -f infrastructure/compose/shared.yml --env-file infrastructure/compose/.env.shared config | grep -E "(POSTGRES_PASSWORD|REDIS_PASSWORD|RABBITMQ_PASSWORD|MINIO_ROOT_PASSWORD)" | head -5
# Check qualification can read secrets
docker compose -f infrastructure/compose/qualification.yml --env-file .env.qual config | grep -E "(POSTGRES_PASSWORD_QUAL|DATABASE_URL)" | head -5
Note: The config command will show the resolved values, so be careful not to expose secrets in logs.
Troubleshooting¶
Missing .env.shared Error¶
If you see errors about missing .env.shared:
# On VPS
cd /opt/po-platform
# Check if file exists
ls -la infrastructure/compose/.env.shared
# If missing, generate it
make secrets
Empty Values in .env.qual¶
If your .env.qual has empty values (like you showed), you need to:
- Generate secrets locally:
make secrets - Copy
infrastructure/compose/.env.qualificationto VPS as.env.qual - Fill in external API keys manually
Secrets Not Matching Between Files¶
The script ensures shared infrastructure passwords match between .env.shared and .env.qual/.env.prod. If you manually edit one file, make sure to update the corresponding values in other files:
POSTGRES_PASSWORDin.env.shared=POSTGRES_PASSWORD_QUALin.env.qualREDIS_PASSWORDin.env.shared=REDIS_PASSWORD_QUALin.env.qualRABBITMQ_PASSWORDin.env.shared=RABBITMQ_PASSWORD_QUALin.env.qualMINIO_ROOT_PASSWORDin.env.shared=MINIO_ROOT_PASSWORD_QUALin.env.qual
Security Best Practices¶
- Never commit
.envfiles - They're in.gitignore - Use strong passwords - The script generates 24-character random passwords
- Rotate secrets regularly - Especially in production
- Limit file permissions - Use
chmod 600on all.envfiles - Use secret management - Consider using tools like HashiCorp Vault for production
See Also¶
- Secrets Management - Detailed secrets documentation
- Environment Setup - Environment configuration guide