mesela yani
This commit is contained in:
@@ -14,7 +14,7 @@ RUN npm install
|
|||||||
COPY frontend/ ./
|
COPY frontend/ ./
|
||||||
|
|
||||||
# Build frontend (output will be in dist/)
|
# Build frontend (output will be in dist/)
|
||||||
RUN npm run build
|
RUN npm run build && test -f dist/index.html
|
||||||
|
|
||||||
# Stage 2: Backend + Runtime
|
# Stage 2: Backend + Runtime
|
||||||
FROM node:20-alpine
|
FROM node:20-alpine
|
||||||
|
|||||||
@@ -15,6 +15,26 @@ const PORT = process.env.PORT || 3000;
|
|||||||
// Security middleware - Helmet'i tamamen kaldır (CORS ve mixed content sorunları için)
|
// Security middleware - Helmet'i tamamen kaldır (CORS ve mixed content sorunları için)
|
||||||
// app.use(helmet()); // Geçici olarak devre dışı
|
// app.use(helmet()); // Geçici olarak devre dışı
|
||||||
|
|
||||||
|
// Basic CSP for SPA and assets to avoid white page due to blocked module scripts
|
||||||
|
// Allow self assets, inline/eval for Vite-built bundles, blobs/data, and API/websocket connections
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
// Only set CSP for HTML responses later, but keeping a permissive default helps some browsers on preload
|
||||||
|
res.setHeader(
|
||||||
|
'Content-Security-Policy',
|
||||||
|
[
|
||||||
|
"default-src 'self' data: blob:;",
|
||||||
|
"script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:;",
|
||||||
|
"style-src 'self' 'unsafe-inline';",
|
||||||
|
"img-src 'self' data: blob:;",
|
||||||
|
"font-src 'self' data:;",
|
||||||
|
"connect-src 'self' http: https: ws: wss:;",
|
||||||
|
"frame-ancestors 'self';",
|
||||||
|
'base-uri \'self\';',
|
||||||
|
].join(' ')
|
||||||
|
);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
// CORS - Her yerden erişime izin ver (tüm route'larda)
|
// CORS - Her yerden erişime izin ver (tüm route'larda)
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
@@ -51,12 +71,21 @@ app.use(express.static(path.join(__dirname, 'public'), {
|
|||||||
res.set('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
res.set('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||||
res.set('Access-Control-Allow-Headers', 'Content-Type, Accept, Origin');
|
res.set('Access-Control-Allow-Headers', 'Content-Type, Accept, Origin');
|
||||||
res.set('Access-Control-Allow-Credentials', 'true');
|
res.set('Access-Control-Allow-Credentials', 'true');
|
||||||
|
// Ensure CSP also present on static (mainly harmless for non-HTML)
|
||||||
|
res.set('Content-Security-Policy',
|
||||||
|
"default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' http: https: ws: wss:; frame-ancestors 'self'; base-uri 'self';"
|
||||||
|
);
|
||||||
|
|
||||||
// Content-Type header'larını doğru ayarla
|
// Content-Type header'larını doğru ayarla
|
||||||
if (filePath.endsWith('.js')) {
|
if (filePath.endsWith('.js')) {
|
||||||
|
// Serve ES modules correctly
|
||||||
res.set('Content-Type', 'application/javascript; charset=utf-8');
|
res.set('Content-Type', 'application/javascript; charset=utf-8');
|
||||||
} else if (filePath.endsWith('.css')) {
|
} else if (filePath.endsWith('.css')) {
|
||||||
res.set('Content-Type', 'text/css; charset=utf-8');
|
res.set('Content-Type', 'text/css; charset=utf-8');
|
||||||
|
} else if (filePath.endsWith('.mjs')) {
|
||||||
|
res.set('Content-Type', 'application/javascript; charset=utf-8');
|
||||||
|
} else if (filePath.endsWith('.svg')) {
|
||||||
|
res.set('Content-Type', 'image/svg+xml');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -113,13 +142,20 @@ app.get('*', (req, res, next) => {
|
|||||||
res.header('Access-Control-Allow-Origin', '*');
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||||
res.header('Access-Control-Allow-Headers', 'Content-Type');
|
res.header('Access-Control-Allow-Headers', 'Content-Type');
|
||||||
|
// Explicit CSP for HTML documents
|
||||||
|
res.setHeader(
|
||||||
|
'Content-Security-Policy',
|
||||||
|
"default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' http: https: ws: wss:; frame-ancestors 'self'; base-uri 'self';"
|
||||||
|
);
|
||||||
|
|
||||||
// Serve frontend index.html for all other routes
|
// Serve frontend index.html for all other routes
|
||||||
const frontendPath = path.join(__dirname, 'public', 'dist', 'index.html');
|
const frontendPath = path.join(__dirname, 'public', 'dist', 'index.html');
|
||||||
res.sendFile(frontendPath, (err) => {
|
res.sendFile(frontendPath, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
// If frontend build doesn't exist, return 404
|
// If frontend build doesn't exist, inform clearly
|
||||||
next();
|
res.status(503).send(
|
||||||
|
'Frontend build not found. Please build the frontend (npm run build) and ensure dist is copied to backend/src/public/dist.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -42,6 +42,14 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Ensure frontend build exists before starting server
|
||||||
|
FRONTEND_INDEX="src/public/dist/index.html"
|
||||||
|
if [ ! -f "$FRONTEND_INDEX" ]; then
|
||||||
|
echo "❌ Frontend build not found at $FRONTEND_INDEX"
|
||||||
|
echo "ℹ️ Please run 'npm run build' in the frontend (or rebuild the Docker image) so the dist assets are available."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Start the application
|
# Start the application
|
||||||
echo "✨ Starting server..."
|
echo "✨ Starting server..."
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user