diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b8c5552 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,63 @@ +# Dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Build outputs +frontend/dist/ +frontend/build/ +backend/dist/ + +# Environment files +.env +.env.local +.env.*.local + +# Git +.git/ +.gitignore +.gitattributes + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +logs/ +*.log + +# Database files (will be created in container) +backend/database/*.db +backend/database/*.db-journal + +# Test files +tests/ +*.test.js +*.spec.js +coverage/ + +# Documentation +*.md +docs/ + +# Deployment scripts +deploy.sh +systemd/ +nginx/ + +# Docker files (don't copy into itself) +Dockerfile +.dockerignore +docker-compose.yml + +# Backups +backups/ + diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..dc5e3d7 --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,203 @@ +# Docker Deployment Guide + +Bu dokümantasyon, Oltalama uygulamasını Docker ile tek container'da çalıştırma rehberidir. + +## Gereksinimler + +- Docker 20.10+ +- Docker Compose 2.0+ (opsiyonel) + +## Hızlı Başlangıç + +### Docker Compose ile (Önerilen) + +1. **Environment dosyası oluştur** (opsiyonel): +```bash +cp backend/.env.example backend/.env +# backend/.env dosyasını düzenle +``` + +2. **Docker Compose ile başlat**: +```bash +docker-compose up -d +``` + +3. **Logları izle**: +```bash +docker-compose logs -f +``` + +4. **Durdur**: +```bash +docker-compose down +``` + +### Docker ile (Manuel) + +1. **Image'ı build et**: +```bash +docker build -t oltalama:latest . +``` + +2. **Container'ı çalıştır**: +```bash +docker run -d \ + --name oltalama \ + -p 3000:3000 \ + -v $(pwd)/data/database:/app/database \ + -v $(pwd)/data/logs:/app/logs \ + -e NODE_ENV=production \ + -e SESSION_SECRET=$(openssl rand -hex 32) \ + -e FRONTEND_URL=http://localhost:3000 \ + oltalama:latest +``` + +## Environment Variables + +Aşağıdaki environment variable'ları ayarlayabilirsiniz: + +- `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 +# Container içine gir +docker exec -it oltalama sh + +# Admin kullanıcı oluştur +node scripts/create-admin.js +``` + +Veya container dışından: + +```bash +docker exec -it oltalama node scripts/create-admin.js +``` + +## Health Check + +Container health check endpoint'i: `http://localhost:3000/health` + +Health check durumunu kontrol etmek için: + +```bash +docker ps +# HEALTHY durumunu göreceksiniz +``` + +## Loglar + +Logları görüntülemek için: + +```bash +# Docker Compose +docker-compose logs -f + +# Docker +docker logs -f oltalama +``` + +## Database Backup + +Database'i yedeklemek için: + +```bash +# Container içindeki database'i kopyala +docker cp oltalama:/app/database/oltalama.db ./backup-$(date +%Y%m%d).db +``` + +## Troubleshooting + +### Container başlamıyor + +1. Logları kontrol edin: +```bash +docker logs oltalama +``` + +2. Port'un kullanılabilir olduğundan emin olun: +```bash +netstat -tuln | grep 3000 +``` + +### Database hatası + +1. Database volume'ünün yazılabilir olduğundan emin olun: +```bash +chmod -R 777 ./data/database +``` + +2. Container'ı yeniden başlatın: +```bash +docker-compose restart +``` + +### Frontend görünmüyor + +1. Frontend build'inin doğru yapıldığından emin olun: +```bash +docker exec oltalama ls -la /app/src/public/dist +``` + +2. Container'ı yeniden build edin: +```bash +docker-compose build --no-cache +docker-compose up -d +``` + +## Production Deployment + +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 +# docker-compose.yml'e ekleyin +deploy: + resources: + limits: + cpus: '1' + memory: 512M +``` + +4. **Düzenli backup alın** + +## Güncelleme + +Uygulamayı güncellemek için: + +```bash +# Yeni image'ı build et +docker-compose build + +# Container'ı yeniden başlat +docker-compose up -d +``` + +## Sorun Bildirimi + +Sorun yaşarsanız, lütfen GitHub Issues'da bildirin. + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..263747b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,55 @@ +# 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 ci + +# Copy frontend source +COPY frontend/ ./ + +# Build frontend (output will be in dist/) +RUN npm run build + +# 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 +RUN npm ci --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"] + diff --git a/README.md b/README.md index e7763c9..de868e5 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,21 @@ curl http://localhost:3000/api/stats/dashboard 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) ### Otomatik Kurulum @@ -239,6 +254,7 @@ node scripts/change-password.js ## 📚 Dokümantasyon - **Ana Doküman:** `README.md` (bu dosya) +- **Docker Kurulumu:** `DOCKER.md` 🐳 (Docker ile tek container) - **Sunucu Kurulumu:** `DEPLOYMENT.md` 🚀 (Production kurulum) - **Ollama AI Entegrasyonu:** `OLLAMA_SETUP.md` 🤖 (AI mail şablon oluşturma) - **Domain Yapılandırma:** `docs/DOMAIN_SETUP.md` 🌐 (Tek/İki domain) diff --git a/backend/src/app.js b/backend/src/app.js index 362d614..3ab3f2f 100644 --- a/backend/src/app.js +++ b/backend/src/app.js @@ -54,8 +54,14 @@ app.updateCorsSettings = updateCorsFromSettings; app.use(express.json()); app.use(express.urlencoded({ extended: true })); -// Serve static files (landing page) -app.use(express.static('src/public')); +// Serve static files (landing page and frontend build) +const path = require('path'); +app.use(express.static(path.join(__dirname, 'public'))); + +// Serve landing page at /landing route +app.get('/landing', (req, res) => { + res.sendFile(path.join(__dirname, 'public', 'landing.html')); +}); // Session middleware app.use(session(sessionConfig)); @@ -93,6 +99,23 @@ app.use('/api/stats', require('./routes/stats.routes')); // Public tracking route (no rate limit on this specific route) 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(); + } + + // 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, return 404 + next(); + } + }); +}); + // 404 handler app.use((req, res) => { res.status(404).json({ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..bd55f57 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +version: '3.8' + +services: + oltalama: + build: + context: . + dockerfile: Dockerfile + container_name: oltalama + ports: + - "3000:3000" + environment: + - NODE_ENV=production + - PORT=3000 + - DB_PATH=/app/database/oltalama.db + - SESSION_SECRET=${SESSION_SECRET:-change-me-in-production} + - FRONTEND_URL=${FRONTEND_URL:-http://localhost:3000} + volumes: + # Persist database + - ./data/database:/app/database + # Persist logs + - ./data/logs:/app/logs + restart: unless-stopped + healthcheck: + test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] + interval: 30s + timeout: 3s + retries: 3 + start_period: 40s + diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..9ff75ca --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,48 @@ +#!/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 + +# Start the application +echo "✨ Starting server..." +exec "$@" + diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 8b0f57b..00ea372 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -4,4 +4,6 @@ import react from '@vitejs/plugin-react' // https://vite.dev/config/ export default defineConfig({ plugins: [react()], + // Build output will be copied to backend in Dockerfile + // For local development, keep default dist/ directory })