Some checks failed
Build & Deploy KLZ Cables / build-and-deploy (push) Failing after 5m50s
273 lines
10 KiB
Markdown
273 lines
10 KiB
Markdown
# 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!
|