> For the complete documentation index, see [llms.txt](https://docs.ipcheck.ing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ipcheck.ing/developer/ru/configuration/security-options.md).

# Параметры безопасности

Бэкенд MyIP проксирует ряд сторонних API, некоторые из них платные. Если оставить его полностью открытым, публичный экземпляр станет анонимным бесплатным прокси для любого, кто его найдёт.

Думайте о защите как о двух слоях, в таком порядке:

1. **Граница сети (рекомендуемый основной слой).** CDN/WAF перед вашим origin-сервером — ниже в качестве примера используется Cloudflare — блокирует вредоносный трафик ещё до того, как он достигнет вашего сервера, и при этом даёт гораздо более мощные инструменты, чем может встроить любое приложение: управляемое обнаружение ботов, гибкие правила ограничения запросов, челленджи и глобальный обзор IP-адресов атакующих.
2. **Само приложение (страховочная сетка).** Четыре переменные окружения встраивают в бэкенд последнюю линию защиты. Их стоит задавать даже за edge — они защитят вас, когда кто-то найдёт реальный адрес вашего origin и полностью обойдёт edge — но это последний рубеж, а не основная защита.

## Сначала защищайте на edge (рекомендуется)

Любой CDN/WAF с правилами ограничения по IP работает так же; ниже шаги для Cloudflare, потому что это самый распространённый вариант, а его бесплатный тариф уже покрывает основы.

{% stepper %}
{% step %}

#### Проксируйте свои DNS-записи через Cloudflare

В панели DNS Cloudflare оставьте запись для вашего hostname MyIP **Через прокси** (оранжевое облако), чтобы весь трафик шёл через edge Cloudflare. MyIP создан для этого: бэкенд уже читает `CF-Connecting-IP` чтобы определять реальные IP клиентов, а его кэшируемые `/api/*` маршруты обслуживаются из edge-кэша, который поглощает значительную часть нагрузки ещё до того, как она дойдёт до вас.
{% endstep %}

{% step %}

#### Добавьте правило ограничения запросов для `/api/*`

В **Security → WAF → Rate limiting rules**, создайте правило, соответствующее пути вашего API — например, выражение `(http.request.uri.path wildcard "/api/*")` — и блокируйте исходный IP, когда он превышает ваш порог. Ограничение запросов доступно на всех тарифах; число правил и варианты окна зависят от тарифа. Поскольку edge-кэш уже отвечает на повторные запросы, обычным посетителям редко нужны большие объёмы запросов — начните строже, чем кажется нужным, и ослабьте ограничение, если реальные пользователи начнут жаловаться.
{% endstep %}

{% step %}

#### Включите защиту от ботов

Включите **Bot Fight Mode** (Security → Bots). Большая часть злоупотреблений публичным экземпляром MyIP — это скриптовый сбор данных с эндпоинтов геолокации, и именно против этого это и направлено. Если ваш тариф поддерживает пользовательские правила WAF, то **Управляемая проверка** для трафика не из браузера к `/api/*` — более мягкая альтернатива, которая никогда жёстко не блокирует реального пользователя.
{% endstep %}

{% step %}

#### Закройте доступ к своему origin

Правила edge помогают только если трафик не может обойти edge. Настройте фаервол вашего origin-сервера так, чтобы он принимал HTTP(S) только от [диапазонов IP Cloudflare](https://www.cloudflare.com/ips/) — или вообще уберите origin из публичного интернета с помощью Cloudflare Tunnel. Если origin отвечает на прямые запросы, атакующий, который узнает его адрес, обойдёт все правила выше; именно для такого сценария и существуют переменные уровня приложения ниже.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
Запросы, обслуженные из кэша Cloudflare, никогда не доходят до origin, поэтому для ограничителей уровня приложения ниже они невидимы — ещё одна причина, почему контролировать объём нужно именно на edge.
{% endhint %}

## Собственная страховочная сетка приложения

Четыре переменные окружения встраивают в бэкенд слой подстраховки. Все четыре необязательны и по умолчанию выключены (или разрешающие).

| Переменная                         | Назначение                                 | По умолчанию       |
| ---------------------------------- | ------------------------------------------ | ------------------ |
| `ALLOWED_DOMAINS`                  | Какие сайты могут вызывать `/api/*`        | `localhost` только |
| `SECURITY_RATE_LIMIT`              | Жёсткий лимит запросов на IP               | `0` — отключено    |
| `SECURITY_DELAY_AFTER`             | Постепенное замедление для каждого IP      | `0` — отключено    |
| `SECURITY_BLACKLIST_LOG_FILE_PATH` | Файл-журнал на диске для IP с ограничением | пусто — файла нет  |

## `ALLOWED_DOMAINS` — проверка Referer

Каждый `/api/*` маршрут проходит через одну проверку Referer. Бэкенд читает `Referer` заголовок, извлекает его **имя хоста**, и требует, чтобы это имя хоста было в списке разрешённых.

Список разрешённых — это `localhost` плюс записи, разделённые запятыми, в `ALLOWED_DOMAINS`.

Отклонения выглядят так: `403`:

| Ситуация                                                              | Ответ                          |
| --------------------------------------------------------------------- | ------------------------------ |
| Нет `Referer` заголовка                                               | `{"error": "Что вы делаете?"}` |
| Referer присутствует, hostname не разрешён (или не удаётся разобрать) | `{"error": "Доступ запрещён"}` |

{% hint style="danger" %}
**Если вы размещаете MyIP на реальном домене, это нужно задать.** При `ALLOWED_DOMAINS` пустом значении только `localhost` проходит — поэтому развертывание, доступное по `https://ip.example.com` или `http://192.168.1.10:18966` получает `403` на каждом API-вызове, и приложение выглядит сломанным, хотя статическая страница загружается нормально.
{% endhint %}

Правила, которые стоит помнить:

* **Только имена хостов.** Без схемы, без порта, без пути: `example.com`, а не `https://example.com:443/`.
* **Точное совпадение.** `example.com` не включает `www.example.com`. Укажите оба.
* **IP-адреса считаются именами хостов.** Если приложение доступно по `http://192.168.1.10:18966` это значит добавить `192.168.1.10`.
* **`localhost` всегда разрешено**, так что для локальной разработки конфигурация не нужна.

{% code title=".env" %}

```bash
ALLOWED_DOMAINS="example.com,www.example.com,ip.example.com"
```

{% endcode %}

{% hint style="warning" %}
Проверка Referer — это средство сдерживания злоупотреблений, а не аутентификация. Любой клиент может отправить произвольный `Referer` заголовок. Она останавливает случайный хотлинкинг и скрипты-однодневки; но не остановит настойчивый скрейпер. Сочетайте её с ограничением запросов.
{% endhint %}

За обратным прокси убедитесь, что ваш прокси пересылает `Referer` заголовок без изменений. См. [Обратный прокси и домены](/developer/ru/getting-started/reverse-proxy-and-domains.md).

## `SECURITY_RATE_LIMIT` — жёсткий лимит

Лимит запросов на IP для `/api/*`, поддерживаемый `express-rate-limit`.

* **Окно**: 20 минут, скользящее.
* **Лимит**: число, которое вы задаёте. `0` или пустое значение означает, что лимитер вообще не подключается.
* **Превышение лимита**: `429` с `{"message": "Слишком много запросов"}`.
* **Исключённый маршрут**: `/api/monitoring`, туннель Sentry, у которого есть собственный лимитер — см. [Мониторинг ошибок](/developer/ru/configuration/error-monitoring.md).

{% hint style="info" %}
Строка запуска выводит `🛡️ Ограничитель запросов включён — N запросов за 60 минут`. Окно, задаваемое в коде, — это **20 минут**.
{% endhint %}

### Что логируется

Бэкенд логирует момент, когда IP пересекает порог — **один раз**, при переходе, а не на каждом последующем заблокированном запросе. Это не даёт злоупотребляющему клиенту, долбящему ограниченный эндпоинт, засорять ваши логи.

```
WARN: IP ограничен по запросам
    ip: "203.0.113.45"
```

Когда настроен DSN бэкенда Sentry, эта же строка дублируется в Sentry.

### Как определяется IP клиента

Ограничитель и строка лога определяют IP вызывающего в таком порядке:

1. `CF-Connecting-IP`
2. первую запись `X-Forwarded-For`
3. `CF-Connecting-IPv6`
4. сетевой адрес, который видит Express

Приложение работает с `trust proxy` установлен в `1`, то есть доверяет ровно одному прокси-хопу заголовков.

{% hint style="warning" %}
Если ваш обратный прокси не задаёт `X-Forwarded-For`, каждый запрос выглядит так, будто он приходит от прокси — один IP, одна общая квота, и первый активный посетитель блокирует доступ всем. Проверьте пересылку заголовков перед включением лимитера.
{% endhint %}

## `SECURITY_DELAY_AFTER` — постепенное замедление

Более мягкий помощник, основанный на `express-slow-down`. Вместо отклонения он задерживает.

* **Окно**: 60 минут, скользящее.
* **Бесплатные запросы**: число, которое вы задаёте. Запросы сверх него обрабатываются медленно.
* **Задержка**: `400 мс × общее число запросов, сделанных в окне`.
* `0` или пустое значение означает, что middleware вообще не подключается.
* То же `/api/monitoring` исключение.

{% hint style="warning" %}
Задержка вычисляется по **общему** числу обращений, а не по превышению — поэтому она начинается высокой и быстро растёт. При `SECURITY_DELAY_AFTER="40"`, запрос 41 уже ждёт около 16 секунд; при `"100"`, запрос 101 ждёт около 40 секунд. Выбирайте значение, понимая, что первый замедленный запрос уже заставит долго ждать, и ожидайте таймауты на стороне клиента после этого.
{% endhint %}

Замедление и ограничение запросов складываются. Считайте `SECURITY_RATE_LIMIT` основной защитой и используйте замедление только когда хотите, чтобы скриптовые всплески не падали, а тормозили.

## `SECURITY_BLACKLIST_LOG_FILE_PATH` — журнал на диске

По желанию. Если задано, каждое срабатывание ограничения также добавляется в обычный текстовый файл.

{% code title=".env" %}

```bash
SECURITY_BLACKLIST_LOG_FILE_PATH="logs/blacklist-ip.log"
```

{% endcode %}

* Путь разрешается **относительно корня приложения**. Отсутствующие каталоги создаются.
* Одна CSV-строка на IP: `ip,count,first-seen-timestamp`.
* Временная метка — это локальное время хоста с явным смещением UTC, например `2026-07-14 10:23:45 +0800`.
* Для повторного нарушителя **счётчик увеличивается, а исходная временная метка остаётся**, так что видно, когда IP появился впервые.

```
203.0.113.45,7,2026-07-14 10:23:45 +0800
198.51.100.9,1,2026-07-15 02:11:07 +0800
```

Если оставить поле пустым, на применении ограничений это никак не скажется — предупреждение в логе всё равно будет появляться. Файл нужен для развертываний, которым нужен постоянный журнал, например чтобы кормить фаервол или скрипт в стиле fail2ban.

{% hint style="info" %}
В Docker записывайте журнал в смонтированный том. Путь внутри записываемого слоя контейнера исчезает при пересоздании контейнера.
{% endhint %}

## Порядок middleware

Стоит знать, когда вы отлаживаете `403` или a `429`:

1. логирование HTTP-запросов, если `LOG_HTTP=true` — поэтому 429 появляются в логах
2. Ограничитель запросов (если включён)
3. Замедление (если включено)
4. Разбор JSON-тела
5. Проверка Referer
6. Обработчик маршрута

Таким образом, ограничение запросов происходит **до** проверки Referer. Поток запросов с плохим Referer всё равно расходует квоту нарушителя — и это желаемое поведение.

Также учтите, что CDN перед приложением отдаёт кэшированные `/api/*` ответы, даже не доходя до origin, поэтому такие запросы невидимы для лимитера. Большинство маршрутов с большим числом чтений можно кэшировать на edge.

## Рекомендуемые значения подстраховки для публичного экземпляра

Даже при настроенном edge задайте их так, чтобы origin мог защищаться сам:

{% tabs %}
{% tab title="Node (.env)" %}
{% code title=".env" %}

```bash
ALLOWED_DOMAINS="example.com,www.example.com"
SECURITY_RATE_LIMIT="600"
SECURITY_BLACKLIST_LOG_FILE_PATH="logs/blacklist-ip.log"
```

{% endcode %}
{% endtab %}

{% tab title="Docker" %}

```bash
docker run -d -p 18966:18966 \
  -e ALLOWED_DOMAINS="example.com,www.example.com" \
  -e SECURITY_RATE_LIMIT="600" \
  -e SECURITY_BLACKLIST_LOG_FILE_PATH="logs/blacklist-ip.log" \
  -v "$(pwd)/logs:/app/logs" \
  --name myip \
  jason5ng32/myip:latest
```

{% endtab %}
{% endtabs %}

Эти числа — отправная точка, а не правило. Подберите их:

* Одна полная загрузка страницы запускает **много** `/api/*` вызовов — источники IP, проверки соединения, DNS-запросы. Один посетитель легко расходует десятки запросов за сеанс.
* Если установить лимит слишком низко, обычные пользователи столкнутся `429` с блокировкой посреди диагностики.
* Следите за журналом и за `IP ограничен по запросам` предупреждениями в течение недели, затем ужесточайте.
* За CGNAT или корпоративным NAT многие реальные пользователи делят один IP. Оставьте запас.

{% hint style="success" %}
Суть слоистой защиты в одном предложении: пусть edge поглощает и фильтрует поток, а эти переменные задайте с большим запасом, чтобы они срабатывали только на трафик, который проскользнул мимо него.
{% endhint %}

## Связанные страницы

* [Переменные окружения](/developer/ru/reference/environment-variables.md) — полный список
* [Обратный прокси и домены](/developer/ru/getting-started/reverse-proxy-and-domains.md) — заголовки, которые ваш прокси должен пересылать
* [Логирование](/developer/ru/configuration/logging.md) — где появляются предупреждения
* [Необязательные API-ключи](/developer/ru/configuration/optional-api-keys.md) — квоты, которые вы защищаете


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ipcheck.ing/developer/ru/configuration/security-options.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
