fix: node-native VPS deploy when disk is low

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Андрей Бобырев
2026-05-24 22:22:41 +03:00
parent 2bfb557993
commit ab5c0084b2
3 changed files with 133 additions and 6 deletions

View File

@@ -19,6 +19,8 @@ services:
postgres: postgres:
image: postgres:16-alpine image: postgres:16-alpine
ports:
- "127.0.0.1:5432:5432"
environment: environment:
POSTGRES_USER: scanner POSTGRES_USER: scanner
POSTGRES_PASSWORD: scanner POSTGRES_PASSWORD: scanner
@@ -34,6 +36,8 @@ services:
redis: redis:
image: redis:7-alpine image: redis:7-alpine
ports:
- "127.0.0.1:6379:6379"
command: redis-server --appendonly yes command: redis-server --appendonly yes
volumes: volumes:
- redis_data:/data - redis_data:/data

View File

@@ -4,7 +4,7 @@ set -euo pipefail
REPO_URL="${DOMAIN_SCANNER_REPO_URL:-https://github.com/andrey271192/Domain_web.git}" REPO_URL="${DOMAIN_SCANNER_REPO_URL:-https://github.com/andrey271192/Domain_web.git}"
BRANCH="${DOMAIN_SCANNER_BRANCH:-main}" BRANCH="${DOMAIN_SCANNER_BRANCH:-main}"
INSTALL_DIR="${DOMAIN_SCANNER_INSTALL_DIR:-/opt/domain-scanner}" INSTALL_DIR="${DOMAIN_SCANNER_INSTALL_DIR:-/opt/domain_web}"
SERVICE_NAME="domain-scanner" SERVICE_NAME="domain-scanner"
NGINX_SITE="domain-scanner" NGINX_SITE="domain-scanner"
APP_PORT="${DOMAIN_SCANNER_PORT:-3000}" APP_PORT="${DOMAIN_SCANNER_PORT:-3000}"
@@ -34,8 +34,9 @@ install_docker() {
fi fi
log "Installing Docker..." log "Installing Docker..."
curl -fsSL https://get.docker.com | sh curl -fsSL https://get.docker.com | sh
systemctl enable docker systemctl enable docker.socket docker.service
systemctl start docker systemctl start docker.socket
systemctl start docker.service
} }
stop_legacy() { stop_legacy() {
@@ -76,15 +77,28 @@ setup_env() {
} }
deploy_compose() { deploy_compose() {
log "Building and starting Docker stack..."
cd "${INSTALL_DIR}" cd "${INSTALL_DIR}"
export PORT="${APP_PORT}" export PORT="${APP_PORT}"
AVAIL_KB=$(df -k "${INSTALL_DIR}" | awk 'NR==2 {print $4}')
if [[ "${AVAIL_KB:-0}" -lt 2500000 ]]; then
log "Low disk — Node-native deploy..."
bash "${INSTALL_DIR}/scripts/install-node.sh"
return
fi
log "Building Docker stack..."
if docker compose version >/dev/null 2>&1; then if docker compose version >/dev/null 2>&1; then
docker compose build --pull if ! docker compose build 2>&1; then
log "Docker build failed — Node-native deploy..."
bash "${INSTALL_DIR}/scripts/install-node.sh"
return
fi
docker compose up -d docker compose up -d
docker compose exec -T web npx prisma db push docker compose exec -T web npx prisma db push
else else
docker-compose build --pull if ! docker-compose build 2>&1; then
bash "${INSTALL_DIR}/scripts/install-node.sh"
return
fi
docker-compose up -d docker-compose up -d
docker-compose exec -T web npx prisma db push docker-compose exec -T web npx prisma db push
fi fi

109
scripts/install-node.sh Normal file
View File

@@ -0,0 +1,109 @@
#!/usr/bin/env bash
# Node-native production deploy (low disk — no Docker image build)
set -euo pipefail
INSTALL_DIR="${DOMAIN_SCANNER_INSTALL_DIR:-/opt/domain_web}"
SERVICE_NAME="domain-scanner"
NGINX_SITE="domain-scanner"
APP_PORT="${DOMAIN_SCANNER_PORT:-3000}"
NODE_PORT="${APP_PORT}"
log() { echo "[domain-scanner-node] $*"; }
install_packages() {
apt-get update -qq
apt-get install -y -qq nginx git curl ca-certificates >/dev/null
if ! command -v node >/dev/null || [[ $(node -v | cut -d. -f1 | tr -d v) -lt 20 ]]; then
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt-get install -y -qq nodejs >/dev/null
fi
}
setup_compose_db() {
cd "${INSTALL_DIR}"
if command -v docker-compose >/dev/null; then
DC=docker-compose
else
DC="docker compose"
fi
$DC up -d postgres redis
sleep 5
}
setup_env() {
if [[ ! -f "${INSTALL_DIR}/.env" ]]; then
SECRET=$(openssl rand -base64 32 2>/dev/null || head -c 32 /dev/urandom | base64)
cat >"${INSTALL_DIR}/.env" <<EOF
DATABASE_URL=postgresql://scanner:scanner@127.0.0.1:5432/domain_scanner?schema=public
REDIS_URL=redis://127.0.0.1:6379
NEXTAUTH_SECRET=${SECRET}
NEXTAUTH_URL=http://$(hostname -I | awk '{print $1}')
NEXT_PUBLIC_APP_URL=http://$(hostname -I | awk '{print $1}')
PORT=${NODE_PORT}
EOF
fi
set -a && source "${INSTALL_DIR}/.env" && set +a
}
build_app() {
cd "${INSTALL_DIR}"
npm ci
npx prisma generate
npm run build
npx prisma db push --accept-data-loss
}
install_systemd() {
cat >"/etc/systemd/system/${SERVICE_NAME}.service" <<EOF
[Unit]
Description=Domain Scanner (Next.js)
After=network.target docker.service
[Service]
Type=simple
WorkingDirectory=${INSTALL_DIR}
EnvironmentFile=${INSTALL_DIR}/.env
ExecStart=/usr/bin/npm start
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable "${SERVICE_NAME}.service"
systemctl restart "${SERVICE_NAME}.service"
}
install_nginx() {
cat >"/etc/nginx/sites-available/${NGINX_SITE}" <<EOF
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
location / {
proxy_pass http://127.0.0.1:${NODE_PORT};
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
}
}
EOF
rm -f /etc/nginx/sites-enabled/geoexport-site /etc/nginx/sites-available/geoexport-site
systemctl stop geoexport-site 2>/dev/null || true
rm -f /etc/nginx/sites-enabled/default
ln -sf "/etc/nginx/sites-available/${NGINX_SITE}" "/etc/nginx/sites-enabled/${NGINX_SITE}"
nginx -t && systemctl restart nginx
}
if [[ "${EUID}" -ne 0 ]]; then echo "Run as root" >&2; exit 1; fi
install_packages
setup_env
setup_compose_db
build_app
install_systemd
install_nginx
log "Done: http://$(hostname -I | awk '{print $1}')/"