fix: shop.service — wait-postgres, диагностика, права .env
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+7
-5
@@ -1,21 +1,23 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Shop Node.js
|
Description=Shop Node.js
|
||||||
After=network.target postgresql.service
|
After=network.target
|
||||||
Wants=postgresql.service
|
Wants=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=www-data
|
User=www-data
|
||||||
Group=www-data
|
Group=www-data
|
||||||
# Путь к клону (package.json): /opt/shop или /opt/shop/shop10
|
|
||||||
WorkingDirectory=/opt/shop/shop10
|
WorkingDirectory=/opt/shop/shop10
|
||||||
EnvironmentFile=/opt/shop/shop10/.env
|
EnvironmentFile=/opt/shop/shop10/.env
|
||||||
# Дождаться PostgreSQL (запуск от root, +)
|
ExecStartPre=+/opt/shop/shop10/scripts/wait-postgres.sh
|
||||||
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'
|
|
||||||
ExecStart=/usr/bin/node src/server.js
|
ExecStart=/usr/bin/node src/server.js
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|
||||||
|
# Логи в journal
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
|
||||||
UMask=0022
|
UMask=0022
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -19,58 +19,83 @@ if [ ! -f "$SHOP_ROOT/package.json" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
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" ]; then
|
||||||
if [ -f "$SHOP_ROOT/.env.example" ]; then
|
if [ -f "$SHOP_ROOT/.env.example" ]; then
|
||||||
cp "$SHOP_ROOT/.env.example" "$SHOP_ROOT/.env"
|
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
|
else
|
||||||
echo "Ошибка: нет .env — создайте из .env.example"
|
echo "Ошибка: нет .env"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! grep -q '^DATABASE_URL=' "$SHOP_ROOT/.env"; then
|
if ! grep -q '^DATABASE_URL=' "$SHOP_ROOT/.env"; then
|
||||||
echo "ВНИМАНИЕ: в .env нет DATABASE_URL"
|
echo "Добавляю DATABASE_URL по умолчанию..."
|
||||||
fi
|
echo 'DATABASE_URL=postgresql://shop:shop@127.0.0.1:5432/shop' >> "$SHOP_ROOT/.env"
|
||||||
|
|
||||||
if ! command -v node >/dev/null; then
|
|
||||||
echo "Ошибка: node не найден"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
NODE_BIN=$(command -v node)
|
NODE_BIN=$(command -v node)
|
||||||
echo "Node: $NODE_BIN ($($NODE_BIN -v))"
|
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"
|
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
|
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|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|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
|
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
|
if ! sudo -u www-data test -r "$SHOP_ROOT/package.json"; then
|
||||||
echo "Предупреждение: www-data не читает $SHOP_ROOT — проверьте права каталога"
|
echo "Ошибка: www-data не читает $SHOP_ROOT"
|
||||||
fi
|
ls -la "$SHOP_ROOT" | head -5
|
||||||
|
exit 1
|
||||||
if command -v pg_isready >/dev/null; then
|
|
||||||
systemctl enable postgresql 2>/dev/null || true
|
|
||||||
systemctl start postgresql 2>/dev/null || true
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable shop
|
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
|
if curl -sf http://127.0.0.1:3000/health; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "OK — служба shop запущена"
|
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
|
systemctl reload caddy 2>/dev/null || true
|
||||||
else
|
else
|
||||||
echo "shop не отвечает на :3000"
|
echo "shop не отвечает на :3000"
|
||||||
journalctl -u shop -n 25 --no-pager
|
journalctl -u shop -n 40 --no-pager
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
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 не установлена
|
## Служба shop не установлена
|
||||||
|
|
||||||
Код обновился, но systemd unit не настроен:
|
Код обновился, но systemd unit не настроен:
|
||||||
|
|||||||
Reference in New Issue
Block a user