# md2vk — Деплой ## Топология ``` https://md2vk.nixg.ru (Caddy на vps02, basic auth) └─ reverse_proxy 10.8.0.2:8420 (WireGuard: vps02 .4 → bigbox .1) └─ docker-контейнер md2vk на bigbox, 127.0.0.1:8420 ``` - Порт приложения **8420** (8000 занят docker-search-api на bigbox). - Контейнер слушает на 127.0.0.1:8420 (снаружи bigbox не открыт). ## bigbox (10.8.0.2) — приложение ```bash cd /opt/md2vk make docker-up # docker compose up -d --build docker ps | grep md2vk # статус curl -s http://127.0.0.1:8420/api/v1/health # {"status":"ok"} ``` - Данные: named volume `md2vk_data` → `/data/md2vk.db` (SQLite). - Секрет: `./secrets/token_encryption_key` → `/run/secrets/token_encryption_key`. - Логи аудита: `./logs/` монтируется в `/logs`. - Health: `/api/v1/health`, проверяется Docker healthcheck. - Восстановление после перезагрузки: `restart: unless-stopped`. - Если надо пересоздать БД — удалить том (только по явной команде, данные!): `docker compose down -v && make docker-up` (НЕ делать без подтверждения). ## Создание пользователя и API-ключа ```bash cd /opt/md2vk source venv/bin/activate TOKEN_ENCRYPTION_KEY_FILE=/opt/md2vk/secrets/token_encryption_key ./scripts/create_user.py \ --name estorozhenko --api-key-out secrets/estorozhenko_api_key.txt # вывод: API key сохранён в secrets/estorozhenko_api_key.txt (md2vk_...) ``` Источник: `scripts/create_user.py` (добавляет User с сгенерированным ключом; ключ отображается один раз). ## vps02 (87.242.100.206) — Caddy Файл `/opt/caddy/Caddyfile` на vps02, секция: ``` md2vk.nixg.ru { basic_auth /* { estorozhenko $2a$14$T5gAji7gmg1t3Ifxw0CJy.jat9vpFfOiJIE8j5bnHynEVH1q.QTPS } reverse_proxy 10.8.0.2:8420 } ``` Применить (контейнер caddy, монтирует Caddyfile): ```bash ssh vps02 docker exec caddy caddy validate --config /etc/caddy/Caddyfile # проверить синтаксис docker exec caddy caddy reload --config /etc/caddy/Caddyfile # перезагрузить # если нужно: docker restart caddy ``` - TLS: Caddy автоматически выпускает Let's Encrypt сертификат для md2vk.nixg.ru (acme в Caddyfile: `email kpa39l@yandex.ru`). - Сертификат на caddy_data (volume), переживает рестарты. ## vps02 — fail2ban (блокировка после 5 попыток) Пакет ставится на vps02 (Debian/Ubuntu): ```bash ssh vps02 sudo apt-get update && sudo apt-get install -y fail2ban ``` Конфиг jail (`/etc/fail2ban/jail.local`) и фильтр (`/etc/fail2ban/filter.d/md2vk.conf`): ```ini # /etc/fail2ban/filter.d/md2vk.conf [Definition] failregex = ^.*"status":401.* ignoreregex = ``` ```ini # /etc/fail2ban/jail.local [md2vk] enabled = true port = http,https filter = md2vk logpath = /var/log/caddy/access.log maxretry = 5 findtime = 600 bantime = -1 action = iptables-allports ``` - Лог Caddy в JSON: настроить в Caddyfile `log { output file /var/log/caddy/access.log format json }` (глобальный блок). - Перезапуск: `sudo systemctl restart fail2ban`. - Проверка: `sudo fail2ban-client status md2vk`. - Ручной unban: `sudo fail2ban-client -c /etc/fail2ban unban `. ## Сквозная проверка ```bash # 1. health через Caddy (без auth → 401) curl -s -o /dev/null -w "%{http_code}\n" https://md2vk.nixg.ru/api/v1/health # 401 # 2. health c auth → 200 curl -s -u 'estorozhenko:<пароль>' https://md2vk.nixg.ru/api/v1/health # {"status":"ok"} # 3. публикация не требует VK-токена? нет — конвертация: curl -s -u 'estorozhenko:<пароль>' -H 'Authorization: Bearer ' \ -X POST https://md2vk.nixg.ru/api/v1/convert \ -H 'Content-Type: application/json' \ -d '{"message_md":"**test** *curl*"}' # format_data # 4. баним проверкой: 5 раз неверный пароль → fail2ban ban IP for i in 1 2 3 4 5 6; do curl -s -o /dev/null -w "%{http_code}\n" -u 'estorozhenko:wrong' https://md2vk.nixg.ru/api/v1/health; done # → 401 ×6, затем соединение DROP (curl timeout) sudo fail2ban-client status md2vk # IP в banned sudo fail2ban-client unban <ваш-ip> ``` ## Восстановление после аварии - Приложение: `docker compose up -d --force-recreate` на bigbox. - Caddy: `docker restart caddy` на vps02 (volume caddy_data хранит сертификаты). - БД: том `md2vk_data`; бэкап = копия `/opt/md2vk/data/md2vk.db` (вне контейнера) — включена в homelab-backup (/opt/backup).