Files
shop10/README.md
T

358 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Shop
Интернет-магазин на **Node.js** с локальной базой **SQLite**.
## Возможности
- Каталог товаров с категориями и поиском
- Корзина и оформление заказа
- Регистрация и вход пользователей
- История заказов в личном кабинете
## Требования
- Node.js 18+
- npm
- На Linux для сборки `better-sqlite3`: `build-essential`, `python3`
---
## Быстрый развёртывание на Ubuntu
Скопируйте блок целиком на чистый сервер Ubuntu 22.04 / 24.04 (от root или через `sudo`):
```bash
# 1. Зависимости системы
apt update
apt install -y git curl build-essential python3
# 2. Node.js 20 LTS
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs
# 3. Клонирование (подставьте URL вашего репозитория)
cd /opt
git clone <URL_РЕПОЗИТОРИЯ> shop
cd shop
# 4. Настройка окружения
cp .env.example .env
# Сгенерируйте секрет сессии:
sed -i "s/change-me-to-a-long-random-string/$(openssl rand -hex 32)/" .env
# 5. Установка приложения
npm install --omit=dev
# 6. Caddy (HTTPS + прокси) — см. раздел ниже; для проверки без домена:
npm start
```
Без Caddy сайт на **http://IP_СЕРВЕРА:3000**. С Caddy — **https://ваш-домен** (любой, указанный в `Caddyfile`).
В `.env` для production задайте (уже есть в `.env.example`):
```env
PORT=3000
HOST=127.0.0.1
NODE_ENV=production
TRUST_PROXY=1
SESSION_SECRET=ваш-длинный-секрет
```
`HOST=127.0.0.1` — Node слушает только localhost; снаружи доступ через Caddy.
При первом запуске создаются `data/shop.db`, `data/sessions.db` и демо-товары.
---
## Запуск как служба (systemd)
Чтобы магазин работал после перезагрузки сервера:
```bash
cp /opt/shop/deploy/shop.service /etc/systemd/system/shop.service
# Код обновляйте от root; НЕ делайте chown -R на весь /opt/shop (ломает git pull)
cd /opt/shop
git config --global --add safe.directory /opt/shop
git pull
npm install --omit=dev
# Запись только в data/ — для пользователя службы www-data
mkdir -p /opt/shop/data
chown -R www-data:www-data /opt/shop/data
chmod +x /opt/shop/scripts/diagnose-502.sh 2>/dev/null || true
systemctl daemon-reload
systemctl enable shop
systemctl start shop
systemctl status shop
# Backend должен ответить:
curl -s http://127.0.0.1:3000/health
# {"ok":true,"service":"shop"}
```
Логи: `journalctl -u shop -f`
---
## Проверка после установки
Перед настройкой Caddy убедитесь, что Node отвечает локально:
```bash
cd /opt/shop
systemctl restart shop
sleep 1
curl -s http://127.0.0.1:3000/health
# {"ok":true,"service":"shop"}
ss -tlnp | grep 3000
# LISTEN ... 127.0.0.1:3000 ... node
journalctl -u shop -n 5 --no-pager
# должна быть строка: Магазин: http://127.0.0.1:3000
```
Если в логе только «База уже содержит товары…» и служба сразу останавливается — обновите код: `git pull` (нужна актуальная версия `seed.js`).
После успешной проверки настройте Caddy и выполните:
```bash
systemctl reload caddy
```
Обновление на сервере одной командой:
```bash
bash /opt/shop/scripts/server-update.sh
```
---
## Caddy — SSL и reverse proxy (рекомендуется)
[Caddy](https://caddyserver.com/) автоматически выпускает и продлевает сертификаты Let's Encrypt.
**Перед установкой:**
1. Домен указывает на IP сервера (A-запись).
2. Открыты порты **80** и **443** в файрволе.
3. Служба `shop` запущена и слушает `127.0.0.1:3000`.
### Установка Caddy на Ubuntu
```bash
apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| tee /etc/apt/sources.list.d/caddy-stable.list
apt update
apt install -y caddy
```
### Конфигурация
В репозитории лежит пример: `caddy/Caddyfile.example`.
```bash
# Замените shop.example.com и email на свои
cp /opt/shop/caddy/Caddyfile.example /etc/caddy/Caddyfile
nano /etc/caddy/Caddyfile
```
Пример `/etc/caddy/Caddyfile`:
```caddyfile
{
email admin@example.com
}
shop.example.com {
encode gzip zstd
reverse_proxy 127.0.0.1:3000
}
```
Проверка и перезапуск:
```bash
caddy validate --config /etc/caddy/Caddyfile
systemctl enable caddy
systemctl reload caddy
systemctl status caddy
```
Сайт откроется по домену из блока `Caddyfile` (в примере — `shop.example.com`).
Логи Caddy: `journalctl -u caddy -f`
### Файрвол (ufw)
```bash
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
```
Порт **3000** наружу не открывайте — к приложению ходят только через Caddy.
### Порядок запуска после перезагрузки
1. `shop` (Node.js на `127.0.0.1:3000`)
2. `caddy` (прокси + HTTPS)
### HTTP 502 при рабочем SSL
**SSL есть, 502 — значит Caddy жив, а Node на `127.0.0.1:3000` не отвечает.**
На сервере выполните:
```bash
bash /opt/shop/scripts/diagnose-502.sh
journalctl -u shop -n 50 --no-pager
curl -v http://127.0.0.1:3000/health
```
**Частые причины и исправление:**
| Причина | Что сделать |
|--------|-------------|
| Служба `shop` не запущена или падает | `systemctl restart shop`, смотрите логи `journalctl -u shop -f` |
| Нет `npm install` / сломан `better-sqlite3` | `cd /opt/shop && npm install --omit=dev` (нужны `build-essential`, `python3`) |
| Нет прав на `data/` у `www-data` | `mkdir -p /opt/shop/data && chown -R www-data:www-data /opt/shop/data` |
| `dubious ownership` / нет `git pull` | `chown -R root:root /opt/shop` + `safe.directory` (см. выше) |
| В `.env` нет `HOST`/`PORT` | `HOST=127.0.0.1`, `PORT=3000`, затем `systemctl restart shop` |
| Неверный путь к `node` в systemd | `which node` → подставьте в `ExecStart` в `/etc/systemd/system/shop.service` |
| Caddy стартовал раньше shop | `cp deploy/caddy-after-shop.conf /etc/systemd/system/caddy.service.d/shop.conf` и `daemon-reload` |
| В логе seed и сразу `Deactivated` | `git pull` — старый `seed.js` вызывал `process.exit` до старта сервера |
**Быстрое восстановление:**
```bash
cd /opt/shop
git config --global --add safe.directory /opt/shop
git pull
npm install --omit=dev
mkdir -p data
chown -R www-data:www-data /opt/shop/data
systemctl restart shop
curl -s http://127.0.0.1:3000/health # должен быть {"ok":true,...}
systemctl reload caddy
```
**Ошибка `dubious ownership` при `git pull`:**
Вы сделали `chown -R www-data` на весь каталог. Верните владельца репозиторию root и оставьте `data/` за www-data:
```bash
chown -R root:root /opt/shop
chown -R www-data:www-data /opt/shop/data
git config --global --add safe.directory /opt/shop
git pull
```
Пока `curl http://127.0.0.1:3000/health` не возвращает OK — HTTPS через Caddy будет отдавать 502.
### Другие проблемы
| Симптом | Решение |
|--------|---------|
| Нет сертификата | DNS, порты 80/443, верный домен в `Caddyfile` |
| Редирект-цикл / нет cookies | В `.env`: `TRUST_PROXY=1`, `NODE_ENV=production` |
---
## Обновление с Git
```bash
cd /opt/shop
bash scripts/server-update.sh
```
Или вручную:
```bash
cd /opt/shop
git config --global --add safe.directory /opt/shop
git pull
npm install --omit=dev
mkdir -p data && chown -R www-data:www-data data
systemctl restart shop
curl -s http://127.0.0.1:3000/health
systemctl reload caddy # если меняли Caddyfile
```
---
## Локальная разработка
```bash
npm install
cp .env.example .env
npm run dev
```
Сайт: [http://localhost:3000](http://localhost:3000)
## Переменные окружения
| Переменная | Описание | По умолчанию |
|------------------|---------------------------|----------------|
| `PORT` | Порт HTTP-сервера | `3000` |
| `HOST` | Адрес привязки | `0.0.0.0` (dev), `127.0.0.1` (prod) |
| `NODE_ENV` | Режим (`production` — secure cookies) | — |
| `TRUST_PROXY` | Доверять заголовкам Caddy (`1`) | — |
| `SESSION_SECRET` | Секрет для сессий | dev-значение |
## Скрипты npm
| Команда | Описание |
|----------------|----------------------------------|
| `npm start` | Запуск сервера (production) |
| `npm run dev` | Запуск с автоперезагрузкой |
| `npm run seed` | Заполнение каталога, если пуст |
## База данных
Локально в каталоге `data/`:
- `shop.db` — товары, пользователи, заказы
- `sessions.db` — сессии
Каталог `data/` в git не попадает (см. `.gitignore`). Делайте резервные копии:
```bash
cp -a data/shop.db data/shop.db.bak
```
## Структура проекта
```
caddy/
Caddyfile.example — пример reverse proxy + SSL
deploy/
shop.service — unit для systemd
scripts/
diagnose-502.sh — проверка при 502
server-update.sh — git pull + restart + health
src/
server.js — точка входа
db.js — схема SQLite
seed.js — демо-данные
routes/ — маршруты
views/ — шаблоны EJS
public/css/ — стили
```
## Репозиторий
```bash
git clone <URL_РЕПОЗИТОРИЯ> shop
cd shop
```