From 1a45487cf11b555b498bc85b567b70e59d79dc45 Mon Sep 17 00:00:00 2001 From: salvacybersec Date: Tue, 11 Nov 2025 05:51:07 +0300 Subject: [PATCH] Fix: Handle .env directory issue in bind mount and use relative API paths for single container --- docker-compose.single.yml | 2 ++ docker-entrypoint.sh | 23 +++++++++++++----- frontend/src/pages/Settings.jsx | 43 +++++++++------------------------ frontend/src/services/api.js | 22 ++++++++++++++++- 4 files changed, 51 insertions(+), 39 deletions(-) diff --git a/docker-compose.single.yml b/docker-compose.single.yml index 1ca8d40..49dbff6 100644 --- a/docker-compose.single.yml +++ b/docker-compose.single.yml @@ -31,6 +31,8 @@ services: - oltalama-logs:/app/backend/logs # .env file (optional bind mount - host'tan container'a) # Eğer host'ta .env yoksa, entrypoint script container içinde oluşturur + # NOT: Host'ta .env dosyası yoksa, Docker onu dizin olarak oluşturabilir + # Entrypoint script bunu otomatik düzeltir - ./backend/.env:/app/backend/.env:rw healthcheck: test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 6f09b09..d9d27a8 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -27,18 +27,29 @@ if [ -z "$SESSION_SECRET" ] || [ "$SESSION_SECRET" = "change-this-to-a-very-stro SESSION_SECRET=$(node -e "console.log(require('crypto').randomBytes(64).toString('hex'))") export SESSION_SECRET + # .env dosyası yolu + ENV_FILE="/app/backend/.env" + + # Eğer .env bir dizin ise (bind mount sorunu), sil ve dosya olarak oluştur + if [ -d "$ENV_FILE" ]; then + echo "⚠️ .env bir dizin olarak tespit edildi, düzeltiliyor..." + rm -rf "$ENV_FILE" + fi + + # .env dizinini oluştur (yoksa) + mkdir -p "$(dirname "$ENV_FILE")" + # Session secret'ı .env dosyasına kaydet (persist) - if [ ! -f "/app/backend/.env" ]; then - mkdir -p /app/backend - echo "SESSION_SECRET=$SESSION_SECRET" > /app/backend/.env + if [ ! -f "$ENV_FILE" ]; then + echo "SESSION_SECRET=$SESSION_SECRET" > "$ENV_FILE" echo "✅ Yeni SESSION_SECRET oluşturuldu ve .env dosyasına kaydedildi" echo "📝 SESSION_SECRET: ${SESSION_SECRET:0:20}... (ilk 20 karakter)" else # Mevcut .env dosyasını güncelle - if grep -q "^SESSION_SECRET=" /app/backend/.env; then - sed -i "s|^SESSION_SECRET=.*|SESSION_SECRET=$SESSION_SECRET|" /app/backend/.env + if grep -q "^SESSION_SECRET=" "$ENV_FILE"; then + sed -i "s|^SESSION_SECRET=.*|SESSION_SECRET=$SESSION_SECRET|" "$ENV_FILE" else - echo "SESSION_SECRET=$SESSION_SECRET" >> /app/backend/.env + echo "SESSION_SECRET=$SESSION_SECRET" >> "$ENV_FILE" fi echo "✅ SESSION_SECRET güncellendi ve .env dosyasına kaydedildi" fi diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx index b48b076..7b005db 100644 --- a/frontend/src/pages/Settings.jsx +++ b/frontend/src/pages/Settings.jsx @@ -13,9 +13,7 @@ import { Grid, } from '@mui/material'; import { Save, Send } from '@mui/icons-material'; -import axios from 'axios'; - -const API_URL = import.meta.env.VITE_API_URL; +import api from '../services/api'; function Settings() { const [settings, setSettings] = useState({ @@ -49,9 +47,7 @@ function Settings() { const loadSettings = async () => { try { - const response = await axios.get(`${API_URL}/api/settings`, { - withCredentials: true, - }); + const response = await api.get('/api/settings'); const data = response.data.data || {}; // Convert array to object @@ -83,9 +79,7 @@ function Settings() { const loadAdminInfo = async () => { try { - const response = await axios.get(`${API_URL}/api/settings/admin`, { - withCredentials: true, - }); + const response = await api.get('/api/settings/admin'); if (response.data.success && response.data.data) { setAdminInfo({ username: response.data.data.username || '', @@ -102,21 +96,21 @@ function Settings() { const handleSave = async () => { try { await Promise.all([ - axios.put(`${API_URL}/api/settings/system`, { + api.put('/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`, { + api.put('/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`, { + api.put('/api/settings/telegram', { telegram_bot_token: settings.telegram_bot_token, telegram_chat_id: settings.telegram_chat_id, }, { withCredentials: true }), - axios.put(`${API_URL}/api/ollama/settings`, { + api.put('/api/ollama/settings', { ollama_server_url: settings.ollama_server_url, ollama_model: settings.ollama_model, }, { withCredentials: true }), @@ -131,11 +125,7 @@ function Settings() { const handleTestMail = async () => { setTestLoading({ ...testLoading, mail: true }); try { - const response = await axios.post( - `${API_URL}/api/settings/test-gmail`, - {}, - { withCredentials: true } - ); + const response = await api.post('/api/settings/test-gmail', {}); setAlerts({ ...alerts, mail: { severity: 'success', message: response.data.message } }); } catch (error) { setAlerts({ @@ -150,11 +140,7 @@ function Settings() { const handleTestTelegram = async () => { setTestLoading({ ...testLoading, telegram: true }); try { - const response = await axios.post( - `${API_URL}/api/settings/test-telegram`, - {}, - { withCredentials: true } - ); + const response = await api.post('/api/settings/test-telegram', {}); setAlerts({ ...alerts, telegram: { severity: 'success', message: response.data.message } }); } catch (error) { setAlerts({ @@ -182,10 +168,7 @@ function Settings() { }, { withCredentials: true }); } - const response = await axios.get( - `${API_URL}/api/ollama/test`, - { withCredentials: true } - ); + const response = await api.get('/api/ollama/test'); if (response.data.success) { setOllamaModels(response.data.data.models || []); @@ -233,11 +216,7 @@ function Settings() { updateData.current_password = adminInfo.current_password; } - const response = await axios.put( - `${API_URL}/api/settings/admin`, - updateData, - { withCredentials: true } - ); + const response = await api.put('/api/settings/admin', updateData); if (response.data.success) { setAlerts({ diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index ab92622..b5a2c3e 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -1,6 +1,26 @@ import axios from 'axios'; -const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; +// Single container setup: Use relative path (same origin) +// Multi-container setup: Use VITE_API_URL or default to localhost:3000 +const getApiUrl = () => { + const envUrl = import.meta.env.VITE_API_URL; + + // If VITE_API_URL is set, use it + if (envUrl) { + return envUrl; + } + + // Single container: same origin, use relative path + // This works because frontend and backend are served from the same port + if (import.meta.env.PROD) { + return ''; // Relative path - same origin + } + + // Development: default to localhost:3000 + return 'http://localhost:3000'; +}; + +const API_URL = getApiUrl(); const api = axios.create({ baseURL: API_URL,