Domain support
This commit is contained in:
25
.env.example
Normal file
25
.env.example
Normal file
@@ -0,0 +1,25 @@
|
||||
# Backend .env örneği
|
||||
# Bu dosyayı kopyalayın ve .env olarak kaydedin
|
||||
|
||||
# Sunucu Ayarları
|
||||
NODE_ENV=production
|
||||
PORT=3000
|
||||
BASE_URL=https://yourdomain.com
|
||||
|
||||
# Session Secret (güçlü bir rastgele değer kullanın)
|
||||
# Oluşturmak için: node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
|
||||
SESSION_SECRET=change-this-to-a-strong-random-secret-key
|
||||
|
||||
# Gmail Ayarları (panelden de girebilirsiniz)
|
||||
GMAIL_USER=
|
||||
GMAIL_APP_PASSWORD=
|
||||
|
||||
# Telegram Bot (panelden de girebilirsiniz)
|
||||
TELEGRAM_BOT_TOKEN=
|
||||
TELEGRAM_CHAT_ID=
|
||||
|
||||
# Database
|
||||
DB_PATH=./database/oltalama.db
|
||||
|
||||
# Log Seviyesi
|
||||
LOG_LEVEL=info
|
||||
19
.gitattributes
vendored
Normal file
19
.gitattributes
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Shell scripts should use LF
|
||||
*.sh text eol=lf
|
||||
|
||||
# Windows batch files should use CRLF
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
|
||||
# Binary files
|
||||
*.db binary
|
||||
*.sqlite binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.pdf binary
|
||||
77
.gitignore
vendored
77
.gitignore
vendored
@@ -1,37 +1,82 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# Environment
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.production
|
||||
.env.*.local
|
||||
|
||||
# Build
|
||||
dist/
|
||||
build/
|
||||
# Database
|
||||
*.db
|
||||
*.db-*
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
database/*.db
|
||||
backend/database/*.db
|
||||
|
||||
# Logs
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Database (regenerate with migrations)
|
||||
*.db
|
||||
*.db-journal
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
# Diagnostic reports
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Build directories
|
||||
dist/
|
||||
build/
|
||||
.cache/
|
||||
.parcel-cache/
|
||||
frontend/dist/
|
||||
frontend/build/
|
||||
|
||||
# Coverage directory
|
||||
coverage/
|
||||
*.lcov
|
||||
.nyc_output
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*.swn
|
||||
*~
|
||||
.DS_Store
|
||||
|
||||
# Temp
|
||||
temp/
|
||||
tmp/
|
||||
# PM2
|
||||
.pm2/
|
||||
ecosystem.config.js
|
||||
|
||||
# Backups
|
||||
backups/
|
||||
*.backup
|
||||
*.bak
|
||||
|
||||
# Test
|
||||
.test/
|
||||
test-results/
|
||||
|
||||
# Misc
|
||||
.tmp/
|
||||
.temp/
|
||||
*.tmp
|
||||
*.temp
|
||||
.sessions/
|
||||
sessions.db
|
||||
|
||||
# OS
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
|
||||
968
DEPLOYMENT.md
Normal file
968
DEPLOYMENT.md
Normal file
@@ -0,0 +1,968 @@
|
||||
# 🚀 Oltalama Panel - Sunucu Kurulum Dokümanı
|
||||
|
||||
Bu doküman, Oltalama Test Yönetim Paneli'nin production sunucusuna kurulumu için hazırlanmıştır.
|
||||
|
||||
## 📋 Gereksinimler
|
||||
|
||||
### Sistem Gereksinimleri
|
||||
- **İşletim Sistemi**: Ubuntu 20.04+ / Debian 11+ / CentOS 8+ (önerilen: Ubuntu 22.04 LTS)
|
||||
- **RAM**: Minimum 1GB, Önerilen 2GB+
|
||||
- **Disk**: Minimum 5GB boş alan
|
||||
- **CPU**: 1 core minimum, 2+ core önerilen
|
||||
|
||||
### Yazılım Gereksinimleri
|
||||
- Node.js 18.x veya üzeri
|
||||
- npm 9.x veya üzeri
|
||||
- Git
|
||||
- PM2 (process manager) veya systemd
|
||||
- SQLite3
|
||||
|
||||
### Opsiyonel
|
||||
- Nginx Proxy Manager (reverse proxy için önerilir)
|
||||
- Certbot/Let's Encrypt (SSL için)
|
||||
- fail2ban (güvenlik için)
|
||||
|
||||
## 🎯 Hızlı Kurulum (Otomatik)
|
||||
|
||||
### 1. Kurulum Scriptini İndir ve Çalıştır
|
||||
|
||||
```bash
|
||||
# Projeyi klonla
|
||||
git clone <repository-url> /opt/oltalama
|
||||
cd /opt/oltalama
|
||||
|
||||
# Kurulum scriptini çalıştırılabilir yap
|
||||
chmod +x deploy.sh
|
||||
|
||||
# Kurulumu başlat (interaktif mod)
|
||||
sudo ./deploy.sh
|
||||
```
|
||||
|
||||
Script otomatik olarak şunları yapacak:
|
||||
- ✅ Node.js kurulumu
|
||||
- ✅ Dependencies kurulumu
|
||||
- ✅ Database migration ve seed
|
||||
- ✅ PM2 ile process management kurulumu
|
||||
- ✅ Auto-restart ve startup konfigürasyonu
|
||||
- ✅ Frontend build
|
||||
- ✅ Güvenlik ayarları
|
||||
|
||||
## 🛠️ Yardımcı Scriptler
|
||||
|
||||
Kurulum sonrası kullanabileceğiniz yardımcı scriptler:
|
||||
|
||||
### Admin Kullanıcısı Oluşturma
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama
|
||||
node scripts/create-admin.js
|
||||
```
|
||||
|
||||
Bu script:
|
||||
- ✅ Yeni admin kullanıcısı oluşturur
|
||||
- ✅ Kullanıcı adı benzersizliği kontrol eder
|
||||
- ✅ Şifre güvenlik validasyonu yapar
|
||||
- ✅ Şifreyi güvenli bir şekilde hash'ler
|
||||
|
||||
### Şifre Değiştirme
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama
|
||||
node scripts/change-password.js
|
||||
```
|
||||
|
||||
Bu script:
|
||||
- ✅ Mevcut admin kullanıcısının şifresini değiştirir
|
||||
- ✅ Şifre güvenlik validasyonu yapar
|
||||
- ✅ Yeni şifreyi güvenli bir şekilde hash'ler
|
||||
|
||||
**Şifre Gereksinimleri:**
|
||||
- En az 8 karakter
|
||||
- En az 1 harf (a-z, A-Z)
|
||||
- En az 1 rakam (0-9)
|
||||
- Önerilen: Özel karakterler (!@#$%^&*)
|
||||
|
||||
## 🔧 Manuel Kurulum
|
||||
|
||||
### 1. Sistem Güncellemesi
|
||||
|
||||
```bash
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
```
|
||||
|
||||
### 2. Node.js Kurulumu
|
||||
|
||||
```bash
|
||||
# Node.js 20.x kurulumu (önerilen)
|
||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
# Versiyonu kontrol et
|
||||
node --version # v20.x.x olmalı
|
||||
npm --version # 10.x.x olmalı
|
||||
```
|
||||
|
||||
### 3. Proje Kurulumu
|
||||
|
||||
```bash
|
||||
# Proje dizinini oluştur
|
||||
sudo mkdir -p /opt/oltalama
|
||||
sudo chown -R $USER:$USER /opt/oltalama
|
||||
|
||||
# Projeyi klonla
|
||||
cd /opt/oltalama
|
||||
git clone <repository-url> .
|
||||
|
||||
# Backend dependencies
|
||||
cd /opt/oltalama/backend
|
||||
npm install --production
|
||||
|
||||
# Frontend dependencies ve build
|
||||
cd /opt/oltalama/frontend
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 4. Çevre Değişkenlerini Ayarla
|
||||
|
||||
#### Backend .env
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama/backend
|
||||
cp .env.example .env
|
||||
nano .env
|
||||
```
|
||||
|
||||
**Önemli ayarlar:**
|
||||
|
||||
```env
|
||||
# Sunucu Ayarları
|
||||
NODE_ENV=production
|
||||
PORT=3000
|
||||
BASE_URL=https://yourdomain.com
|
||||
|
||||
# Session Secret (güçlü bir değer oluştur)
|
||||
SESSION_SECRET=uzun-rastgele-gizli-anahtar-buraya-gelecek
|
||||
|
||||
# Gmail Ayarları (panelden de girebilirsiniz)
|
||||
GMAIL_USER=your-email@gmail.com
|
||||
GMAIL_APP_PASSWORD=your-app-password
|
||||
|
||||
# Telegram Bot (panelden de girebilirsiniz)
|
||||
TELEGRAM_BOT_TOKEN=your-bot-token
|
||||
TELEGRAM_CHAT_ID=your-chat-id
|
||||
|
||||
# Database
|
||||
DB_PATH=/opt/oltalama/backend/database/oltalama.db
|
||||
|
||||
# Log Seviyesi
|
||||
LOG_LEVEL=info
|
||||
```
|
||||
|
||||
**Session Secret oluşturma:**
|
||||
```bash
|
||||
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
|
||||
```
|
||||
|
||||
#### Frontend .env
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama/frontend
|
||||
cp .env.example .env
|
||||
nano .env
|
||||
```
|
||||
|
||||
```env
|
||||
# Backend API URL (Nginx Proxy Manager ile yönlendirme yapacaksanız domain)
|
||||
VITE_API_BASE_URL=https://yourdomain.com
|
||||
|
||||
# Veya lokal test için
|
||||
# VITE_API_BASE_URL=http://localhost:3000
|
||||
```
|
||||
|
||||
### 5. Database Kurulumu
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama/backend
|
||||
|
||||
# Migrations çalıştır
|
||||
node migrations/run-migrations.js
|
||||
|
||||
# Admin kullanıcısı oluştur
|
||||
node -e "
|
||||
const bcrypt = require('bcrypt');
|
||||
const readline = require('readline');
|
||||
const { sequelize } = require('./src/config/database');
|
||||
const AdminUser = require('./src/models/AdminUser');
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
(async () => {
|
||||
await sequelize.authenticate();
|
||||
|
||||
rl.question('Admin kullanıcı adı: ', async (username) => {
|
||||
rl.question('Admin şifresi: ', async (password) => {
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
await AdminUser.create({
|
||||
username,
|
||||
password_hash: hashedPassword,
|
||||
email: null,
|
||||
full_name: 'Administrator'
|
||||
});
|
||||
console.log('Admin kullanıcısı oluşturuldu!');
|
||||
rl.close();
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
})();
|
||||
"
|
||||
```
|
||||
|
||||
**Admin Kullanıcısı:**
|
||||
- Kurulum sırasında oluşturulacak
|
||||
- Kullanıcı adı ve şifre: İnteraktif olarak sizden istenecek
|
||||
- Şifre gereksinimleri:
|
||||
- En az 8 karakter
|
||||
- En az 1 harf ve 1 rakam içermeli
|
||||
- Güçlü şifre kullanmanız önerilir
|
||||
|
||||
### 6. PM2 ile Process Management
|
||||
|
||||
#### PM2 Kurulumu
|
||||
|
||||
```bash
|
||||
sudo npm install -g pm2
|
||||
```
|
||||
|
||||
#### PM2 Konfigürasyonu
|
||||
|
||||
`/opt/oltalama/ecosystem.config.js` dosyası:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'oltalama-backend',
|
||||
cwd: '/opt/oltalama/backend',
|
||||
script: 'src/app.js',
|
||||
instances: 1,
|
||||
exec_mode: 'cluster',
|
||||
watch: false,
|
||||
max_memory_restart: '500M',
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 3000,
|
||||
},
|
||||
error_file: '/var/log/oltalama/backend-error.log',
|
||||
out_file: '/var/log/oltalama/backend-out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||
},
|
||||
{
|
||||
name: 'oltalama-frontend',
|
||||
cwd: '/opt/oltalama/frontend',
|
||||
script: 'npm',
|
||||
args: 'run preview',
|
||||
instances: 1,
|
||||
exec_mode: 'fork',
|
||||
watch: false,
|
||||
max_memory_restart: '300M',
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 4173,
|
||||
},
|
||||
error_file: '/var/log/oltalama/frontend-error.log',
|
||||
out_file: '/var/log/oltalama/frontend-out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
#### PM2 Başlatma
|
||||
|
||||
```bash
|
||||
# Log dizini oluştur
|
||||
sudo mkdir -p /var/log/oltalama
|
||||
sudo chown -R $USER:$USER /var/log/oltalama
|
||||
|
||||
# Frontend build (eğer henüz build etmediyseniz)
|
||||
cd /opt/oltalama/frontend
|
||||
npm run build
|
||||
|
||||
# PM2 ile uygulamayı başlat
|
||||
cd /opt/oltalama
|
||||
pm2 start ecosystem.config.js
|
||||
|
||||
# Durumu kontrol et
|
||||
pm2 status
|
||||
|
||||
# Logları izle
|
||||
pm2 logs
|
||||
|
||||
# Startup script oluştur (sunucu yeniden başladığında otomatik başlasın)
|
||||
pm2 startup
|
||||
# Komutu çıktıdaki komutu çalıştırın
|
||||
|
||||
# Mevcut durumu kaydet
|
||||
pm2 save
|
||||
```
|
||||
|
||||
#### PM2 Komutları
|
||||
|
||||
```bash
|
||||
pm2 status # Durum kontrolü
|
||||
pm2 logs # Tüm loglar
|
||||
pm2 logs oltalama-backend # Backend logları
|
||||
pm2 logs oltalama-frontend # Frontend logları
|
||||
pm2 restart all # Tümünü yeniden başlat
|
||||
pm2 restart oltalama-backend # Backend'i yeniden başlat
|
||||
pm2 stop all # Tümünü durdur
|
||||
pm2 delete all # Tümünü sil
|
||||
```
|
||||
|
||||
### 7. Systemd Service Alternatifi (PM2 yerine)
|
||||
|
||||
PM2 yerine systemd kullanmak isterseniz:
|
||||
|
||||
#### Backend Service
|
||||
|
||||
`/etc/systemd/system/oltalama-backend.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Oltalama Backend Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=www-data
|
||||
WorkingDirectory=/opt/oltalama/backend
|
||||
Environment=NODE_ENV=production
|
||||
ExecStart=/usr/bin/node /opt/oltalama/backend/src/app.js
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=append:/var/log/oltalama/backend.log
|
||||
StandardError=append:/var/log/oltalama/backend-error.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
#### Frontend Service
|
||||
|
||||
`/etc/systemd/system/oltalama-frontend.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Oltalama Frontend Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=www-data
|
||||
WorkingDirectory=/opt/oltalama/frontend
|
||||
Environment=NODE_ENV=production
|
||||
ExecStart=/usr/bin/npm run preview
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=append:/var/log/oltalama/frontend.log
|
||||
StandardError=append:/var/log/oltalama/frontend-error.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
#### Servisleri Başlat
|
||||
|
||||
```bash
|
||||
# Servisleri yükle
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
# Servisleri başlat
|
||||
sudo systemctl start oltalama-backend
|
||||
sudo systemctl start oltalama-frontend
|
||||
|
||||
# Başlangıçta otomatik başlasın
|
||||
sudo systemctl enable oltalama-backend
|
||||
sudo systemctl enable oltalama-frontend
|
||||
|
||||
# Durumu kontrol et
|
||||
sudo systemctl status oltalama-backend
|
||||
sudo systemctl status oltalama-frontend
|
||||
```
|
||||
|
||||
## 🌐 Nginx Proxy Manager Kurulumu
|
||||
|
||||
### Portlar
|
||||
|
||||
- **Backend**: `http://localhost:3000`
|
||||
- **Frontend**: `http://localhost:4173`
|
||||
|
||||
### Nginx Proxy Manager Ayarları
|
||||
|
||||
1. **Nginx Proxy Manager'a giriş yapın**
|
||||
2. **Proxy Hosts** → **Add Proxy Host**
|
||||
|
||||
#### Frontend Proxy Host
|
||||
|
||||
```
|
||||
Domain Names: yourdomain.com
|
||||
Scheme: http
|
||||
Forward Hostname/IP: localhost
|
||||
Forward Port: 4173
|
||||
Cache Assets: ✓
|
||||
Block Common Exploits: ✓
|
||||
Websockets Support: ✓
|
||||
|
||||
SSL:
|
||||
- Force SSL: ✓
|
||||
- HTTP/2 Support: ✓
|
||||
- HSTS Enabled: ✓
|
||||
```
|
||||
|
||||
#### Backend API Proxy (Eğer ayrı subdomain kullanacaksanız)
|
||||
|
||||
```
|
||||
Domain Names: api.yourdomain.com
|
||||
Scheme: http
|
||||
Forward Hostname/IP: localhost
|
||||
Forward Port: 3000
|
||||
Block Common Exploits: ✓
|
||||
Websockets Support: ✓
|
||||
|
||||
SSL:
|
||||
- Force SSL: ✓
|
||||
- HTTP/2 Support: ✓
|
||||
- HSTS Enabled: ✓
|
||||
```
|
||||
|
||||
**Custom Nginx Configuration (Advanced sekmesi):**
|
||||
|
||||
```nginx
|
||||
location /api {
|
||||
proxy_pass http://localhost:3000;
|
||||
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;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
```
|
||||
|
||||
## 🔒 Güvenlik Önerileri
|
||||
|
||||
### 1. Firewall Ayarları
|
||||
|
||||
```bash
|
||||
# UFW kurulumu ve ayarları
|
||||
sudo apt install ufw
|
||||
|
||||
# SSH izin ver (bağlantınızı koparmayın!)
|
||||
sudo ufw allow 22/tcp
|
||||
|
||||
# Backend ve Frontend portları (sadece localhost'tan erişilebilir olmalı)
|
||||
# Nginx Proxy Manager kullanıyorsanız bu portları kapatın
|
||||
sudo ufw deny 3000/tcp
|
||||
sudo ufw deny 4173/tcp
|
||||
|
||||
# HTTP/HTTPS (Nginx Proxy Manager için)
|
||||
sudo ufw allow 80/tcp
|
||||
sudo ufw allow 443/tcp
|
||||
|
||||
# Firewall'ı aktifleştir
|
||||
sudo ufw enable
|
||||
```
|
||||
|
||||
### 2. Admin Şifresini Değiştir (Gerekirse)
|
||||
|
||||
Şifrenizi değiştirmek isterseniz:
|
||||
|
||||
```bash
|
||||
# Backend dizinine git
|
||||
cd /opt/oltalama/backend
|
||||
|
||||
# Yeni şifre oluşturma scripti
|
||||
node -e "
|
||||
const bcrypt = require('bcrypt');
|
||||
const readline = require('readline');
|
||||
const { sequelize } = require('./src/config/database');
|
||||
const { AdminUser } = require('./src/models');
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
(async () => {
|
||||
await sequelize.authenticate();
|
||||
|
||||
rl.question('Admin kullanıcı adı: ', async (username) => {
|
||||
rl.question('Yeni şifre: ', async (password) => {
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
await AdminUser.update(
|
||||
{ password_hash: hashedPassword },
|
||||
{ where: { username } }
|
||||
);
|
||||
console.log('Şifre değiştirildi!');
|
||||
rl.close();
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
})();
|
||||
"
|
||||
```
|
||||
|
||||
### 3. Dosya İzinleri
|
||||
|
||||
```bash
|
||||
# Proje dizini izinleri
|
||||
sudo chown -R www-data:www-data /opt/oltalama
|
||||
sudo chmod -R 755 /opt/oltalama
|
||||
|
||||
# .env dosyalarını koru
|
||||
sudo chmod 600 /opt/oltalama/backend/.env
|
||||
sudo chmod 600 /opt/oltalama/frontend/.env
|
||||
|
||||
# Database izinleri
|
||||
sudo chmod 600 /opt/oltalama/backend/database/oltalama.db
|
||||
```
|
||||
|
||||
### 4. Fail2Ban Kurulumu (Opsiyonel)
|
||||
|
||||
```bash
|
||||
sudo apt install fail2ban
|
||||
|
||||
# /etc/fail2ban/jail.local
|
||||
sudo nano /etc/fail2ban/jail.local
|
||||
```
|
||||
|
||||
```ini
|
||||
[DEFAULT]
|
||||
bantime = 3600
|
||||
findtime = 600
|
||||
maxretry = 5
|
||||
|
||||
[sshd]
|
||||
enabled = true
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl restart fail2ban
|
||||
```
|
||||
|
||||
### 5. Düzenli Güncellemeler
|
||||
|
||||
```bash
|
||||
# Sistem güncellemeleri
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# Node paketleri
|
||||
cd /opt/oltalama/backend && npm update
|
||||
cd /opt/oltalama/frontend && npm update
|
||||
|
||||
# PM2 güncelleme
|
||||
pm2 update
|
||||
```
|
||||
|
||||
## 💾 Yedekleme
|
||||
|
||||
### 1. Database Yedekleme
|
||||
|
||||
```bash
|
||||
# Manuel yedekleme
|
||||
cp /opt/oltalama/backend/database/oltalama.db \
|
||||
/opt/oltalama/backups/oltalama-$(date +%Y%m%d-%H%M%S).db
|
||||
```
|
||||
|
||||
### 2. Otomatik Yedekleme Script
|
||||
|
||||
`/opt/oltalama/backup.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
BACKUP_DIR="/opt/oltalama/backups"
|
||||
DB_PATH="/opt/oltalama/backend/database/oltalama.db"
|
||||
DATE=$(date +%Y%m%d-%H%M%S)
|
||||
|
||||
# Backup dizini oluştur
|
||||
mkdir -p $BACKUP_DIR
|
||||
|
||||
# Database yedekle
|
||||
cp $DB_PATH "$BACKUP_DIR/oltalama-$DATE.db"
|
||||
|
||||
# 30 günden eski yedekleri sil
|
||||
find $BACKUP_DIR -name "oltalama-*.db" -mtime +30 -delete
|
||||
|
||||
echo "Backup completed: oltalama-$DATE.db"
|
||||
```
|
||||
|
||||
```bash
|
||||
chmod +x /opt/oltalama/backup.sh
|
||||
|
||||
# Crontab ekle (her gün saat 03:00'te)
|
||||
crontab -e
|
||||
# Ekle:
|
||||
0 3 * * * /opt/oltalama/backup.sh >> /var/log/oltalama/backup.log 2>&1
|
||||
```
|
||||
|
||||
### 3. Tam Sistem Yedeği
|
||||
|
||||
```bash
|
||||
# Tüm projeyi yedekle
|
||||
tar -czf /backup/oltalama-full-$(date +%Y%m%d).tar.gz \
|
||||
/opt/oltalama \
|
||||
/etc/systemd/system/oltalama-*.service \
|
||||
/var/log/oltalama
|
||||
```
|
||||
|
||||
## 🔄 Güncelleme
|
||||
|
||||
### Git ile Güncelleme
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama
|
||||
|
||||
# Değişiklikleri al
|
||||
git pull origin main
|
||||
|
||||
# Backend güncelleme
|
||||
cd backend
|
||||
npm install --production
|
||||
node migrations/run-migrations.js
|
||||
|
||||
# Frontend güncelleme
|
||||
cd ../frontend
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# Servisleri yeniden başlat
|
||||
pm2 restart all
|
||||
# veya
|
||||
sudo systemctl restart oltalama-backend
|
||||
sudo systemctl restart oltalama-frontend
|
||||
```
|
||||
|
||||
## 📊 Monitoring ve Loglar
|
||||
|
||||
### PM2 Monitoring
|
||||
|
||||
```bash
|
||||
# Dashboard
|
||||
pm2 monit
|
||||
|
||||
# Memory/CPU kullanımı
|
||||
pm2 list
|
||||
```
|
||||
|
||||
### Log Dosyaları
|
||||
|
||||
```bash
|
||||
# Backend logs
|
||||
tail -f /var/log/oltalama/backend.log
|
||||
tail -f /var/log/oltalama/backend-error.log
|
||||
|
||||
# Frontend logs
|
||||
tail -f /var/log/oltalama/frontend.log
|
||||
|
||||
# PM2 logs
|
||||
pm2 logs --lines 100
|
||||
```
|
||||
|
||||
### Log Rotation
|
||||
|
||||
`/etc/logrotate.d/oltalama`:
|
||||
|
||||
```
|
||||
/var/log/oltalama/*.log {
|
||||
daily
|
||||
rotate 30
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
create 0640 www-data www-data
|
||||
sharedscripts
|
||||
postrotate
|
||||
pm2 reloadLogs
|
||||
endscript
|
||||
}
|
||||
```
|
||||
|
||||
## 🐛 Sorun Giderme
|
||||
|
||||
### Port Zaten Kullanımda
|
||||
|
||||
```bash
|
||||
# Port 3000'i kullanan process'i bul
|
||||
sudo lsof -i :3000
|
||||
|
||||
# Process'i öldür
|
||||
sudo kill -9 <PID>
|
||||
```
|
||||
|
||||
### Database Locked
|
||||
|
||||
```bash
|
||||
# SQLite lock'ları temizle
|
||||
fuser -k /opt/oltalama/backend/database/oltalama.db
|
||||
```
|
||||
|
||||
### PM2 Çalışmıyor
|
||||
|
||||
```bash
|
||||
# PM2'yi sıfırla
|
||||
pm2 kill
|
||||
pm2 start ecosystem.config.js
|
||||
pm2 save
|
||||
```
|
||||
|
||||
### High Memory Usage
|
||||
|
||||
```bash
|
||||
# Memory kullanımını kontrol et
|
||||
pm2 list
|
||||
|
||||
# Uygulamayı yeniden başlat
|
||||
pm2 restart oltalama-backend --update-env
|
||||
```
|
||||
|
||||
## 👥 Kullanıcı Yönetimi
|
||||
|
||||
### Yeni Admin Kullanıcısı Ekleme
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama
|
||||
node scripts/create-admin.js
|
||||
```
|
||||
|
||||
### Admin Şifresi Değiştirme
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama
|
||||
node scripts/change-password.js
|
||||
```
|
||||
|
||||
### Admin Kullanıcısını Manuel Oluşturma (SQL)
|
||||
|
||||
```bash
|
||||
# Şifre hash'i oluştur
|
||||
node -p "require('bcrypt').hashSync('YourPassword123', 10)"
|
||||
|
||||
# SQLite ile kullanıcı ekle
|
||||
cd /opt/oltalama/backend
|
||||
sqlite3 database/oltalama.db
|
||||
|
||||
INSERT INTO admin_user (username, password_hash, full_name, created_at, updated_at)
|
||||
VALUES ('newadmin', '$2b$10$...', 'New Admin', datetime('now'), datetime('now'));
|
||||
|
||||
.quit
|
||||
```
|
||||
|
||||
### Tüm Admin Kullanıcılarını Listele
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama/backend
|
||||
sqlite3 database/oltalama.db "SELECT id, username, full_name, email, created_at FROM admin_user;"
|
||||
```
|
||||
|
||||
### Admin Kullanıcısı Sil
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama/backend
|
||||
sqlite3 database/oltalama.db "DELETE FROM admin_user WHERE username='oldadmin';"
|
||||
```
|
||||
|
||||
## 📝 Opsiyonel: Manuel Nginx Kurulumu
|
||||
|
||||
Nginx Proxy Manager yerine klasik Nginx kullanmak isterseniz:
|
||||
|
||||
### Nginx Kurulumu
|
||||
|
||||
```bash
|
||||
sudo apt install nginx
|
||||
```
|
||||
|
||||
### Nginx Konfigürasyonu
|
||||
|
||||
`/etc/nginx/sites-available/oltalama`:
|
||||
|
||||
```nginx
|
||||
# Upstream tanımları
|
||||
upstream backend {
|
||||
server localhost:3000;
|
||||
keepalive 64;
|
||||
}
|
||||
|
||||
upstream frontend {
|
||||
server localhost:4173;
|
||||
keepalive 64;
|
||||
}
|
||||
|
||||
# HTTP to HTTPS redirect
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name yourdomain.com;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
# HTTPS server
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name yourdomain.com;
|
||||
|
||||
# SSL sertifikaları (Let's Encrypt ile oluşturun)
|
||||
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;
|
||||
|
||||
# SSL ayarları
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# Security headers
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Client body size
|
||||
client_max_body_size 10M;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;
|
||||
|
||||
# Backend API
|
||||
location /api {
|
||||
proxy_pass http://backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# Tracking endpoint
|
||||
location /t/ {
|
||||
proxy_pass http://backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Frontend
|
||||
location / {
|
||||
proxy_pass http://frontend;
|
||||
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;
|
||||
}
|
||||
|
||||
# Logs
|
||||
access_log /var/log/nginx/oltalama-access.log;
|
||||
error_log /var/log/nginx/oltalama-error.log;
|
||||
}
|
||||
```
|
||||
|
||||
### Nginx'i Aktifleştir
|
||||
|
||||
```bash
|
||||
# Symlink oluştur
|
||||
sudo ln -s /etc/nginx/sites-available/oltalama /etc/nginx/sites-enabled/
|
||||
|
||||
# Konfigürasyonu test et
|
||||
sudo nginx -t
|
||||
|
||||
# Nginx'i yeniden başlat
|
||||
sudo systemctl restart nginx
|
||||
sudo systemctl enable nginx
|
||||
```
|
||||
|
||||
### SSL Sertifikası (Let's Encrypt)
|
||||
|
||||
```bash
|
||||
# Certbot kurulumu
|
||||
sudo apt install certbot python3-certbot-nginx
|
||||
|
||||
# Sertifika oluştur
|
||||
sudo certbot --nginx -d yourdomain.com
|
||||
|
||||
# Otomatik yenileme
|
||||
sudo certbot renew --dry-run
|
||||
```
|
||||
|
||||
## ✅ Kurulum Kontrolü
|
||||
|
||||
### Sistemin Çalıştığını Kontrol Et
|
||||
|
||||
```bash
|
||||
# Servis durumları
|
||||
pm2 status
|
||||
# veya
|
||||
sudo systemctl status oltalama-backend
|
||||
sudo systemctl status oltalama-frontend
|
||||
|
||||
# Port dinleme kontrolü
|
||||
sudo netstat -tulpn | grep -E ':(3000|4173)'
|
||||
|
||||
# HTTP istekleri
|
||||
curl http://localhost:3000/api/health
|
||||
curl http://localhost:4173
|
||||
|
||||
# Domain kontrolü (Nginx Proxy Manager kurulduysa)
|
||||
curl https://yourdomain.com
|
||||
```
|
||||
|
||||
### Performans Testi
|
||||
|
||||
```bash
|
||||
# Backend response time
|
||||
time curl http://localhost:3000/api/health
|
||||
|
||||
# Memory kullanımı
|
||||
free -h
|
||||
|
||||
# Disk kullanımı
|
||||
df -h
|
||||
```
|
||||
|
||||
## 📞 Destek
|
||||
|
||||
Sorun yaşarsanız:
|
||||
1. Logları kontrol edin: `pm2 logs` veya `/var/log/oltalama/`
|
||||
2. GitHub Issues'da sorun bildirin
|
||||
3. Dokümanı tekrar gözden geçirin
|
||||
|
||||
## 📚 Ek Kaynaklar
|
||||
|
||||
- [PM2 Documentation](https://pm2.keymetrics.io/)
|
||||
- [Nginx Documentation](https://nginx.org/en/docs/)
|
||||
- [Node.js Best Practices](https://github.com/goldbergyoni/nodebestpractices)
|
||||
- [SQLite Documentation](https://www.sqlite.org/docs.html)
|
||||
|
||||
---
|
||||
|
||||
**Son Güncelleme**: 2025-11-10
|
||||
**Versiyon**: 1.0.0
|
||||
|
||||
65
README.md
65
README.md
@@ -25,7 +25,7 @@ npm run dev # ✅ Çalışıyor (background)
|
||||
```
|
||||
|
||||
**API:** http://localhost:3000
|
||||
**Default Admin:** admin / admin123
|
||||
**Default Admin:** Kurulum sırasında oluşturulur
|
||||
|
||||
### Frontend ✅ TAMAMLANDI
|
||||
|
||||
@@ -36,7 +36,7 @@ npm run dev # ✅ Çalışıyor (background)
|
||||
```
|
||||
|
||||
**UI:** http://localhost:5173
|
||||
**Default Admin:** admin / admin123
|
||||
**Default Admin:** Kurulum sırasında oluşturulur
|
||||
|
||||
## 📂 Proje Yapısı
|
||||
|
||||
@@ -178,9 +178,70 @@ curl http://localhost:3000/api/stats/dashboard
|
||||
|
||||
Sistem kullanıma hazır. Gmail ve Telegram ayarlarını yaparak phishing testlerinizi başlatabilirsiniz.
|
||||
|
||||
## 🚀 Sunucu Kurulumu (Production)
|
||||
|
||||
### Otomatik Kurulum
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama
|
||||
sudo ./deploy.sh
|
||||
```
|
||||
|
||||
### Manuel Kurulum
|
||||
|
||||
Detaylı sunucu kurulum talimatları için:
|
||||
|
||||
```bash
|
||||
cat DEPLOYMENT.md
|
||||
```
|
||||
|
||||
**Önemli dosyalar:**
|
||||
- `DEPLOYMENT.md` - Detaylı sunucu kurulum kılavuzu
|
||||
- `deploy.sh` - Otomatik kurulum scripti
|
||||
- `systemd/` - Systemd servis dosyaları
|
||||
- `nginx/` - Nginx konfigürasyon örneği
|
||||
|
||||
**Portlar:**
|
||||
- Backend: `3000` (değiştirilebilir)
|
||||
- Frontend: `4173` (değiştirilebilir)
|
||||
|
||||
**Domain Seçenekleri:**
|
||||
- ✅ **Tek Domain** (önerilen): `yourdomain.com` - Path-based routing
|
||||
- ✅ **İki Domain**: `api.yourdomain.com` + `panel.yourdomain.com` - CORS aktif
|
||||
|
||||
**Process Manager:**
|
||||
- ✅ PM2 (önerilen - otomatik restart, monitoring)
|
||||
- ✅ Systemd (native Linux service)
|
||||
|
||||
**Reverse Proxy:**
|
||||
- ✅ Nginx Proxy Manager (önerilen - GUI)
|
||||
- ✅ Nginx (manuel konfig: `nginx/oltalama.conf`)
|
||||
|
||||
## 🛠️ Yardımcı Scriptler
|
||||
|
||||
### Admin Kullanıcı Yönetimi
|
||||
|
||||
```bash
|
||||
# Yeni admin kullanıcısı oluştur
|
||||
node scripts/create-admin.js
|
||||
|
||||
# Admin şifresini değiştir
|
||||
node scripts/change-password.js
|
||||
```
|
||||
|
||||
**Özellikler:**
|
||||
- ✅ İnteraktif kullanıcı oluşturma
|
||||
- ✅ Şifre güvenlik validasyonu (min 8 karakter, harf+rakam)
|
||||
- ✅ Benzersiz kullanıcı adı kontrolü
|
||||
- ✅ Güvenli bcrypt hash'leme
|
||||
|
||||
## 📚 Dokümantasyon
|
||||
|
||||
- **Ana Doküman:** `README.md` (bu dosya)
|
||||
- **Sunucu Kurulumu:** `DEPLOYMENT.md` 🚀 (Production kurulum)
|
||||
- **Domain Yapılandırma:** `docs/DOMAIN_SETUP.md` 🌐 (Tek/İki domain)
|
||||
- **Nginx Proxy Manager:** `docs/NGINX_PROXY_MANAGER.md` 🔄 (Reverse proxy)
|
||||
- **Güvenlik Rehberi:** `SECURITY.md` 🔒 (Güvenlik en iyi uygulamaları)
|
||||
- **Hızlı Başlangıç:** `QUICKSTART.md` ⚡ (5 dakika)
|
||||
- **Kullanım Kılavuzu:** `KULLANIM.md` 📖 (Detaylı)
|
||||
- **Development Plan:** `devpan.md` 🏗️ (Teknik detay)
|
||||
|
||||
454
SECURITY.md
Normal file
454
SECURITY.md
Normal file
@@ -0,0 +1,454 @@
|
||||
# 🔒 Güvenlik Rehberi
|
||||
|
||||
Oltalama Test Yönetim Paneli için güvenlik en iyi uygulamaları ve önerileri.
|
||||
|
||||
## 🎯 Temel Güvenlik Prensipleri
|
||||
|
||||
### 1. Admin Kullanıcı Güvenliği
|
||||
|
||||
#### Güçlü Şifre Kullanımı
|
||||
|
||||
**Minimum Gereksinimler:**
|
||||
- En az 8 karakter
|
||||
- En az 1 büyük harf
|
||||
- En az 1 küçük harf
|
||||
- En az 1 rakam
|
||||
- Önerilen: En az 1 özel karakter (!@#$%^&*)
|
||||
|
||||
**Önerilen Şifre Uzunluğu:** 12+ karakter
|
||||
|
||||
**Güçlü Şifre Örnekleri:**
|
||||
- ✅ `S3cur3P@ssw0rd!`
|
||||
- ✅ `MyT3st#2025!Pass`
|
||||
- ✅ `Phish1ng$Test@2025`
|
||||
|
||||
**Zayıf Şifreler (KULLANMAYIN):**
|
||||
- ❌ `admin123`
|
||||
- ❌ `password`
|
||||
- ❌ `12345678`
|
||||
- ❌ `qwerty123`
|
||||
|
||||
#### Şifre Yönetimi
|
||||
|
||||
```bash
|
||||
# Şifre değiştirme (90 günde bir önerilir)
|
||||
cd /opt/oltalama
|
||||
node scripts/change-password.js
|
||||
|
||||
# Yeni admin kullanıcısı ekleme
|
||||
node scripts/create-admin.js
|
||||
```
|
||||
|
||||
#### Varsayılan Kullanıcı
|
||||
|
||||
- ⚠️ **ÖNEMLİ:** Sistem varsayılan kullanıcı ile gelmiyor
|
||||
- ✅ Kurulum sırasında güvenli bir kullanıcı oluşturmanız gerekir
|
||||
- ✅ Şifreniz bcrypt ile hash'lenmiş olarak saklanır
|
||||
|
||||
### 2. Sunucu Güvenliği
|
||||
|
||||
#### Firewall Konfigürasyonu
|
||||
|
||||
```bash
|
||||
# UFW kurulumu
|
||||
sudo apt install ufw
|
||||
|
||||
# Gerekli portları aç
|
||||
sudo ufw allow 22/tcp # SSH
|
||||
sudo ufw allow 80/tcp # HTTP
|
||||
sudo ufw allow 443/tcp # HTTPS
|
||||
|
||||
# Uygulama portlarını kapat (reverse proxy kullanın)
|
||||
sudo ufw deny 3000/tcp # Backend
|
||||
sudo ufw deny 4173/tcp # Frontend
|
||||
|
||||
# Firewall'ı aktifleştir
|
||||
sudo ufw enable
|
||||
|
||||
# Durumu kontrol et
|
||||
sudo ufw status
|
||||
```
|
||||
|
||||
#### SSH Güvenliği
|
||||
|
||||
```bash
|
||||
# /etc/ssh/sshd_config
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication no # SSH key kullanın
|
||||
PubkeyAuthentication yes
|
||||
Port 22 # Veya özel bir port
|
||||
|
||||
# SSH servisini yeniden başlat
|
||||
sudo systemctl restart sshd
|
||||
```
|
||||
|
||||
#### Fail2Ban Kurulumu
|
||||
|
||||
```bash
|
||||
# Fail2Ban kurulumu
|
||||
sudo apt install fail2ban
|
||||
|
||||
# Konfigürasyon
|
||||
sudo nano /etc/fail2ban/jail.local
|
||||
```
|
||||
|
||||
```ini
|
||||
[DEFAULT]
|
||||
bantime = 3600
|
||||
findtime = 600
|
||||
maxretry = 5
|
||||
|
||||
[sshd]
|
||||
enabled = true
|
||||
port = 22
|
||||
logpath = /var/log/auth.log
|
||||
|
||||
[nginx-http-auth]
|
||||
enabled = true
|
||||
filter = nginx-http-auth
|
||||
port = http,https
|
||||
logpath = /var/log/nginx/error.log
|
||||
```
|
||||
|
||||
```bash
|
||||
# Fail2Ban'ı başlat
|
||||
sudo systemctl restart fail2ban
|
||||
sudo systemctl enable fail2ban
|
||||
|
||||
# Durumu kontrol et
|
||||
sudo fail2ban-client status
|
||||
```
|
||||
|
||||
### 3. SSL/TLS Sertifikası
|
||||
|
||||
#### Let's Encrypt ile Ücretsiz SSL
|
||||
|
||||
```bash
|
||||
# Certbot kurulumu
|
||||
sudo apt install certbot python3-certbot-nginx
|
||||
|
||||
# Sertifika oluşturma
|
||||
sudo certbot --nginx -d yourdomain.com
|
||||
|
||||
# Otomatik yenileme testi
|
||||
sudo certbot renew --dry-run
|
||||
```
|
||||
|
||||
#### SSL Konfigürasyonu
|
||||
|
||||
**Minimum TLS Versiyonu:** TLSv1.2 ve TLSv1.3
|
||||
|
||||
```nginx
|
||||
# Nginx SSL ayarları
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
|
||||
# HSTS header
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
||||
```
|
||||
|
||||
### 4. Database Güvenliği
|
||||
|
||||
#### Dosya İzinleri
|
||||
|
||||
```bash
|
||||
# Database dosya izinleri
|
||||
sudo chmod 600 /opt/oltalama/backend/database/oltalama.db
|
||||
sudo chown www-data:www-data /opt/oltalama/backend/database/oltalama.db
|
||||
|
||||
# Backup dizini izinleri
|
||||
sudo chmod 700 /opt/oltalama/backups
|
||||
sudo chown www-data:www-data /opt/oltalama/backups
|
||||
```
|
||||
|
||||
#### Düzenli Yedekleme
|
||||
|
||||
```bash
|
||||
# Otomatik yedekleme scripti
|
||||
# /opt/oltalama/backup.sh
|
||||
|
||||
#!/bin/bash
|
||||
BACKUP_DIR="/opt/oltalama/backups"
|
||||
DB_PATH="/opt/oltalama/backend/database/oltalama.db"
|
||||
DATE=$(date +%Y%m%d-%H%M%S)
|
||||
|
||||
# Yedek al
|
||||
cp $DB_PATH "$BACKUP_DIR/oltalama-$DATE.db"
|
||||
|
||||
# Eski yedekleri sil (30 günden eski)
|
||||
find $BACKUP_DIR -name "oltalama-*.db" -mtime +30 -delete
|
||||
|
||||
# Backup'ı şifrele (opsiyonel)
|
||||
gpg --symmetric --cipher-algo AES256 "$BACKUP_DIR/oltalama-$DATE.db"
|
||||
rm "$BACKUP_DIR/oltalama-$DATE.db"
|
||||
```
|
||||
|
||||
```bash
|
||||
# Crontab ekle
|
||||
crontab -e
|
||||
# Ekle: Her gün saat 03:00'te yedek al
|
||||
0 3 * * * /opt/oltalama/backup.sh >> /var/log/oltalama/backup.log 2>&1
|
||||
```
|
||||
|
||||
### 5. Uygulama Güvenliği
|
||||
|
||||
#### Çevre Değişkenleri
|
||||
|
||||
```bash
|
||||
# .env dosya izinleri
|
||||
sudo chmod 600 /opt/oltalama/backend/.env
|
||||
sudo chmod 600 /opt/oltalama/frontend/.env
|
||||
|
||||
# Sahibi ayarla
|
||||
sudo chown www-data:www-data /opt/oltalama/backend/.env
|
||||
sudo chown www-data:www-data /opt/oltalama/frontend/.env
|
||||
```
|
||||
|
||||
#### Session Secret
|
||||
|
||||
```bash
|
||||
# Güçlü session secret oluştur
|
||||
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
|
||||
|
||||
# .env dosyasına ekle
|
||||
SESSION_SECRET=uzun-rastgele-gizli-anahtar-buraya
|
||||
```
|
||||
|
||||
#### Rate Limiting
|
||||
|
||||
Uygulama zaten rate limiting kullanıyor:
|
||||
- Login endpoint: 5 istek / dakika
|
||||
- API endpoints: 100 istek / 15 dakika
|
||||
|
||||
#### Security Headers
|
||||
|
||||
Uygulama otomatik olarak şu güvenlik başlıklarını ekliyor:
|
||||
- `X-Content-Type-Options: nosniff`
|
||||
- `X-Frame-Options: SAMEORIGIN`
|
||||
- `X-XSS-Protection: 1; mode=block`
|
||||
- `Strict-Transport-Security` (HTTPS ile)
|
||||
|
||||
### 6. Gmail Güvenliği
|
||||
|
||||
#### App Password Kullanımı
|
||||
|
||||
✅ **Doğru:** Gmail App Password kullanın
|
||||
❌ **Yanlış:** Normal Gmail şifresi kullanmayın
|
||||
|
||||
**App Password Oluşturma:**
|
||||
1. Google Hesabı → Güvenlik
|
||||
2. 2 Adımlı Doğrulama'yı aktifleştir
|
||||
3. Uygulama Şifreleri → Mail
|
||||
4. Oluşturulan şifreyi panele girin
|
||||
|
||||
**Güvenlik İpuçları:**
|
||||
- App Password'ü asla paylaşmayın
|
||||
- Düzenli olarak değiştirin (6 ayda bir)
|
||||
- Kullanılmayan app password'leri silin
|
||||
|
||||
### 7. Telegram Bot Güvenliği
|
||||
|
||||
#### Bot Token Güvenliği
|
||||
|
||||
```bash
|
||||
# .env dosyasında saklayın
|
||||
TELEGRAM_BOT_TOKEN=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz
|
||||
|
||||
# Asla git'e commit etmeyin
|
||||
echo ".env" >> .gitignore
|
||||
```
|
||||
|
||||
#### Chat ID Doğrulama
|
||||
|
||||
```bash
|
||||
# Sadece belirli chat ID'lere bildirim gönderin
|
||||
# Bot'u sadece bilinen kişilerle paylaşın
|
||||
```
|
||||
|
||||
### 8. Log Yönetimi
|
||||
|
||||
#### Log Dosyalarını Koruma
|
||||
|
||||
```bash
|
||||
# Log dizini izinleri
|
||||
sudo chmod 750 /var/log/oltalama
|
||||
sudo chown www-data:www-data /var/log/oltalama
|
||||
|
||||
# Log dosyaları izinleri
|
||||
sudo chmod 640 /var/log/oltalama/*.log
|
||||
```
|
||||
|
||||
#### Log Rotation
|
||||
|
||||
```bash
|
||||
# /etc/logrotate.d/oltalama
|
||||
/var/log/oltalama/*.log {
|
||||
daily
|
||||
rotate 30
|
||||
compress
|
||||
delaycompress
|
||||
missingok
|
||||
notifempty
|
||||
create 0640 www-data www-data
|
||||
sharedscripts
|
||||
postrotate
|
||||
pm2 reloadLogs
|
||||
endscript
|
||||
}
|
||||
```
|
||||
|
||||
#### Hassas Bilgileri Loglamayın
|
||||
|
||||
- ❌ Şifreler
|
||||
- ❌ Session token'lar
|
||||
- ❌ API keys
|
||||
- ❌ Kredi kartı bilgileri
|
||||
|
||||
### 9. Düzenli Güncellemeler
|
||||
|
||||
#### Sistem Güncellemeleri
|
||||
|
||||
```bash
|
||||
# Sistem paketlerini güncelle
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# Güvenlik güncellemelerini otomatik yap
|
||||
sudo apt install unattended-upgrades
|
||||
sudo dpkg-reconfigure -plow unattended-upgrades
|
||||
```
|
||||
|
||||
#### Uygulama Güncellemeleri
|
||||
|
||||
```bash
|
||||
# Backend dependencies
|
||||
cd /opt/oltalama/backend
|
||||
npm audit
|
||||
npm audit fix
|
||||
|
||||
# Frontend dependencies
|
||||
cd /opt/oltalama/frontend
|
||||
npm audit
|
||||
npm audit fix
|
||||
|
||||
# PM2 güncelleme
|
||||
sudo npm update -g pm2
|
||||
pm2 update
|
||||
```
|
||||
|
||||
### 10. Monitoring ve Alerting
|
||||
|
||||
#### PM2 Monitoring
|
||||
|
||||
```bash
|
||||
# PM2 status
|
||||
pm2 status
|
||||
|
||||
# Memory ve CPU kullanımı
|
||||
pm2 monit
|
||||
|
||||
# Error logları izle
|
||||
pm2 logs --err
|
||||
```
|
||||
|
||||
#### Sistem Monitoring
|
||||
|
||||
```bash
|
||||
# Disk kullanımı
|
||||
df -h
|
||||
|
||||
# Memory kullanımı
|
||||
free -h
|
||||
|
||||
# CPU kullanımı
|
||||
top
|
||||
|
||||
# Network bağlantıları
|
||||
sudo netstat -tulpn
|
||||
```
|
||||
|
||||
## 🚨 Güvenlik Kontrol Listesi
|
||||
|
||||
### Kurulum Sonrası
|
||||
|
||||
- [ ] Güçlü admin şifresi oluşturuldu
|
||||
- [ ] .env dosya izinleri ayarlandı (600)
|
||||
- [ ] Database izinleri ayarlandı (600)
|
||||
- [ ] Firewall yapılandırıldı
|
||||
- [ ] SSL sertifikası kuruldu
|
||||
- [ ] Fail2Ban kuruldu
|
||||
- [ ] SSH key-based auth aktif
|
||||
- [ ] Otomatik yedekleme ayarlandı
|
||||
- [ ] Log rotation yapılandırıldı
|
||||
|
||||
### Aylık Kontroller
|
||||
|
||||
- [ ] Sistem güncellemeleri yapıldı
|
||||
- [ ] npm audit çalıştırıldı
|
||||
- [ ] Loglar gözden geçirildi
|
||||
- [ ] Yedekler test edildi
|
||||
- [ ] Disk kullanımı kontrol edildi
|
||||
|
||||
### Üç Aylık Kontroller
|
||||
|
||||
- [ ] Admin şifresi değiştirildi
|
||||
- [ ] Gmail App Password yenilendi
|
||||
- [ ] Kullanılmayan kullanıcılar silindi
|
||||
- [ ] SSL sertifikası kontrol edildi
|
||||
|
||||
### Yıllık Kontroller
|
||||
|
||||
- [ ] Tam sistem denetimi yapıldı
|
||||
- [ ] Güvenlik politikaları gözden geçirildi
|
||||
- [ ] Yedekleme stratejisi gözden geçirildi
|
||||
|
||||
## 🔍 Güvenlik Olaylarına Müdahale
|
||||
|
||||
### Şüpheli Aktivite Tespiti
|
||||
|
||||
```bash
|
||||
# Son giriş denemeleri
|
||||
sudo tail -100 /var/log/auth.log
|
||||
|
||||
# Fail2Ban ban listesi
|
||||
sudo fail2ban-client status sshd
|
||||
|
||||
# Nginx access logları
|
||||
sudo tail -100 /var/log/nginx/oltalama-access.log
|
||||
|
||||
# Uygulama error logları
|
||||
pm2 logs --err --lines 100
|
||||
```
|
||||
|
||||
### Güvenlik İhlali Durumunda
|
||||
|
||||
1. **Hemen:**
|
||||
- Tüm admin şifrelerini değiştir
|
||||
- Gmail App Password'ü yenile
|
||||
- Telegram Bot Token'ı yenile
|
||||
- Session secret'ı değiştir ve tüm servisleri yeniden başlat
|
||||
|
||||
2. **Kısa Vadede:**
|
||||
- Tüm logları yedekle
|
||||
- Şüpheli IP adreslerini banla
|
||||
- Sistem taraması yap
|
||||
|
||||
3. **Uzun Vadede:**
|
||||
- Güvenlik politikalarını gözden geçir
|
||||
- İhlal raporunu hazırla
|
||||
- Ek güvenlik önlemleri al
|
||||
|
||||
## 📚 Ek Kaynaklar
|
||||
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)
|
||||
- [Express.js Security Best Practices](https://expressjs.com/en/advanced/best-practice-security.html)
|
||||
- [Nginx Security Tips](https://nginx.org/en/docs/http/ngx_http_ssl_module.html)
|
||||
|
||||
---
|
||||
|
||||
**Son Güncelleme:** 2025-11-10
|
||||
**Versiyon:** 1.0.0
|
||||
|
||||
⚠️ **UYARI:** Bu sistem sadece yasal ve etik phishing testleri için kullanılmalıdır. Kötü niyetli kullanım yasaktır ve suçtur.
|
||||
|
||||
@@ -14,10 +14,41 @@ const PORT = process.env.PORT || 3000;
|
||||
|
||||
// Security middleware
|
||||
app.use(helmet());
|
||||
app.use(cors({
|
||||
origin: process.env.FRONTEND_URL || 'http://localhost:3001',
|
||||
|
||||
// Dynamic CORS configuration (will be updated from settings)
|
||||
let corsOptions = {
|
||||
origin: process.env.FRONTEND_URL || 'http://localhost:5173',
|
||||
credentials: true,
|
||||
}));
|
||||
};
|
||||
|
||||
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
|
||||
app.use(express.json());
|
||||
|
||||
@@ -97,6 +97,89 @@ exports.updateTelegramSettings = async (req, res, next) => {
|
||||
}
|
||||
};
|
||||
|
||||
// Update System settings (domain, etc.)
|
||||
exports.updateSystemSettings = async (req, res, next) => {
|
||||
try {
|
||||
const { base_url, frontend_url, cors_enabled } = req.body;
|
||||
|
||||
if (base_url !== undefined) {
|
||||
if (base_url) {
|
||||
// Remove trailing slash if exists
|
||||
const cleanUrl = base_url.trim().replace(/\/$/, '');
|
||||
|
||||
// Basic URL validation
|
||||
try {
|
||||
new URL(cleanUrl);
|
||||
} catch (e) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Geçersiz Base URL formatı. Örnek: https://yourdomain.com',
|
||||
});
|
||||
}
|
||||
|
||||
await Settings.upsert({
|
||||
key: 'base_url',
|
||||
value: cleanUrl,
|
||||
is_encrypted: false,
|
||||
description: 'Base URL for tracking links (backend)',
|
||||
});
|
||||
|
||||
// Update process.env for immediate use
|
||||
process.env.BASE_URL = cleanUrl;
|
||||
} else {
|
||||
await Settings.destroy({ where: { key: 'base_url' } });
|
||||
}
|
||||
}
|
||||
|
||||
if (frontend_url !== undefined) {
|
||||
if (frontend_url) {
|
||||
// Remove trailing slash if exists
|
||||
const cleanUrl = frontend_url.trim().replace(/\/$/, '');
|
||||
|
||||
// Basic URL validation
|
||||
try {
|
||||
new URL(cleanUrl);
|
||||
} catch (e) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Geçersiz Frontend URL formatı. Örnek: https://panel.yourdomain.com',
|
||||
});
|
||||
}
|
||||
|
||||
await Settings.upsert({
|
||||
key: 'frontend_url',
|
||||
value: cleanUrl,
|
||||
is_encrypted: false,
|
||||
description: 'Frontend URL (for CORS)',
|
||||
});
|
||||
} else {
|
||||
await Settings.destroy({ where: { key: 'frontend_url' } });
|
||||
}
|
||||
}
|
||||
|
||||
if (cors_enabled !== undefined) {
|
||||
await Settings.upsert({
|
||||
key: 'cors_enabled',
|
||||
value: cors_enabled ? 'true' : 'false',
|
||||
is_encrypted: false,
|
||||
description: 'Enable CORS for separate domains',
|
||||
});
|
||||
}
|
||||
|
||||
// Update CORS configuration if available
|
||||
if (req.app && req.app.updateCorsSettings) {
|
||||
await req.app.updateCorsSettings();
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Sistem ayarları güncellendi. CORS ayarları uygulandı.',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Test Gmail connection
|
||||
exports.testGmail = async (req, res, next) => {
|
||||
try {
|
||||
|
||||
@@ -30,6 +30,11 @@ const TrackingToken = sequelize.define('TrackingToken', {
|
||||
type: DataTypes.STRING(50),
|
||||
defaultValue: 'bank',
|
||||
},
|
||||
from_name: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: true,
|
||||
comment: 'Custom sender name for email (e.g., "HR Department", "Management")',
|
||||
},
|
||||
mail_subject: {
|
||||
type: DataTypes.STRING(500),
|
||||
allowNull: true,
|
||||
|
||||
@@ -9,6 +9,7 @@ router.use(requireAuth);
|
||||
router.get('/', settingsController.getAllSettings);
|
||||
router.put('/gmail', settingsController.updateGmailSettings);
|
||||
router.put('/telegram', settingsController.updateTelegramSettings);
|
||||
router.put('/system', settingsController.updateSystemSettings);
|
||||
router.post('/test-gmail', settingsController.testGmail);
|
||||
router.post('/test-telegram', settingsController.testTelegram);
|
||||
|
||||
|
||||
@@ -45,14 +45,19 @@ class MailService {
|
||||
}
|
||||
}
|
||||
|
||||
async sendMail(to, subject, htmlBody) {
|
||||
async sendMail(to, subject, htmlBody, fromName = null) {
|
||||
try {
|
||||
if (!this.transporter) {
|
||||
await this.initializeTransporter();
|
||||
}
|
||||
|
||||
// Use custom from_name if provided, otherwise use default
|
||||
const from = fromName
|
||||
? `${fromName} <${this.fromAddress.match(/<(.+)>/)?.[1] || this.fromAddress}>`
|
||||
: this.fromAddress;
|
||||
|
||||
const mailOptions = {
|
||||
from: this.fromAddress,
|
||||
from,
|
||||
to,
|
||||
subject,
|
||||
html: htmlBody,
|
||||
|
||||
@@ -5,7 +5,7 @@ const logger = require('../config/logger');
|
||||
|
||||
class TokenService {
|
||||
async createToken(data) {
|
||||
const { company_id, target_email, employee_name, template_type } = data;
|
||||
const { company_id, target_email, employee_name, template_type, from_name } = data;
|
||||
|
||||
// Generate unique token
|
||||
let token = generateTrackingToken();
|
||||
@@ -45,6 +45,7 @@ class TokenService {
|
||||
target_email,
|
||||
employee_name,
|
||||
template_type,
|
||||
from_name: from_name || null,
|
||||
mail_subject: template.subject_template.replace('{{company_name}}', company.name),
|
||||
});
|
||||
|
||||
@@ -78,8 +79,13 @@ class TokenService {
|
||||
throw new Error('Mail template not found');
|
||||
}
|
||||
|
||||
// Get base URL from settings or env
|
||||
const { Settings } = require('../models');
|
||||
const baseUrlSetting = await Settings.findOne({ where: { key: 'base_url' } });
|
||||
const baseUrl = baseUrlSetting?.value || process.env.BASE_URL || 'http://localhost:3000';
|
||||
|
||||
// Prepare template data
|
||||
const trackingUrl = `${process.env.BASE_URL}/t/${token.token}`;
|
||||
const trackingUrl = `${baseUrl}/t/${token.token}`;
|
||||
const currentDate = new Date().toLocaleDateString('tr-TR', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
@@ -99,8 +105,8 @@ class TokenService {
|
||||
const htmlBody = mailService.renderTemplate(template.body_html, templateData);
|
||||
const subject = mailService.renderTemplate(template.subject_template, templateData);
|
||||
|
||||
// Send mail
|
||||
await mailService.sendMail(token.target_email, subject, htmlBody);
|
||||
// Send mail with custom from_name if provided
|
||||
await mailService.sendMail(token.target_email, subject, htmlBody, token.from_name);
|
||||
|
||||
// Update token
|
||||
await token.update({
|
||||
|
||||
@@ -20,6 +20,13 @@ const createTokenSchema = Joi.object({
|
||||
.max(255)
|
||||
.allow(null, '')
|
||||
.optional(),
|
||||
from_name: Joi.string()
|
||||
.max(255)
|
||||
.allow(null, '')
|
||||
.optional()
|
||||
.messages({
|
||||
'string.max': 'From name must be less than 255 characters',
|
||||
}),
|
||||
template_type: Joi.string()
|
||||
.max(50)
|
||||
.default('bank')
|
||||
|
||||
562
deploy.sh
Executable file
562
deploy.sh
Executable file
@@ -0,0 +1,562 @@
|
||||
#!/bin/bash
|
||||
|
||||
###############################################################################
|
||||
# Oltalama Test Yönetim Paneli - Otomatik Kurulum Scripti
|
||||
# Version: 1.0.0
|
||||
# Date: 2025-11-10
|
||||
###############################################################################
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
# Renkli çıktılar
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Değişkenler
|
||||
INSTALL_DIR="/opt/oltalama"
|
||||
LOG_DIR="/var/log/oltalama"
|
||||
BACKUP_DIR="${INSTALL_DIR}/backups"
|
||||
USER="www-data"
|
||||
NODE_VERSION="20"
|
||||
|
||||
# Fonksiyonlar
|
||||
print_header() {
|
||||
echo -e "\n${BLUE}╔═══════════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${BLUE}║ ║${NC}"
|
||||
echo -e "${BLUE}║ Oltalama Test Yönetim Paneli - Kurulum Scripti ║${NC}"
|
||||
echo -e "${BLUE}║ Version 1.0.0 ║${NC}"
|
||||
echo -e "${BLUE}║ ║${NC}"
|
||||
echo -e "${BLUE}╚═══════════════════════════════════════════════════════════════╝${NC}\n"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✓ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}✗ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠ $1${NC}"
|
||||
}
|
||||
|
||||
print_info() {
|
||||
echo -e "${BLUE}ℹ $1${NC}"
|
||||
}
|
||||
|
||||
check_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
print_error "Bu script root yetkisi ile çalıştırılmalıdır."
|
||||
print_info "Lütfen 'sudo ./deploy.sh' komutunu kullanın."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_os() {
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
. /etc/os-release
|
||||
OS=$ID
|
||||
VERSION=$VERSION_ID
|
||||
print_success "İşletim sistemi tespit edildi: $PRETTY_NAME"
|
||||
else
|
||||
print_error "İşletim sistemi tespit edilemedi!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
install_nodejs() {
|
||||
print_info "Node.js ${NODE_VERSION}.x kuruluyor..."
|
||||
|
||||
if command -v node &> /dev/null; then
|
||||
CURRENT_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
|
||||
if [[ $CURRENT_VERSION -ge $NODE_VERSION ]]; then
|
||||
print_success "Node.js $(node -v) zaten yüklü."
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# NodeSource repository ekle
|
||||
curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash -
|
||||
apt-get install -y nodejs
|
||||
|
||||
print_success "Node.js $(node -v) kuruldu."
|
||||
print_success "npm $(npm -v) kuruldu."
|
||||
}
|
||||
|
||||
install_dependencies() {
|
||||
print_info "Sistem bağımlılıkları kuruluyor..."
|
||||
apt-get update
|
||||
apt-get install -y git curl wget build-essential sqlite3
|
||||
print_success "Sistem bağımlılıkları kuruldu."
|
||||
}
|
||||
|
||||
install_pm2() {
|
||||
print_info "PM2 process manager kuruluyor..."
|
||||
npm install -g pm2
|
||||
print_success "PM2 $(pm2 -v) kuruldu."
|
||||
}
|
||||
|
||||
setup_directories() {
|
||||
print_info "Dizinler oluşturuluyor..."
|
||||
|
||||
mkdir -p $LOG_DIR
|
||||
mkdir -p $BACKUP_DIR
|
||||
mkdir -p "${INSTALL_DIR}/backend/database"
|
||||
|
||||
print_success "Dizinler oluşturuldu."
|
||||
}
|
||||
|
||||
install_project() {
|
||||
print_info "Proje dosyaları kontrol ediliyor..."
|
||||
|
||||
# Eğer script zaten proje dizininde çalıştırılıyorsa
|
||||
if [[ -f "$(pwd)/backend/package.json" ]]; then
|
||||
CURRENT_DIR=$(pwd)
|
||||
print_info "Mevcut dizinden kurulum yapılıyor: $CURRENT_DIR"
|
||||
|
||||
if [[ "$CURRENT_DIR" != "$INSTALL_DIR" ]]; then
|
||||
print_info "Dosyalar $INSTALL_DIR dizinine kopyalanıyor..."
|
||||
rsync -av --exclude 'node_modules' --exclude '.git' \
|
||||
"$CURRENT_DIR/" "$INSTALL_DIR/"
|
||||
fi
|
||||
else
|
||||
print_error "Proje dosyaları bulunamadı!"
|
||||
print_info "Script'i proje dizininde çalıştırın veya projeyi klonlayın."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_success "Proje dosyaları hazır."
|
||||
}
|
||||
|
||||
install_backend() {
|
||||
print_info "Backend dependencies kuruluyor..."
|
||||
cd "${INSTALL_DIR}/backend"
|
||||
|
||||
npm install --production
|
||||
|
||||
print_success "Backend dependencies kuruldu."
|
||||
}
|
||||
|
||||
install_frontend() {
|
||||
print_info "Frontend dependencies kuruluyor..."
|
||||
cd "${INSTALL_DIR}/frontend"
|
||||
|
||||
npm install
|
||||
|
||||
print_success "Frontend dependencies kuruldu."
|
||||
}
|
||||
|
||||
setup_env_files() {
|
||||
print_info "Çevre değişkenleri ayarlanıyor..."
|
||||
|
||||
# Backend .env
|
||||
if [[ ! -f "${INSTALL_DIR}/backend/.env" ]]; then
|
||||
cp "${INSTALL_DIR}/backend/.env.example" "${INSTALL_DIR}/backend/.env"
|
||||
|
||||
# Session secret oluştur
|
||||
SESSION_SECRET=$(node -e "console.log(require('crypto').randomBytes(64).toString('hex'))")
|
||||
|
||||
# .env dosyasını güncelle
|
||||
sed -i "s|NODE_ENV=development|NODE_ENV=production|g" "${INSTALL_DIR}/backend/.env"
|
||||
sed -i "s|SESSION_SECRET=.*|SESSION_SECRET=${SESSION_SECRET}|g" "${INSTALL_DIR}/backend/.env"
|
||||
sed -i "s|DB_PATH=.*|DB_PATH=${INSTALL_DIR}/backend/database/oltalama.db|g" "${INSTALL_DIR}/backend/.env"
|
||||
|
||||
print_success "Backend .env dosyası oluşturuldu."
|
||||
print_warning "Gmail ve Telegram ayarlarını panelden yapabilirsiniz."
|
||||
else
|
||||
print_info "Backend .env dosyası zaten mevcut."
|
||||
fi
|
||||
|
||||
# Frontend .env
|
||||
if [[ ! -f "${INSTALL_DIR}/frontend/.env" ]]; then
|
||||
cp "${INSTALL_DIR}/frontend/.env.example" "${INSTALL_DIR}/frontend/.env"
|
||||
print_success "Frontend .env dosyası oluşturuldu."
|
||||
else
|
||||
print_info "Frontend .env dosyası zaten mevcut."
|
||||
fi
|
||||
}
|
||||
|
||||
setup_admin_user() {
|
||||
print_info "Admin kullanıcısı oluşturuluyor..."
|
||||
|
||||
# Check if admin already exists
|
||||
ADMIN_COUNT=$(sqlite3 "${INSTALL_DIR}/backend/database/oltalama.db" "SELECT COUNT(*) FROM admin_user;" 2>/dev/null || echo "0")
|
||||
|
||||
if [[ "$ADMIN_COUNT" -gt 0 ]]; then
|
||||
print_info "Admin kullanıcısı zaten mevcut, atlanıyor."
|
||||
return
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_warning "╔═══════════════════════════════════════════════════════════════╗"
|
||||
print_warning "║ Admin Kullanıcı Bilgilerini Oluşturun ║"
|
||||
print_warning "╚═══════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Username
|
||||
while true; do
|
||||
read -p "Admin kullanıcı adı (en az 3 karakter): " ADMIN_USERNAME
|
||||
if [[ ${#ADMIN_USERNAME} -ge 3 ]]; then
|
||||
break
|
||||
else
|
||||
print_error "Kullanıcı adı en az 3 karakter olmalıdır!"
|
||||
fi
|
||||
done
|
||||
|
||||
# Password with validation
|
||||
while true; do
|
||||
read -sp "Admin şifresi (en az 8 karakter, harf ve rakam içermeli): " ADMIN_PASSWORD
|
||||
echo ""
|
||||
|
||||
# Password length check
|
||||
if [[ ${#ADMIN_PASSWORD} -lt 8 ]]; then
|
||||
print_error "Şifre en az 8 karakter olmalıdır!"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check for letters and numbers
|
||||
if ! [[ "$ADMIN_PASSWORD" =~ [a-zA-Z] ]] || ! [[ "$ADMIN_PASSWORD" =~ [0-9] ]]; then
|
||||
print_error "Şifre hem harf hem de rakam içermelidir!"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Confirm password
|
||||
read -sp "Şifreyi tekrar girin: " ADMIN_PASSWORD_CONFIRM
|
||||
echo ""
|
||||
|
||||
if [[ "$ADMIN_PASSWORD" == "$ADMIN_PASSWORD_CONFIRM" ]]; then
|
||||
break
|
||||
else
|
||||
print_error "Şifreler eşleşmiyor! Tekrar deneyin."
|
||||
fi
|
||||
done
|
||||
|
||||
# Create admin user using Node.js
|
||||
cd "${INSTALL_DIR}/backend"
|
||||
|
||||
cat > /tmp/create_admin.js << EOF
|
||||
const bcrypt = require('bcrypt');
|
||||
const { sequelize } = require('./src/config/database');
|
||||
const AdminUser = require('./src/models/AdminUser');
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
|
||||
const hashedPassword = await bcrypt.hash('${ADMIN_PASSWORD}', 10);
|
||||
|
||||
await AdminUser.create({
|
||||
username: '${ADMIN_USERNAME}',
|
||||
password_hash: hashedPassword,
|
||||
email: null,
|
||||
full_name: 'Administrator',
|
||||
});
|
||||
|
||||
console.log('✓ Admin kullanıcısı oluşturuldu');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('✗ Hata:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
EOF
|
||||
|
||||
node /tmp/create_admin.js
|
||||
rm -f /tmp/create_admin.js
|
||||
|
||||
print_success "Admin kullanıcısı oluşturuldu: ${ADMIN_USERNAME}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
setup_database() {
|
||||
print_info "Database oluşturuluyor..."
|
||||
cd "${INSTALL_DIR}/backend"
|
||||
|
||||
# Migrations
|
||||
node migrations/run-migrations.js
|
||||
print_success "Database migrations tamamlandı."
|
||||
|
||||
# Seed sample data (companies and templates only, not admin user)
|
||||
ADMIN_COUNT=$(sqlite3 "${INSTALL_DIR}/backend/database/oltalama.db" "SELECT COUNT(*) FROM admin_user;" 2>/dev/null || echo "0")
|
||||
|
||||
if [[ "$ADMIN_COUNT" -eq 0 ]]; then
|
||||
# Seed only non-admin data
|
||||
cat > /tmp/seed_data.js << 'EOF'
|
||||
const { sequelize } = require('./src/config/database');
|
||||
const { Company, MailTemplate } = require('./src/models');
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
|
||||
// Seed companies
|
||||
const companies = [
|
||||
{ name: 'Türk Telekom', domain: 'turktelekom.com.tr', description: 'Türkiye\'nin lider telekomünikasyon şirketi' },
|
||||
{ name: 'İş Bankası', domain: 'isbank.com.tr', description: 'Türkiye\'nin en büyük özel sermayeli bankası' },
|
||||
{ name: 'PTT', domain: 'ptt.gov.tr', description: 'Posta ve Telgraf Teşkilatı' },
|
||||
];
|
||||
|
||||
for (const company of companies) {
|
||||
await Company.findOrCreate({ where: { name: company.name }, defaults: company });
|
||||
}
|
||||
|
||||
// Seed templates
|
||||
const templates = [
|
||||
{
|
||||
name: 'Banka Güvenlik Uyarısı',
|
||||
template_type: 'bank',
|
||||
subject_template: '🔒 {{company_name}} - Hesap Güvenlik Uyarısı',
|
||||
body_html: '<html><body style="font-family: Arial, sans-serif; line-height: 1.6;"><div style="max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #ddd;"><h2 style="color: #d32f2f;">🔒 Güvenlik Uyarısı</h2><p>Sayın {{employee_name}},</p><p>{{company_name}} hesabınızda şüpheli bir aktivite tespit edildi. Hesabınızın güvenliğini sağlamak için lütfen aşağıdaki bağlantıya tıklayarak kimlik doğrulaması yapın.</p><p style="text-align: center; margin: 30px 0;"><a href="{{tracking_url}}" style="background-color: #d32f2f; color: white; padding: 12px 30px; text-decoration: none; border-radius: 5px; display: inline-block;">Hesabımı Doğrula</a></p><p style="color: #666; font-size: 12px;">Bu işlemi 24 saat içinde yapmazsanız hesabınız geçici olarak askıya alınabilir.</p><p style="color: #666; font-size: 12px;">Tarih: {{current_date}}</p><hr style="border: none; border-top: 1px solid #eee; margin: 20px 0;"><p style="color: #999; font-size: 11px;">Bu bir phishing testidir. Gerçek bir güvenlik tehdidi değildir.</p></div></body></html>',
|
||||
description: 'Banka hesap güvenliği temalı phishing test maili',
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
name: 'E-Devlet Sistem Güncellemesi',
|
||||
template_type: 'edevlet',
|
||||
subject_template: '⚠️ E-Devlet - Sistem Güncellemesi Gerekli',
|
||||
body_html: '<html><body style="font-family: Arial, sans-serif; line-height: 1.6;"><div style="max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #ddd;"><div style="background-color: #c62828; color: white; padding: 15px; text-align: center;"><h2 style="margin: 0;">E-DEVLET KAPISI</h2></div><div style="padding: 20px;"><p>Sayın {{employee_name}},</p><p>E-Devlet sistemimizde önemli bir güvenlik güncellemesi yapılmaktadır. Hesabınıza erişiminizi sürdürebilmek için lütfen kimlik bilgilerinizi güncelleyin.</p><p style="text-align: center; margin: 30px 0;"><a href="{{tracking_url}}" style="background-color: #c62828; color: white; padding: 12px 30px; text-decoration: none; border-radius: 5px; display: inline-block;">Bilgilerimi Güncelle</a></p><p style="background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 10px; color: #856404;">⚠️ Bu işlemi 48 saat içinde tamamlamazsanız E-Devlet hesabınız askıya alınacaktır.</p><p style="color: #666; font-size: 12px;">İşlem Tarihi: {{current_date}}</p></div><div style="background-color: #f5f5f5; padding: 15px; text-align: center; color: #666; font-size: 11px;"><p>Bu bir phishing farkındalık testidir.</p><p>© {{current_year}} E-Devlet Kapısı</p></div></div></body></html>',
|
||||
description: 'E-Devlet sistem güncellemesi temalı phishing test maili',
|
||||
active: true,
|
||||
},
|
||||
];
|
||||
|
||||
for (const template of templates) {
|
||||
await MailTemplate.findOrCreate({ where: { template_type: template.template_type }, defaults: template });
|
||||
}
|
||||
|
||||
console.log('✓ Örnek veriler oluşturuldu');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('✗ Hata:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
EOF
|
||||
|
||||
node /tmp/seed_data.js
|
||||
rm -f /tmp/seed_data.js
|
||||
print_success "Örnek veriler oluşturuldu (şirketler ve mail şablonları)."
|
||||
else
|
||||
print_info "Database zaten veri içeriyor, seed atlanıyor."
|
||||
fi
|
||||
}
|
||||
|
||||
build_frontend() {
|
||||
print_info "Frontend build ediliyor..."
|
||||
cd "${INSTALL_DIR}/frontend"
|
||||
|
||||
npm run build
|
||||
|
||||
print_success "Frontend build tamamlandı."
|
||||
}
|
||||
|
||||
setup_pm2() {
|
||||
print_info "PM2 konfigürasyonu yapılıyor..."
|
||||
|
||||
# ecosystem.config.js oluştur
|
||||
cat > "${INSTALL_DIR}/ecosystem.config.js" << 'EOF'
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'oltalama-backend',
|
||||
cwd: '/opt/oltalama/backend',
|
||||
script: 'src/app.js',
|
||||
instances: 1,
|
||||
exec_mode: 'cluster',
|
||||
watch: false,
|
||||
max_memory_restart: '500M',
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 3000,
|
||||
},
|
||||
error_file: '/var/log/oltalama/backend-error.log',
|
||||
out_file: '/var/log/oltalama/backend-out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||
},
|
||||
{
|
||||
name: 'oltalama-frontend',
|
||||
cwd: '/opt/oltalama/frontend',
|
||||
script: 'npm',
|
||||
args: 'run preview',
|
||||
instances: 1,
|
||||
exec_mode: 'fork',
|
||||
watch: false,
|
||||
max_memory_restart: '300M',
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 4173,
|
||||
},
|
||||
error_file: '/var/log/oltalama/frontend-error.log',
|
||||
out_file: '/var/log/oltalama/frontend-out.log',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||
},
|
||||
],
|
||||
};
|
||||
EOF
|
||||
|
||||
print_success "PM2 konfigürasyon dosyası oluşturuldu."
|
||||
}
|
||||
|
||||
start_services() {
|
||||
print_info "Servisler başlatılıyor..."
|
||||
|
||||
cd "${INSTALL_DIR}"
|
||||
|
||||
# PM2 ile başlat
|
||||
pm2 start ecosystem.config.js
|
||||
|
||||
# Startup script oluştur
|
||||
pm2 startup systemd -u root --hp /root
|
||||
pm2 save
|
||||
|
||||
print_success "Servisler başlatıldı."
|
||||
|
||||
# Durum göster
|
||||
sleep 2
|
||||
pm2 status
|
||||
}
|
||||
|
||||
setup_permissions() {
|
||||
print_info "Dosya izinleri ayarlanıyor..."
|
||||
|
||||
# Dizin sahipliği
|
||||
chown -R ${USER}:${USER} ${INSTALL_DIR}
|
||||
chown -R ${USER}:${USER} ${LOG_DIR}
|
||||
|
||||
# .env dosyaları
|
||||
chmod 600 "${INSTALL_DIR}/backend/.env"
|
||||
chmod 600 "${INSTALL_DIR}/frontend/.env"
|
||||
|
||||
# Database
|
||||
chmod 600 "${INSTALL_DIR}/backend/database/oltalama.db"
|
||||
|
||||
print_success "Dosya izinleri ayarlandı."
|
||||
}
|
||||
|
||||
setup_firewall() {
|
||||
print_info "Firewall ayarlanıyor..."
|
||||
|
||||
if command -v ufw &> /dev/null; then
|
||||
# SSH izin ver
|
||||
ufw allow 22/tcp comment 'SSH'
|
||||
|
||||
# HTTP/HTTPS izin ver
|
||||
ufw allow 80/tcp comment 'HTTP'
|
||||
ufw allow 443/tcp comment 'HTTPS'
|
||||
|
||||
# Backend ve Frontend portlarını engelle (sadece localhost'tan erişilebilir)
|
||||
ufw deny 3000/tcp comment 'Oltalama Backend (use reverse proxy)'
|
||||
ufw deny 4173/tcp comment 'Oltalama Frontend (use reverse proxy)'
|
||||
|
||||
# UFW'yi aktifleştir (sadece henüz aktif değilse)
|
||||
if ! ufw status | grep -q "Status: active"; then
|
||||
print_warning "UFW firewall aktifleştiriliyor..."
|
||||
print_warning "SSH bağlantınız kopmayacak (port 22 açık)."
|
||||
read -p "Devam etmek için ENTER'a basın..."
|
||||
echo "y" | ufw enable
|
||||
fi
|
||||
|
||||
print_success "Firewall ayarlandı."
|
||||
else
|
||||
print_warning "UFW bulunamadı, firewall ayarları atlanıyor."
|
||||
fi
|
||||
}
|
||||
|
||||
setup_backup_cron() {
|
||||
print_info "Otomatik yedekleme ayarlanıyor..."
|
||||
|
||||
# Backup script oluştur
|
||||
cat > "${INSTALL_DIR}/backup.sh" << 'EOF'
|
||||
#!/bin/bash
|
||||
BACKUP_DIR="/opt/oltalama/backups"
|
||||
DB_PATH="/opt/oltalama/backend/database/oltalama.db"
|
||||
DATE=$(date +%Y%m%d-%H%M%S)
|
||||
|
||||
mkdir -p $BACKUP_DIR
|
||||
cp $DB_PATH "$BACKUP_DIR/oltalama-$DATE.db"
|
||||
find $BACKUP_DIR -name "oltalama-*.db" -mtime +30 -delete
|
||||
|
||||
echo "Backup completed: oltalama-$DATE.db"
|
||||
EOF
|
||||
|
||||
chmod +x "${INSTALL_DIR}/backup.sh"
|
||||
|
||||
# Crontab ekle
|
||||
CRON_JOB="0 3 * * * ${INSTALL_DIR}/backup.sh >> ${LOG_DIR}/backup.log 2>&1"
|
||||
(crontab -l 2>/dev/null | grep -v "backup.sh"; echo "$CRON_JOB") | crontab -
|
||||
|
||||
print_success "Otomatik yedekleme ayarlandı (her gün saat 03:00)."
|
||||
}
|
||||
|
||||
print_completion() {
|
||||
echo -e "\n${GREEN}╔═══════════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${GREEN}║ ║${NC}"
|
||||
echo -e "${GREEN}║ 🎉 Kurulum Tamamlandı! 🎉 ║${NC}"
|
||||
echo -e "${GREEN}║ ║${NC}"
|
||||
echo -e "${GREEN}╚═══════════════════════════════════════════════════════════════╝${NC}\n"
|
||||
|
||||
print_info "Servis Bilgileri:"
|
||||
echo -e " Backend: ${BLUE}http://localhost:3000${NC}"
|
||||
echo -e " Frontend: ${BLUE}http://localhost:4173${NC}"
|
||||
|
||||
print_info "\nAdmin Hesabı:"
|
||||
echo -e " ${GREEN}✓${NC} Kurulum sırasında oluşturuldu"
|
||||
echo -e " ${GREEN}✓${NC} Güvenli şifre kullanıldı"
|
||||
|
||||
print_info "\nYapılması Gerekenler:"
|
||||
echo " 1. Nginx Proxy Manager'da reverse proxy ayarları yapın"
|
||||
echo " 2. Frontend için: yourdomain.com → localhost:4173"
|
||||
echo " 3. Backend API için path: /api → localhost:3000"
|
||||
echo " 4. SSL sertifikası ekleyin"
|
||||
echo " 5. Panele giriş yapın ve Gmail/Telegram ayarlarını yapın"
|
||||
|
||||
print_info "\nYararlı Komutlar:"
|
||||
echo " Servis durumu: pm2 status"
|
||||
echo " Logları izle: pm2 logs"
|
||||
echo " Servis yeniden başlat: pm2 restart all"
|
||||
echo " Servis durdur: pm2 stop all"
|
||||
|
||||
print_info "\nDokümantasyon:"
|
||||
echo " Detaylı kurulum kılavuzu: ${INSTALL_DIR}/DEPLOYMENT.md"
|
||||
echo " Kullanım kılavuzu: ${INSTALL_DIR}/KULLANIM.md"
|
||||
echo " Hızlı başlangıç: ${INSTALL_DIR}/QUICKSTART.md"
|
||||
|
||||
print_success "\nKurulum başarıyla tamamlandı!"
|
||||
}
|
||||
|
||||
# Ana kurulum fonksiyonu
|
||||
main() {
|
||||
print_header
|
||||
|
||||
check_root
|
||||
check_os
|
||||
|
||||
print_info "Kurulum başlıyor...\n"
|
||||
|
||||
install_dependencies
|
||||
install_nodejs
|
||||
install_pm2
|
||||
setup_directories
|
||||
install_project
|
||||
install_backend
|
||||
install_frontend
|
||||
setup_env_files
|
||||
setup_database
|
||||
setup_admin_user
|
||||
build_frontend
|
||||
setup_pm2
|
||||
setup_permissions
|
||||
start_services
|
||||
setup_firewall
|
||||
setup_backup_cron
|
||||
|
||||
print_completion
|
||||
}
|
||||
|
||||
# Script'i çalıştır
|
||||
main "$@"
|
||||
|
||||
396
docs/DOMAIN_SETUP.md
Normal file
396
docs/DOMAIN_SETUP.md
Normal file
@@ -0,0 +1,396 @@
|
||||
# 🌐 Domain Yapılandırma Rehberi
|
||||
|
||||
Oltalama Panel için domain yapılandırma seçenekleri ve kurulum rehberi.
|
||||
|
||||
## 📋 İki Seçenek
|
||||
|
||||
### Seçenek 1: Tek Domain (Önerilen) ⭐
|
||||
|
||||
**Yapı:**
|
||||
```
|
||||
yourdomain.com/ → Frontend
|
||||
yourdomain.com/api/ → Backend API
|
||||
yourdomain.com/t/ → Tracking Links
|
||||
```
|
||||
|
||||
**Avantajları:**
|
||||
- ✅ CORS sorunu yok
|
||||
- ✅ Tek SSL sertifikası
|
||||
- ✅ Kolay kurulum
|
||||
- ✅ Basit yönetim
|
||||
|
||||
**Dezavantajları:**
|
||||
- ⚠️ Reverse proxy gerekli (Nginx Proxy Manager)
|
||||
|
||||
### Seçenek 2: İki Ayrı Domain
|
||||
|
||||
**Yapı:**
|
||||
```
|
||||
panel.yourdomain.com → Frontend
|
||||
api.yourdomain.com → Backend API & Tracking
|
||||
```
|
||||
|
||||
**Avantajları:**
|
||||
- ✅ Servisler birbirinden izole
|
||||
- ✅ Bağımsız ölçeklendirme
|
||||
- ✅ Farklı sunucularda çalışabilir
|
||||
|
||||
**Dezavantajları:**
|
||||
- ⚠️ CORS yapılandırması gerekli
|
||||
- ⚠️ İki SSL sertifikası
|
||||
- ⚠️ Daha karmaşık kurulum
|
||||
|
||||
## 🚀 Seçenek 1: Tek Domain Kurulumu
|
||||
|
||||
### 1. DNS Ayarları
|
||||
|
||||
```
|
||||
yourdomain.com A 123.456.789.10
|
||||
www.yourdomain.com CNAME yourdomain.com
|
||||
```
|
||||
|
||||
### 2. Nginx Proxy Manager Kurulumu
|
||||
|
||||
**Proxy Host Ekle:**
|
||||
|
||||
```
|
||||
Domain: yourdomain.com, www.yourdomain.com
|
||||
Scheme: http
|
||||
Forward Hostname: localhost
|
||||
Forward Port: 4173
|
||||
SSL: ✓ Force SSL, HTTP/2, HSTS
|
||||
```
|
||||
|
||||
**Advanced Config:**
|
||||
|
||||
```nginx
|
||||
location /api {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /t/ {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Oltalama Panel Ayarları
|
||||
|
||||
Panele giriş yapın → **Ayarlar** → **Genel Ayarlar**
|
||||
|
||||
```
|
||||
☐ İki Ayrı Domain Kullan (kapalı bırakın)
|
||||
Domain (Base URL): https://yourdomain.com
|
||||
```
|
||||
|
||||
### 4. Test
|
||||
|
||||
```bash
|
||||
# Frontend
|
||||
curl https://yourdomain.com
|
||||
|
||||
# Backend API
|
||||
curl https://yourdomain.com/api/health
|
||||
|
||||
# Tracking
|
||||
curl -I https://yourdomain.com/t/test-token
|
||||
```
|
||||
|
||||
## 🔀 Seçenek 2: İki Domain Kurulumu
|
||||
|
||||
### 1. DNS Ayarları
|
||||
|
||||
```
|
||||
api.yourdomain.com A 123.456.789.10
|
||||
panel.yourdomain.com A 123.456.789.10
|
||||
```
|
||||
|
||||
### 2. Nginx Proxy Manager - Backend
|
||||
|
||||
**Proxy Host Ekle (Backend):**
|
||||
|
||||
```
|
||||
Domain: api.yourdomain.com
|
||||
Scheme: http
|
||||
Forward Hostname: localhost
|
||||
Forward Port: 3000
|
||||
SSL: ✓ Force SSL, HTTP/2, HSTS
|
||||
```
|
||||
|
||||
### 3. Nginx Proxy Manager - Frontend
|
||||
|
||||
**Proxy Host Ekle (Frontend):**
|
||||
|
||||
```
|
||||
Domain: panel.yourdomain.com
|
||||
Scheme: http
|
||||
Forward Hostname: localhost
|
||||
Forward Port: 4173
|
||||
SSL: ✓ Force SSL, HTTP/2, HSTS
|
||||
```
|
||||
|
||||
### 4. Oltalama Panel Ayarları
|
||||
|
||||
Panele giriş yapın → **Ayarlar** → **Genel Ayarlar**
|
||||
|
||||
```
|
||||
☑ İki Ayrı Domain Kullan (aktif et)
|
||||
Backend Domain: https://api.yourdomain.com
|
||||
Frontend Domain: https://panel.yourdomain.com
|
||||
```
|
||||
|
||||
**Kaydet** butonuna tıklayın. CORS otomatik olarak yapılandırılacaktır.
|
||||
|
||||
### 5. Frontend Ortam Değişkenleri
|
||||
|
||||
`/opt/oltalama/frontend/.env`:
|
||||
|
||||
```env
|
||||
VITE_API_URL=https://api.yourdomain.com
|
||||
```
|
||||
|
||||
Frontend'i yeniden build edin:
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama/frontend
|
||||
npm run build
|
||||
pm2 restart oltalama-frontend
|
||||
```
|
||||
|
||||
### 6. Test
|
||||
|
||||
```bash
|
||||
# Frontend
|
||||
curl https://panel.yourdomain.com
|
||||
|
||||
# Backend API
|
||||
curl https://api.yourdomain.com/api/health
|
||||
|
||||
# Tracking
|
||||
curl -I https://api.yourdomain.com/t/test-token
|
||||
|
||||
# CORS test
|
||||
curl -I -X OPTIONS https://api.yourdomain.com/api/health \
|
||||
-H "Origin: https://panel.yourdomain.com" \
|
||||
-H "Access-Control-Request-Method: GET"
|
||||
```
|
||||
|
||||
## 🔧 Port Ayarları
|
||||
|
||||
### Varsayılan Portlar
|
||||
|
||||
- **Backend**: `3000`
|
||||
- **Frontend**: `4173`
|
||||
- **Nginx Proxy Manager**: `80` (HTTP), `443` (HTTPS)
|
||||
|
||||
### Farklı Portlar Kullanma
|
||||
|
||||
Eğer backend veya frontend'i farklı portlarda çalıştırmak isterseniz:
|
||||
|
||||
#### Backend Port Değiştirme
|
||||
|
||||
**1. Backend .env:**
|
||||
```env
|
||||
PORT=8080
|
||||
```
|
||||
|
||||
**2. PM2 Ecosystem Config:**
|
||||
```javascript
|
||||
{
|
||||
name: 'oltalama-backend',
|
||||
env: {
|
||||
PORT: 8080,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**3. Nginx Proxy Manager:**
|
||||
```
|
||||
Forward Port: 8080
|
||||
```
|
||||
|
||||
**4. Restart:**
|
||||
```bash
|
||||
pm2 restart oltalama-backend
|
||||
```
|
||||
|
||||
#### Frontend Port Değiştirme
|
||||
|
||||
**1. Frontend package.json:**
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"preview": "vite preview --port 5000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**2. PM2 Ecosystem Config:**
|
||||
```javascript
|
||||
{
|
||||
name: 'oltalama-frontend',
|
||||
env: {
|
||||
PORT: 5000,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**3. Nginx Proxy Manager:**
|
||||
```
|
||||
Forward Port: 5000
|
||||
```
|
||||
|
||||
**4. Restart:**
|
||||
```bash
|
||||
pm2 restart oltalama-frontend
|
||||
```
|
||||
|
||||
## 🔒 SSL/TLS Sertifikaları
|
||||
|
||||
### Let's Encrypt (Otomatik)
|
||||
|
||||
Nginx Proxy Manager üzerinden otomatik:
|
||||
|
||||
1. Proxy Host ayarlarına girin
|
||||
2. **SSL** sekmesine gidin
|
||||
3. **Request a new SSL Certificate** seçin
|
||||
4. **Force SSL**, **HTTP/2**, **HSTS** aktif edin
|
||||
5. Email girin ve **I Agree** işaretleyin
|
||||
6. **Save**
|
||||
|
||||
Sertifika otomatik olarak yenilenecektir.
|
||||
|
||||
### Manuel SSL (Opsiyonel)
|
||||
|
||||
```bash
|
||||
# Certbot kurulumu
|
||||
sudo apt install certbot
|
||||
|
||||
# Sertifika oluşturma
|
||||
sudo certbot certonly --standalone -d yourdomain.com
|
||||
|
||||
# Sertifikalar
|
||||
/etc/letsencrypt/live/yourdomain.com/fullchain.pem
|
||||
/etc/letsencrypt/live/yourdomain.com/privkey.pem
|
||||
```
|
||||
|
||||
## 🐛 Sorun Giderme
|
||||
|
||||
### Problem: "Failed to load resource: net::ERR_BLOCKED_BY_CLIENT"
|
||||
|
||||
**Sebep:** AdBlock/uBlock Origin tracking URL'lerini engelliyor
|
||||
|
||||
**Çözüm:**
|
||||
- Test için AdBlock'u devre dışı bırakın
|
||||
- Veya tracking URL pattern'ini değiştirin
|
||||
|
||||
### Problem: CORS hatası
|
||||
|
||||
**Semptomlar:**
|
||||
```
|
||||
Access to XMLHttpRequest at 'https://api.yourdomain.com/api/...'
|
||||
from origin 'https://panel.yourdomain.com' has been blocked by CORS policy
|
||||
```
|
||||
|
||||
**Çözüm:**
|
||||
1. Panelden CORS ayarlarını kontrol edin
|
||||
2. **İki Ayrı Domain Kullan** aktif mi?
|
||||
3. Frontend ve Backend URL'leri doğru mu?
|
||||
4. Backend'i restart edin: `pm2 restart oltalama-backend`
|
||||
|
||||
### Problem: 502 Bad Gateway
|
||||
|
||||
**Çözüm:**
|
||||
```bash
|
||||
# Backend çalışıyor mu?
|
||||
pm2 status
|
||||
|
||||
# Port dinleniyor mu?
|
||||
sudo netstat -tulpn | grep 3000
|
||||
|
||||
# Firewall açık mı?
|
||||
sudo ufw status
|
||||
```
|
||||
|
||||
### Problem: Tracking linkleri çalışmıyor
|
||||
|
||||
**Çözüm:**
|
||||
1. Panelde Base URL doğru ayarlanmış mı?
|
||||
2. `/t/` route Nginx'de tanımlı mı?
|
||||
3. Backend loglarını kontrol edin:
|
||||
```bash
|
||||
pm2 logs oltalama-backend --lines 50
|
||||
```
|
||||
|
||||
## 📊 Karşılaştırma Tablosu
|
||||
|
||||
| Özellik | Tek Domain | İki Domain |
|
||||
|---------|------------|------------|
|
||||
| **Kurulum Süresi** | 15 dakika | 30 dakika |
|
||||
| **CORS** | Gerekli değil | Gerekli |
|
||||
| **SSL Sertifikası** | 1 tane | 2 tane |
|
||||
| **Reverse Proxy** | Gerekli | Opsiyonel |
|
||||
| **DNS Kaydı** | 1 domain | 2 subdomain |
|
||||
| **Güvenlik** | Yüksek | Yüksek |
|
||||
| **Ölçeklenebilirlik** | Orta | Yüksek |
|
||||
| **Bakım** | Kolay | Orta |
|
||||
| **Maliyet** | Düşük | Düşük |
|
||||
| **Önerilen** | ✅ **Evet** | Özel durumlar |
|
||||
|
||||
## 🎯 Hangi Seçeneği Seçmeliyim?
|
||||
|
||||
### Tek Domain Seçin Eğer:
|
||||
- ✅ Basit kurulum istiyorsanız
|
||||
- ✅ CORS ile uğraşmak istemiyorsanız
|
||||
- ✅ Tek sunucuda çalışacaksanız
|
||||
- ✅ Yeni başlıyorsanız
|
||||
|
||||
### İki Domain Seçin Eğer:
|
||||
- ✅ Frontend ve backend'i farklı sunucularda çalıştıracaksanız
|
||||
- ✅ Servislerinizi izole etmek istiyorsanız
|
||||
- ✅ Farklı takımlar frontend/backend'i yönetecekse
|
||||
- ✅ Bağımsız ölçeklendirme gerekiyorsa
|
||||
|
||||
## 📝 Özet: Hızlı Kurulum
|
||||
|
||||
### Tek Domain (5 Adım)
|
||||
|
||||
```bash
|
||||
# 1. Sunucu başlatın
|
||||
pm2 start ecosystem.config.js
|
||||
|
||||
# 2. Nginx Proxy Manager'a domain ekleyin
|
||||
# 3. SSL sertifikası alın (Let's Encrypt)
|
||||
# 4. Panelde domain ayarlayın
|
||||
# 5. Test edin
|
||||
```
|
||||
|
||||
### İki Domain (8 Adım)
|
||||
|
||||
```bash
|
||||
# 1. Sunucu başlatın
|
||||
pm2 start ecosystem.config.js
|
||||
|
||||
# 2. Nginx Proxy Manager'a backend domain ekleyin
|
||||
# 3. Nginx Proxy Manager'a frontend domain ekleyin
|
||||
# 4. SSL sertifikaları alın (Let's Encrypt)
|
||||
# 5. Frontend .env dosyasını güncelleyin
|
||||
# 6. Frontend'i yeniden build edin
|
||||
# 7. Panelde CORS ve domain ayarlarını yapın
|
||||
# 8. Test edin
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Son Güncelleme:** 2025-11-10
|
||||
**Versiyon:** 1.0.0
|
||||
|
||||
**İpucu:** İlk kurulumda **Tek Domain** kullanmanızı öneririz. İhtiyaç duyduğunuzda daha sonra **İki Domain**'e geçebilirsiniz.
|
||||
|
||||
438
docs/NGINX_PROXY_MANAGER.md
Normal file
438
docs/NGINX_PROXY_MANAGER.md
Normal file
@@ -0,0 +1,438 @@
|
||||
# 🌐 Nginx Proxy Manager Kurulum Rehberi
|
||||
|
||||
Oltalama Panel için Nginx Proxy Manager (NPM) ile reverse proxy kurulumu.
|
||||
|
||||
## 📋 Neden Tek Domain?
|
||||
|
||||
**Önerilen Yapı:** Tek domain, path-based routing
|
||||
|
||||
### Avantajları:
|
||||
- ✅ **CORS Sorunu Yok**: Frontend ve backend aynı origin'de
|
||||
- ✅ **Tek SSL Sertifikası**: Sadece bir domain için sertifika
|
||||
- ✅ **Basit Yönetim**: Tek entry point
|
||||
- ✅ **Kolay Kurulum**: Daha az konfigürasyon
|
||||
|
||||
### Alternatif: İki Subdomain
|
||||
|
||||
Eğer iki ayrı subdomain kullanmak isterseniz:
|
||||
- `panel.yourdomain.com` → Frontend
|
||||
- `api.yourdomain.com` → Backend
|
||||
|
||||
**Not:** Bu durumda CORS ayarları gerekir ve iki SSL sertifikası gerekir.
|
||||
|
||||
## 🚀 Nginx Proxy Manager Kurulumu
|
||||
|
||||
### 1. Docker ile NPM Kurulumu
|
||||
|
||||
```bash
|
||||
# Docker ve Docker Compose kurulumu (eğer yoksa)
|
||||
sudo apt update
|
||||
sudo apt install docker.io docker-compose -y
|
||||
|
||||
# NPM dizini oluştur
|
||||
mkdir -p ~/nginx-proxy-manager
|
||||
cd ~/nginx-proxy-manager
|
||||
```
|
||||
|
||||
**docker-compose.yml:**
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
services:
|
||||
app:
|
||||
image: 'jc21/nginx-proxy-manager:latest'
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '80:80' # HTTP
|
||||
- '443:443' # HTTPS
|
||||
- '81:81' # Admin Panel
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./letsencrypt:/etc/letsencrypt
|
||||
```
|
||||
|
||||
```bash
|
||||
# NPM başlat
|
||||
docker-compose up -d
|
||||
|
||||
# Logları izle
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### 2. NPM Admin Paneline Giriş
|
||||
|
||||
1. Tarayıcıdan `http://sunucu-ip:81` adresine gidin
|
||||
2. İlk giriş bilgileri:
|
||||
- Email: `admin@example.com`
|
||||
- Şifre: `changeme`
|
||||
3. Giriş yaptıktan sonra **mutlaka** email ve şifreyi değiştirin
|
||||
|
||||
## 🔧 Tek Domain Konfigürasyonu (Önerilen)
|
||||
|
||||
### Adım 1: Proxy Host Ekle
|
||||
|
||||
NPM Admin Panel → **Hosts** → **Proxy Hosts** → **Add Proxy Host**
|
||||
|
||||
#### Details Sekmesi:
|
||||
|
||||
```
|
||||
Domain Names: yourdomain.com
|
||||
www.yourdomain.com
|
||||
|
||||
Scheme: http
|
||||
Forward Hostname: localhost (veya Oltalama sunucusunun IP'si)
|
||||
Forward Port: 4173
|
||||
|
||||
☑ Cache Assets
|
||||
☑ Block Common Exploits
|
||||
☑ Websockets Support
|
||||
```
|
||||
|
||||
#### SSL Sekmesi:
|
||||
|
||||
```
|
||||
SSL Certificate: Request a new SSL Certificate
|
||||
|
||||
☑ Force SSL
|
||||
☑ HTTP/2 Support
|
||||
☑ HSTS Enabled
|
||||
☑ HSTS Subdomains
|
||||
|
||||
Email Address: youremail@example.com
|
||||
☑ I Agree to the Let's Encrypt Terms of Service
|
||||
```
|
||||
|
||||
#### Advanced Sekmesi:
|
||||
|
||||
**Custom Nginx Configuration:**
|
||||
|
||||
```nginx
|
||||
# Backend API routing
|
||||
location /api {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# Tracking endpoint
|
||||
location /t/ {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# No cache for tracking
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
add_header Pragma "no-cache";
|
||||
add_header Expires "0";
|
||||
}
|
||||
|
||||
# Health check endpoint
|
||||
location /health {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
# Frontend static files
|
||||
location / {
|
||||
proxy_pass http://localhost: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;
|
||||
}
|
||||
```
|
||||
|
||||
### Adım 2: Oltalama Panel Ayarları
|
||||
|
||||
Panele giriş yapın → **Ayarlar** → **Genel Ayarlar**
|
||||
|
||||
```
|
||||
Domain (Base URL): https://yourdomain.com
|
||||
```
|
||||
|
||||
**Önemli:**
|
||||
- Protokolü ekleyin: `https://`
|
||||
- Sondaki `/` karakterini eklemeyin
|
||||
- Subdomain kullanıyorsanız: `https://panel.yourdomain.com`
|
||||
|
||||
## 🔀 İki Domain Konfigürasyonu (Alternatif)
|
||||
|
||||
### Oltalama Panel Ayarları
|
||||
|
||||
Panele giriş yapın → **Ayarlar** → **Genel Ayarlar**
|
||||
|
||||
```
|
||||
☑ İki Ayrı Domain Kullan (CORS Aktif Et)
|
||||
Backend Domain: https://api.yourdomain.com
|
||||
Frontend Domain: https://panel.yourdomain.com
|
||||
```
|
||||
|
||||
**Önemli:**
|
||||
- CORS checkbox'ını işaretleyin
|
||||
- Her iki domain'i de `https://` ile girin
|
||||
- Sondaki `/` karakterini eklemeyin
|
||||
|
||||
## 🔀 Nginx Proxy Manager - İki Domain Kurulumu
|
||||
|
||||
Eğer backend ve frontend'i ayırmak isterseniz:
|
||||
|
||||
### Backend Proxy Host
|
||||
|
||||
```
|
||||
Domain Names: api.yourdomain.com
|
||||
Scheme: http
|
||||
Forward Hostname: localhost
|
||||
Forward Port: 3000
|
||||
|
||||
SSL: ✓ Force SSL, HTTP/2, HSTS
|
||||
```
|
||||
|
||||
### Frontend Proxy Host
|
||||
|
||||
```
|
||||
Domain Names: panel.yourdomain.com
|
||||
Scheme: http
|
||||
Forward Hostname: localhost
|
||||
Forward Port: 4173
|
||||
|
||||
SSL: ✓ Force SSL, HTTP/2, HSTS
|
||||
```
|
||||
|
||||
**Advanced (Frontend):**
|
||||
|
||||
```nginx
|
||||
# Proxy backend API calls
|
||||
location /api {
|
||||
proxy_pass https://api.yourdomain.com;
|
||||
proxy_ssl_server_name on;
|
||||
proxy_set_header Host api.yourdomain.com;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
```
|
||||
|
||||
### CORS Ayarları
|
||||
|
||||
İki domain kullanıyorsanız CORS otomatik olarak ayarlanır. Sadece panelden ayarları yapın:
|
||||
|
||||
**Panelden Ayarlama (Önerilen):**
|
||||
|
||||
1. Giriş yapın → **Ayarlar** → **Genel Ayarlar**
|
||||
2. **☑ İki Ayrı Domain Kullan** checkbox'ını işaretleyin
|
||||
3. **Backend Domain**: `https://api.yourdomain.com`
|
||||
4. **Frontend Domain**: `https://panel.yourdomain.com`
|
||||
5. **Kaydet** butonuna tıklayın
|
||||
|
||||
CORS ayarları otomatik olarak uygulanacaktır.
|
||||
|
||||
**Manuel .env Ayarları (Opsiyonel):**
|
||||
|
||||
Backend `.env` (varsayılan):
|
||||
```env
|
||||
FRONTEND_URL=http://localhost:5173
|
||||
```
|
||||
|
||||
Production'da panel ayarları bu değeri override edecektir.
|
||||
|
||||
## ✅ Test ve Doğrulama
|
||||
|
||||
### 1. DNS Kontrolü
|
||||
|
||||
```bash
|
||||
# Domain çözümleniyor mu?
|
||||
nslookup yourdomain.com
|
||||
|
||||
# Ping testi
|
||||
ping yourdomain.com
|
||||
```
|
||||
|
||||
### 2. SSL Sertifikası Kontrolü
|
||||
|
||||
```bash
|
||||
# SSL sertifikası geçerli mi?
|
||||
curl -I https://yourdomain.com
|
||||
|
||||
# Detaylı SSL testi
|
||||
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com
|
||||
```
|
||||
|
||||
### 3. Endpoint Testleri
|
||||
|
||||
```bash
|
||||
# Frontend erişilebilir mi?
|
||||
curl https://yourdomain.com
|
||||
|
||||
# Backend API erişilebilir mi?
|
||||
curl https://yourdomain.com/api/health
|
||||
|
||||
# Tracking endpoint çalışıyor mu?
|
||||
curl -I https://yourdomain.com/t/test-token
|
||||
```
|
||||
|
||||
### 4. Tarayıcı Testleri
|
||||
|
||||
1. `https://yourdomain.com` adresine gidin
|
||||
2. Login sayfası açılmalı
|
||||
3. Developer Console'da hata olmamalı
|
||||
4. Network sekmesinde:
|
||||
- Frontend dosyaları (JS, CSS) yüklenmeli
|
||||
- API istekleri `/api/*` başarılı olmalı
|
||||
- CORS hatası olmamalı
|
||||
|
||||
## 🐛 Sorun Giderme
|
||||
|
||||
### Problem: 502 Bad Gateway
|
||||
|
||||
**Çözüm:**
|
||||
```bash
|
||||
# Backend çalışıyor mu?
|
||||
pm2 status
|
||||
|
||||
# Port dinleniyor mu?
|
||||
sudo netstat -tulpn | grep -E ':(3000|4173)'
|
||||
|
||||
# Firewall açık mı?
|
||||
sudo ufw status
|
||||
```
|
||||
|
||||
### Problem: SSL Sertifikası Alınamıyor
|
||||
|
||||
**Çözüm:**
|
||||
1. DNS kayıtlarının doğru olduğundan emin olun
|
||||
2. 80 ve 443 portlarının açık olduğunu kontrol edin
|
||||
3. Domain'in sunucuyu gösterdiğinden emin olun
|
||||
|
||||
```bash
|
||||
# Port 80 ve 443 dinleniyor mu?
|
||||
sudo netstat -tulpn | grep -E ':(80|443)'
|
||||
|
||||
# Firewall kuralları
|
||||
sudo ufw allow 80/tcp
|
||||
sudo ufw allow 443/tcp
|
||||
```
|
||||
|
||||
### Problem: CORS Hatası
|
||||
|
||||
**İki subdomain kullanıyorsanız:**
|
||||
|
||||
1. Backend `.env` dosyasında `CORS_ORIGIN` ayarlayın
|
||||
2. Frontend'den API URL'i doğru mu kontrol edin
|
||||
3. Backend'i yeniden başlatın
|
||||
|
||||
```bash
|
||||
cd /opt/oltalama/backend
|
||||
pm2 restart oltalama-backend
|
||||
```
|
||||
|
||||
### Problem: Tracking Linkleri Çalışmıyor
|
||||
|
||||
**Çözüm:**
|
||||
|
||||
1. Panelde doğru domain ayarlandığından emin olun
|
||||
2. `/t/` route'unun proxy'de tanımlı olduğunu kontrol edin
|
||||
3. Backend loglarını kontrol edin:
|
||||
|
||||
```bash
|
||||
pm2 logs oltalama-backend --lines 50
|
||||
```
|
||||
|
||||
## 📊 Performans Optimizasyonu
|
||||
|
||||
### NPM Cache Ayarları
|
||||
|
||||
**Advanced Nginx Config:**
|
||||
|
||||
```nginx
|
||||
# Static dosyalar için cache
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
proxy_pass http://localhost:4173;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# API istekleri için cache yok
|
||||
location /api {
|
||||
proxy_pass http://localhost:3000;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
```nginx
|
||||
# Rate limit tanımı
|
||||
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
||||
|
||||
location /api {
|
||||
limit_req zone=api_limit burst=20 nodelay;
|
||||
limit_req_status 429;
|
||||
|
||||
proxy_pass http://localhost:3000;
|
||||
# ... diğer ayarlar
|
||||
}
|
||||
```
|
||||
|
||||
## 🔒 Güvenlik İpuçları
|
||||
|
||||
1. **NPM Admin Paneli Güvenliği:**
|
||||
- Port 81'i firewall'dan kapatın (sadece lokal erişim)
|
||||
- Güçlü şifre kullanın
|
||||
- 2FA aktif edin (eğer varsa)
|
||||
|
||||
```bash
|
||||
# NPM admin paneline sadece lokal erişim
|
||||
sudo ufw deny 81/tcp
|
||||
```
|
||||
|
||||
2. **SSL/TLS:**
|
||||
- Her zaman Let's Encrypt kullanın
|
||||
- Force SSL aktif edin
|
||||
- HSTS etkinleştirin
|
||||
|
||||
3. **Headers:**
|
||||
- NPM otomatik güvenlik başlıkları ekler
|
||||
- Ek başlıklar için Advanced Nginx Config kullanın
|
||||
|
||||
## 📝 Özet Karşılaştırma
|
||||
|
||||
| Özellik | Tek Domain | İki Subdomain |
|
||||
|---------|------------|---------------|
|
||||
| CORS | ✅ Yok | ⚠️ Gerekli |
|
||||
| SSL | ✅ 1 Sertifika | ⚠️ 2 Sertifika |
|
||||
| Kurulum | ✅ Kolay | ⚠️ Orta |
|
||||
| Yönetim | ✅ Basit | ⚠️ Karmaşık |
|
||||
| DNS | ✅ 1 Kayıt | ⚠️ 2 Kayıt |
|
||||
| Önerilen | ✅ **Evet** | ⚠️ İhtiyaç varsa |
|
||||
|
||||
## 🎯 Sonuç
|
||||
|
||||
**Önerimiz:** Tek domain kullanın (`yourdomain.com`)
|
||||
|
||||
- Frontend: `yourdomain.com/`
|
||||
- Backend: `yourdomain.com/api/`
|
||||
- Tracking: `yourdomain.com/t/`
|
||||
|
||||
Bu yapı en kolay ve en sorunsuz çözümdür.
|
||||
|
||||
---
|
||||
|
||||
**Son Güncelleme:** 2025-11-10
|
||||
**Versiyon:** 1.0.0
|
||||
|
||||
@@ -11,14 +11,19 @@ import {
|
||||
Divider,
|
||||
} from '@mui/material';
|
||||
import { Save, Send } from '@mui/icons-material';
|
||||
import { FormControlLabel, Checkbox } from '@mui/material';
|
||||
import axios from 'axios';
|
||||
|
||||
const API_URL = import.meta.env.VITE_API_URL;
|
||||
|
||||
function Settings() {
|
||||
const [settings, setSettings] = useState({
|
||||
base_url: '',
|
||||
frontend_url: '',
|
||||
cors_enabled: false,
|
||||
gmail_user: '',
|
||||
gmail_app_password: '',
|
||||
gmail_from_name: '',
|
||||
telegram_bot_token: '',
|
||||
telegram_chat_id: '',
|
||||
});
|
||||
@@ -36,11 +41,24 @@ function Settings() {
|
||||
withCredentials: true,
|
||||
});
|
||||
const data = response.data.data || {};
|
||||
|
||||
// Convert array to object
|
||||
const settingsObj = {};
|
||||
if (Array.isArray(data)) {
|
||||
data.forEach(item => {
|
||||
settingsObj[item.key] = item.value === '********' ? '' : item.value;
|
||||
});
|
||||
}
|
||||
|
||||
setSettings({
|
||||
gmail_user: data.gmail_user || '',
|
||||
gmail_app_password: data.gmail_app_password || '',
|
||||
telegram_bot_token: data.telegram_bot_token || '',
|
||||
telegram_chat_id: data.telegram_chat_id || '',
|
||||
base_url: settingsObj.base_url || '',
|
||||
frontend_url: settingsObj.frontend_url || '',
|
||||
cors_enabled: settingsObj.cors_enabled === 'true',
|
||||
gmail_user: settingsObj.gmail_user || '',
|
||||
gmail_app_password: settingsObj.gmail_password || '',
|
||||
gmail_from_name: settingsObj.gmail_from_name || '',
|
||||
telegram_bot_token: settingsObj.telegram_bot_token || '',
|
||||
telegram_chat_id: settingsObj.telegram_chat_id || '',
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to load settings:', error);
|
||||
@@ -52,9 +70,15 @@ function Settings() {
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
axios.put(`${API_URL}/api/settings/system`, {
|
||||
base_url: settings.base_url,
|
||||
frontend_url: settings.frontend_url,
|
||||
cors_enabled: settings.cors_enabled,
|
||||
}, { withCredentials: true }),
|
||||
axios.put(`${API_URL}/api/settings/gmail`, {
|
||||
gmail_user: settings.gmail_user,
|
||||
gmail_app_password: settings.gmail_app_password,
|
||||
gmail_from_name: settings.gmail_from_name,
|
||||
}, { withCredentials: true }),
|
||||
axios.put(`${API_URL}/api/settings/telegram`, {
|
||||
telegram_bot_token: settings.telegram_bot_token,
|
||||
@@ -64,7 +88,7 @@ function Settings() {
|
||||
alert('Ayarlar kaydedildi!');
|
||||
} catch (error) {
|
||||
console.error('Failed to save settings:', error);
|
||||
alert('Ayarlar kaydedilemedi');
|
||||
alert('Ayarlar kaydedilemedi: ' + (error.response?.data?.error || error.message));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -124,10 +148,72 @@ function Settings() {
|
||||
</Typography>
|
||||
|
||||
<Grid container spacing={3}>
|
||||
{/* System Settings */}
|
||||
<Grid item xs={12}>
|
||||
<Paper sx={{ p: 3 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
🌐 Genel Ayarlar
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
Domain ve genel sistem ayarları
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
|
||||
<strong>Tek Domain (Önerilen):</strong> Frontend ve backend aynı domainde, path ile ayrılır<br/>
|
||||
<strong>İki Domain:</strong> Frontend ve backend farklı domainlerde (CORS gerekir)
|
||||
</Typography>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={settings.cors_enabled}
|
||||
onChange={(e) =>
|
||||
setSettings({ ...settings, cors_enabled: e.target.checked })
|
||||
}
|
||||
/>
|
||||
}
|
||||
label="İki Ayrı Domain Kullan (CORS Aktif Et)"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
margin="normal"
|
||||
label={settings.cors_enabled ? "Backend Domain (Base URL)" : "Domain (Base URL)"}
|
||||
type="url"
|
||||
placeholder="https://yourdomain.com"
|
||||
value={settings.base_url}
|
||||
onChange={(e) =>
|
||||
setSettings({ ...settings, base_url: e.target.value })
|
||||
}
|
||||
helperText={
|
||||
settings.cors_enabled
|
||||
? "Backend API domain'i. Örnek: https://api.yourdomain.com"
|
||||
: "Hem frontend hem backend için kullanılacak domain. Örnek: https://yourdomain.com"
|
||||
}
|
||||
/>
|
||||
|
||||
{settings.cors_enabled && (
|
||||
<TextField
|
||||
fullWidth
|
||||
margin="normal"
|
||||
label="Frontend Domain"
|
||||
type="url"
|
||||
placeholder="https://panel.yourdomain.com"
|
||||
value={settings.frontend_url}
|
||||
onChange={(e) =>
|
||||
setSettings({ ...settings, frontend_url: e.target.value })
|
||||
}
|
||||
helperText="Frontend panel domain'i. CORS için gerekli."
|
||||
/>
|
||||
)}
|
||||
</Paper>
|
||||
</Grid>
|
||||
|
||||
{/* Gmail Settings */}
|
||||
<Grid item xs={12} md={6}>
|
||||
<Paper sx={{ p: 3 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Gmail Ayarları
|
||||
📧 Gmail Ayarları
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
Gmail App Password kullanın (2FA aktif olmalı)
|
||||
@@ -152,6 +238,18 @@ function Settings() {
|
||||
onChange={(e) =>
|
||||
setSettings({ ...settings, gmail_app_password: e.target.value })
|
||||
}
|
||||
helperText="Google Hesap → Güvenlik → 2FA → Uygulama Şifreleri"
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
margin="normal"
|
||||
label="Gönderen Adı (Varsayılan)"
|
||||
value={settings.gmail_from_name}
|
||||
onChange={(e) =>
|
||||
setSettings({ ...settings, gmail_from_name: e.target.value })
|
||||
}
|
||||
placeholder="Güvenlik Ekibi"
|
||||
helperText="Mail gönderirken görünecek varsayılan isim"
|
||||
/>
|
||||
|
||||
{alerts.mail && (
|
||||
|
||||
@@ -247,6 +247,14 @@ function TokenDetail() {
|
||||
</Typography>
|
||||
<Typography variant="body1">{token.company?.name}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
Gönderen Adı
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
{token.from_name || 'Varsayılan'}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Paper>
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ function Tokens() {
|
||||
company_id: '',
|
||||
target_email: '',
|
||||
employee_name: '',
|
||||
from_name: '',
|
||||
template_type: 'bank',
|
||||
});
|
||||
|
||||
@@ -65,7 +66,7 @@ function Tokens() {
|
||||
try {
|
||||
await tokenService.createAndSend(formData);
|
||||
setOpenDialog(false);
|
||||
setFormData({ company_id: '', target_email: '', employee_name: '', template_type: 'bank' });
|
||||
setFormData({ company_id: '', target_email: '', employee_name: '', from_name: '', template_type: 'bank' });
|
||||
loadData();
|
||||
alert('Token oluşturuldu ve mail gönderildi!');
|
||||
} catch (error) {
|
||||
@@ -170,6 +171,15 @@ function Tokens() {
|
||||
value={formData.employee_name}
|
||||
onChange={(e) => setFormData({ ...formData, employee_name: e.target.value })}
|
||||
/>
|
||||
<TextField
|
||||
margin="dense"
|
||||
label="Gönderen Adı (Opsiyonel)"
|
||||
fullWidth
|
||||
value={formData.from_name}
|
||||
onChange={(e) => setFormData({ ...formData, from_name: e.target.value })}
|
||||
placeholder="Ör: X Şirketi İnsan Kaynakları, MGT Yönetici"
|
||||
helperText="Belirtilmezse varsayılan gönderen adı kullanılır"
|
||||
/>
|
||||
<TextField
|
||||
select
|
||||
margin="dense"
|
||||
|
||||
132
nginx/oltalama.conf
Normal file
132
nginx/oltalama.conf
Normal file
@@ -0,0 +1,132 @@
|
||||
# Oltalama Nginx Configuration
|
||||
# /etc/nginx/sites-available/oltalama
|
||||
|
||||
# Upstream definitions
|
||||
upstream backend {
|
||||
server localhost:3000;
|
||||
keepalive 64;
|
||||
}
|
||||
|
||||
upstream frontend {
|
||||
server localhost:4173;
|
||||
keepalive 64;
|
||||
}
|
||||
|
||||
# HTTP to HTTPS redirect
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name yourdomain.com;
|
||||
|
||||
# Let's Encrypt verification
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/html;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS server
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name yourdomain.com;
|
||||
|
||||
# SSL certificates (update with your actual paths)
|
||||
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;
|
||||
|
||||
# SSL configuration
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_session_tickets off;
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
# Security headers
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
|
||||
|
||||
# Client body size
|
||||
client_max_body_size 10M;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
|
||||
|
||||
# Rate limiting zone
|
||||
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
||||
limit_req_status 429;
|
||||
|
||||
# Backend API endpoints
|
||||
location /api {
|
||||
# Rate limiting
|
||||
limit_req zone=api_limit burst=20 nodelay;
|
||||
|
||||
proxy_pass http://backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# Tracking endpoint (no rate limiting for legitimate tracking)
|
||||
location /t/ {
|
||||
proxy_pass http://backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# Cache control
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
add_header Pragma "no-cache";
|
||||
add_header Expires "0";
|
||||
}
|
||||
|
||||
# Frontend static files
|
||||
location / {
|
||||
proxy_pass http://frontend;
|
||||
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;
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
proxy_pass http://frontend;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# Logs
|
||||
access_log /var/log/nginx/oltalama-access.log combined;
|
||||
error_log /var/log/nginx/oltalama-error.log warn;
|
||||
}
|
||||
|
||||
117
scripts/change-password.js
Executable file
117
scripts/change-password.js
Executable file
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Admin Password Change Script
|
||||
* Usage: node scripts/change-password.js
|
||||
*/
|
||||
|
||||
const bcrypt = require('bcrypt');
|
||||
const readline = require('readline');
|
||||
const path = require('path');
|
||||
|
||||
// Set correct path for database config
|
||||
process.chdir(path.join(__dirname, '../backend'));
|
||||
|
||||
const { sequelize } = require('../backend/src/config/database');
|
||||
const AdminUser = require('../backend/src/models/AdminUser');
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
const question = (query) => new Promise((resolve) => rl.question(query, resolve));
|
||||
|
||||
const validatePassword = (password) => {
|
||||
if (password.length < 8) {
|
||||
return 'Şifre en az 8 karakter olmalıdır!';
|
||||
}
|
||||
if (!/[a-zA-Z]/.test(password)) {
|
||||
return 'Şifre en az bir harf içermelidir!';
|
||||
}
|
||||
if (!/[0-9]/.test(password)) {
|
||||
return 'Şifre en az bir rakam içermelidir!';
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
console.log('\n╔═══════════════════════════════════════════════════════════════╗');
|
||||
console.log('║ Oltalama Panel - Admin Şifre Değiştir ║');
|
||||
console.log('╚═══════════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
// Connect to database
|
||||
await sequelize.authenticate();
|
||||
console.log('✓ Database bağlantısı başarılı\n');
|
||||
|
||||
// Get username
|
||||
const username = await question('Admin kullanıcı adı: ');
|
||||
|
||||
// Check if user exists
|
||||
const user = await AdminUser.findOne({ where: { username } });
|
||||
if (!user) {
|
||||
console.log('✗ Kullanıcı bulunamadı!');
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Get new password
|
||||
let password;
|
||||
while (true) {
|
||||
// Disable echo for password input
|
||||
const originalWrite = rl._writeToOutput;
|
||||
rl._writeToOutput = function (stringToWrite) {
|
||||
if (stringToWrite.charCodeAt(0) === 13) {
|
||||
rl.output.write('\n');
|
||||
} else {
|
||||
rl.output.write('*');
|
||||
}
|
||||
};
|
||||
|
||||
password = await question('Yeni şifre (en az 8 karakter, harf ve rakam): ');
|
||||
console.log(); // New line after hidden input
|
||||
|
||||
const validationError = validatePassword(password);
|
||||
if (validationError) {
|
||||
console.log(`✗ ${validationError}\n`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const passwordConfirm = await question('Şifreyi tekrar girin: ');
|
||||
console.log(); // New line after hidden input
|
||||
|
||||
// Restore echo
|
||||
rl._writeToOutput = originalWrite;
|
||||
|
||||
if (password !== passwordConfirm) {
|
||||
console.log('✗ Şifreler eşleşmiyor!\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Update password
|
||||
console.log('\n⏳ Şifre güncelleniyor...');
|
||||
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
await user.update({
|
||||
password_hash: hashedPassword,
|
||||
});
|
||||
|
||||
console.log('\n✓ Şifre başarıyla değiştirildi!');
|
||||
console.log(`\nKullanıcı: ${username}`);
|
||||
console.log('Yeni şifre: ********** (güvenli bir şekilde saklandı)');
|
||||
console.log('\n✓ Artık yeni şifrenizle giriş yapabilirsiniz.\n');
|
||||
|
||||
rl.close();
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('\n✗ Hata:', error.message);
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
|
||||
142
scripts/create-admin.js
Executable file
142
scripts/create-admin.js
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Admin User Creation Script
|
||||
* Usage: node scripts/create-admin.js
|
||||
*/
|
||||
|
||||
const bcrypt = require('bcrypt');
|
||||
const readline = require('readline');
|
||||
const path = require('path');
|
||||
|
||||
// Set correct path for database config
|
||||
process.chdir(path.join(__dirname, '../backend'));
|
||||
|
||||
const { sequelize } = require('../backend/src/config/database');
|
||||
const AdminUser = require('../backend/src/models/AdminUser');
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
const question = (query) => new Promise((resolve) => rl.question(query, resolve));
|
||||
const questionHidden = (query) => {
|
||||
return new Promise((resolve) => {
|
||||
rl.question(query, (answer) => {
|
||||
resolve(answer);
|
||||
});
|
||||
rl._writeToOutput = () => {}; // Hide input
|
||||
});
|
||||
};
|
||||
|
||||
const validatePassword = (password) => {
|
||||
if (password.length < 8) {
|
||||
return 'Şifre en az 8 karakter olmalıdır!';
|
||||
}
|
||||
if (!/[a-zA-Z]/.test(password)) {
|
||||
return 'Şifre en az bir harf içermelidir!';
|
||||
}
|
||||
if (!/[0-9]/.test(password)) {
|
||||
return 'Şifre en az bir rakam içermelidir!';
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
console.log('\n╔═══════════════════════════════════════════════════════════════╗');
|
||||
console.log('║ Oltalama Panel - Admin Kullanıcı Oluştur ║');
|
||||
console.log('╚═══════════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
// Connect to database
|
||||
await sequelize.authenticate();
|
||||
console.log('✓ Database bağlantısı başarılı\n');
|
||||
|
||||
// Get username
|
||||
let username;
|
||||
while (true) {
|
||||
username = await question('Admin kullanıcı adı (en az 3 karakter): ');
|
||||
if (username.length >= 3) {
|
||||
// Check if username exists
|
||||
const existing = await AdminUser.findOne({ where: { username } });
|
||||
if (existing) {
|
||||
console.log('✗ Bu kullanıcı adı zaten kullanılıyor!\n');
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
console.log('✗ Kullanıcı adı en az 3 karakter olmalıdır!\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Get password
|
||||
let password;
|
||||
while (true) {
|
||||
// Disable echo for password input
|
||||
const originalWrite = rl._writeToOutput;
|
||||
rl._writeToOutput = function (stringToWrite) {
|
||||
if (stringToWrite.charCodeAt(0) === 13) {
|
||||
rl.output.write('\n');
|
||||
} else {
|
||||
rl.output.write('*');
|
||||
}
|
||||
};
|
||||
|
||||
password = await question('Admin şifresi (en az 8 karakter, harf ve rakam): ');
|
||||
console.log(); // New line after hidden input
|
||||
|
||||
const validationError = validatePassword(password);
|
||||
if (validationError) {
|
||||
console.log(`✗ ${validationError}\n`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const passwordConfirm = await question('Şifreyi tekrar girin: ');
|
||||
console.log(); // New line after hidden input
|
||||
|
||||
// Restore echo
|
||||
rl._writeToOutput = originalWrite;
|
||||
|
||||
if (password !== passwordConfirm) {
|
||||
console.log('✗ Şifreler eşleşmiyor!\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Get optional details
|
||||
const fullName = await question('Tam ad (opsiyonel, ENTER ile geç): ');
|
||||
const email = await question('E-posta (opsiyonel, ENTER ile geç): ');
|
||||
|
||||
// Create admin user
|
||||
console.log('\n⏳ Admin kullanıcısı oluşturuluyor...');
|
||||
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
await AdminUser.create({
|
||||
username,
|
||||
password_hash: hashedPassword,
|
||||
email: email || null,
|
||||
full_name: fullName || 'Administrator',
|
||||
});
|
||||
|
||||
console.log('\n✓ Admin kullanıcısı başarıyla oluşturuldu!');
|
||||
console.log(`\nKullanıcı adı: ${username}`);
|
||||
console.log('Şifre: ********** (güvenli bir şekilde saklandı)');
|
||||
|
||||
if (fullName) console.log(`Tam ad: ${fullName}`);
|
||||
if (email) console.log(`E-posta: ${email}`);
|
||||
|
||||
console.log('\n✓ Artık panele giriş yapabilirsiniz.\n');
|
||||
|
||||
rl.close();
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('\n✗ Hata:', error.message);
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
|
||||
29
systemd/oltalama-backend.service
Normal file
29
systemd/oltalama-backend.service
Normal file
@@ -0,0 +1,29 @@
|
||||
[Unit]
|
||||
Description=Oltalama Backend Service
|
||||
Documentation=https://github.com/yourusername/oltalama
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=www-data
|
||||
Group=www-data
|
||||
WorkingDirectory=/opt/oltalama/backend
|
||||
Environment=NODE_ENV=production
|
||||
Environment=PORT=3000
|
||||
ExecStart=/usr/bin/node /opt/oltalama/backend/src/app.js
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=append:/var/log/oltalama/backend.log
|
||||
StandardError=append:/var/log/oltalama/backend-error.log
|
||||
|
||||
# Security settings
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ReadWritePaths=/opt/oltalama/backend/database
|
||||
ReadWritePaths=/var/log/oltalama
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
27
systemd/oltalama-frontend.service
Normal file
27
systemd/oltalama-frontend.service
Normal file
@@ -0,0 +1,27 @@
|
||||
[Unit]
|
||||
Description=Oltalama Frontend Service
|
||||
Documentation=https://github.com/yourusername/oltalama
|
||||
After=network.target oltalama-backend.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=www-data
|
||||
Group=www-data
|
||||
WorkingDirectory=/opt/oltalama/frontend
|
||||
Environment=NODE_ENV=production
|
||||
Environment=PORT=4173
|
||||
ExecStart=/usr/bin/npm run preview
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=append:/var/log/oltalama/frontend.log
|
||||
StandardError=append:/var/log/oltalama/frontend-error.log
|
||||
|
||||
# Security settings
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
Reference in New Issue
Block a user