Compare commits
2 Commits
main
...
f0b61735cc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0b61735cc | ||
|
|
c62478937e |
@@ -1,13 +1,7 @@
|
|||||||
# Dependencies
|
# Node modules
|
||||||
node_modules/
|
node_modules/
|
||||||
npm-debug.log*
|
npm-debug.log
|
||||||
yarn-debug.log*
|
yarn-error.log
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# Build outputs
|
|
||||||
frontend/dist/
|
|
||||||
frontend/build/
|
|
||||||
backend/dist/
|
|
||||||
|
|
||||||
# Environment files
|
# Environment files
|
||||||
.env
|
.env
|
||||||
@@ -17,7 +11,6 @@ backend/dist/
|
|||||||
# Git
|
# Git
|
||||||
.git/
|
.git/
|
||||||
.gitignore
|
.gitignore
|
||||||
.gitattributes
|
|
||||||
|
|
||||||
# IDE
|
# IDE
|
||||||
.vscode/
|
.vscode/
|
||||||
@@ -34,30 +27,35 @@ Thumbs.db
|
|||||||
logs/
|
logs/
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
# Database files (will be created in container)
|
# Database (will be in volume)
|
||||||
backend/database/*.db
|
database/
|
||||||
backend/database/*.db-journal
|
*.db
|
||||||
|
*.db-journal
|
||||||
|
|
||||||
# Test files
|
# Build artifacts
|
||||||
tests/
|
dist/
|
||||||
*.test.js
|
build/
|
||||||
*.spec.js
|
.cache/
|
||||||
coverage/
|
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
*.md
|
*.md
|
||||||
docs/
|
docs/
|
||||||
|
|
||||||
# Deployment scripts
|
# Docker
|
||||||
|
Dockerfile*
|
||||||
|
docker-compose*.yml
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Deployment
|
||||||
deploy.sh
|
deploy.sh
|
||||||
systemd/
|
systemd/
|
||||||
nginx/
|
nginx/
|
||||||
|
|
||||||
# Docker files (don't copy into itself)
|
# Testing
|
||||||
Dockerfile
|
coverage/
|
||||||
.dockerignore
|
.nyc_output/
|
||||||
docker-compose.yml
|
|
||||||
|
|
||||||
# Backups
|
# Temporary files
|
||||||
backups/
|
tmp/
|
||||||
|
temp/
|
||||||
|
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ After=network.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=www-data
|
User=oltalama
|
||||||
WorkingDirectory=/opt/oltalama/backend
|
WorkingDirectory=/opt/oltalama/backend
|
||||||
Environment=NODE_ENV=production
|
Environment=NODE_ENV=production
|
||||||
ExecStart=/usr/bin/node /opt/oltalama/backend/src/app.js
|
ExecStart=/usr/bin/node /opt/oltalama/backend/src/app.js
|
||||||
@@ -362,7 +362,7 @@ After=network.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=www-data
|
User=oltalama
|
||||||
WorkingDirectory=/opt/oltalama/frontend
|
WorkingDirectory=/opt/oltalama/frontend
|
||||||
Environment=NODE_ENV=production
|
Environment=NODE_ENV=production
|
||||||
ExecStart=/usr/bin/npm run preview
|
ExecStart=/usr/bin/npm run preview
|
||||||
@@ -522,7 +522,7 @@ const rl = readline.createInterface({
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Proje dizini izinleri
|
# Proje dizini izinleri
|
||||||
sudo chown -R www-data:www-data /opt/oltalama
|
sudo chown -R oltalama:oltalama /opt/oltalama
|
||||||
sudo chmod -R 755 /opt/oltalama
|
sudo chmod -R 755 /opt/oltalama
|
||||||
|
|
||||||
# .env dosyalarını koru
|
# .env dosyalarını koru
|
||||||
@@ -687,7 +687,7 @@ pm2 logs --lines 100
|
|||||||
delaycompress
|
delaycompress
|
||||||
missingok
|
missingok
|
||||||
notifempty
|
notifempty
|
||||||
create 0640 www-data www-data
|
create 0640 oltalama oltalama
|
||||||
sharedscripts
|
sharedscripts
|
||||||
postrotate
|
postrotate
|
||||||
pm2 reloadLogs
|
pm2 reloadLogs
|
||||||
|
|||||||
542
DOCKER.md
542
DOCKER.md
@@ -1,203 +1,509 @@
|
|||||||
# Docker Deployment Guide
|
# 🐳 Docker Deployment Guide
|
||||||
|
|
||||||
Bu dokümantasyon, Oltalama uygulamasını Docker ile tek container'da çalıştırma rehberidir.
|
## Oltalama Test Yönetim Paneli - Docker ile Kurulum
|
||||||
|
|
||||||
## Gereksinimler
|
Bu dokümantasyon, projeyi Docker ve Docker Compose kullanarak nasıl çalıştıracağınızı açıklar.
|
||||||
|
|
||||||
- Docker 20.10+
|
---
|
||||||
- Docker Compose 2.0+ (opsiyonel)
|
|
||||||
|
|
||||||
## Hızlı Başlangıç
|
## 📋 İçindekiler
|
||||||
|
|
||||||
### Docker Compose ile (Önerilen)
|
- [Gereksinimler](#gereksinimler)
|
||||||
|
- [Hızlı Başlangıç](#hızlı-başlangıç)
|
||||||
|
- [Development Modu](#development-modu)
|
||||||
|
- [Production Modu](#production-modu)
|
||||||
|
- [Ortam Değişkenleri](#ortam-değişkenleri)
|
||||||
|
- [Veri Yedekleme](#veri-yedekleme)
|
||||||
|
- [İleri Seviye Kullanım](#ileri-seviye-kullanım)
|
||||||
|
|
||||||
1. **Environment dosyası oluştur** (opsiyonel):
|
---
|
||||||
|
|
||||||
|
## 🔧 Gereksinimler
|
||||||
|
|
||||||
|
- **Docker**: 20.10 veya üzeri
|
||||||
|
- **Docker Compose**: 2.0 veya üzeri
|
||||||
|
- **Git**: (projeyi klonlamak için)
|
||||||
|
|
||||||
|
### Docker Kurulumu
|
||||||
|
|
||||||
|
#### Ubuntu/Debian:
|
||||||
```bash
|
```bash
|
||||||
cp backend/.env.example backend/.env
|
# Docker kurulumu
|
||||||
# backend/.env dosyasını düzenle
|
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||||
|
sudo sh get-docker.sh
|
||||||
|
|
||||||
|
# Docker Compose kurulumu (eğer yoksa)
|
||||||
|
sudo apt-get install docker-compose-plugin
|
||||||
|
|
||||||
|
# Kullanıcıyı docker grubuna ekle
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
newgrp docker
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Docker Compose ile başlat**:
|
#### RedHat/Oracle/CentOS:
|
||||||
```bash
|
```bash
|
||||||
docker-compose up -d
|
# Docker kurulumu
|
||||||
|
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||||
|
|
||||||
|
# Docker'ı başlat ve aktifleştir
|
||||||
|
sudo systemctl start docker
|
||||||
|
sudo systemctl enable docker
|
||||||
|
|
||||||
|
# Kullanıcıyı docker grubuna ekle
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
newgrp docker
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Logları izle**:
|
---
|
||||||
|
|
||||||
|
## 🚀 Hızlı Başlangıç
|
||||||
|
|
||||||
|
### 1. Projeyi Klonlayın
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose logs -f
|
git clone <repository-url> oltalama
|
||||||
|
cd oltalama
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Durdur**:
|
### 2. Environment Dosyasını Hazırlayın
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose down
|
# Örnek dosyadan kopyalayın
|
||||||
|
cat > .env << 'EOF'
|
||||||
|
SESSION_SECRET=your-strong-random-secret-here
|
||||||
|
GMAIL_USER=your-email@gmail.com
|
||||||
|
GMAIL_APP_PASSWORD=your-gmail-app-password
|
||||||
|
TELEGRAM_BOT_TOKEN=your-bot-token
|
||||||
|
TELEGRAM_CHAT_ID=your-chat-id
|
||||||
|
OLLAMA_SERVER_URL=http://host.docker.internal:11434
|
||||||
|
OLLAMA_MODEL=llama3.2:latest
|
||||||
|
VITE_API_URL=http://localhost:3000
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Editör ile açın ve konfigüre edin
|
||||||
|
nano .env
|
||||||
```
|
```
|
||||||
|
|
||||||
### Docker ile (Manuel)
|
**Minimum gerekli ayarlar:**
|
||||||
|
```env
|
||||||
1. **Image'ı build et**:
|
SESSION_SECRET=very-strong-random-secret-here
|
||||||
```bash
|
GMAIL_USER=your-email@gmail.com
|
||||||
docker build -t oltalama:latest .
|
GMAIL_APP_PASSWORD=your-gmail-app-password
|
||||||
|
TELEGRAM_BOT_TOKEN=your-bot-token
|
||||||
|
TELEGRAM_CHAT_ID=your-chat-id
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Container'ı çalıştır**:
|
### 3. Production Modunda Başlatın
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d \
|
# Container'ları build edin ve başlatın
|
||||||
--name oltalama \
|
docker compose up -d
|
||||||
-p 3000:3000 \
|
|
||||||
-v $(pwd)/data/database:/app/database \
|
# Logları görüntüleyin
|
||||||
-v $(pwd)/data/logs:/app/logs \
|
docker compose logs -f
|
||||||
-e NODE_ENV=production \
|
|
||||||
-e SESSION_SECRET=$(openssl rand -hex 32) \
|
|
||||||
-e FRONTEND_URL=http://localhost:3000 \
|
|
||||||
oltalama:latest
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Environment Variables
|
### 4. Admin Kullanıcısı Oluşturun
|
||||||
|
|
||||||
Aşağıdaki environment variable'ları ayarlayabilirsiniz:
|
İlk çalıştırmada admin kullanıcısı oluşturmanız gerekir:
|
||||||
|
|
||||||
- `NODE_ENV`: Ortam (production/development)
|
|
||||||
- `PORT`: Server portu (varsayılan: 3000)
|
|
||||||
- `DB_PATH`: Database dosya yolu (varsayılan: /app/database/oltalama.db)
|
|
||||||
- `SESSION_SECRET`: Session secret key (üretmek için: `openssl rand -hex 32`)
|
|
||||||
- `FRONTEND_URL`: Frontend URL'i (CORS için)
|
|
||||||
|
|
||||||
Daha fazla environment variable için `backend/.env.example` dosyasına bakın.
|
|
||||||
|
|
||||||
## Veri Kalıcılığı
|
|
||||||
|
|
||||||
Database ve log dosyaları volume'lerde saklanır:
|
|
||||||
|
|
||||||
- `./data/database`: SQLite database dosyaları
|
|
||||||
- `./data/logs`: Uygulama logları
|
|
||||||
|
|
||||||
İlk çalıştırmada bu dizinler otomatik oluşturulur.
|
|
||||||
|
|
||||||
## Admin Kullanıcı Oluşturma
|
|
||||||
|
|
||||||
İlk kurulumda admin kullanıcı oluşturmak için:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Container içine gir
|
# Backend container'a bağlanın
|
||||||
docker exec -it oltalama sh
|
docker compose exec backend sh
|
||||||
|
|
||||||
# Admin kullanıcı oluştur
|
# Admin kullanıcı scripti çalıştırın
|
||||||
node scripts/create-admin.js
|
node scripts/create-admin.js
|
||||||
|
|
||||||
|
# Container'dan çıkın
|
||||||
|
exit
|
||||||
```
|
```
|
||||||
|
|
||||||
Veya container dışından:
|
### 5. Uygulamaya Erişin
|
||||||
|
|
||||||
|
- **Frontend**: http://localhost:4173
|
||||||
|
- **Backend API**: http://localhost:3000
|
||||||
|
- **Health Check**: http://localhost:3000/health
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💻 Development Modu
|
||||||
|
|
||||||
|
Development modunda hot-reload aktif olur ve kod değişiklikleri anında yansır.
|
||||||
|
|
||||||
|
### Başlatma
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker exec -it oltalama node scripts/create-admin.js
|
# Development compose ile başlat
|
||||||
|
docker compose -f docker-compose.dev.yml up
|
||||||
|
|
||||||
|
# Veya arka planda çalıştır
|
||||||
|
docker compose -f docker-compose.dev.yml up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
## Health Check
|
### Özellikler
|
||||||
|
|
||||||
Container health check endpoint'i: `http://localhost:3000/health`
|
- ✅ **Hot Reload**: Kod değişiklikleri anında yansır
|
||||||
|
- ✅ **Volume Mount**: Local klasörler container'a mount edilir
|
||||||
|
- ✅ **Debug Modu**: Detaylı log çıktıları
|
||||||
|
- ✅ **Nodemon**: Backend için otomatik restart
|
||||||
|
|
||||||
Health check durumunu kontrol etmek için:
|
### Development Portları
|
||||||
|
|
||||||
|
- **Frontend (Vite Dev Server)**: http://localhost:5173
|
||||||
|
- **Backend**: http://localhost:3000
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏭 Production Modu
|
||||||
|
|
||||||
|
Production modu için optimize edilmiş, multi-stage build ile küçük image boyutu.
|
||||||
|
|
||||||
|
### Başlatma
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker ps
|
# Production compose ile başlat
|
||||||
# HEALTHY durumunu göreceksiniz
|
docker compose up -d
|
||||||
|
|
||||||
|
# Durum kontrolü
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
# Logları görüntüle
|
||||||
|
docker compose logs -f backend
|
||||||
|
docker compose logs -f frontend
|
||||||
```
|
```
|
||||||
|
|
||||||
## Loglar
|
### Container Yönetimi
|
||||||
|
|
||||||
Logları görüntülemek için:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Docker Compose
|
# Tüm servisleri durdur
|
||||||
docker-compose logs -f
|
docker compose stop
|
||||||
|
|
||||||
# Docker
|
# Tüm servisleri başlat
|
||||||
docker logs -f oltalama
|
docker compose start
|
||||||
|
|
||||||
|
# Tüm servisleri yeniden başlat
|
||||||
|
docker compose restart
|
||||||
|
|
||||||
|
# Servisleri kaldır (veri korunur)
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
# Servisleri ve volume'leri kaldır (VERİ SİLİNİR!)
|
||||||
|
docker compose down -v
|
||||||
```
|
```
|
||||||
|
|
||||||
## Database Backup
|
### Build İşlemleri
|
||||||
|
|
||||||
Database'i yedeklemek için:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Container içindeki database'i kopyala
|
# Image'ları yeniden build et
|
||||||
docker cp oltalama:/app/database/oltalama.db ./backup-$(date +%Y%m%d).db
|
docker compose build
|
||||||
|
|
||||||
|
# Cache kullanmadan build et
|
||||||
|
docker compose build --no-cache
|
||||||
|
|
||||||
|
# Belirli bir servisi build et
|
||||||
|
docker compose build backend
|
||||||
```
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
---
|
||||||
|
|
||||||
### Container başlamıyor
|
## 🔐 Ortam Değişkenleri
|
||||||
|
|
||||||
|
### Backend Değişkenleri
|
||||||
|
|
||||||
|
| Değişken | Açıklama | Varsayılan | Zorunlu |
|
||||||
|
|----------|----------|------------|---------|
|
||||||
|
| `NODE_ENV` | Çalışma ortamı | `production` | ❌ |
|
||||||
|
| `PORT` | Backend portu | `3000` | ❌ |
|
||||||
|
| `SESSION_SECRET` | Session şifreleme anahtarı | - | ✅ |
|
||||||
|
| `GMAIL_USER` | Gmail hesabı | - | ✅ |
|
||||||
|
| `GMAIL_APP_PASSWORD` | Gmail uygulama şifresi | - | ✅ |
|
||||||
|
| `TELEGRAM_BOT_TOKEN` | Telegram bot token | - | ✅ |
|
||||||
|
| `TELEGRAM_CHAT_ID` | Telegram chat ID | - | ✅ |
|
||||||
|
| `DOMAIN_URL` | Backend domain | `http://localhost:3000` | ❌ |
|
||||||
|
| `FRONTEND_URL` | Frontend domain | `http://localhost:4173` | ❌ |
|
||||||
|
| `OLLAMA_SERVER_URL` | Ollama AI server URL | `http://host.docker.internal:11434` | ❌ |
|
||||||
|
| `OLLAMA_MODEL` | Ollama model adı | `llama3.2:latest` | ❌ |
|
||||||
|
|
||||||
|
### Frontend Değişkenleri
|
||||||
|
|
||||||
|
| Değişken | Açıklama | Varsayılan | Zorunlu |
|
||||||
|
|----------|----------|------------|---------|
|
||||||
|
| `VITE_API_URL` | Backend API URL | `http://localhost:3000` | ✅ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💾 Veri Yedekleme
|
||||||
|
|
||||||
|
### Manuel Yedekleme
|
||||||
|
|
||||||
1. Logları kontrol edin:
|
|
||||||
```bash
|
```bash
|
||||||
docker logs oltalama
|
# Database yedekle
|
||||||
|
docker compose exec backend sh -c "cd database && tar czf /tmp/backup.tar.gz *.db"
|
||||||
|
docker compose cp backend:/tmp/backup.tar.gz ./backup-$(date +%Y%m%d).tar.gz
|
||||||
|
|
||||||
|
# Logs yedekle
|
||||||
|
docker compose exec backend sh -c "cd logs && tar czf /tmp/logs-backup.tar.gz *.log"
|
||||||
|
docker compose cp backend:/tmp/logs-backup.tar.gz ./logs-backup-$(date +%Y%m%d).tar.gz
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Port'un kullanılabilir olduğundan emin olun:
|
### Otomatik Yedekleme (Cron)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
netstat -tuln | grep 3000
|
# Yedekleme scripti oluştur
|
||||||
|
cat > backup.sh << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
BACKUP_DIR="/backup/oltalama"
|
||||||
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||||||
|
|
||||||
|
mkdir -p $BACKUP_DIR
|
||||||
|
|
||||||
|
# Database backup
|
||||||
|
docker compose exec -T backend sh -c "cd database && tar czf - *.db" > "$BACKUP_DIR/db-$DATE.tar.gz"
|
||||||
|
|
||||||
|
# Eski yedekleri sil (30 günden eski)
|
||||||
|
find $BACKUP_DIR -name "db-*.tar.gz" -mtime +30 -delete
|
||||||
|
|
||||||
|
echo "Backup completed: $DATE"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x backup.sh
|
||||||
|
|
||||||
|
# Crontab'a ekle (her gün 02:00'de)
|
||||||
|
(crontab -l 2>/dev/null; echo "0 2 * * * /path/to/backup.sh >> /var/log/oltalama-backup.log 2>&1") | crontab -
|
||||||
```
|
```
|
||||||
|
|
||||||
### Database hatası
|
### Geri Yükleme
|
||||||
|
|
||||||
1. Database volume'ünün yazılabilir olduğundan emin olun:
|
|
||||||
```bash
|
```bash
|
||||||
chmod -R 777 ./data/database
|
# Database geri yükle
|
||||||
|
docker compose cp ./backup-20250101.tar.gz backend:/tmp/
|
||||||
|
docker compose exec backend sh -c "cd database && tar xzf /tmp/backup-20250101.tar.gz"
|
||||||
|
docker compose restart backend
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Container'ı yeniden başlatın:
|
---
|
||||||
|
|
||||||
|
## 🔧 İleri Seviye Kullanım
|
||||||
|
|
||||||
|
### Nginx ile Reverse Proxy
|
||||||
|
|
||||||
|
Nginx reverse proxy eklemek için:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose restart
|
# Nginx profili ile başlat
|
||||||
|
docker compose --profile with-nginx up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
### Frontend görünmüyor
|
`nginx.conf` dosyasını düzenleyin:
|
||||||
|
|
||||||
1. Frontend build'inin doğru yapıldığından emin olun:
|
```nginx
|
||||||
```bash
|
# nginx/nginx.conf
|
||||||
docker exec oltalama ls -la /app/src/public/dist
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name yourdomain.com;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://frontend:4173;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://backend:3000/api/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Container'ı yeniden build edin:
|
### Resource Limits
|
||||||
```bash
|
|
||||||
docker-compose build --no-cache
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
## Production Deployment
|
Production ortamında resource limitleri ekleyin:
|
||||||
|
|
||||||
Production için:
|
|
||||||
|
|
||||||
1. **Güvenli SESSION_SECRET kullanın**:
|
|
||||||
```bash
|
|
||||||
export SESSION_SECRET=$(openssl rand -hex 64)
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **HTTPS için reverse proxy kullanın** (Nginx, Traefik, vb.)
|
|
||||||
|
|
||||||
3. **Resource limitleri ayarlayın**:
|
|
||||||
```yaml
|
```yaml
|
||||||
# docker-compose.yml'e ekleyin
|
# docker-compose.yml içine ekle
|
||||||
|
services:
|
||||||
|
backend:
|
||||||
|
# ... diğer ayarlar
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
cpus: '1'
|
cpus: '1'
|
||||||
memory: 512M
|
memory: 512M
|
||||||
|
reservations:
|
||||||
|
cpus: '0.5'
|
||||||
|
memory: 256M
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Düzenli backup alın**
|
### Health Check Monitoring
|
||||||
|
|
||||||
## Güncelleme
|
Container'ların sağlık durumunu izleyin:
|
||||||
|
|
||||||
Uygulamayı güncellemek için:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Yeni image'ı build et
|
# Health status kontrolü
|
||||||
docker-compose build
|
docker compose ps
|
||||||
|
|
||||||
# Container'ı yeniden başlat
|
# Detaylı health check logları
|
||||||
docker-compose up -d
|
docker inspect --format='{{json .State.Health}}' oltalama-backend | jq
|
||||||
```
|
```
|
||||||
|
|
||||||
## Sorun Bildirimi
|
### Ollama ile Kullanım
|
||||||
|
|
||||||
Sorun yaşarsanız, lütfen GitHub Issues'da bildirin.
|
Eğer Ollama host makinede çalışıyorsa:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Host'tan Ollama'ya erişim için
|
||||||
|
# .env dosyasında:
|
||||||
|
OLLAMA_SERVER_URL=http://host.docker.internal:11434
|
||||||
|
OLLAMA_MODEL=llama3.2:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Ollama'yı da Docker'da çalıştırmak için:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml'e ekle
|
||||||
|
services:
|
||||||
|
ollama:
|
||||||
|
image: ollama/ollama:latest
|
||||||
|
container_name: oltalama-ollama
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "11434:11434"
|
||||||
|
volumes:
|
||||||
|
- ollama-data:/root/.ollama
|
||||||
|
networks:
|
||||||
|
- oltalama-network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
ollama-data:
|
||||||
|
driver: local
|
||||||
|
```
|
||||||
|
|
||||||
|
Sonra `.env` dosyasında:
|
||||||
|
```env
|
||||||
|
OLLAMA_SERVER_URL=http://ollama:11434
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
|
### Problem: Container başlamıyor
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Logları kontrol et
|
||||||
|
docker compose logs backend
|
||||||
|
docker compose logs frontend
|
||||||
|
|
||||||
|
# Container'ı interaktif başlat
|
||||||
|
docker compose run --rm backend sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: Database erişim hatası
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Volume'leri kontrol et
|
||||||
|
docker volume ls
|
||||||
|
docker volume inspect oltalama_backend-data
|
||||||
|
|
||||||
|
# İzinleri düzelt
|
||||||
|
docker compose exec backend chown -R oltalama:oltalama /app/database
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: Port conflict
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Kullanılan portları kontrol et
|
||||||
|
sudo lsof -i :3000
|
||||||
|
sudo lsof -i :4173
|
||||||
|
|
||||||
|
# Farklı port kullan
|
||||||
|
docker compose up -d --force-recreate
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problem: Image boyutu çok büyük
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Kullanılmayan image'ları temizle
|
||||||
|
docker system prune -a
|
||||||
|
|
||||||
|
# Build cache'i temizle
|
||||||
|
docker builder prune
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Monitoring
|
||||||
|
|
||||||
|
### Container İstatistikleri
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Gerçek zamanlı resource kullanımı
|
||||||
|
docker stats
|
||||||
|
|
||||||
|
# Belirli container'lar için
|
||||||
|
docker stats oltalama-backend oltalama-frontend
|
||||||
|
```
|
||||||
|
|
||||||
|
### Log Yönetimi
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Son 100 satır
|
||||||
|
docker compose logs --tail=100 backend
|
||||||
|
|
||||||
|
# Gerçek zamanlı takip
|
||||||
|
docker compose logs -f
|
||||||
|
|
||||||
|
# Belirli bir zaman aralığı
|
||||||
|
docker compose logs --since="2025-01-01T00:00:00"
|
||||||
|
|
||||||
|
# Belirli bir service
|
||||||
|
docker compose logs backend
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Production Deployment Checklist
|
||||||
|
|
||||||
|
- [ ] `.env` dosyasını production değerleri ile doldur
|
||||||
|
- [ ] `SESSION_SECRET` için güçlü random string oluştur
|
||||||
|
- [ ] Gmail App Password oluştur ve ayarla
|
||||||
|
- [ ] Telegram bot token ve chat ID ayarla
|
||||||
|
- [ ] Domain URL'lerini güncelle
|
||||||
|
- [ ] Nginx reverse proxy yapılandır (opsiyonel)
|
||||||
|
- [ ] SSL/TLS sertifikası ekle
|
||||||
|
- [ ] Firewall kurallarını ayarla
|
||||||
|
- [ ] Admin kullanıcı oluştur
|
||||||
|
- [ ] Otomatik yedekleme sistemi kur
|
||||||
|
- [ ] Health check monitoring kur
|
||||||
|
- [ ] Log rotation yapılandır
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Ek Kaynaklar
|
||||||
|
|
||||||
|
- [Docker Documentation](https://docs.docker.com/)
|
||||||
|
- [Docker Compose Documentation](https://docs.docker.com/compose/)
|
||||||
|
- [Best Practices for Node.js in Docker](https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🆘 Destek
|
||||||
|
|
||||||
|
Sorun yaşıyorsanız:
|
||||||
|
|
||||||
|
1. Logları kontrol edin: `docker compose logs`
|
||||||
|
2. Container durumunu kontrol edin: `docker compose ps`
|
||||||
|
3. Health check durumunu kontrol edin
|
||||||
|
4. Issue açın veya dokümantasyonu inceleyin
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**🎉 Artık Docker ile hazırsınız!**
|
||||||
|
|
||||||
|
|||||||
55
Dockerfile
55
Dockerfile
@@ -1,55 +0,0 @@
|
|||||||
# Multi-stage build for Oltalama application
|
|
||||||
# Stage 1: Build frontend
|
|
||||||
FROM node:20-alpine AS frontend-builder
|
|
||||||
|
|
||||||
WORKDIR /app/frontend
|
|
||||||
|
|
||||||
# Copy frontend package files
|
|
||||||
COPY frontend/package*.json ./
|
|
||||||
|
|
||||||
# Install frontend dependencies
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Copy frontend source
|
|
||||||
COPY frontend/ ./
|
|
||||||
|
|
||||||
# Build frontend (output will be in dist/)
|
|
||||||
RUN npm run build && test -f dist/index.html
|
|
||||||
|
|
||||||
# Stage 2: Backend + Runtime
|
|
||||||
FROM node:20-alpine
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Install system dependencies for sqlite3
|
|
||||||
RUN apk add --no-cache python3 make g++ sqlite
|
|
||||||
|
|
||||||
# Copy backend package files
|
|
||||||
COPY backend/package*.json ./
|
|
||||||
|
|
||||||
# Install backend dependencies (production only)
|
|
||||||
RUN npm install --only=production
|
|
||||||
|
|
||||||
# Copy backend source
|
|
||||||
COPY backend/ ./
|
|
||||||
|
|
||||||
# Copy frontend build from previous stage to backend public directory
|
|
||||||
COPY --from=frontend-builder /app/frontend/dist ./src/public/dist
|
|
||||||
|
|
||||||
# Create database directory
|
|
||||||
RUN mkdir -p database
|
|
||||||
|
|
||||||
# Expose port
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
# Health check
|
|
||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
|
|
||||||
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
|
|
||||||
|
|
||||||
# Start script that runs migrations and seeds before starting the server
|
|
||||||
COPY docker-entrypoint.sh /usr/local/bin/
|
|
||||||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
|
||||||
|
|
||||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
|
||||||
CMD ["node", "src/app.js"]
|
|
||||||
|
|
||||||
60
README.md
60
README.md
@@ -179,21 +179,6 @@ curl http://localhost:3000/api/stats/dashboard
|
|||||||
|
|
||||||
Sistem kullanıma hazır. Gmail ve Telegram ayarlarını yaparak phishing testlerinizi başlatabilirsiniz.
|
Sistem kullanıma hazır. Gmail ve Telegram ayarlarını yaparak phishing testlerinizi başlatabilirsiniz.
|
||||||
|
|
||||||
## 🐳 Docker ile Kurulum (Önerilen)
|
|
||||||
|
|
||||||
Tek container'da çalıştırmak için:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Docker Compose ile (en kolay)
|
|
||||||
docker-compose up -d
|
|
||||||
|
|
||||||
# Veya Docker ile
|
|
||||||
docker build -t oltalama:latest .
|
|
||||||
docker run -d -p 3000:3000 --name oltalama oltalama:latest
|
|
||||||
```
|
|
||||||
|
|
||||||
**Detaylı Docker dokümantasyonu:** `DOCKER.md`
|
|
||||||
|
|
||||||
## 🚀 Sunucu Kurulumu (Production)
|
## 🚀 Sunucu Kurulumu (Production)
|
||||||
|
|
||||||
### Otomatik Kurulum
|
### Otomatik Kurulum
|
||||||
@@ -203,20 +188,53 @@ cd /opt/oltalama
|
|||||||
sudo ./deploy.sh
|
sudo ./deploy.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### Manuel Kurulum
|
### 🐳 Docker ile Deployment (Önerilen)
|
||||||
|
|
||||||
Detaylı sunucu kurulum talimatları için:
|
Docker kullanarak tek komutla deploy edin (tüm platformlarda çalışır):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cat DEPLOYMENT.md
|
# 1. .env dosyası oluştur
|
||||||
|
nano .env
|
||||||
|
# SESSION_SECRET, GMAIL, TELEGRAM ayarlarını girin
|
||||||
|
|
||||||
|
# 2. Servisleri başlat
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# 3. Admin kullanıcı oluştur
|
||||||
|
docker compose exec backend node scripts/create-admin.js
|
||||||
|
|
||||||
|
# 4. Erişim
|
||||||
|
# Frontend: http://localhost:4173
|
||||||
|
# Backend: http://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Development Modu (Hot Reload):**
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.dev.yml up
|
||||||
|
```
|
||||||
|
|
||||||
|
**Detaylı Döküman:** `DOCKER.md` 📦
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🖥️ Native Deployment (Linux Sunucu)
|
||||||
|
|
||||||
|
Otomatik deployment scripti ile:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bash deploy.sh # Tüm Linux dağıtımları desteklenir
|
||||||
```
|
```
|
||||||
|
|
||||||
**Önemli dosyalar:**
|
**Önemli dosyalar:**
|
||||||
- `DEPLOYMENT.md` - Detaylı sunucu kurulum kılavuzu
|
- `DEPLOYMENT.md` - Detaylı sunucu kurulum kılavuzu
|
||||||
- `deploy.sh` - Otomatik kurulum scripti
|
- `deploy.sh` - Otomatik kurulum scripti (apt & dnf/yum)
|
||||||
|
- `DOCKER.md` - Docker deployment kılavuzu 🐳
|
||||||
- `systemd/` - Systemd servis dosyaları
|
- `systemd/` - Systemd servis dosyaları
|
||||||
- `nginx/` - Nginx konfigürasyon örneği
|
- `nginx/` - Nginx konfigürasyon örneği
|
||||||
|
|
||||||
|
**Desteklenen Sistemler:**
|
||||||
|
- ✅ Ubuntu, Debian, Oracle Linux, RHEL, CentOS, Fedora
|
||||||
|
|
||||||
**Portlar:**
|
**Portlar:**
|
||||||
- Backend: `3000` (değiştirilebilir)
|
- Backend: `3000` (değiştirilebilir)
|
||||||
- Frontend: `4173` (değiştirilebilir)
|
- Frontend: `4173` (değiştirilebilir)
|
||||||
@@ -254,8 +272,8 @@ node scripts/change-password.js
|
|||||||
## 📚 Dokümantasyon
|
## 📚 Dokümantasyon
|
||||||
|
|
||||||
- **Ana Doküman:** `README.md` (bu dosya)
|
- **Ana Doküman:** `README.md` (bu dosya)
|
||||||
- **Docker Kurulumu:** `DOCKER.md` 🐳 (Docker ile tek container)
|
- **Docker Deployment:** `DOCKER.md` 🐳 (Docker kurulum ve yönetim)
|
||||||
- **Sunucu Kurulumu:** `DEPLOYMENT.md` 🚀 (Production kurulum)
|
- **Sunucu Kurulumu:** `DEPLOYMENT.md` 🚀 (Native Linux kurulum)
|
||||||
- **Ollama AI Entegrasyonu:** `OLLAMA_SETUP.md` 🤖 (AI mail şablon oluşturma)
|
- **Ollama AI Entegrasyonu:** `OLLAMA_SETUP.md` 🤖 (AI mail şablon oluşturma)
|
||||||
- **Domain Yapılandırma:** `docs/DOMAIN_SETUP.md` 🌐 (Tek/İki domain)
|
- **Domain Yapılandırma:** `docs/DOMAIN_SETUP.md` 🌐 (Tek/İki domain)
|
||||||
- **Nginx Proxy Manager:** `docs/NGINX_PROXY_MANAGER.md` 🔄 (Reverse proxy)
|
- **Nginx Proxy Manager:** `docs/NGINX_PROXY_MANAGER.md` 🔄 (Reverse proxy)
|
||||||
|
|||||||
12
SECURITY.md
12
SECURITY.md
@@ -155,11 +155,11 @@ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; prelo
|
|||||||
```bash
|
```bash
|
||||||
# Database dosya izinleri
|
# Database dosya izinleri
|
||||||
sudo chmod 600 /opt/oltalama/backend/database/oltalama.db
|
sudo chmod 600 /opt/oltalama/backend/database/oltalama.db
|
||||||
sudo chown www-data:www-data /opt/oltalama/backend/database/oltalama.db
|
sudo chown oltalama:oltalama /opt/oltalama/backend/database/oltalama.db
|
||||||
|
|
||||||
# Backup dizini izinleri
|
# Backup dizini izinleri
|
||||||
sudo chmod 700 /opt/oltalama/backups
|
sudo chmod 700 /opt/oltalama/backups
|
||||||
sudo chown www-data:www-data /opt/oltalama/backups
|
sudo chown oltalama:oltalama /opt/oltalama/backups
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Düzenli Yedekleme
|
#### Düzenli Yedekleme
|
||||||
@@ -201,8 +201,8 @@ sudo chmod 600 /opt/oltalama/backend/.env
|
|||||||
sudo chmod 600 /opt/oltalama/frontend/.env
|
sudo chmod 600 /opt/oltalama/frontend/.env
|
||||||
|
|
||||||
# Sahibi ayarla
|
# Sahibi ayarla
|
||||||
sudo chown www-data:www-data /opt/oltalama/backend/.env
|
sudo chown oltalama:oltalama /opt/oltalama/backend/.env
|
||||||
sudo chown www-data:www-data /opt/oltalama/frontend/.env
|
sudo chown oltalama:oltalama /opt/oltalama/frontend/.env
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Session Secret
|
#### Session Secret
|
||||||
@@ -273,7 +273,7 @@ echo ".env" >> .gitignore
|
|||||||
```bash
|
```bash
|
||||||
# Log dizini izinleri
|
# Log dizini izinleri
|
||||||
sudo chmod 750 /var/log/oltalama
|
sudo chmod 750 /var/log/oltalama
|
||||||
sudo chown www-data:www-data /var/log/oltalama
|
sudo chown oltalama:oltalama /var/log/oltalama
|
||||||
|
|
||||||
# Log dosyaları izinleri
|
# Log dosyaları izinleri
|
||||||
sudo chmod 640 /var/log/oltalama/*.log
|
sudo chmod 640 /var/log/oltalama/*.log
|
||||||
@@ -290,7 +290,7 @@ sudo chmod 640 /var/log/oltalama/*.log
|
|||||||
delaycompress
|
delaycompress
|
||||||
missingok
|
missingok
|
||||||
notifempty
|
notifempty
|
||||||
create 0640 www-data www-data
|
create 0640 oltalama oltalama
|
||||||
sharedscripts
|
sharedscripts
|
||||||
postrotate
|
postrotate
|
||||||
pm2 reloadLogs
|
pm2 reloadLogs
|
||||||
|
|||||||
43
backend/.dockerignore
Normal file
43
backend/.dockerignore
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Node modules
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Database (will be in volume)
|
||||||
|
database/
|
||||||
|
*.db
|
||||||
|
*.db-journal
|
||||||
|
|
||||||
|
# Logs (will be in volume)
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
*.md
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
coverage/
|
||||||
|
.nyc_output/
|
||||||
|
|
||||||
|
# Migrations (already applied)
|
||||||
|
migrations/
|
||||||
|
seeders/
|
||||||
|
|
||||||
|
# Temporary
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
|
||||||
54
backend/Dockerfile
Normal file
54
backend/Dockerfile
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Backend Dockerfile
|
||||||
|
# Multi-stage build for optimized production image
|
||||||
|
|
||||||
|
# Stage 1: Build stage
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm ci --only=production
|
||||||
|
|
||||||
|
# Stage 2: Production stage
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Install required packages
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
sqlite \
|
||||||
|
tini
|
||||||
|
|
||||||
|
# Create app user
|
||||||
|
RUN addgroup -g 1001 -S oltalama && \
|
||||||
|
adduser -S oltalama -u 1001 -G oltalama
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy dependencies from builder
|
||||||
|
COPY --from=builder /app/node_modules ./node_modules
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY --chown=oltalama:oltalama . .
|
||||||
|
|
||||||
|
# Create necessary directories
|
||||||
|
RUN mkdir -p database logs && \
|
||||||
|
chown -R oltalama:oltalama /app
|
||||||
|
|
||||||
|
# Switch to non-root user
|
||||||
|
USER oltalama
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
|
||||||
|
|
||||||
|
# Use tini as entrypoint for proper signal handling
|
||||||
|
ENTRYPOINT ["/sbin/tini", "--"]
|
||||||
|
|
||||||
|
# Start application
|
||||||
|
CMD ["node", "src/app.js"]
|
||||||
|
|
||||||
33
backend/Dockerfile.dev
Normal file
33
backend/Dockerfile.dev
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Backend Development Dockerfile
|
||||||
|
# Hot reload enabled with nodemon
|
||||||
|
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Install required packages
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
sqlite \
|
||||||
|
tini
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install all dependencies (including dev)
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Create necessary directories
|
||||||
|
RUN mkdir -p database logs
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Use tini as entrypoint
|
||||||
|
ENTRYPOINT ["/sbin/tini", "--"]
|
||||||
|
|
||||||
|
# Start with nodemon for hot reload
|
||||||
|
CMD ["npm", "run", "dev"]
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
require('dotenv').config({ path: require('path').join(__dirname, '../.env') });
|
require('dotenv').config({ path: require('path').join(__dirname, '../.env') });
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const session = require('express-session');
|
const session = require('express-session');
|
||||||
// const helmet = require('helmet'); // Geçici olarak devre dışı
|
const helmet = require('helmet');
|
||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
const logger = require('./config/logger');
|
const logger = require('./config/logger');
|
||||||
const sessionConfig = require('./config/session');
|
const sessionConfig = require('./config/session');
|
||||||
@@ -12,109 +12,50 @@ const { apiLimiter } = require('./middlewares/rateLimiter');
|
|||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
|
|
||||||
// Security middleware - Helmet'i tamamen kaldır (CORS ve mixed content sorunları için)
|
// Security middleware
|
||||||
// app.use(helmet()); // Geçici olarak devre dışı
|
app.use(helmet());
|
||||||
|
|
||||||
// Basic CSP for SPA and assets to avoid white page due to blocked module scripts
|
// Dynamic CORS configuration (will be updated from settings)
|
||||||
// Allow self assets, inline/eval for Vite-built bundles, blobs/data, and API/websocket connections
|
let corsOptions = {
|
||||||
app.use((req, res, next) => {
|
origin: process.env.FRONTEND_URL || 'http://localhost:5173',
|
||||||
// Only set CSP for HTML responses later, but keeping a permissive default helps some browsers on preload
|
|
||||||
res.setHeader(
|
|
||||||
'Content-Security-Policy',
|
|
||||||
[
|
|
||||||
"default-src 'self' data: blob:;",
|
|
||||||
"script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:;",
|
|
||||||
"style-src 'self' 'unsafe-inline';",
|
|
||||||
"img-src 'self' data: blob:;",
|
|
||||||
"font-src 'self' data:;",
|
|
||||||
"connect-src 'self' http: https: ws: wss:;",
|
|
||||||
"frame-ancestors 'self';",
|
|
||||||
'base-uri \'self\';',
|
|
||||||
].join(' ')
|
|
||||||
);
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
// CORS - Her yerden erişime izin ver (tüm route'larda)
|
|
||||||
app.use((req, res, next) => {
|
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
|
||||||
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
|
|
||||||
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
|
||||||
res.header('Access-Control-Allow-Credentials', 'true');
|
|
||||||
|
|
||||||
// OPTIONS request'i için hemen cevap ver
|
|
||||||
if (req.method === 'OPTIONS') {
|
|
||||||
return res.sendStatus(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
// CORS middleware'i de ekle (çift güvence)
|
|
||||||
app.use(cors({
|
|
||||||
origin: '*', // Tüm origin'lere izin ver
|
|
||||||
credentials: true,
|
credentials: true,
|
||||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
};
|
||||||
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Origin', 'Accept'],
|
|
||||||
}));
|
app.use((req, res, next) => {
|
||||||
|
cors(corsOptions)(req, res, next);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Function to update CORS from database
|
||||||
|
const updateCorsFromSettings = async () => {
|
||||||
|
try {
|
||||||
|
const { Settings } = require('./models');
|
||||||
|
const corsEnabledSetting = await Settings.findOne({ where: { key: 'cors_enabled' } });
|
||||||
|
const frontendUrlSetting = await Settings.findOne({ where: { key: 'frontend_url' } });
|
||||||
|
|
||||||
|
if (corsEnabledSetting && corsEnabledSetting.value === 'true' && frontendUrlSetting) {
|
||||||
|
corsOptions.origin = frontendUrlSetting.value;
|
||||||
|
logger.info(`CORS enabled for: ${frontendUrlSetting.value}`);
|
||||||
|
} else {
|
||||||
|
// Default: allow both frontend and backend on same origin
|
||||||
|
corsOptions.origin = process.env.FRONTEND_URL || 'http://localhost:5173';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn('Could not load CORS settings from database, using defaults');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update CORS on startup (with delay to ensure DB is ready)
|
||||||
|
setTimeout(updateCorsFromSettings, 2000);
|
||||||
|
|
||||||
|
// Export for use in settings controller
|
||||||
|
app.updateCorsSettings = updateCorsFromSettings;
|
||||||
|
|
||||||
// Body parsing middleware
|
// Body parsing middleware
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
// Serve static files (landing page and frontend build)
|
// Serve static files (landing page)
|
||||||
const path = require('path');
|
app.use(express.static('src/public'));
|
||||||
app.use(express.static(path.join(__dirname, 'public'), {
|
|
||||||
setHeaders: (res, filePath) => {
|
|
||||||
// CORS headers for ALL static files (CSS, JS, images, etc.)
|
|
||||||
res.set('Access-Control-Allow-Origin', '*');
|
|
||||||
res.set('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
||||||
res.set('Access-Control-Allow-Headers', 'Content-Type, Accept, Origin');
|
|
||||||
res.set('Access-Control-Allow-Credentials', 'true');
|
|
||||||
// Ensure CSP also present on static (mainly harmless for non-HTML)
|
|
||||||
res.set('Content-Security-Policy',
|
|
||||||
"default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' http: https: ws: wss:; frame-ancestors 'self'; base-uri 'self';"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Content-Type header'larını doğru ayarla
|
|
||||||
if (filePath.endsWith('.js')) {
|
|
||||||
// Serve ES modules correctly
|
|
||||||
res.set('Content-Type', 'application/javascript; charset=utf-8');
|
|
||||||
} else if (filePath.endsWith('.css')) {
|
|
||||||
res.set('Content-Type', 'text/css; charset=utf-8');
|
|
||||||
} else if (filePath.endsWith('.mjs')) {
|
|
||||||
res.set('Content-Type', 'application/javascript; charset=utf-8');
|
|
||||||
} else if (filePath.endsWith('.svg')) {
|
|
||||||
res.set('Content-Type', 'image/svg+xml');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Serve compiled frontend assets at /assets (Vite output)
|
|
||||||
app.use('/assets', express.static(path.join(__dirname, 'public', 'dist', 'assets'), {
|
|
||||||
setHeaders: (res, filePath) => {
|
|
||||||
res.set('Access-Control-Allow-Origin', '*');
|
|
||||||
res.set('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
||||||
res.set('Access-Control-Allow-Headers', 'Content-Type, Accept, Origin');
|
|
||||||
res.set('Access-Control-Allow-Credentials', 'true');
|
|
||||||
res.set('Content-Security-Policy',
|
|
||||||
"default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' http: https: ws: wss:; frame-ancestors 'self'; base-uri 'self';"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (filePath.endsWith('.js') || filePath.endsWith('.mjs')) {
|
|
||||||
res.set('Content-Type', 'application/javascript; charset=utf-8');
|
|
||||||
} else if (filePath.endsWith('.css')) {
|
|
||||||
res.set('Content-Type', 'text/css; charset=utf-8');
|
|
||||||
} else if (filePath.endsWith('.svg')) {
|
|
||||||
res.set('Content-Type', 'image/svg+xml');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Serve landing page at /landing route
|
|
||||||
app.get('/landing', (req, res) => {
|
|
||||||
res.sendFile(path.join(__dirname, 'public', 'landing.html'));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Session middleware
|
// Session middleware
|
||||||
app.use(session(sessionConfig));
|
app.use(session(sessionConfig));
|
||||||
@@ -152,35 +93,6 @@ app.use('/api/stats', require('./routes/stats.routes'));
|
|||||||
// Public tracking route (no rate limit on this specific route)
|
// Public tracking route (no rate limit on this specific route)
|
||||||
app.use('/t', require('./routes/tracking.routes'));
|
app.use('/t', require('./routes/tracking.routes'));
|
||||||
|
|
||||||
// Serve frontend SPA (must be after API routes)
|
|
||||||
app.get('*', (req, res, next) => {
|
|
||||||
// Skip if it's an API route, tracking route, or landing page
|
|
||||||
if (req.path.startsWith('/api') || req.path.startsWith('/t') || req.path.startsWith('/landing') || req.path.startsWith('/health')) {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// CORS headers for HTML
|
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
|
||||||
res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
||||||
res.header('Access-Control-Allow-Headers', 'Content-Type');
|
|
||||||
// Explicit CSP for HTML documents
|
|
||||||
res.setHeader(
|
|
||||||
'Content-Security-Policy',
|
|
||||||
"default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' http: https: ws: wss:; frame-ancestors 'self'; base-uri 'self';"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Serve frontend index.html for all other routes
|
|
||||||
const frontendPath = path.join(__dirname, 'public', 'dist', 'index.html');
|
|
||||||
res.sendFile(frontendPath, (err) => {
|
|
||||||
if (err) {
|
|
||||||
// If frontend build doesn't exist, inform clearly
|
|
||||||
res.status(503).send(
|
|
||||||
'Frontend build not found. Please build the frontend (npm run build) and ensure dist is copied to backend/src/public/dist.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 404 handler
|
// 404 handler
|
||||||
app.use((req, res) => {
|
app.use((req, res) => {
|
||||||
res.status(404).json({
|
res.status(404).json({
|
||||||
@@ -198,15 +110,14 @@ const startServer = async () => {
|
|||||||
// Test database connection
|
// Test database connection
|
||||||
await testConnection();
|
await testConnection();
|
||||||
|
|
||||||
// Start listening on all interfaces (0.0.0.0) to allow remote access
|
// Start listening
|
||||||
app.listen(PORT, '0.0.0.0', () => {
|
app.listen(PORT, () => {
|
||||||
logger.info(`🚀 Server is running on port ${PORT}`);
|
logger.info(`🚀 Server is running on port ${PORT}`);
|
||||||
logger.info(`📊 Environment: ${process.env.NODE_ENV || 'development'}`);
|
logger.info(`📊 Environment: ${process.env.NODE_ENV || 'development'}`);
|
||||||
logger.info(`🔗 Health check: http://0.0.0.0:${PORT}/health`);
|
logger.info(`🔗 Health check: http://localhost:${PORT}/health`);
|
||||||
console.log(`\n✨ Oltalama Backend Server Started!`);
|
console.log(`\n✨ Oltalama Backend Server Started!`);
|
||||||
console.log(`🌐 API: http://0.0.0.0:${PORT}/api`);
|
console.log(`🌐 API: http://localhost:${PORT}/api`);
|
||||||
console.log(`🎯 Tracking: http://0.0.0.0:${PORT}/t/:token`);
|
console.log(`🎯 Tracking: http://localhost:${PORT}/t/:token\n`);
|
||||||
console.log(`🌍 Server listening on all interfaces (0.0.0.0:${PORT})\n`);
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to start server:', error);
|
logger.error('Failed to start server:', error);
|
||||||
|
|||||||
@@ -166,9 +166,14 @@ exports.updateSystemSettings = async (req, res, next) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update CORS configuration if available
|
||||||
|
if (req.app && req.app.updateCorsSettings) {
|
||||||
|
await req.app.updateCorsSettings();
|
||||||
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Sistem ayarları güncellendi.',
|
message: 'Sistem ayarları güncellendi. CORS ayarları uygulandı.',
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
|
|||||||
75
deploy.sh
75
deploy.sh
@@ -19,7 +19,7 @@ NC='\033[0m' # No Color
|
|||||||
INSTALL_DIR="/opt/oltalama"
|
INSTALL_DIR="/opt/oltalama"
|
||||||
LOG_DIR="/var/log/oltalama"
|
LOG_DIR="/var/log/oltalama"
|
||||||
BACKUP_DIR="${INSTALL_DIR}/backups"
|
BACKUP_DIR="${INSTALL_DIR}/backups"
|
||||||
USER="www-data"
|
USER="oltalama" # Tüm sistemler için ortak kullanıcı
|
||||||
NODE_VERSION="20"
|
NODE_VERSION="20"
|
||||||
|
|
||||||
# Fonksiyonlar
|
# Fonksiyonlar
|
||||||
@@ -62,6 +62,21 @@ check_os() {
|
|||||||
OS=$ID
|
OS=$ID
|
||||||
VERSION=$VERSION_ID
|
VERSION=$VERSION_ID
|
||||||
print_success "İşletim sistemi tespit edildi: $PRETTY_NAME"
|
print_success "İşletim sistemi tespit edildi: $PRETTY_NAME"
|
||||||
|
|
||||||
|
# Paket yöneticisi tespit et
|
||||||
|
if command -v apt-get &> /dev/null; then
|
||||||
|
PKG_MANAGER="apt"
|
||||||
|
print_info "Paket yöneticisi: APT (Debian/Ubuntu)"
|
||||||
|
elif command -v dnf &> /dev/null; then
|
||||||
|
PKG_MANAGER="dnf"
|
||||||
|
print_info "Paket yöneticisi: DNF (RedHat/Oracle/Fedora)"
|
||||||
|
elif command -v yum &> /dev/null; then
|
||||||
|
PKG_MANAGER="yum"
|
||||||
|
print_info "Paket yöneticisi: YUM (RedHat/CentOS)"
|
||||||
|
else
|
||||||
|
print_error "Desteklenen paket yöneticisi bulunamadı!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
print_error "İşletim sistemi tespit edilemedi!"
|
print_error "İşletim sistemi tespit edilemedi!"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -80,8 +95,13 @@ install_nodejs() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# NodeSource repository ekle
|
# NodeSource repository ekle
|
||||||
|
if [[ "$PKG_MANAGER" == "apt" ]]; then
|
||||||
curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash -
|
curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash -
|
||||||
apt-get install -y nodejs
|
apt-get install -y nodejs
|
||||||
|
elif [[ "$PKG_MANAGER" == "dnf" ]] || [[ "$PKG_MANAGER" == "yum" ]]; then
|
||||||
|
curl -fsSL https://rpm.nodesource.com/setup_${NODE_VERSION}.x | bash -
|
||||||
|
$PKG_MANAGER install -y nodejs
|
||||||
|
fi
|
||||||
|
|
||||||
print_success "Node.js $(node -v) kuruldu."
|
print_success "Node.js $(node -v) kuruldu."
|
||||||
print_success "npm $(npm -v) kuruldu."
|
print_success "npm $(npm -v) kuruldu."
|
||||||
@@ -89,8 +109,20 @@ install_nodejs() {
|
|||||||
|
|
||||||
install_dependencies() {
|
install_dependencies() {
|
||||||
print_info "Sistem bağımlılıkları kuruluyor..."
|
print_info "Sistem bağımlılıkları kuruluyor..."
|
||||||
|
|
||||||
|
if [[ "$PKG_MANAGER" == "apt" ]]; then
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y git curl wget build-essential sqlite3
|
apt-get install -y git curl wget build-essential sqlite3
|
||||||
|
elif [[ "$PKG_MANAGER" == "dnf" ]] || [[ "$PKG_MANAGER" == "yum" ]]; then
|
||||||
|
$PKG_MANAGER update -y
|
||||||
|
# EPEL repository (bazı paketler için gerekli)
|
||||||
|
$PKG_MANAGER install -y epel-release 2>/dev/null || true
|
||||||
|
# Paketleri kur
|
||||||
|
$PKG_MANAGER install -y git curl wget gcc-c++ make sqlite
|
||||||
|
# Development tools
|
||||||
|
$PKG_MANAGER groupinstall -y "Development Tools" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
print_success "Sistem bağımlılıkları kuruldu."
|
print_success "Sistem bağımlılıkları kuruldu."
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +142,18 @@ setup_directories() {
|
|||||||
print_success "Dizinler oluşturuldu."
|
print_success "Dizinler oluşturuldu."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_user() {
|
||||||
|
print_info "Sistem kullanıcısı kontrol ediliyor..."
|
||||||
|
|
||||||
|
if id "$USER" &>/dev/null; then
|
||||||
|
print_success "Kullanıcı '$USER' zaten mevcut."
|
||||||
|
else
|
||||||
|
print_info "Kullanıcı '$USER' oluşturuluyor..."
|
||||||
|
useradd -r -s /bin/bash -d $INSTALL_DIR -m $USER
|
||||||
|
print_success "Kullanıcı '$USER' oluşturuldu."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
install_project() {
|
install_project() {
|
||||||
print_info "Proje dosyaları kontrol ediliyor..."
|
print_info "Proje dosyaları kontrol ediliyor..."
|
||||||
|
|
||||||
@@ -441,6 +485,9 @@ setup_firewall() {
|
|||||||
print_info "Firewall ayarlanıyor..."
|
print_info "Firewall ayarlanıyor..."
|
||||||
|
|
||||||
if command -v ufw &> /dev/null; then
|
if command -v ufw &> /dev/null; then
|
||||||
|
# Ubuntu/Debian - UFW
|
||||||
|
print_info "UFW kullanılıyor..."
|
||||||
|
|
||||||
# SSH izin ver
|
# SSH izin ver
|
||||||
ufw allow 22/tcp comment 'SSH'
|
ufw allow 22/tcp comment 'SSH'
|
||||||
|
|
||||||
@@ -460,9 +507,30 @@ setup_firewall() {
|
|||||||
echo "y" | ufw enable
|
echo "y" | ufw enable
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_success "Firewall ayarlandı."
|
print_success "Firewall ayarlandı (UFW)."
|
||||||
|
elif command -v firewall-cmd &> /dev/null; then
|
||||||
|
# RedHat/Oracle/CentOS - firewalld
|
||||||
|
print_info "firewalld kullanılıyor..."
|
||||||
|
|
||||||
|
# firewalld'yi başlat ve aktifleştir
|
||||||
|
systemctl start firewalld 2>/dev/null || true
|
||||||
|
systemctl enable firewalld 2>/dev/null || true
|
||||||
|
|
||||||
|
# HTTP/HTTPS izin ver
|
||||||
|
firewall-cmd --permanent --add-service=http
|
||||||
|
firewall-cmd --permanent --add-service=https
|
||||||
|
firewall-cmd --permanent --add-service=ssh
|
||||||
|
|
||||||
|
# Backend ve Frontend portları sadece localhost'tan erişilebilir
|
||||||
|
# (reverse proxy kullanılacağı için dışarıdan erişim kapalı)
|
||||||
|
|
||||||
|
# Yeniden yükle
|
||||||
|
firewall-cmd --reload
|
||||||
|
|
||||||
|
print_success "Firewall ayarlandı (firewalld)."
|
||||||
else
|
else
|
||||||
print_warning "UFW bulunamadı, firewall ayarları atlanıyor."
|
print_warning "Firewall bulunamadı, firewall ayarları atlanıyor."
|
||||||
|
print_warning "Güvenlik için manuel olarak firewall yapılandırmanız önerilir."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,6 +608,7 @@ main() {
|
|||||||
install_dependencies
|
install_dependencies
|
||||||
install_nodejs
|
install_nodejs
|
||||||
install_pm2
|
install_pm2
|
||||||
|
create_user
|
||||||
setup_directories
|
setup_directories
|
||||||
install_project
|
install_project
|
||||||
install_backend
|
install_backend
|
||||||
|
|||||||
67
docker-compose.dev.yml
Normal file
67
docker-compose.dev.yml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
# Development Docker Compose
|
||||||
|
# Hot reload enabled, volumes mounted
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Backend Service (Development)
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ./backend
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
container_name: oltalama-backend-dev
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
- PORT=3000
|
||||||
|
- SESSION_SECRET=dev-secret-change-in-production
|
||||||
|
- GMAIL_USER=${GMAIL_USER}
|
||||||
|
- GMAIL_APP_PASSWORD=${GMAIL_APP_PASSWORD}
|
||||||
|
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
|
||||||
|
- TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID}
|
||||||
|
- DOMAIN_URL=http://localhost:3000
|
||||||
|
- FRONTEND_URL=http://localhost:5173
|
||||||
|
- OLLAMA_SERVER_URL=${OLLAMA_SERVER_URL:-http://host.docker.internal:11434}
|
||||||
|
- OLLAMA_MODEL=${OLLAMA_MODEL:-llama3.2:latest}
|
||||||
|
volumes:
|
||||||
|
- ./backend:/app
|
||||||
|
- /app/node_modules
|
||||||
|
- backend-data:/app/database
|
||||||
|
- backend-logs:/app/logs
|
||||||
|
networks:
|
||||||
|
- oltalama-network
|
||||||
|
command: npm run dev
|
||||||
|
|
||||||
|
# Frontend Service (Development)
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ./frontend
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
container_name: oltalama-frontend-dev
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "5173:5173"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
- VITE_API_URL=http://localhost:3000
|
||||||
|
volumes:
|
||||||
|
- ./frontend:/app
|
||||||
|
- /app/node_modules
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
networks:
|
||||||
|
- oltalama-network
|
||||||
|
command: npm run dev
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
backend-data:
|
||||||
|
driver: local
|
||||||
|
backend-logs:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
oltalama-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
@@ -1,27 +1,89 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
oltalama:
|
# Backend Service
|
||||||
|
backend:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: ./backend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: oltalama
|
container_name: oltalama-backend
|
||||||
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "0.0.0.0:3000:3000"
|
- "3000:3000"
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- PORT=3000
|
- PORT=3000
|
||||||
- DB_PATH=/app/database/oltalama.db
|
- SESSION_SECRET=${SESSION_SECRET:-change-this-secret-in-production}
|
||||||
- SESSION_SECRET=${SESSION_SECRET:-change-me-in-production}
|
- GMAIL_USER=${GMAIL_USER}
|
||||||
- FRONTEND_URL=${FRONTEND_URL:-http://localhost:3000}
|
- GMAIL_APP_PASSWORD=${GMAIL_APP_PASSWORD}
|
||||||
|
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
|
||||||
|
- TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID}
|
||||||
|
- DOMAIN_URL=${DOMAIN_URL:-http://localhost:3000}
|
||||||
|
- FRONTEND_URL=${FRONTEND_URL:-http://localhost:4173}
|
||||||
|
- OLLAMA_SERVER_URL=${OLLAMA_SERVER_URL:-http://host.docker.internal:11434}
|
||||||
|
- OLLAMA_MODEL=${OLLAMA_MODEL:-llama3.2:latest}
|
||||||
volumes:
|
volumes:
|
||||||
# Persist database
|
- backend-data:/app/database
|
||||||
- ./data/database:/app/database
|
- backend-logs:/app/logs
|
||||||
# Persist logs
|
networks:
|
||||||
- ./data/logs:/app/logs
|
- oltalama-network
|
||||||
restart: unless-stopped
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
|
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 3s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 40s
|
start_period: 40s
|
||||||
|
|
||||||
|
# Frontend Service
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: ./frontend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: oltalama-frontend
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "4173:4173"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- VITE_API_URL=${VITE_API_URL:-http://localhost:3000}
|
||||||
|
depends_on:
|
||||||
|
backend:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- oltalama-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:4173"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# Nginx Reverse Proxy (Optional)
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: oltalama-nginx
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./nginx/ssl:/etc/nginx/ssl:ro
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
- frontend
|
||||||
|
networks:
|
||||||
|
- oltalama-network
|
||||||
|
profiles:
|
||||||
|
- with-nginx
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
backend-data:
|
||||||
|
driver: local
|
||||||
|
backend-logs:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
oltalama-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "🚀 Starting Oltalama application..."
|
|
||||||
|
|
||||||
# Ensure database directory exists
|
|
||||||
mkdir -p database
|
|
||||||
|
|
||||||
# Run database migrations
|
|
||||||
echo "📊 Running database migrations..."
|
|
||||||
if node migrations/run-migrations.js; then
|
|
||||||
echo "✅ Migrations completed successfully"
|
|
||||||
else
|
|
||||||
echo "⚠️ Migration failed, but continuing..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if we should seed the database
|
|
||||||
# Only seed if database is empty (no admin users)
|
|
||||||
if [ ! -f "database/oltalama.db" ] || [ ! -s "database/oltalama.db" ]; then
|
|
||||||
echo "🌱 Database is empty, seeding initial data..."
|
|
||||||
if node seeders/run-seeders.js; then
|
|
||||||
echo "✅ Seeding completed successfully"
|
|
||||||
else
|
|
||||||
echo "⚠️ Seeding failed, but continuing..."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# Check if admin user exists
|
|
||||||
if command -v sqlite3 >/dev/null 2>&1; then
|
|
||||||
ADMIN_COUNT=$(sqlite3 database/oltalama.db "SELECT COUNT(*) FROM admin_user;" 2>/dev/null || echo "0")
|
|
||||||
if [ "$ADMIN_COUNT" = "0" ]; then
|
|
||||||
echo "🌱 Database exists but no admin user found. Running seeders..."
|
|
||||||
if node seeders/run-seeders.js; then
|
|
||||||
echo "✅ Seeding completed successfully"
|
|
||||||
else
|
|
||||||
echo "⚠️ Seeding failed, but continuing..."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "✅ Database already initialized with admin user(s), skipping seeders."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "⚠️ sqlite3 command not found, skipping admin user check."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ensure frontend build exists before starting server
|
|
||||||
FRONTEND_INDEX="src/public/dist/index.html"
|
|
||||||
if [ ! -f "$FRONTEND_INDEX" ]; then
|
|
||||||
echo "❌ Frontend build not found at $FRONTEND_INDEX"
|
|
||||||
echo "ℹ️ Please run 'npm run build' in the frontend (or rebuild the Docker image) so the dist assets are available."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Start the application
|
|
||||||
echo "✨ Starting server..."
|
|
||||||
exec "$@"
|
|
||||||
|
|
||||||
33
frontend/.dockerignore
Normal file
33
frontend/.dockerignore
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Node modules
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Build artifacts
|
||||||
|
dist/
|
||||||
|
.cache/
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
*.md
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
coverage/
|
||||||
|
|
||||||
|
# Temporary
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
|
||||||
49
frontend/Dockerfile
Normal file
49
frontend/Dockerfile
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Frontend Dockerfile
|
||||||
|
# Multi-stage build for optimized production image
|
||||||
|
|
||||||
|
# Stage 1: Build stage
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build for production
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Stage 2: Production stage
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Create app user
|
||||||
|
RUN addgroup -g 1001 -S oltalama && \
|
||||||
|
adduser -S oltalama -u 1001 -G oltalama
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy built assets from builder
|
||||||
|
COPY --from=builder --chown=oltalama:oltalama /app/dist ./dist
|
||||||
|
COPY --from=builder --chown=oltalama:oltalama /app/package*.json ./
|
||||||
|
|
||||||
|
# Install only production dependencies (for preview server)
|
||||||
|
RUN npm ci --only=production
|
||||||
|
|
||||||
|
# Switch to non-root user
|
||||||
|
USER oltalama
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 4173
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost:4173 || exit 1
|
||||||
|
|
||||||
|
# Start preview server
|
||||||
|
CMD ["npm", "run", "preview", "--", "--host", "0.0.0.0"]
|
||||||
|
|
||||||
22
frontend/Dockerfile.dev
Normal file
22
frontend/Dockerfile.dev
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Frontend Development Dockerfile
|
||||||
|
# Hot reload enabled with Vite
|
||||||
|
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install all dependencies (including dev)
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Expose Vite dev server port
|
||||||
|
EXPOSE 5173
|
||||||
|
|
||||||
|
# Start Vite dev server with host binding
|
||||||
|
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||||
|
|
||||||
@@ -1,18 +1,6 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
const resolveApiUrl = () => {
|
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000';
|
||||||
if (import.meta.env.VITE_API_URL) {
|
|
||||||
return import.meta.env.VITE_API_URL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window !== 'undefined' && window.location?.origin) {
|
|
||||||
return window.location.origin;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'http://localhost:3000';
|
|
||||||
};
|
|
||||||
|
|
||||||
const API_URL = resolveApiUrl();
|
|
||||||
|
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: API_URL,
|
baseURL: API_URL,
|
||||||
|
|||||||
@@ -4,17 +4,4 @@ import react from '@vitejs/plugin-react'
|
|||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
base: '/', // Base path - root'tan servis edilecek
|
|
||||||
build: {
|
|
||||||
assetsDir: 'assets',
|
|
||||||
// Relative path'ler kullan (absolute değil)
|
|
||||||
rollupOptions: {
|
|
||||||
output: {
|
|
||||||
// Asset dosyaları için relative path
|
|
||||||
assetFileNames: 'assets/[name]-[hash][extname]',
|
|
||||||
chunkFileNames: 'assets/[name]-[hash].js',
|
|
||||||
entryFileNames: 'assets/[name]-[hash].js',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ After=network.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=www-data
|
User=oltalama
|
||||||
Group=www-data
|
Group=oltalama
|
||||||
WorkingDirectory=/opt/oltalama/backend
|
WorkingDirectory=/opt/oltalama/backend
|
||||||
Environment=NODE_ENV=production
|
Environment=NODE_ENV=production
|
||||||
Environment=PORT=3000
|
Environment=PORT=3000
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ After=network.target oltalama-backend.service
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=www-data
|
User=oltalama
|
||||||
Group=www-data
|
Group=oltalama
|
||||||
WorkingDirectory=/opt/oltalama/frontend
|
WorkingDirectory=/opt/oltalama/frontend
|
||||||
Environment=NODE_ENV=production
|
Environment=NODE_ENV=production
|
||||||
Environment=PORT=4173
|
Environment=PORT=4173
|
||||||
|
|||||||
Reference in New Issue
Block a user