Старый favicon.svg (стилизованная «A» от скаффолдинга) заменён на оптимизированный для 16-32px вариант logo-mark: кривые-отражения + точка на тёмном фоне, тот же градиент #b794ff→#6c4ed4. - public/favicon.svg — новый 64×64 viewBox, утолщённые штрихи - public/favicon.ico — 32×32 (sharp → PNG-in-ICO) - public/apple-touch-icon.png — 180×180 для iOS - scripts/build-favicon.mjs + npm run build:favicon - BaseLayout: добавлены <link> на ico (fallback) и apple-touch-icon
10 KiB
anotherreflections.ru — v2 (Astro)
Проект
Главный сайт-портал ролевой группы «Иные Отражения». Переделан со старого WordPress 6.9 (тема darkness-10, 23 активных плагина) на статический Astro 5 + Content Collections + markdown.
Сервер
| Параметр | Значение |
|---|---|
| Хост | web.hhivp.com (45.10.53.206 / 45.10.53.242) |
| Deploy path | /opt/docker/sites/anotherreflections-ru-v2/ (git clone) |
| Git remote | git.striker.su/striker/anotherreflections-website-v2 (ветка main) |
| Контейнер | anotherreflections-ru-v2 (nginx:1.29-alpine) |
| Внутренний порт | 80 |
| Внешний порт | 127.0.0.1:4084 (nginx-хост → proxy_pass) |
| nginx vhost | /etc/nginx/conf.d/anotherreflections.ru |
| OG-image / лого | public/og-image.png, public/logo*.svg |
Cutover (2026-05-20)
Со старого WordPress (контейнер anotherreflections-ru на :4080) — на новый Astro-контейнер (:4084). Старый контейнер и БД оставлены для отката на 1-2 недели.
Откат за 1 минуту:
ssh striker@web.hhivp.com
sudo sed -i 's|127.0.0.1:4084|127.0.0.1:4080|g' /etc/nginx/conf.d/anotherreflections.ru
sudo nginx -t && sudo systemctl reload nginx
Бэкап перед cutover в /opt/backup/anotherreflections-pre-v2-cutover-20260521-024027/:
wp-site-tree.tgz(349 МБ) — весь/opt/docker/sites/anotherreflections-ru/wp-db-anotherreflctions_ru.sql.gz(5.6 МБ) — mysqldump БД (наdb.hhivp.comMySQL)anotherreflections.ru.nginx— старый vhost (proxy 4080)
Также резерв-копия vhost в /opt/backup/nginx-bak/20260521-024433/anotherreflections.ru.bak.20260520-wp.
Стек
- Astro 5 (6.3.6) + Content Collections — каждая
.astroстраница рендерится вdist/.../index.htmlприnpm run build(SSG, без runtime JS-фреймворка). - @astrojs/rss — RSS-фиды (общий + per-category) под IPB RSS Importer.
- @astrojs/sitemap —
sitemap-index.xmlавтоматически. - sanitize-html — очистка HTML тела поста для
<content:encoded>в RSS. - sharp (devDep) — генерация OG-image PNG из SVG.
Структура
src/
├── content/
│ ├── posts/*.md (50 постов 2009-2015, мигрированы из WP)
│ ├── pages/*.md (6 страниц: O нас, Наши друзья, страницы про игры)
│ └── _categories.json (10 категорий-справочник)
├── components/
│ ├── BrandMark.astro (SVG-знак в шапке)
│ ├── SocialLinks.astro (плавающая правая колонка: Telegram, ВК, ↑)
│ ├── Analytics.astro (Яндекс.Метрика + GA, скрипты с type=text/plain
│ │ активируются после consent)
│ └── CookieConsent.astro (152-ФЗ-баннер, ar-consent в localStorage+cookie)
├── layouts/BaseLayout.astro
├── pages/
│ ├── index.astro (hero + лента всех постов)
│ ├── [slug].astro (один пост или одна страница, slug совпадает с WP)
│ ├── 404.astro
│ ├── miry.astro (8 игровых вселенных карточками)
│ ├── kontakty.astro (email + Telegram + ВК)
│ ├── privacy.astro (политика + кнопка «Отозвать согласие»)
│ ├── feed.xml.ts (общий RSS, фильтр по RSS_CUTOFF)
│ ├── sitemap.txt.ts (plain-text список всех URL)
│ └── category/
│ ├── [slug].astro
│ └── [slug]/feed.xml.ts (per-category RSS)
├── lib/rss-helpers.ts (рендер md→HTML для <content:encoded>)
├── styles/global.css (тёмная тема, decorative ::before/::after звёзды)
└── consts.ts (SITE_TITLE, WORLDS, ANALYTICS, CATEGORY_COLORS, plural())
public/
├── favicon.svg (брендовый знак на тёмном фоне, оптимизирован под 16-32px)
├── favicon.ico (32×32 PNG-in-ICO, генерируется из favicon.svg)
├── apple-touch-icon.png (180×180 для iOS home screen)
├── logo.svg, logo-mark.svg
├── og-image.png (1200×630 для расшаривания в TG/VK/Twitter)
├── og-image.svg (исходник)
├── robots.txt (allow all, Host для Yandex, AI-crawlers)
├── ai.txt (Train/Cite/Quote: yes)
├── llms.txt (формат llmstxt.org)
└── wp-content/uploads/ (4 файла, перенесены со старого WP: header_bg + NY-baner)
scripts/
├── migrate-wp.mjs (одноразовый: _wp-export.json → src/content/*.md)
├── build-og-image.mjs (sharp → public/og-image.png из SVG)
└── build-favicon.mjs (sharp → public/favicon.ico + apple-touch-icon.png из favicon.svg; `npm run build:favicon`)
Dockerfile (multi-stage: node:22-alpine builds → nginx:1.29-alpine serves)
nginx.conf (gzip, кэш _astro/ 1y, MIME application/rss+xml для feed)
docker-compose.yml (контейнер на 127.0.0.1:4084)
.gitea/workflows/deploy.yml (push в main → SSH-деплой на web)
RSS под IPB Importer
RSS_CUTOFF в src/consts.ts (по умолчанию 2026-05-20) — фид отдаёт только посты с pubDate ≥ cutoff. Архив 2009-2015 на сайте остаётся, в форумы через RSS Importer не вбрасывается. Чтобы добавить пост в фид — публикуем с датой ≥ cutoff и пересобираем.
RSS 2.0 strict: <pubDate> в RFC-822, <guid isPermaLink="true"> = URL поста (IPB дедуплицирует), <content:encoded> с CDATA + полным HTML тела, <lastBuildDate> обновляется при каждом build.
URLs:
/feed.xml— общий/category/<slug>/feed.xml— по категории
Аналитика и cookie consent
- Яндекс.Метрика 13938862 (с webvisor) и Google gtag GT-PH39R3X. ID-шки в
src/consts.ts:ANALYTICS. - Оба скрипта в
Analytics.astroимеютtype="text/plain" data-cookieconsent="statistics"— браузер их не выполняет, пока пользователь не нажмёт «Принять» в баннере. CookieConsent.astroактивирует скрипты при согласии, сохраняет выбор вlocalStorage+cookie ar-consent=accept|deny(12 мес).- На
/privacy/кнопка «Отозвать согласие» — ставитar-consent=denyодним кликом.
Деплой
Через CI/CD (Gitea Actions) — push в main:
- Workflow
.gitea/workflows/deploy.ymlстартует. - SSH на
web.hhivp.comс ключом из секретаSSH_PRIVATE_KEY(base64). git fetch+git reset --hard origin/main→docker compose build --pull→docker compose up -d→docker image prune -af --filter "until=168h".- Verify-шаг:
curl -sf -H "Host: anotherreflections.ru" http://127.0.0.1:4084/.
Секреты в Gitea (/repos/striker/anotherreflections-website-v2/actions/secrets): SSH_PRIVATE_KEY, SSH_HOST=web.hhivp.com, SSH_USER=striker, SSH_PORT=22. Deploy-ключ — ~/.ssh/anotherreflections-v2-deploy{,.pub} локально, .pub в ~striker/.ssh/authorized_keys на web.
Вручную (с локалки):
cd /opt/docker/sites/anotherreflections-ru-v2
git pull
docker compose build && docker compose up -d
База данных
В новой версии БД нет. Старый WP оставлен с БД anotherreflctions_ru (sic, с опечаткой) на db.hhivp.com (45.10.53.205, MySQL), user u_anotherreflections, prefix anm_. После 1-2 недель наблюдения за новой версией — старый WP-контейнер можно удалить, БД и snapshot тоже.
SEO/AI файлы
public/robots.txt— статика, разрешено всё; явно перечислены GPTBot/ClaudeBot/Google-Extended/CCBot/PerplexityBot/anthropic-ai; ссылки на sitemap-index.xml и sitemap.txtpublic/ai.txt— Train/Cite/Quote: yes (по спецификации spawning.ai)public/llms.txt— формат llmstxt.org с описанием проекта, ключевыми страницами, форумами, RSS-фидами, контактамиsrc/pages/sitemap.txt.ts— генерирует plain-text список 68 URL при каждом билде@astrojs/sitemap—sitemap-index.xml+sitemap-0.xmlXML-формат
Скриншоты-источники
В E:/Projects/ лежат финальные:
anotherreflections-logo.svg/.png— знак + надписьanotherreflections-logo-mark.svg/.png— только знак
Локальная разработка
npm install
npm run dev # → http://localhost:4321
npm run build # → dist/ (статика)
npm run preview # просмотр build
npm run migrate # одноразовая миграция _wp-export.json → md (уже сделана)
История
- 2026-05-20: v1 (WordPress 6.9 + darkness-10 + 23 плагина, контейнер на :4080) переделан на Astro 5. Новый репо
git.striker.su/striker/anotherreflections-website-v2. Cutover в production через nginx proxy_pass swap. См. такжеmemory/project_anotherreflections_main_site.md. - 2026-05-07: 6 IPB-форумов проекта мигрированы со str-u-01 на web.hhivp.com (порты 4091-4096). См.
memory/project_anotherreflections_forums.md.