From 1196bc3d1141929a9459718df4f8dcecaba1dc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=91=D0=BE=D0=B1?= =?UTF-8?q?=D1=8B=D1=80=D0=B5=D0=B2?= Date: Sun, 24 May 2026 23:19:03 +0300 Subject: [PATCH] fix(deploy): sync static assets and nginx CSS route Copy .next/static and public into standalone after build; serve /_next/static from nginx; verify CSS in install.sh. Co-authored-by: Cursor --- docs/DEPLOYMENT.md | 12 +++++++----- install.sh | 20 ++++++++++++++++++++ package.json | 1 + scripts/install-node.sh | 9 +++++++++ scripts/sync-standalone-assets.sh | 29 +++++++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 5 deletions(-) create mode 100755 scripts/sync-standalone-assets.sh diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index d95aca7..b1d7b56 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -13,13 +13,15 @@ docker compose exec web npx prisma db push curl -fsSL https://raw.githubusercontent.com/andrey271192/Domain_web/main/install.sh | sudo bash ``` -Install path: `/opt/domain_web` -Service: Docker Compose (`web`, `postgres`, `redis`) -Nginx site: `domain-scanner` on port 80 → app `:3000` +Install path: `/opt/domain-scanner` (lite VPS install via `install.sh`) +Service: `domain-scanner.service` — `npm start` from repo root (not standalone `server.js` alone) +Nginx site: `domain-scanner` on port 80 → app `:3000`, with `/_next/static/` served from disk + +**CSS / static assets:** After `next build`, run `scripts/sync-standalone-assets.sh` (also via `postbuild`) so `.next/static` and `public` exist under `.next/standalone` for Docker. Host deploy must keep `${INSTALL_DIR}/.next/static` — never run `node .next/standalone/server.js` without that copy. ## Environment on server -Edit `/opt/domain_web/.env`: +Edit `/opt/domain-scanner/.env`: - `NEXTAUTH_SECRET` — auto-generated on first install - `NEXTAUTH_URL` / `NEXT_PUBLIC_APP_URL` — public IP or domain @@ -39,5 +41,5 @@ Place certbot in front of nginx or terminate TLS at a reverse proxy. ## Upgrades ```bash -cd /opt/domain_web && git pull && docker compose up -d --build +cd /opt/domain-scanner && git pull && npm ci && npm run build && systemctl restart domain-scanner nginx ``` diff --git a/install.sh b/install.sh index 0964c9e..9a46967 100755 --- a/install.sh +++ b/install.sh @@ -109,6 +109,7 @@ build_app() { npx prisma generate npx prisma db push npm run build + bash scripts/sync-standalone-assets.sh "${INSTALL_DIR}" # Keep production deps at repo root; `next start` is more reliable than # standalone on small VPS (avoids incomplete traced node_modules). npm ci --omit=dev @@ -154,6 +155,13 @@ server { client_max_body_size 32m; + location /_next/static/ { + alias ${INSTALL_DIR}/.next/static/; + expires 1y; + add_header Cache-Control "public, max-age=31536000, immutable"; + access_log off; + } + location / { proxy_pass http://127.0.0.1:${APP_PORT}; proxy_http_version 1.1; @@ -188,6 +196,18 @@ verify() { echo "Health check failed on port ${APP_PORT}" >&2 exit 1 fi + local css + css="$(find "${INSTALL_DIR}/.next/static/css" -name '*.css' -type f 2>/dev/null | head -1 || true)" + if [[ -z "${css}" ]]; then + echo "ERROR: no CSS build output in .next/static/css" >&2 + exit 1 + fi + local css_url="/_next/static/css/$(basename "${css}")" + if ! curl -fsSI "http://127.0.0.1${css_url}" | grep -qi 'content-type:.*css'; then + echo "ERROR: CSS not served (${css_url})" >&2 + exit 1 + fi + log "CSS OK: ${css_url}" local title title="$(curl -fsS "http://127.0.0.1/" | grep -o '[^<]*' | head -1 || true)" if echo "${title}" | grep -qi geoexport; then diff --git a/package.json b/package.json index 0590846..294f059 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "dev": "next dev", "build": "prisma generate && next build", + "postbuild": "bash scripts/sync-standalone-assets.sh", "start": "next start", "lint": "eslint", "postinstall": "prisma generate", diff --git a/scripts/install-node.sh b/scripts/install-node.sh index 53deeb3..6c5ab38 100644 --- a/scripts/install-node.sh +++ b/scripts/install-node.sh @@ -50,6 +50,7 @@ build_app() { npm ci npx prisma generate npm run build + bash scripts/sync-standalone-assets.sh "${INSTALL_DIR}" npx prisma db push --accept-data-loss } @@ -81,6 +82,14 @@ server { listen 80 default_server; listen [::]:80 default_server; server_name _; + + location /_next/static/ { + alias ${INSTALL_DIR}/.next/static/; + expires 1y; + add_header Cache-Control "public, max-age=31536000, immutable"; + access_log off; + } + location / { proxy_pass http://127.0.0.1:${NODE_PORT}; proxy_http_version 1.1; diff --git a/scripts/sync-standalone-assets.sh b/scripts/sync-standalone-assets.sh new file mode 100755 index 0000000..ad7785a --- /dev/null +++ b/scripts/sync-standalone-assets.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# Copy Next.js static assets into standalone output (required for `node server.js`). +set -euo pipefail + +ROOT="${1:-$(cd "$(dirname "$0")/.." && pwd)}" +STANDALONE="${ROOT}/.next/standalone" +STATIC_SRC="${ROOT}/.next/static" +PUBLIC_SRC="${ROOT}/public" + +if [[ ! -d "${STANDALONE}" ]]; then + echo "[sync-standalone-assets] No .next/standalone — skipping (non-standalone build?)" >&2 + exit 0 +fi + +if [[ ! -d "${STATIC_SRC}" ]]; then + echo "[sync-standalone-assets] ERROR: missing ${STATIC_SRC} — run npm run build first" >&2 + exit 1 +fi + +mkdir -p "${STANDALONE}/.next" +rm -rf "${STANDALONE}/.next/static" +cp -a "${STATIC_SRC}" "${STANDALONE}/.next/static" + +if [[ -d "${PUBLIC_SRC}" ]]; then + rm -rf "${STANDALONE}/public" + cp -a "${PUBLIC_SRC}" "${STANDALONE}/public" +fi + +echo "[sync-standalone-assets] OK: .next/static + public → ${STANDALONE}"