Skip to content

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:

  1. .env.shared - Shared infrastructure (PostgreSQL, Redis, RabbitMQ, MinIO, Grafana)
  2. .env.qual - Qualification environment services
  3. .env.prod - Production environment services (if using production)

Step 1: Generate Secrets Locally

Run the secrets generation script from your local development machine:

# From project root
make secrets

Or directly:

./infrastructure/scripts/generate-secrets.sh

This will create: - infrastructure/compose/.env.shared - infrastructure/compose/.env.qualification - infrastructure/compose/.env.production

Step 2: Copy Files to VPS

# 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:

# On VPS
cd /opt/po-platform
git pull
# Then manually copy/decrypt the .env files

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:

# Traefik (if using Cloudflare DNS challenge)
CF_DNS_API_TOKEN=your_cloudflare_token

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:

  1. Generate secrets locally: make secrets
  2. Copy infrastructure/compose/.env.qualification to VPS as .env.qual
  3. 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_PASSWORD in .env.shared = POSTGRES_PASSWORD_QUAL in .env.qual
  • REDIS_PASSWORD in .env.shared = REDIS_PASSWORD_QUAL in .env.qual
  • RABBITMQ_PASSWORD in .env.shared = RABBITMQ_PASSWORD_QUAL in .env.qual
  • MINIO_ROOT_PASSWORD in .env.shared = MINIO_ROOT_PASSWORD_QUAL in .env.qual

Security Best Practices

  1. Never commit .env files - They're in .gitignore
  2. Use strong passwords - The script generates 24-character random passwords
  3. Rotate secrets regularly - Especially in production
  4. Limit file permissions - Use chmod 600 on all .env files
  5. Use secret management - Consider using tools like HashiCorp Vault for production

See Also