# Environment Variables Cleanup - Summary ## What Was Done Cleaned up the fragile, overkill environment variable mess and replaced it with a simple, clean, robust **fully automated** system. ## Changes Made ### 1. Dockerfile ✅ **Before**: 4 build args including runtime-only variables (SENTRY_DSN) **After**: 3 build args - only `NEXT_PUBLIC_*` variables that need to be baked into the client bundle ```dockerfile # Only these build args now: ARG NEXT_PUBLIC_BASE_URL ARG NEXT_PUBLIC_UMAMI_WEBSITE_ID ARG NEXT_PUBLIC_UMAMI_SCRIPT_URL ``` ### 2. docker-compose.yml ✅ **Before**: 12+ individual environment variables listed **After**: Single `env_file: .env` directive ```yaml app: image: registry.infra.mintel.me/mintel/klz-cables.com:latest env_file: - .env # All runtime vars loaded from here ``` ### 3. .gitea/workflows/deploy.yml ✅ **Before**: Passing 12+ environment variables individually via SSH command (fragile!) **After**: **Fully automated** - workflow creates `.env` file from Gitea secrets and uploads it ```yaml # Before (FRAGILE): ssh root@alpha.mintel.me \ "MAIL_FROM='${{ secrets.MAIL_FROM }}' \ MAIL_HOST='${{ secrets.MAIL_HOST }}' \ ... (12+ variables) \ /home/deploy/deploy.sh" # After (AUTOMATED): # 1. Create .env from secrets cat > /tmp/klz-cables.env << EOF NODE_ENV=production NEXT_PUBLIC_BASE_URL=${{ secrets.NEXT_PUBLIC_BASE_URL }} # ... all other vars from secrets EOF # 2. Upload to server scp /tmp/klz-cables.env root@alpha.mintel.me:/home/deploy/sites/klz-cables.com/.env # 3. Deploy ssh root@alpha.mintel.me "cd /home/deploy/sites/klz-cables.com && docker-compose up -d" ``` ### 4. New Files Created ✅ - **`.env.production`** - Template for reference (not used in automation) - **`docs/DEPLOYMENT.md`** - Complete deployment guide - **`docs/SERVER_SETUP.md`** - Server setup instructions - **`docs/ENV_MIGRATION.md`** - Migration guide from old to new system ### 5. Updated Files ✅ - **`.env.example`** - Clear documentation of all variables with build-time vs runtime notes ## Architecture ### Build Time (CI/CD) ``` Gitea Workflow ↓ Only passes NEXT_PUBLIC_* as --build-arg ↓ Docker Build ↓ Validates env vars ↓ Bakes NEXT_PUBLIC_* into client bundle ↓ Push to Registry ``` ### Runtime (Production Server) - FULLY AUTOMATED ``` Gitea Secrets ↓ Workflow creates .env file ↓ SCP uploads to server ↓ Secured (chmod 600, chown deploy:deploy) ↓ docker-compose.yml (env_file: .env) ↓ Loads .env into container ↓ Application runs with full config ``` ## Key Benefits ### 1. Simplicity - **Before**: 15+ Gitea secrets, variables in 3+ places - **After**: All secrets in Gitea, automatically deployed ### 2. Clarity - **Before**: Confusing duplication, unclear which vars go where - **After**: Clear separation - build args vs runtime env file ### 3. Robustness - **Before**: Fragile SSH command with 12+ inline variables - **After**: Robust automated file generation and upload ### 4. Security - **Before**: Secrets potentially exposed in CI logs - **After**: Secrets masked in logs, .env auto-secured on server ### 5. Maintainability - **Before**: Update in 3 places (Dockerfile, docker-compose.yml, deploy.yml) - **After**: Update Gitea secrets only - deployment is automatic ### 6. **Zero Manual Steps** 🎉 - **Before**: Manual .env file creation on server (error-prone, can be forgotten) - **After**: **Fully automated** - .env file created and uploaded on every deployment ## What You Need to Do ### Required Gitea Secrets Ensure these secrets are configured in your Gitea repository: **Build-Time (NEXT_PUBLIC_*):** - `NEXT_PUBLIC_BASE_URL` - Production URL (e.g., `https://klz-cables.com`) - `NEXT_PUBLIC_UMAMI_WEBSITE_ID` - Umami analytics ID - `NEXT_PUBLIC_UMAMI_SCRIPT_URL` - Umami script URL **Runtime:** - `SENTRY_DSN` - Error tracking DSN - `MAIL_HOST` - SMTP server - `MAIL_PORT` - SMTP port (e.g., `587`) - `MAIL_USERNAME` - SMTP username - `MAIL_PASSWORD` - SMTP password - `MAIL_FROM` - Sender email - `MAIL_RECIPIENTS` - Recipient emails (comma-separated) **Infrastructure:** - `REGISTRY_USER` - Docker registry username - `REGISTRY_PASS` - Docker registry password - `ALPHA_SSH_KEY` - SSH private key for deployment server **Notifications:** - `GOTIFY_URL` - Gotify notification server URL - `GOTIFY_TOKEN` - Gotify application token ### That's It! **No manual steps required.** Just push to main branch and the workflow will: 1. ✅ Build Docker image with NEXT_PUBLIC_* build args 2. ✅ Create .env file from all secrets 3. ✅ Upload .env to server 4. ✅ Secure .env file (600 permissions, deploy:deploy ownership) 5. ✅ Pull latest image 6. ✅ Deploy with docker-compose ## Files Changed ``` Modified: ├── Dockerfile (removed redundant build args) ├── docker-compose.yml (use env_file instead of individual vars) ├── .gitea/workflows/deploy.yml (automated .env creation & upload) ├── .env.example (clear documentation) ├── lib/services/create-services.ts (removed redundant dotenv usage) └── scripts/migrate-*.ts (removed redundant dotenv usage) Created: ├── .env.production (reference template) ├── docs/DEPLOYMENT.md (deployment guide) ├── docs/SERVER_SETUP.md (server setup guide) ├── docs/ENV_MIGRATION.md (migration guide) └── ENV_CLEANUP_SUMMARY.md (this file) ``` ## Deployment Flow ``` ┌─────────────────────────────────────────────────────────────┐ │ Developer pushes to main branch │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ Gitea Workflow Triggered │ │ │ │ 1. Build Docker image (NEXT_PUBLIC_* build args) │ │ 2. Push to registry │ │ 3. Generate .env from secrets │ │ 4. Upload .env to server via SCP │ │ 5. SSH to server and deploy │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ Production Server │ │ │ │ 1. .env file secured (600, deploy:deploy) │ │ 2. Docker login to registry │ │ 3. Pull latest image │ │ 4. docker-compose down │ │ 5. docker-compose up -d (loads .env) │ │ 6. Health checks pass │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ ✅ Deployment Complete - Gotify Notification Sent │ └─────────────────────────────────────────────────────────────┘ ``` ## Comparison: Before vs After | Aspect | Before | After | |--------|--------|-------| | **Gitea Secrets** | 15+ secrets | Same secrets, better organized | | **Build Args** | 4 vars (including runtime-only) | 3 vars (NEXT_PUBLIC_* only) | | **Runtime Vars** | Passed via SSH command | Auto-generated .env file | | **Manual Steps** | ❌ Manual .env creation | ✅ Fully automated | | **Maintenance** | Update in 3 places | Update Gitea secrets only | | **Security** | Secrets in CI logs | Secrets masked, .env secured | | **Clarity** | Confusing duplication | Clear separation | | **Robustness** | Fragile SSH command | Robust automation | | **Error-Prone** | ❌ Can forget .env | ✅ Impossible to forget | ## Documentation - **[DEPLOYMENT.md](docs/DEPLOYMENT.md)** - Complete deployment guide - **[SERVER_SETUP.md](docs/SERVER_SETUP.md)** - Server setup instructions (mostly automated now) - **[ENV_MIGRATION.md](docs/ENV_MIGRATION.md)** - Migration from old to new system - **[.env.example](.env.example)** - Environment variables reference - **[.env.production](.env.production)** - Production template (for reference) ## Troubleshooting ### Deployment Fails 1. **Check Gitea secrets** - Ensure all required secrets are set 2. **Check workflow logs** - Look for specific error messages 3. **SSH to server** - Verify .env file exists and has correct permissions 4. **Check container logs** - `docker-compose logs -f app` ### .env File Issues The workflow automatically: - Creates .env from secrets - Uploads to server - Sets 600 permissions - Sets deploy:deploy ownership If there are issues, check the workflow logs for the "📝 Preparing environment configuration" step. ### Missing Environment Variables If a variable is missing: 1. Add it to Gitea secrets 2. Update `.gitea/workflows/deploy.yml` to include it in the .env generation 3. Push to trigger new deployment --- **Result**: Environment variable management is now simple, clean, robust, and **fully automated**! 🎉 No more manual .env file creation. No more forgotten configuration. No more fragile SSH commands. Just push and deploy!