diff --git a/deploy/shop.service b/deploy/shop.service index 3829616..c4c562e 100644 --- a/deploy/shop.service +++ b/deploy/shop.service @@ -1,21 +1,23 @@ [Unit] Description=Shop Node.js -After=network.target postgresql.service -Wants=postgresql.service +After=network.target +Wants=network-online.target [Service] Type=simple User=www-data Group=www-data -# Путь к клону (package.json): /opt/shop или /opt/shop/shop10 WorkingDirectory=/opt/shop/shop10 EnvironmentFile=/opt/shop/shop10/.env -# Дождаться PostgreSQL (запуск от root, +) -ExecStartPre=+/bin/bash -c 'for i in $(seq 1 60); do pg_isready -h 127.0.0.1 -p 5432 -q && exit 0; sleep 1; done; echo "PostgreSQL не отвечает на 127.0.0.1:5432"; exit 1' +ExecStartPre=+/opt/shop/shop10/scripts/wait-postgres.sh ExecStart=/usr/bin/node src/server.js Restart=on-failure RestartSec=5 +# Логи в journal +StandardOutput=journal +StandardError=journal + UMask=0022 [Install] diff --git a/scripts/diagnose-shop-service.sh b/scripts/diagnose-shop-service.sh new file mode 100644 index 0000000..c0ed2ad --- /dev/null +++ b/scripts/diagnose-shop-service.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Диагностика службы shop +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/shop-root.sh" + +echo "=== Диагностика shop.service ===" +echo "SHOP_ROOT=$SHOP_ROOT" +echo + +echo "1. Unit" +systemctl cat shop.service 2>/dev/null | head -25 || echo " shop.service не найден" +echo + +echo "2. PostgreSQL" +systemctl is-active postgresql 2>/dev/null || systemctl is-active 'postgresql@*' 2>/dev/null || echo " postgresql: не active" +pg_isready -q 2>/dev/null && echo " pg_isready (socket): OK" || echo " pg_isready (socket): FAIL" +pg_isready -h 127.0.0.1 -p 5432 -q 2>/dev/null && echo " pg_isready 127.0.0.1: OK" || echo " pg_isready 127.0.0.1: FAIL" +echo + +echo "3. .env" +if [ -f "$SHOP_ROOT/.env" ]; then + ls -la "$SHOP_ROOT/.env" + grep -E '^(DATABASE_URL|HOST|PORT|NODE_ENV)=' "$SHOP_ROOT/.env" | sed 's/=.*/=***/' || true +else + echo " .env не найден" +fi +echo + +echo "4. www-data доступ" +sudo -u www-data test -r "$SHOP_ROOT/package.json" && echo " package.json: OK" || echo " package.json: FAIL" +sudo -u www-data test -x "$SHOP_ROOT" && echo " каталог: OK" || echo " каталог: FAIL" +echo + +echo "5. Тест Node (5 сек)" +set +e +timeout 8 sudo -u www-data bash -c "cd '$SHOP_ROOT' && set -a && source .env 2>/dev/null && set +a && node src/server.js" 2>&1 | head -20 +set -e +echo + +echo "6. journalctl shop" +journalctl -u shop -n 30 --no-pager 2>/dev/null || true diff --git a/scripts/install-shop-service.sh b/scripts/install-shop-service.sh index c2e761e..ae4e3d0 100644 --- a/scripts/install-shop-service.sh +++ b/scripts/install-shop-service.sh @@ -19,58 +19,83 @@ if [ ! -f "$SHOP_ROOT/package.json" ]; then exit 1 fi +# .env: shop10 или старый /opt/shop +if [ ! -f "$SHOP_ROOT/.env" ] && [ -f /opt/shop/.env ]; then + cp /opt/shop/.env "$SHOP_ROOT/.env" + echo "Скопирован .env из /opt/shop" +fi + if [ ! -f "$SHOP_ROOT/.env" ]; then if [ -f "$SHOP_ROOT/.env.example" ]; then cp "$SHOP_ROOT/.env.example" "$SHOP_ROOT/.env" - echo "Создан .env из .env.example — отредактируйте SESSION_SECRET и DATABASE_URL" + if command -v openssl >/dev/null; then + sed -i "s/change-me-to-a-long-random-string/$(openssl rand -hex 32)/" "$SHOP_ROOT/.env" + fi + echo "Создан .env — проверьте DATABASE_URL" else - echo "Ошибка: нет .env — создайте из .env.example" + echo "Ошибка: нет .env" exit 1 fi fi if ! grep -q '^DATABASE_URL=' "$SHOP_ROOT/.env"; then - echo "ВНИМАНИЕ: в .env нет DATABASE_URL" -fi - -if ! command -v node >/dev/null; then - echo "Ошибка: node не найден" - exit 1 + echo "Добавляю DATABASE_URL по умолчанию..." + echo 'DATABASE_URL=postgresql://shop:shop@127.0.0.1:5432/shop' >> "$SHOP_ROOT/.env" fi NODE_BIN=$(command -v node) echo "Node: $NODE_BIN ($($NODE_BIN -v))" +chmod +x "$SHOP_ROOT/scripts/wait-postgres.sh" 2>/dev/null || true + +if command -v pg_isready >/dev/null; then + bash "$SCRIPT_DIR/install-postgresql-ubuntu.sh" 2>/dev/null || true + systemctl enable postgresql 2>/dev/null || true + systemctl start postgresql 2>/dev/null || true + bash "$SCRIPT_DIR/setup-postgres-ubuntu.sh" 2>/dev/null || true +fi + npm install --omit=dev --prefix "$SHOP_ROOT" +# Доступ www-data: чтение кода и .env (systemd читает .env от root, но на всякий случай) +chmod o+x /opt /opt/shop 2>/dev/null || true +chmod -R a+rX "$SHOP_ROOT" +chmod 640 "$SHOP_ROOT/.env" +chown root:www-data "$SHOP_ROOT/.env" 2>/dev/null || chmod 644 "$SHOP_ROOT/.env" + cp -f "$SHOP_ROOT/deploy/shop.service" /etc/systemd/system/shop.service sed -i "s|WorkingDirectory=.*|WorkingDirectory=${SHOP_ROOT}|" /etc/systemd/system/shop.service sed -i "s|EnvironmentFile=.*|EnvironmentFile=${SHOP_ROOT}/.env|" /etc/systemd/system/shop.service +sed -i "s|ExecStartPre=.*|ExecStartPre=+${SHOP_ROOT}/scripts/wait-postgres.sh|" /etc/systemd/system/shop.service sed -i "s|ExecStart=.*|ExecStart=${NODE_BIN} src/server.js|" /etc/systemd/system/shop.service -# www-data должен читать код (не меняем владельца всего дерева — только доступ на чтение) -chmod -R a+rX "$SHOP_ROOT" 2>/dev/null || true if ! sudo -u www-data test -r "$SHOP_ROOT/package.json"; then - echo "Предупреждение: www-data не читает $SHOP_ROOT — проверьте права каталога" -fi - -if command -v pg_isready >/dev/null; then - systemctl enable postgresql 2>/dev/null || true - systemctl start postgresql 2>/dev/null || true + echo "Ошибка: www-data не читает $SHOP_ROOT" + ls -la "$SHOP_ROOT" | head -5 + exit 1 fi systemctl daemon-reload systemctl enable shop -systemctl restart shop -sleep 2 +echo "Запуск shop..." +if ! systemctl restart shop; then + echo "" + echo "=== Ошибка запуска — лог ===" + journalctl -u shop -n 40 --no-pager + echo "" + bash "$SCRIPT_DIR/diagnose-shop-service.sh" || true + exit 1 +fi + +sleep 3 if curl -sf http://127.0.0.1:3000/health; then echo "" echo "OK — служба shop запущена" - systemctl status shop --no-pager -l | head -12 + systemctl status shop --no-pager | head -15 systemctl reload caddy 2>/dev/null || true else echo "shop не отвечает на :3000" - journalctl -u shop -n 25 --no-pager + journalctl -u shop -n 40 --no-pager exit 1 fi diff --git a/scripts/wait-postgres.sh b/scripts/wait-postgres.sh new file mode 100644 index 0000000..7572cac --- /dev/null +++ b/scripts/wait-postgres.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# Ожидание PostgreSQL (сокет или TCP 127.0.0.1:5432) +for i in $(seq 1 45); do + if pg_isready -q 2>/dev/null; then + exit 0 + fi + if pg_isready -h 127.0.0.1 -p 5432 -q 2>/dev/null; then + exit 0 + fi + sleep 1 +done +echo "PostgreSQL недоступен (проверьте: systemctl status postgresql)" +exit 1 diff --git a/wiki/Troubleshooting.md b/wiki/Troubleshooting.md index b59f085..55afa8e 100644 --- a/wiki/Troubleshooting.md +++ b/wiki/Troubleshooting.md @@ -52,6 +52,32 @@ cp /opt/shop/shop10.bak.*/.env /opt/shop/shop10/.env 2>/dev/null || cp /opt/shop bash /opt/shop/shop10/scripts/server-update.sh ``` +## Job for shop.service failed (control process exited) + +Чаще всего не запущен PostgreSQL или не прошёл `ExecStartPre`: + +```bash +cd /opt/shop/shop10 +git pull +sudo bash scripts/install-postgresql-ubuntu.sh +bash scripts/setup-postgres-ubuntu.sh +sudo bash scripts/install-shop-service.sh +``` + +Диагностика: + +```bash +bash /opt/shop/shop10/scripts/diagnose-shop-service.sh +journalctl -u shop -n 50 --no-pager +``` + +Скопировать старый `.env`: + +```bash +cp /opt/shop/.env /opt/shop/shop10/.env +sudo bash /opt/shop/shop10/scripts/install-shop-service.sh +``` + ## Служба shop не установлена Код обновился, но systemd unit не настроен: