nginx: vhost для v2 (порт 4146, 301-карта для legacy WP cyrillic slugs) + CLAUDE.md проекта
This commit is contained in:
91
CLAUDE.md
Normal file
91
CLAUDE.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# pushkinohistory.ru — Vite+React v2
|
||||
|
||||
Сайт «История города Пушкино». Редизайн с WordPress (v1, контейнер `pushkinohistory-ru:4143`) на статический Vite+React+Tailwind (контейнер `pushkinohistory-ru-v2:4146`).
|
||||
|
||||
## Стек
|
||||
|
||||
- Vite 6 + React 18 + Tailwind 3
|
||||
- PT Serif (заголовки/основной текст) + IBM Plex Sans (UI)
|
||||
- Express 4 + compression (runtime сервер, отдаёт prerendered HTML + `/api/news.json` + `/feed/`)
|
||||
- Puppeteer для prerender (chromium в build-стадии)
|
||||
- fast-xml-parser для агрегатора внешних RSS
|
||||
|
||||
## Структура
|
||||
|
||||
```
|
||||
src/
|
||||
App.jsx # клиентский роутер (window.history + popstate), 301-карта oldSlug → newSlug
|
||||
components/ # Header, Sidebar, Footer, PostCard
|
||||
content/ # JSON-контент: posts, pages, partners, ads, transport, feeds
|
||||
pages/ # Home, Post, Page, Category, News, NotFound
|
||||
server/index.js # Express: /api/health, /api/news.json, /uploads/, /feed/, статика
|
||||
scripts/
|
||||
convert_posts.py # WP DB → src/content/{posts,pages}.json
|
||||
build-rss.js # генератор IPB-совместимого RSS (full content в CDATA)
|
||||
build-sitemap.js # sitemap.xml + robots.txt
|
||||
build-slugs.js # routes.json для prerender
|
||||
prerender.js # SPA → статичные HTML по маршрутам через puppeteer
|
||||
pull-external-rss.js # cron: внешние RSS → data/news.json (агрегатор)
|
||||
public/uploads/ # картинки, перенесены из WP /wp-content/uploads/
|
||||
nginx/ # vhost для прода (симлинк из /etc/nginx/conf.d/)
|
||||
```
|
||||
|
||||
## Контент
|
||||
|
||||
Скрейп из WP DB (`pushkinohistory_ru` на `db.hhivp.com`):
|
||||
- 7 постов + 4 страницы
|
||||
- 6 картинок в `public/uploads/`
|
||||
- URL-encoded кириллические slugs WP → транслитерированы (`/segodnya-nochyu-rossiyane-uvidyat-pervoe/`); старые URL → 301 через `nginx/map`
|
||||
|
||||
## RSS
|
||||
|
||||
- **Свой `/feed/`** — IPB-совместимый RSS 2.0 с полным HTML в `<content:encoded>`, стабильными `<guid isPermaLink>`, `<dc:creator>`, категориями. Для импорта в `forum.pushkinohistory.ru`.
|
||||
- **Внешние фиды** — `src/content/feeds.json` (список URL), парсятся cron-скриптом `scripts/pull-external-rss.js` → `data/news.json` (bind-mount), фронт читает client-side через `/api/news.json`. Каждое добавление источника = редактирование `feeds.json` + push.
|
||||
|
||||
## Деплой
|
||||
|
||||
```bash
|
||||
# Локально:
|
||||
cd E:\Projects\pushkinohistory-ru-v2
|
||||
git add . && git commit -m "..." && git push
|
||||
|
||||
# На web.hhivp.com:
|
||||
ssh striker@web.hhivp.com
|
||||
cd /opt/docker/sites/pushkinohistory-ru-v2
|
||||
git pull && docker compose up -d --build
|
||||
```
|
||||
|
||||
CI/CD автоматизация — Gitea Actions с SSH-deploy (см. `.gitea/workflows/deploy.yml`).
|
||||
|
||||
## Контейнер
|
||||
|
||||
- Image: `pushkinohistory-ru-v2:latest` (мультистейдж: builder с puppeteer/chromium → runtime node:22-alpine + express)
|
||||
- Порт: `127.0.0.1:4146`
|
||||
- Bind-mounts:
|
||||
- `/opt/www/pushkinohistory.ru/uploads-v2 → /app/public/uploads (ro)` — динамические uploads
|
||||
- `/opt/docker/sites/pushkinohistory-ru-v2/data → /app/data (ro)` — `news.json` от cron
|
||||
- nginx vhost: `/etc/nginx/conf.d/pushkinohistory.ru` → симлинк на `nginx/pushkinohistory.ru.conf` в этом репо
|
||||
|
||||
## Откат на WP v1
|
||||
|
||||
Старый WP в `/opt/docker/sites/pushkinohistory-ru/` (контейнер `pushkinohistory-ru:4143`) сохранён. Чтобы откатиться:
|
||||
|
||||
```bash
|
||||
ssh striker@web.hhivp.com
|
||||
sudo ln -sfn /opt/docker/sites/pushkinohistory-ru/nginx/pushkinohistory.ru.conf /etc/nginx/conf.d/pushkinohistory.ru
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
## БД (WP, v1)
|
||||
|
||||
DB на `db.hhivp.com` (45.10.53.205), `pushkinohistory_ru`/`u_pushhist`, prefix `ph_`. **Не удалять** — нужна для отката и как источник для повторного скрейпа.
|
||||
|
||||
## Форум
|
||||
|
||||
`forum.pushkinohistory.ru` — IPB 4.x в отдельном контейнере `forum-pushkinohistory-ru:4144`. **v2 редизайном не затронут.**
|
||||
|
||||
## История
|
||||
|
||||
- 2026-05-08: v1 контейнеризован, миграция со str-u-01 на web.hhivp.com
|
||||
- 2026-05-14: фикс trust-proxy.conf для Docker bridges (Better WP Security)
|
||||
- 2026-05-21: v2 редизайн — Vite+React+Tailwind, отказ от WP, RSS-агрегатор внешних фидов + свой RSS для IPB
|
||||
100
nginx/pushkinohistory.ru.conf
Normal file
100
nginx/pushkinohistory.ru.conf
Normal file
@@ -0,0 +1,100 @@
|
||||
# pushkinohistory.ru — Vite+React (v2)
|
||||
# Container: pushkinohistory-ru-v2 on 127.0.0.1:4146
|
||||
# v2 cutover: 2026-05-21 (старый WP на :4143 оставлен в /opt/docker/sites/pushkinohistory-ru как backup)
|
||||
|
||||
# 301-редиректы со старых URL-encoded WP slugs (cyrillic) на новые транслитерированные.
|
||||
# nginx уже декодирует URI до cyrillic'а, поэтому в ключах map'а — кириллица в UTF-8.
|
||||
map $request_uri $legacy_redirect {
|
||||
default "";
|
||||
~^/добро-пожаловать/?$ /dobro-pozhalovat/;
|
||||
~^/фото/?$ /foto/;
|
||||
~^/сегодня-ночью-россияне-увидят-первое-суперлуние-года-волчью-луну/?$ /segodnya-nochyu-rossiyane-uvidyat-pervoe/;
|
||||
~^/первые-20-градусные-морозы/?$ /pervye-20-gradusnye-morozy/;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name pushkinohistory.ru www.pushkinohistory.ru;
|
||||
include /etc/nginx/templates/letsencrypt.conf;
|
||||
location / { return 301 https://pushkinohistory.ru$request_uri; }
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen 443 quic;
|
||||
listen [::]:443 ssl;
|
||||
listen [::]:443 quic;
|
||||
http2 on;
|
||||
server_name www.pushkinohistory.ru;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/pushkinohistory.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/pushkinohistory.ru/privkey.pem;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/pushkinohistory.ru/chain.pem;
|
||||
include /etc/nginx/templates/ssl.conf;
|
||||
include /etc/nginx/templates/security-headers.conf;
|
||||
include /etc/nginx/templates/rugov-block.conf;
|
||||
|
||||
return 301 https://pushkinohistory.ru$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen 443 quic;
|
||||
listen [::]:443 ssl;
|
||||
listen [::]:443 quic;
|
||||
http2 on;
|
||||
server_name pushkinohistory.ru;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/pushkinohistory.ru/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/pushkinohistory.ru/privkey.pem;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/pushkinohistory.ru/chain.pem;
|
||||
include /etc/nginx/templates/ssl.conf;
|
||||
include /etc/nginx/templates/security-headers.conf;
|
||||
include /etc/nginx/templates/rugov-block.conf;
|
||||
include /etc/nginx/templates/letsencrypt.conf;
|
||||
|
||||
access_log /var/log/nginx/access/pushkinohistory.ru.access.log;
|
||||
error_log /var/log/nginx/errors/pushkinohistory.ru.error.log warn;
|
||||
|
||||
client_max_body_size 4M;
|
||||
|
||||
# 301-редиректы с легаси WP-slugs на новые транслитерированные пути
|
||||
if ($legacy_redirect != "") {
|
||||
return 301 $legacy_redirect;
|
||||
}
|
||||
|
||||
# WP-эндпоинты — больше не существуют, отдаём 410 Gone (помогает поисковикам пометить как удалённые)
|
||||
location ~* ^/(wp-admin|wp-login\.php|wp-content|wp-includes|xmlrpc\.php|wp-cron\.php|wp-config\.php|readme\.html)$ {
|
||||
return 410;
|
||||
}
|
||||
|
||||
# RSS-фид (статичный файл, отдаётся из dist)
|
||||
location = /feed/ {
|
||||
proxy_pass http://127.0.0.1:4146;
|
||||
include /etc/nginx/templates/proxy.conf;
|
||||
add_header Content-Type "application/rss+xml; charset=utf-8" always;
|
||||
add_header Cache-Control "public, max-age=600" always;
|
||||
}
|
||||
|
||||
# Агрегатор новостей: апдейтится по cron, кешируем коротко
|
||||
location = /api/news.json {
|
||||
proxy_pass http://127.0.0.1:4146;
|
||||
include /etc/nginx/templates/proxy.conf;
|
||||
add_header Cache-Control "public, max-age=120" always;
|
||||
}
|
||||
|
||||
# Картинки/статические ассеты — кешируем подольше
|
||||
location ~* ^/(uploads|assets)/ {
|
||||
proxy_pass http://127.0.0.1:4146;
|
||||
include /etc/nginx/templates/proxy.conf;
|
||||
add_header Cache-Control "public, max-age=604800, immutable" always;
|
||||
proxy_cache_valid 200 7d;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:4146;
|
||||
include /etc/nginx/templates/proxy.conf;
|
||||
proxy_read_timeout 30s;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user