mirror of
https://github.com/taylanbakircioglu/haproxy-openmanager.git
synced 2026-09-21 01:53:24 +00:00
ef26860df9
Until now the only record of what happened was `user_activity_logs`, which stores non-GET 2xx operations with no bodies. When something failed you could see that a counter went up, never what was sent or what came back. This adds one queryable timeline covering both directions: - inbound: every API call, including GETs and including 4xx/5xx, with the user, client IP, status, duration and — redacted, size-capped — the request and response bodies. - outbound: every HTTP call the backend makes, tagged with who it went to (ACME/Let's Encrypt, Cloudflare, GoDaddy, HAProxy stats, agents, the ACME diagnostics probe). Outbound rows inherit the inbound request's id, so one operator action and the CA/DNS calls it triggered read as a single trace: opening a failed "Request Certificate" shows the exact POST /acme/new-order and the CA's 429 underneath. Implementation notes: - Capture is a pure-ASGI middleware that TEES the request and response streams rather than draining them. `await request.body()` inside a BaseHTTPMiddleware would consume the receive channel and break the raw-body agent heartbeat handler. Registered last so it is outermost: it then sees the final client-visible response and seeds correlation_id_context before the error handler reads it. - Rows are written by a batching background writer with a bounded queue, so the request path never awaits the database and a saturated logger drops rows visibly (surfaced on the page) instead of blocking. Redaction runs on the writer, off the request coroutine. - Secrets never land: headers are an allowlist with Authorization/Cookie kept only as a presence marker; body keys and value shapes are redacted (passwords, tokens, api_token, API keys, private-key PEMs, JWTs); the ACME JWS request body is never stored, because a stored protected+signature pair is a replayable credential — a summary is logged instead; DNS-provider errors record only the exception type; the ACME HTTP-01 challenge endpoint is excluded so key_authorization is never captured. - Retention is operator-configurable in Settings -> Request Log: separate day counts for successful and failed rows (7 / 30) plus a hard row cap (500k), whichever is reached first. Pruned in batches under a Postgres advisory lock, with the day counts bound as parameters, never interpolated. - New permissions requestlog.read / requestlog.manage. super_admin and security_admin get both, operator gets read, viewer gets neither. Schema: one new table (request_logs) plus its settings seed, SCHEMA_VERSION 10 -> 11, auto-migrated. No existing table altered, no agent or rendered-config change. Kill switches: REQUEST_LOG_ENABLED=false (middleware never registered) or the `enabled` toggle in Settings. Tests: 245 new (7 backend files + 1 frontend), full suite 1655 backend + 17 frontend passing.
324 lines
7.6 KiB
Markdown
324 lines
7.6 KiB
Markdown
# Configuration Guide - HAProxy OpenManager
|
||
|
||
## 📋 Yapılandırma Dosyaları
|
||
|
||
### Dosya Yapısı
|
||
|
||
```
|
||
haproxy-openmanager/
|
||
├── .env.template # ✅ Template (GIT'e commit edilir)
|
||
├── .env # ❌ Gerçek config (GIT'e commit EDİLMEZ)
|
||
├── .gitignore # .env dosyalarını korur
|
||
└── CONFIG.md # Bu dosya
|
||
```
|
||
|
||
## 🎯 Quick Start
|
||
|
||
### 1. Template'den Config Oluşturma
|
||
|
||
```bash
|
||
# Template'i kopyala
|
||
cp .env.template .env
|
||
|
||
# Gerçek değerleri düzenle
|
||
nano .env
|
||
```
|
||
|
||
### 2. Örnek Yapılandırmalar
|
||
|
||
#### Development (Local)
|
||
```bash
|
||
# .env dosyası
|
||
PUBLIC_URL=http://localhost:8000
|
||
MANAGEMENT_BASE_URL=http://localhost:8000
|
||
DEBUG=True
|
||
LOG_LEVEL=DEBUG
|
||
```
|
||
|
||
#### Staging
|
||
```bash
|
||
# .env dosyası veya K8s ConfigMap
|
||
PUBLIC_URL=https://haproxy-staging.example.com
|
||
MANAGEMENT_BASE_URL=https://haproxy-staging.example.com
|
||
DEBUG=False
|
||
LOG_LEVEL=INFO
|
||
```
|
||
|
||
#### Production (OpenShift)
|
||
```bash
|
||
# K8s ConfigMap: k8s/manifests/07-configmaps.yaml
|
||
data:
|
||
PUBLIC_URL: 'https://haproxy-manager.example.com'
|
||
MANAGEMENT_BASE_URL: 'https://haproxy-manager.example.com'
|
||
DEBUG: 'False'
|
||
LOG_LEVEL: 'INFO'
|
||
```
|
||
|
||
## 🔐 Güvenlik
|
||
|
||
### Hassas Bilgiler
|
||
|
||
`.env` dosyası hassas bilgiler içerir:
|
||
- ❌ Database şifreleri
|
||
- ❌ Secret key'ler
|
||
- ❌ API token'ları
|
||
|
||
**Bu yüzden**:
|
||
- ✅ `.env` → `.gitignore`'da (commit edilmez)
|
||
- ✅ `.env.template` → Git'e commit edilir (örnek değerler)
|
||
- ✅ Production'da: Kubernetes Secrets kullan
|
||
|
||
### .gitignore Kontrolü
|
||
|
||
```bash
|
||
# .env dosyalarının ignore edildiğini kontrol et
|
||
grep "^\.env" .gitignore
|
||
|
||
# Çıktı olmalı:
|
||
# .env
|
||
# .env.local
|
||
# .env.development.local
|
||
# .env.test.local
|
||
# .env.production.local
|
||
```
|
||
|
||
## 📚 Environment Variable Detayları
|
||
|
||
### PUBLIC_URL
|
||
|
||
**Ne İşe Yarar**: Agent kurulum script'lerinde kullanılır
|
||
|
||
**Örnekler**:
|
||
```bash
|
||
# Development
|
||
PUBLIC_URL=http://localhost:8000
|
||
|
||
# Production
|
||
PUBLIC_URL=https://haproxy-manager.example.com
|
||
|
||
# OpenShift
|
||
PUBLIC_URL=https://haproxy-manager.example.com
|
||
```
|
||
|
||
**Nasıl Kullanılır**:
|
||
1. Agent Management sayfasından "Generate Install Script"
|
||
2. Script içinde `{{MANAGEMENT_URL}}` bu değerle değiştirilir
|
||
3. Agent bu URL'ye bağlanarak backend'i dinler
|
||
|
||
### REACT_APP_API_URL
|
||
|
||
**Ne İşe Yarar**: Frontend'in backend'e bağlanacağı URL
|
||
|
||
**Özel Durum**:
|
||
```bash
|
||
# Boş bırakılırsa → Auto-detect (production için önerilen)
|
||
REACT_APP_API_URL=
|
||
|
||
# Development için explicit
|
||
REACT_APP_API_URL=http://localhost:8000
|
||
```
|
||
|
||
**Auto-detect Mantığı**:
|
||
```javascript
|
||
// frontend/src/utils/api.js
|
||
if (process.env.REACT_APP_API_URL) {
|
||
return process.env.REACT_APP_API_URL;
|
||
}
|
||
|
||
// Production'da same-origin kullan
|
||
if (window.location) {
|
||
return `${window.location.protocol}//${window.location.hostname}`;
|
||
}
|
||
```
|
||
|
||
### REQUEST_LOG_ENABLED (v1.11.0)
|
||
|
||
**Ne İşe Yarar**: Request/Response Log özelliğinin sert (hard) kill-switch'i. `false` yapıldığında
|
||
loglama middleware'i ASGI zincirine **hiç eklenmez**, yazıcı ve retention görevleri başlatılmaz —
|
||
yani sıfır ek yük, ayar okuması bile yapılmaz. Değişiklik için restart gerekir.
|
||
|
||
**Örnekler**:
|
||
```bash
|
||
# Varsayılan: açık
|
||
REQUEST_LOG_ENABLED=true
|
||
|
||
# Tamamen kapat (ör. çok yüksek trafikli kurulum, veya regülasyon gereği)
|
||
REQUEST_LOG_ENABLED=false
|
||
```
|
||
|
||
**Nasıl Kullanılır**:
|
||
1. Restart gerektirmeden kapatmak isterseniz bunun yerine **Settings → Request Log → Enable request
|
||
log** anahtarını kullanın; o anında etkili olur.
|
||
2. Retention süreleri, gövde (body) yakalama, örnekleme oranı ve hariç tutulan path'ler bu env
|
||
değişkeniyle değil, veritabanındaki `requestlog.*` ayarlarıyla yönetilir — arayüzden düzenlenir.
|
||
3. Disk büyümesi asıl operasyonel konudur: sırasıyla `sample_rate`'i düşürün, `capture_get`'i
|
||
kapatın, `capture_bodies`'i kapatın, sonra `success_retention_days`'i kısaltın.
|
||
|
||
### REQUEST_LOG_QUEUE_MAX / REQUEST_LOG_BATCH_SIZE / REQUEST_LOG_FLUSH_MS (v1.11.0)
|
||
|
||
**Ne İşe Yarar**: Log satırlarını yazan arka plan görevinin ayarları. Satırlar sınırlı bir kuyruğa
|
||
konur ve toplu (batch) INSERT ile yazılır; böylece istek yolu asla veritabanını beklemez.
|
||
|
||
**Örnekler**:
|
||
```bash
|
||
# Worker başına kuyruk derinliği. Dolduğunda satırlar DÜŞÜRÜLÜR (sayılır ve
|
||
# Request Log sayfasında gösterilir), istek bloklanmaz.
|
||
REQUEST_LOG_QUEUE_MAX=2000
|
||
|
||
# Tek INSERT'te kaç satır yazılacağı (havuzdan istek başına değil, batch başına
|
||
# bir bağlantı alınır)
|
||
REQUEST_LOG_BATCH_SIZE=100
|
||
|
||
# Yarım dolu bir batch'in en fazla ne kadar bekletileceği (ms)
|
||
REQUEST_LOG_FLUSH_MS=500
|
||
```
|
||
|
||
**Nasıl Kullanılır**:
|
||
1. Request Log sayfasında "rows dropped" uyarısı görüyorsanız önce `REQUEST_LOG_QUEUE_MAX`'ı
|
||
artırın; sorun devam ederse `sample_rate`'i düşürün.
|
||
2. Bu üç değer worker başınadır — `UVICORN_WORKERS` arttıkça toplam bellek de o oranda artar.
|
||
|
||
## 🚀 Deployment Senaryoları
|
||
|
||
### Docker Compose
|
||
|
||
```bash
|
||
# 1. .env dosyası oluştur
|
||
cp .env.template .env
|
||
|
||
# 2. Değerleri düzenle
|
||
nano .env
|
||
|
||
# 3. Başlat
|
||
docker-compose up -d
|
||
|
||
# 4. Kontrol et
|
||
docker-compose logs backend | grep "PUBLIC_URL"
|
||
```
|
||
|
||
### Kubernetes/OpenShift
|
||
|
||
```bash
|
||
# 1. ConfigMap'i düzenle
|
||
vim k8s/manifests/07-configmaps.yaml
|
||
|
||
# 2. Apply
|
||
kubectl apply -f k8s/manifests/
|
||
|
||
# 3. Kontrol et
|
||
kubectl get configmap backend-config -n haproxy-manager -o yaml
|
||
```
|
||
|
||
### Manuel (Development)
|
||
|
||
```bash
|
||
# 1. Backend
|
||
cd backend
|
||
cp ../.env.template .env
|
||
export $(cat .env | xargs)
|
||
uvicorn main:app --reload
|
||
|
||
# 2. Frontend (başka terminal)
|
||
cd frontend
|
||
export REACT_APP_API_URL=http://localhost:8000
|
||
npm start
|
||
```
|
||
|
||
## 🔧 Troubleshooting
|
||
|
||
### Agent Script'inde Yanlış URL
|
||
|
||
**Sorun**: Agent script hala eski URL içeriyor
|
||
|
||
**Çözüm**:
|
||
```bash
|
||
# 1. Backend'deki değeri kontrol et
|
||
docker exec haproxy-openmanager-backend env | grep PUBLIC_URL
|
||
|
||
# 2. Container'ı yeniden başlat
|
||
docker-compose restart backend
|
||
|
||
# 3. Yeni script oluştur
|
||
# UI'dan tekrar "Generate Install Script"
|
||
```
|
||
|
||
### Frontend Backend'e Bağlanamıyor
|
||
|
||
**Sorun**: CORS hatası veya connection refused
|
||
|
||
**Çözüm**:
|
||
```bash
|
||
# 1. Frontend config'i kontrol et
|
||
docker exec haproxy-openmanager-frontend env | grep REACT_APP_API_URL
|
||
|
||
# 2. Browser console'da kontrol et
|
||
# [API Config] Base URL: http://localhost:8000
|
||
|
||
# 3. Network sekmesinde request URL'i kontrol et
|
||
```
|
||
|
||
## 📖 En İyi Pratikler
|
||
|
||
### ✅ YAPILMASI GEREKENLER
|
||
|
||
1. **Her ortam için ayrı değerler**
|
||
```
|
||
Dev: PUBLIC_URL=http://localhost:8000
|
||
Staging: PUBLIC_URL=https://staging.example.com
|
||
Prod: PUBLIC_URL=https://prod.example.com
|
||
```
|
||
|
||
2. **Template'i güncelle**
|
||
- Yeni variable eklendiğinde `.env.template`'e ekle
|
||
- Dokümantasyon ile birlikte
|
||
|
||
3. **Secrets kullan (Production)**
|
||
```yaml
|
||
# K8s Secret
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: backend-secret
|
||
data:
|
||
SECRET_KEY: <base64-encoded>
|
||
```
|
||
|
||
### ❌ YAPILMAMASI GEREKENLER
|
||
|
||
1. **`.env` dosyasını commit etmeyin**
|
||
```bash
|
||
# Yanlış!
|
||
git add .env
|
||
|
||
# Doğru!
|
||
git add .env.template
|
||
```
|
||
|
||
2. **Production secret'larını template'e koymayın**
|
||
```bash
|
||
# .env.template içinde YANLIŞLAR:
|
||
SECRET_KEY=actual-production-secret-12345 ❌
|
||
DATABASE_URL=postgresql://admin:realpass@prod-db ❌
|
||
|
||
# Doğru:
|
||
SECRET_KEY=your-secret-key-change-this-in-production ✅
|
||
DATABASE_URL=postgresql://user:pass@host:5432/db ✅
|
||
```
|
||
|
||
3. **Hardcoded URL kullanmayın**
|
||
```python
|
||
# Yanlış!
|
||
MANAGEMENT_URL = "https://my-server.com" ❌
|
||
|
||
# Doğru!
|
||
MANAGEMENT_URL = os.getenv("PUBLIC_URL") ✅
|
||
```
|
||
|
||
## 🆘 Yardım
|
||
|
||
Sorularınız için:
|
||
- 📘 Bu dosya: `CONFIG.md`
|
||
- 📗 Ana dokümantasyon: `README.md`
|
||
- 📙 Template: `.env.template`
|
||
|