This commit is contained in:
276
docs/ENV_MIGRATION.md
Normal file
276
docs/ENV_MIGRATION.md
Normal file
@@ -0,0 +1,276 @@
|
||||
# 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
|
||||
|
||||
```yaml
|
||||
# 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 `.env` file 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
|
||||
|
||||
```yaml
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
git push origin main
|
||||
```
|
||||
|
||||
The CI/CD workflow will:
|
||||
1. Build with only `NEXT_PUBLIC_*` build args
|
||||
2. Push to registry
|
||||
3. SSH to server and run deploy.sh
|
||||
4. Deploy.sh will use the `.env` file for runtime vars
|
||||
|
||||
### Step 5: Verify Migration
|
||||
|
||||
After deployment, verify everything works:
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
1. Revert the changes in git:
|
||||
```bash
|
||||
git revert HEAD
|
||||
git push origin main
|
||||
```
|
||||
|
||||
2. Re-add the removed Gitea secrets
|
||||
|
||||
3. 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:
|
||||
```bash
|
||||
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:
|
||||
```bash
|
||||
# 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:
|
||||
1. Remove it immediately: `git rm .env && git commit -m "Remove .env"`
|
||||
2. Rotate all credentials in the file
|
||||
3. Update the `.gitignore` to ensure it doesn't happen again (already done)
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter issues during migration:
|
||||
|
||||
1. Check the logs: `docker-compose logs -f app`
|
||||
2. Verify .env file exists and has correct permissions
|
||||
3. Ensure all required variables are set
|
||||
4. Review [DEPLOYMENT.md](./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! 🎉
|
||||
Reference in New Issue
Block a user