# syntax=docker/dockerfile:1 # Панель — один процесс и один образ: express отдаёт и API, и собранный фронт # (core/server/spa.ts), отдельный nginx ей не нужен. # # Контекст сборки — каталог самой панели, и ничего выше него не требуется: # вендоренная копия ядра закоммичена вместе с исходниками, поэтому образ # собирается из чистого checkout'а, без ma7engine рядом. Обновляется копия # отдельно и осознанно — `npm run update` во фронте, диффом в ревью. # # docker build -t admin-hub . # docker run -p 8080:8080 -e ADMIN_PASS=… -e ADMIN_JWT_SECRET=… admin-hub # ─── фронт: собирается и остаётся только как dist ─────────────────────────── FROM node:24-alpine AS frontend WORKDIR /app/frontend COPY frontend/package.json frontend/package-lock.json ./ RUN npm ci COPY frontend/ ./ # prebuild зовёт update.sh. Ядра рядом в образе нет, и скрипт штатно берёт уже # синхронизированную копию из src/core — это его нормальная ветка, не ошибка. RUN npm run build # ─── рантайм: бэкенд плюс собранный фронт ─────────────────────────────────── FROM node:24-alpine AS runtime WORKDIR /app/backend COPY backend/package.json backend/package-lock.json ./ # tsx лежит в dependencies намеренно: сервер и в деве, и в образе стартует одной # и той же командой. Компиляция в JS дала бы образ меньше, но развела бы дев и # прод, а в этой панели пути и команды всюду одинаковы — на том же основании # ядро ездит копией, а не алиасом. RUN npm ci --omit=dev COPY backend/ ./ # staticDir по умолчанию — ../frontend/dist от каталога сервера. COPY --from=frontend /app/frontend/dist /app/frontend/dist ENV NODE_ENV=production ENV PORT=8080 EXPOSE 8080 # NODE_ENV=production включает разбор X-Forwarded-For в рейт-лимите: за прокси # без него все клиенты схлопываются в один ключ и блокируют вход всем сразу. # # ADMIN_PASS (или ADMIN_PASS_HASH) и ADMIN_JWT_SECRET значений по умолчанию не # имеют — без них процесс не поднимется. Это не недосмотр: тихо работающая # панель с паролем по умолчанию хуже не стартовавшей. USER node HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD wget -qO- "http://127.0.0.1:${PORT}/" >/dev/null 2>&1 || exit 1 CMD ["npm", "start"]