4.1 KiB
4.1 KiB
IP-gate: ограничение доступа на время разработки
Задача
Сайт доступен на реальном домене (через VPS + NPM + Netbird), но находится в активной разработке/тестировании. Нужно ограничить доступ, не мешая разработке и полному тестированию функционала (включая OAuth и webhook-и).
Решение
IP-whitelist на уровне Fastify (onRequest хук). Только запросы с разрешённых IP проходят. Внешние webhook-и и OAuth callback-и исключены из проверки.
Конфигурация
.env
SITE_ACCESS_IPS=1.2.3.4,5.6.7.8
- Не задана или пуста — защита отключена
- IP через запятую, пробелы игнорируются (трим)
request.ipвозвращает реальный IP клиента благодаряtrustProxy: true
Архитектура
Новый плагин: server/src/plugins/ip-gate.js
Регистрируется в server/src/index.js перед всеми маршрутами.
fastify.register(async function ipGate(fastify, opts) {
fastify.addHook('onRequest', async (request, reply) => {
// защита выключена
// путь в исключениях
// ip в списке
// иначе 403
})
})
Логика onRequest
SITE_ACCESS_IPSпуст →return(пропустить)- Путь запроса в списке исключений →
return request.ipесть вSITE_ACCESS_IPS→return- Иначе →
reply.code(403).type('text/html').send(htmlPage)
Исключения
Маршруты, которые должны работать всегда (их вызывают внешние сервисы, а не браузер тестировщика):
| Путь | Причина |
|---|---|
/api/auth/oauth/vk/callback |
VK OAuth callback |
/api/auth/oauth/yandex/callback |
Yandex OAuth callback |
/api/webhooks/yookassa |
YooKassa payment webhook |
/api/admin/notifications/telegram/webhook |
Telegram webhook |
Статика (загружается браузером тестировщика, поэтому тоже проверяется):
/uploads/*и/uploads-resized/*— не исключаем, блокируются вместе со всем остальным
403-страница
HTML-страница с информацией о магазине и статусе разработки:
- Название: «Любимый Креатив»
- Подзаголовок: «Изделия ручной работы: вещи с характером и вниманием к деталям»
- Сообщение: «Сайт находится в разработке и скоро будет доступен»
- Показывает IP посетителя (чтобы можно было сообщить для добавления в whitelist)
- Минимальная стилизация (чистый HTML + inline CSS, без внешних ресурсов)
Точки регистрации
В server/src/index.js:
// после trustProxy, перед маршрутами
await fastify.register(require('./plugins/ip-gate'))
Тестирование
- Юнит-тесты:
server/src/plugins/__tests__/ip-gate.test.js- IP в списке → запрос проходит
- IP не в списке → 403
- Путь-исключение → проходит с любым IP
SITE_ACCESS_IPSне задан → защита выключена- Пробелы в списке IP → корректная работа
Включение/выключение
- Включить: задать
SITE_ACCESS_IPSв.env - Выключить: удалить
SITE_ACCESS_IPSили оставить пустым - Перезапуск сервера не требуется если используется
node --watch