# 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 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 shop cd shop ```