Личный сайт и блог. Nuxt на своём сервере, два языка.2026

lyoraeth.art

Nuxt 4Vue 3TypeScriptTailwind SanityNitroSatoriDockerCI/CD

Комментарии не хотел модерировать через админку: заходить в студию CMS ради одной кнопки — больше возни, чем стоит задача. Новый комментарий приходит письмом, в письме — кнопка «Одобрить». Ссылка под ней подписана HMAC-SHA256 от id документа ключом записи, эндпоинт сверяет подпись через timingSafeEqual и патчит запись. Почту комментатор не оставляет, только ник, который придумал сам.

Проект строится на таком подходе: внешний сервис или пара десятков строк своего кода. Сайт живёт на моём VPS: Nuxt 4 с серверным рендером, в Docker, деплой по пушу в main. Пайплайн собирает образ, отправляет в реестр и перезапускает контейнер — от коммита до живого сайта минуты три. Аналитика — Umami в том же compose, без кук и баннера согласия. Шрифты локально, сторонних скриптов на странице нет. Cloudflare — только DNS.

Контент — работы, посты и настройки вроде статуса доступности — в Sanity, запрашивается серверными роутами. Токен в браузер не попадает. Под блогом — издательская система: два языка, оглавление из разметки при рендере, полоса прогресса чтения, источники под статьёй и комментарии. Обложку для соцсетей сайт рисует сам: Satori собирает SVG, resvg переводит в PNG, шрифты лежат на сервере. Читается сайт и машинами: llms-full.txt собирается из CMS по запросу, форма контакта зарегистрирована как инструмент для агента.

HSTS с preload, COOP, запрет фрейминга и Permissions-Policy, отключающая камеру, микрофон, геолокацию. CSP в режиме Report-Only: список разрешённого собран, нарушения приходят письмом, но на блокировку не переключено — сначала надо убедиться, что список полный. Размеры картинок из метаданных ассета проставляются явно, макет не прыгает при загрузке. AVIF убран из цепочки: трансформация на CDN иногда не успевала прогреться, фолбэки в <picture> ломались на серверном рендере. Тестов мало — два юнита на композаблы и один сквозной прогон по страницам.

Открыть проект