7.8 KiB
Environment Variables Migration Guide
This guide helps you migrate from the old fragile environment variable setup to the new clean, robust system.
What Changed?
Before (Fragile & Overkill)
❌ Problems:
- Environment variables passed individually via SSH (12+ vars)
- Duplicate definitions in Dockerfile, docker-compose.yml, and deploy.yml
- Build args included runtime-only variables (SENTRY_DSN, MAIL_, REDIS_)
- No single source of truth
- Difficult to maintain and error-prone
# Old deploy.yml - FRAGILE!
ssh root@alpha.mintel.me \
"MAIL_FROM='${{ secrets.MAIL_FROM }}' \
MAIL_HOST='${{ secrets.MAIL_HOST }}' \
MAIL_PASSWORD='${{ secrets.MAIL_PASSWORD }}' \
MAIL_PORT='${{ secrets.MAIL_PORT }}' \
MAIL_RECIPIENTS='${{ secrets.MAIL_RECIPIENTS }}' \
MAIL_USERNAME='${{ secrets.MAIL_USERNAME }}' \
NEXT_PUBLIC_BASE_URL='${{ secrets.NEXT_PUBLIC_BASE_URL }}' \
... (12+ variables) \
/home/deploy/deploy.sh"
After (Clean & Robust)
✅ Benefits:
- Single
.envfile on server contains all runtime variables - Only
NEXT_PUBLIC_*variables passed as build args (3 vars) - Clear separation: build-time vs runtime
- Easy to maintain and update
- Single source of truth per environment
# New deploy.yml - CLEAN!
ssh root@alpha.mintel.me "/home/deploy/deploy.sh"
Migration Steps
Step 1: Update Gitea Secrets
Remove these secrets (no longer needed in CI/CD):
- ❌
MAIL_FROM - ❌
MAIL_HOST - ❌
MAIL_PASSWORD - ❌
MAIL_PORT - ❌
MAIL_RECIPIENTS - ❌
MAIL_USERNAME - ❌
NODE_ENV - ❌
REDIS_URL - ❌
REDIS_KEY_PREFIX - ❌
SENTRY_DSN(from build args)
Keep these secrets (still needed for build):
- ✅
NEXT_PUBLIC_BASE_URL - ✅
NEXT_PUBLIC_UMAMI_WEBSITE_ID - ✅
NEXT_PUBLIC_UMAMI_SCRIPT_URL - ✅
REGISTRY_USER - ✅
REGISTRY_PASS - ✅
ALPHA_SSH_KEY - ✅
GOTIFY_URL - ✅
GOTIFY_TOKEN
Step 2: Create .env File on Server
SSH to the production server and create the .env file:
ssh root@alpha.mintel.me
# Create .env file
cat > /home/deploy/sites/klz-cables.com/.env << 'EOF'
# Application
NODE_ENV=production
NEXT_PUBLIC_BASE_URL=https://klz-cables.com
# Analytics
NEXT_PUBLIC_UMAMI_WEBSITE_ID=your-actual-id
NEXT_PUBLIC_UMAMI_SCRIPT_URL=https://analytics.infra.mintel.me/script.js
# Error Tracking
SENTRY_DSN=your-actual-dsn
# Email
MAIL_HOST=smtp.eu.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=your-actual-username
MAIL_PASSWORD=your-actual-password
MAIL_FROM=KLZ Cables <noreply@klz-cables.com>
MAIL_RECIPIENTS=info@klz-cables.com
# Redis
REDIS_URL=redis://redis:6379/2
REDIS_KEY_PREFIX=klz:
# Varnish
VARNISH_CACHE_SIZE=256m
EOF
# Secure the file
chmod 600 /home/deploy/sites/klz-cables.com/.env
chown deploy:deploy /home/deploy/sites/klz-cables.com/.env
Important: Replace all your-actual-* placeholders with real values from your old Gitea secrets.
Step 3: Update Deployment Script
Update /home/deploy/deploy.sh to use the new approach:
cat > /home/deploy/deploy.sh << 'EOF'
#!/bin/bash
set -e
PROJECT_DIR="/home/deploy/sites/klz-cables.com"
echo "╔══════════════════════════════════════════════════════════════════════════════╗"
echo "║ KLZ Cables - Deployment Script ║"
echo "╚══════════════════════════════════════════════════════════════════════════════╝"
echo ""
cd "$PROJECT_DIR"
# Check if .env file exists
if [ ! -f .env ]; then
echo "❌ ERROR: .env file not found at $PROJECT_DIR/.env"
exit 1
fi
echo "🔐 Logging into Docker registry..."
echo "$REGISTRY_PASS" | docker login registry.infra.mintel.me -u "$REGISTRY_USER" --password-stdin
echo "🔄 Pulling latest image..."
docker pull registry.infra.mintel.me/mintel/klz-cables.com:latest
echo "🔄 Stopping existing containers..."
docker-compose down
echo "🚀 Starting new containers..."
docker-compose up -d
echo "⏳ Waiting for services to be healthy..."
sleep 10
echo "🔍 Checking service status..."
docker-compose ps
echo ""
echo "✅ Deployment complete!"
EOF
chmod +x /home/deploy/deploy.sh
Step 4: Deploy Updated Code
The new code is already in the repository. Just push to trigger deployment:
git push origin main
The CI/CD workflow will:
- Build with only
NEXT_PUBLIC_*build args - Push to registry
- SSH to server and run deploy.sh
- Deploy.sh will use the
.envfile for runtime vars
Step 5: Verify Migration
After deployment, verify everything works:
# SSH to server
ssh root@alpha.mintel.me
# Check containers are running
cd /home/deploy/sites/klz-cables.com
docker-compose ps
# Verify environment variables are loaded
docker-compose exec app env | grep -E "NODE_ENV|NEXT_PUBLIC|MAIL|REDIS"
# Check application logs
docker-compose logs -f app
# Test the website
curl -I https://klz-cables.com
Comparison Table
| Aspect | Before | After |
|---|---|---|
| Gitea Secrets | 15+ secrets | 8 secrets |
| Build Args | 4 vars (including runtime-only) | 3 vars (NEXT_PUBLIC_* only) |
| Runtime Vars | Passed via SSH command | Loaded from .env file |
| Maintenance | Update in 3 places | Update in 1 place |
| Security | Secrets in CI logs | Secrets only on server |
| Clarity | Confusing duplication | Clear separation |
| Robustness | Fragile SSH command | Robust file-based config |
Rollback Plan
If you need to rollback to the old system:
-
Revert the changes in git:
git revert HEAD git push origin main -
Re-add the removed Gitea secrets
-
The old deployment will work again
FAQ
Q: Why keep NEXT_PUBLIC_* in both build args and .env file?
A: NEXT_PUBLIC_* variables are special in Next.js - they're embedded into the JavaScript bundle at build time. They must be provided as build args. However, they're also needed at runtime for server-side rendering, so they're in the .env file too.
Q: Can I update environment variables without rebuilding?
A: Yes, for runtime-only variables (MAIL_, REDIS_, SENTRY_DSN, etc.). Just edit the .env file on the server and restart containers:
nano /home/deploy/sites/klz-cables.com/.env
docker-compose down && docker-compose up -d
For NEXT_PUBLIC_* variables, you need to rebuild the Docker image since they're baked into the client bundle.
Q: Where should I store the .env file backup?
A: Keep a secure backup outside the server:
# Download from server
scp root@alpha.mintel.me:/home/deploy/sites/klz-cables.com/.env \
~/secure-backups/klz-cables.env.backup
# Store in password manager or encrypted storage
Q: What if I accidentally commit .env to git?
A:
- Remove it immediately:
git rm .env && git commit -m "Remove .env" - Rotate all credentials in the file
- Update the
.gitignoreto ensure it doesn't happen again (already done)
Support
If you encounter issues during migration:
- Check the logs:
docker-compose logs -f app - Verify .env file exists and has correct permissions
- Ensure all required variables are set
- Review DEPLOYMENT.md for detailed troubleshooting
Summary
The new system is:
- ✅ Simpler: One .env file instead of scattered variables
- ✅ Cleaner: Clear separation of build vs runtime
- ✅ Robust: File-based config instead of fragile SSH commands
- ✅ Secure: Secrets stay on server, not in CI logs
- ✅ Maintainable: Single source of truth per environment
You've successfully migrated from a fragile, overkill setup to a clean, production-ready configuration! 🎉