- Главная: тихая кнопка «Помахать» (web/js/wave.js), общий счётчик для всех посетителей - server/server.mjs: мини-API (/api/waves, /api/wave), счётчик хранится вне репозитория (/var/lib/vizitka-site/waves.json), лимит раз в секунду с IP, проверка Origin - deploy: systemd-сервис vizitka-api, проксирование /api в nginx, setup-server.sh ставит nodejs - CI: после git pull перезапускает API - Домен https://me.ibrash.duckdns.org вместо заглушки, исправлен пробел в шапке - README и заметки обновлены Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
- Репозиторий: `git@git.ibrash.duckdns.org:aibrash/vizitka-site.git` (Gitea 1.27), ветка `main`
|
||||
- Сервер: `root@192.168.10.112` (Debian 12, имя хоста `visitka-site`): клон репозитория в `/opt/vizitka-site`, nginx отдаёт его папку `web/`, пока по HTTP внутри сети
|
||||
- Публичного домена пока нет: в OG-тегах и `sitemap.xml` стоит заглушка `https://example.com` (как заменить: раздел 5)
|
||||
- Домен: `https://me.ibrash.duckdns.org` (HTTPS терминирует отдельный прокси на openresty перед сервером). Он прописан в OG-тегах, `sitemap.xml` и `robots.txt`; как сменить: раздел 5
|
||||
|
||||
---
|
||||
|
||||
@@ -71,6 +71,7 @@ web/ то, что уходит на сервер (nginx root)
|
||||
js/card.js заполняет главную из config.json
|
||||
js/nav.js верхнее меню из config.pages (скрывает draft), подсветка текущего раздела
|
||||
js/count.js числа «набегают» при появлении
|
||||
js/wave.js кнопка «Помахать» со счётчиком на главной (говорит с /api)
|
||||
arch/ список проектов + arch/<проект>/ (три страницы)
|
||||
projects/ список + projects/amans-world/ + projects/homelab/
|
||||
training/ work/ fixed/ ЧЕРНОВИКИ будущих страниц (draft, noindex), в меню не видны
|
||||
@@ -79,8 +80,9 @@ web/ то, что уходит на сервер (nginx root)
|
||||
fonts/ woff2 Onest и лицензия
|
||||
404.html, favicon.svg, robots.txt, sitemap.xml
|
||||
templates/page.html шаблон новой страницы
|
||||
server/ server.mjs: мини-API счётчика «Помахать» (Node, без зависимостей)
|
||||
tools/ gen_arch.py, gen_projects.py: генераторы страниц архитектуры и проектов
|
||||
deploy/ nginx-site.conf, setup-server.sh (разовая настройка сервера)
|
||||
deploy/ nginx-site.conf, vizitka-api.service, setup-server.sh (разовая настройка сервера)
|
||||
.gitea/workflows/deploy.yml CI
|
||||
```
|
||||
|
||||
@@ -88,6 +90,15 @@ deploy/ nginx-site.conf, setup-server.sh (разовая наст
|
||||
Содержимое берётся из `web/config.json` (имя, `photo`, `status`, `tagline`, `facts`, `tags`, `cta`, `email`, `socials`). Если `photo` пустое, показываются инициалы. До загрузки конфига страница скрыта (`html.js:not(.ready) body[data-hide] .page`), чтобы вёрстка не прыгала; без JS всё видно сразу.
|
||||
Хоумлаб на главной не упоминается **намеренно** (так просил владелец).
|
||||
|
||||
### Кнопка «Помахать» (интерактив на главной)
|
||||
Тихая «призрачная» кнопка внизу карточки «Давай общаться»: прозрачная, тонкая рамка, цвет `--muted`, не конкурирует с ссылками. При клике ладонь машет (`@keyframes wave`, как в приветствии), число плавно докручивается, всплывает маленькое «+1». Счётчик общий для всех посетителей.
|
||||
- Фронтенд: `web/js/wave.js` и блок `.wave-row` в `index.html`. Если API недоступно (например, при просмотре через `python3 -m http.server`), блок прячется (`visibility:hidden`, место зарезервировано, чтобы вёрстка не прыгала).
|
||||
- Бэкенд: `server/server.mjs`, `GET /api/waves` и `POST /api/wave`. Лимит: не чаще раза в секунду с одного IP и не больше 300 в минуту на всех; POST принимается только с разрешённых сайтов (`ALLOWED_ORIGINS`); тело запроса игнорируется, от клиента данные не берутся.
|
||||
- **Счётчик не сбрасывается:** хранится в `/var/lib/vizitka-site/waves.json` (создаётся systemd, вне репозитория), пишется атомарно, перед каждой записью предыдущее значение копируется в `waves.json.bak`, при остановке сервиса значение сохраняется. `git pull`, пуши и перезапуски сервера его не трогают. Не клади файл счётчика внутрь репозитория.
|
||||
- Сервис `vizitka-api` (systemd, `DynamicUser`, песочница, `MemoryMax=96M`), настройки в `/etc/vizitka-api.env` (создаются один раз и потом не перезаписываются), nginx проксирует `/api/` на `127.0.0.1:8787` и передаёт IP посетителя (`X-Client-IP`).
|
||||
- Локальная проверка: `DATA_FILE=/tmp/waves.json STATIC_DIR=web PORT=8791 node server/server.mjs` и открыть `http://localhost:8791`.
|
||||
- Править текст кнопки и числа: прямо в `web/index.html` и `web/js/wave.js`.
|
||||
|
||||
### Меню и страницы
|
||||
Меню рисует `js/nav.js` из `config.json` → `pages`. На главной оно появляется, только если есть опубликованные страницы. Внутренние страницы всегда показывают имя и пункты. На узких экранах фамилия в шапке прячется (чтобы влезли все пункты).
|
||||
|
||||
@@ -142,15 +153,15 @@ magick src.png -strip -resize 640x640\> -quality 74 имя-sm.webp
|
||||
## 5. Деплой и CI
|
||||
|
||||
### Схема (простая)
|
||||
`push в main` → Gitea Actions (`.gitea/workflows/deploy.yml`) заходит по ssh на `root@192.168.10.112` и делает `git pull` в `/opt/vizitka-site` → nginx раздаёт `/opt/vizitka-site/web`, перезапуск не нужен. Сборки нет: что лежит в `web/`, то и на сайте.
|
||||
`push в main` → Gitea Actions (`.gitea/workflows/deploy.yml`) заходит по ssh на `root@192.168.10.112`, делает `git pull` в `/opt/vizitka-site` и перезапускает API счётчика (`systemctl restart vizitka-api`) → nginx раздаёт `/opt/vizitka-site/web`. Для статики перезапуск не нужен; сборки нет: что лежит в `web/`, то и на сайте.
|
||||
|
||||
Репозиторий публичный, поэтому сервер клонирует и обновляет его по HTTPS без ключей и паролей: `https://git.ibrash.duckdns.org/aibrash/vizitka-site.git`. Если репозиторий станет закрытым, на сервер придётся добавить deploy-ключ (в Gitea: репозиторий → Настройки → Deploy keys) или токен.
|
||||
|
||||
### Что настроено на сервере (сделано, `deploy/setup-server.sh`)
|
||||
```bash
|
||||
./deploy/setup-server.sh root@192.168.10.112 # ставит nginx и git, клонирует репозиторий в /opt/vizitka-site, подключает deploy/nginx-site.conf
|
||||
./deploy/setup-server.sh root@192.168.10.112 # ставит nginx, git и nodejs, клонирует репозиторий в /opt/vizitka-site, включает сервис vizitka-api и подключает deploy/nginx-site.conf
|
||||
```
|
||||
Скрипт безопасно запускать повторно: если клон уже есть, он делает `git pull`, и заново применяет конфиг nginx (там `root /opt/vizitka-site/web`, сжатие, кэш, 404, строгий CSP, скрытые файлы закрыты).
|
||||
Скрипт безопасно запускать повторно: если клон уже есть, он делает `git pull`, обновляет systemd-юнит и заново применяет конфиг nginx (`/etc/vizitka-api.env` не перезаписывается, счётчик не трогается) (там `root /opt/vizitka-site/web`, сжатие, кэш, 404, строгий CSP, скрытые файлы закрыты).
|
||||
Если нужно поменять конфиг nginx: правь `deploy/nginx-site.conf` и снова запусти скрипт. Если `/opt/vizitka-site` уже был не репозиторием, скрипт откладывает его в `/opt/vizitka-site.old-<время>`, а не удаляет (одна такая папка там сейчас лежит, это старая выкладка через rsync, её можно удалить).
|
||||
|
||||
### Что нужно для работы CI
|
||||
@@ -166,11 +177,11 @@ ssh root@192.168.10.112 'cd /opt/vizitka-site && git pull --ff-only'
|
||||
|
||||
### HTTPS и домен (позже)
|
||||
Сейчас сервер отдаёт HTTP только внутри сети. Для публичного доступа лучше поставить перед ним обратный прокси (Caddy или nginx на отдельном хосте с сертификатом) или Cloudflare Tunnel, а сам сервер с сайтом не выставлять наружу напрямую рядом с остальными домашними устройствами.
|
||||
Заглушка `https://example.com` лежит в OG-тегах всех `.html`, в `web/sitemap.xml` и `web/robots.txt`. Раньше домен подставлял скрипт выкладки, теперь выкладки-скрипта нет, поэтому когда выберешь домен, замени один раз и закоммить:
|
||||
Домен `me.ibrash.duckdns.org` уже подставлен в OG-теги, `sitemap.xml`, `robots.txt` и в `tools/`. Если домен сменится, замени один раз и закоммить (и поправь `ORIGINS`/`ALLOWED_ORIGINS` для API: `/etc/vizitka-api.env`, потом `systemctl restart vizitka-api`):
|
||||
```bash
|
||||
grep -rlF 'https://example.com' web tools | xargs sed -i 's|https://example.com|https://ТВОЙ.ДОМЕН|g'
|
||||
grep -rlF 'https://me.ibrash.duckdns.org' web tools | xargs sed -i 's|https://me.ibrash.duckdns.org|https://НОВЫЙ.ДОМЕН|g'
|
||||
```
|
||||
(в `tools/` она тоже есть, чтобы генераторы не вернули заглушку).
|
||||
Реальный IP посетителя nginx берёт из `X-Forwarded-For` (`set_real_ip_from` для частных сетей в `deploy/nginx-site.conf`): если передний прокси поменяется и не будет присылать этот заголовок, лимит «раз в секунду» станет общим на всех, проверь по `access.log`.
|
||||
|
||||
---
|
||||
|
||||
@@ -205,7 +216,7 @@ python3 -m http.server 8787 --directory web # локальный просм
|
||||
|
||||
**Что осталось сделать (на момент написания).**
|
||||
1. Убедиться, что в Gitea есть runner и CI срабатывает на пуш (секрет `DEPLOY_SSH_KEY` уже добавлен). Удалить с сервера `/opt/vizitka-site.old-*`.
|
||||
2. Выбрать домен, включить HTTPS через прокси или туннель, заменить заглушку `example.com` (раздел 5).
|
||||
2. Проверить, что кнопка «Помахать» в проде получает реальные IP посетителей (смотреть `/var/log/nginx/access.log`) и что счётчик переживает перезапуск (`systemctl restart vizitka-api`).
|
||||
3. Реальные ники (в `config.json` у Telegram и Instagram стоят короткие ники и их handle могут быть временными), проверка текстов про игру и про хоумлаб.
|
||||
4. Страницы Тренировки, Работа, Фикс (черновики уже лежат в `web/`).
|
||||
5. Фото сервера для хоумлаба вместо иллюстрации, больше кадров игры (Backrooms, песочница, паркур).
|
||||
|
||||
Reference in New Issue
Block a user