diff --git a/mnemo_cards_backend/Dockerfile b/mnemo_cards_backend/Dockerfile index b738bf1..c85dee0 100644 --- a/mnemo_cards_backend/Dockerfile +++ b/mnemo_cards_backend/Dockerfile @@ -50,8 +50,6 @@ ENV PORT=3000 \ BACKUP_DIR=/app/backups \ WORK_DIR=/app \ DEBUG=false \ - CERTS_PATH= \ - DUAL_MODE=false \ ADMIN_IDS= EXPOSE 3000 @@ -60,11 +58,11 @@ EXPOSE 3000 # Increased start-period to 90s to allow server initialization (Isar DB, cron jobs, etc.) # Isar может долго инициализироваться при первом запуске или при большом объеме данных # Используем 127.0.0.1 для healthcheck (внутри контейнера работает даже если сервер слушает на 0.0.0.0) -# Сервер работает по HTTPS, поэтому проверяем https:// с флагом -k для игнорирования проверки сертификата +# Сервер работает только по HTTP (HTTPS обрабатывается на уровне reverse proxy в Coolify) # Пробуем curl, если не работает - используем wget как fallback HEALTHCHECK --interval=15s --timeout=10s --start-period=90s --retries=3 \ - CMD curl -f -sS -k --max-time 8 --connect-timeout 3 https://127.0.0.1:${PORT:-3000}/health > /dev/null 2>&1 || \ - wget --quiet --no-check-certificate --tries=1 --timeout=8 --spider https://127.0.0.1:${PORT:-3000}/health || exit 1 + CMD curl -f -sS --max-time 8 --connect-timeout 3 http://127.0.0.1:${PORT:-3000}/health > /dev/null 2>&1 || \ + wget --quiet --tries=1 --timeout=8 --spider http://127.0.0.1:${PORT:-3000}/health || exit 1 # Start server - все настройки читаются из environment variables CMD ["/app/server"] diff --git a/mnemo_cards_backend/lib/api/mnemo_shelf.dart b/mnemo_cards_backend/lib/api/mnemo_shelf.dart index 6229973..fa1a908 100644 --- a/mnemo_cards_backend/lib/api/mnemo_shelf.dart +++ b/mnemo_cards_backend/lib/api/mnemo_shelf.dart @@ -46,10 +46,6 @@ class MnemoShelf { ? InternetAddress(addressArg) : InternetAddress.anyIPv4; final port = int.tryParse(portArg ?? '') ?? 3000; - final certs = Platform.environment['CERTS_PATH']; // null = HTTP without SSL - final dualMode = Platform.environment['DUAL_MODE'] == 'true' || - Platform.environment['DUAL_MODE'] == - '1'; // Запуск HTTP и HTTPS одновременно // V2 APIs (new RESTful API with OAuth2/JWT) final v2Routers = [ @@ -89,20 +85,6 @@ class MnemoShelf { // ..mount('/', createStaticHandler('public')); // Configure a pipeline with proper CORS configuration - // Поддерживаем как HTTP (разработка), так и HTTPS (продакшен) - // Note: allowedOrigins is kept for reference but not used since we allow all origins - // final allowedOrigins = [ - // 'https://1592725-cf88967.twc1.net', - // 'https://1592725-cf88967.twc1.net:443', - // '5492281-cf88967.twc1.net', - // '5492281-cf88967.twc1.net:8443' - // 'http://localhost:*', - // 'http://localhost:51717', // для разработки - // 'http://localhost:3000', // для разработки - // 'http://localhost:8000', // для разработки - // 'http://127.0.0.1:8000', // для разработки - // ]; - final corsConfig = { 'Access-Control-Allow-Origin': '*', // Разрешаем все домены для гибкости 'Access-Control-Allow-Methods': @@ -113,12 +95,6 @@ class MnemoShelf { 'Access-Control-Max-Age': '86400', }; - // Добавляем HSTS только для HTTPS соединений - if (certs != null) { - corsConfig['Strict-Transport-Security'] = - 'max-age=31536000; includeSubDomains'; - } - // CORS middleware that handles preflight requests Middleware corsMiddleware() { return (Handler innerHandler) { @@ -172,92 +148,17 @@ class MnemoShelf { final handler = rootRouter.call; - if (dualMode) { - // Запуск HTTP и HTTPS серверов одновременно - await _startDualServers(handler, address, port, certs); - } else { - // Обычный запуск одного сервера - final server = await _createServer( - handler, - address, - port, - securityContext: certs != null ? getSecurityContext(certs) : null, - poweredByHeader: null, - shared: true, - ); - - final protocol = certs != null ? 'https' : 'http'; - print( - 'Serving app at $protocol://${server.address.address}:${server.port}'); - final url = '$protocol://${server.address.address}:${server.port}'; - print('Server listening on $url'); - - if (certs != null) { - print('HTTPS enabled with SSL certificates from: $certs'); - print('Domain: 1592725-cf88967.twc1.net'); - } - } - } - - Future _startDualServers( - Handler handler, InternetAddress address, int port, String? certs) async { - print('🚀 Starting DUAL mode: HTTP + HTTPS servers'); - - // HTTP сервер на указанном порту - final httpServer = await _createServer( + // Запуск HTTP сервера (HTTPS обрабатывается на уровне reverse proxy в Coolify) + final server = await _createServer( handler, address, port, - securityContext: null, // HTTP без SSL poweredByHeader: null, shared: true, ); - // HTTPS сервер на порту + 1 (например, 8443 -> 8081) - final httpsPort = port + 1; - final httpsServer = await _createServer( - handler, - address, - httpsPort, - securityContext: certs != null ? getSecurityContext(certs) : null, - poweredByHeader: null, - shared: true, - ); - - print('✅ Both servers started successfully!'); - print( - '📡 HTTP server: http://${httpServer.address.address}:${httpServer.port}'); - print( - '🔒 HTTPS server: https://${httpsServer.address.address}:${httpsServer.port}'); - - if (certs != null) { - print('🔐 HTTPS enabled with SSL certificates from: $certs'); - print('🌐 Domain: 1592725-cf88967.twc1.net'); - } - } - - SecurityContext getSecurityContext(String path) { - // Для Let's Encrypt используем fullchain.pem и privkey.pem - // Для самоподписанных сертификатов используем server.crt и server.key - String serverCert, key; - - // if (path.contains('letsencrypt') || path.contains('/etc/letsencrypt/')) { - // // Let's Encrypt сертификаты - // // serverCert = path + '/fullchain.pem'; - // // key = path + '/privkey.pem'; - // } else { - // // // Самоподписанные сертификаты - // // serverCert = path.startsWith('/') - // // ? path + '/server.crt' - // // : Platform.script.resolve('$path/server.crt').toFilePath(); - // // key = path.startsWith('/') - // // ? path + '/server.key' - // // : Platform.script.resolve('$path/server.key').toFilePath(); - // } - - return SecurityContext(withTrustedRoots: false); - // ..useCertificateChain(serverCert) - // ..usePrivateKey(key); + print('Serving app at http://${server.address.address}:${server.port}'); + print('Server listening on http://${server.address.address}:${server.port}'); } logger(String tag) => (String msg, bool isError) { @@ -272,22 +173,17 @@ class MnemoShelf { Handler handler, InternetAddress address, int port, { - SecurityContext? securityContext, int? backlog, bool shared = false, String? poweredByHeader = 'Dart with package:shelf', }) async { backlog ??= 0; - var server = await (securityContext == null - ? HttpServer.bind(address, port, backlog: backlog, shared: shared) - : HttpServer.bindSecure( - address, - port, - securityContext, - backlog: backlog, - shared: shared, - requestClientCertificate: true, - )); + final server = await HttpServer.bind( + address, + port, + backlog: backlog, + shared: shared, + ); // Запускаем обработку запросов (неблокирующая операция) // serveRequests запускает обработку запросов в фоне и возвращает управление сразу shelf_io.serveRequests(server, handler, poweredByHeader: poweredByHeader);