Ограничение доступа по IP в Nginx

Пошаговая настройка доступа к сайту или отдельному location в Nginx только с разрешённых IP-адресов и подсетей.

Nginx позволяет разрешать или запрещать доступ к сайту, административному разделу или отдельному URL по IP-адресу клиента.

Такой способ подходит для:

  • административных панелей;
  • внутренних API;
  • служебных страниц;
  • тестовых сайтов;
  • webhook endpoint;
  • страниц мониторинга;
  • временно закрытых разделов.

В этой инструкции рассматривается только ограничение доступа по IPv4 и IPv6 с помощью директив allow и deny.

Проверено на: Ubuntu Server 24.04 LTS
Уровень сложности: начальный
Время выполнения: около 10–15 минут
Требуемый доступ: пользователь с правами sudo

Что будет настроено

После выполнения инструкции можно будет:

  • разрешить доступ одному IP;
  • разрешить доступ подсети;
  • закрыть сайт для остальных клиентов;
  • ограничить только отдельный location;
  • проверить порядок правил;
  • учитывать reverse proxy и X-Forwarded-For;
  • диагностировать ошибку 403 Forbidden;
  • безопасно отменить ограничение.

Важное предупреждение

Ошибка в IP-правилах может заблокировать доступ администратора.

Перед применением:

  • оставьте открытую SSH-сессию;
  • запишите свой внешний IP;
  • проверьте, используется ли VPN;
  • учтите динамический IP;
  • проверьте наличие reverse proxy;
  • создайте резервную копию конфигурации.

Определение текущего IP

С административного компьютера узнайте публичный IP.

В Linux:

curl -4 ifconfig.me

Для IPv6:

curl -6 ifconfig.me

Если команда выполняется через VPN, будет показан адрес VPN.

Проверка адреса в журнале Nginx

Создайте запрос к сайту:

curl -I https://example.com

На сервере:

sudo tail -20 /var/log/nginx/access.log

Если для сайта используется отдельный журнал:

sudo tail -20   /var/log/nginx/example.com.access.log

Первое поле обычно содержит IP клиента.

Базовый принцип allow и deny

Пример:

allow 192.0.2.10;
deny all;

Nginx проверяет правила сверху вниз.

Если IP совпал с allow, доступ разрешён.

Остальные клиенты попадут под:

deny all;

и получат:

403 Forbidden

Разрешение одного IPv4-адреса

Откройте конфигурацию сайта:

sudo nano   /etc/nginx/sites-available/example.com

Внутри server добавьте:

server {
    listen 80;
    listen [::]:80;

    server_name example.com;

    allow 192.0.2.10;
    deny all;

    root /var/www/example.com/html;
    index index.html;
}

Замените:

192.0.2.10

на разрешённый IP.

Разрешение нескольких IP

allow 192.0.2.10;
allow 198.51.100.25;
allow 203.0.113.15;
deny all;

Порядок важен: deny all должен находиться после разрешающих правил.

Разрешение подсети

Для подсети /24:

allow 192.0.2.0/24;
deny all;

Это разрешает диапазон:

192.0.2.0–192.0.2.255

Для одной рабочей станции лучше указывать конкретный адрес /32.

Разрешение localhost

Для локальных запросов:

allow 127.0.0.1;
allow ::1;
deny all;

Это удобно для:

  • локального мониторинга;
  • healthcheck;
  • внутренних скриптов;
  • тестов с самого сервера.

Разрешение IPv6

Пример одного IPv6-адреса:

allow 2001:db8::10;
deny all;

Пример подсети:

allow 2001:db8:100::/64;
deny all;

Если сайт слушает IPv6, не ограничивайтесь только IPv4-правилами.

Ограничение всего виртуального хоста

Правила внутри server применяются ко всему сайту:

server {
    server_name admin.example.com;

    allow 192.0.2.10;
    allow 2001:db8::10;
    deny all;

    location / {
        proxy_pass http://127.0.0.1:3000;
    }
}

Ограничение только отдельного location

Пример для /admin/:

server {
    server_name example.com;

    root /var/www/example.com/html;

    location / {
        try_files $uri $uri/ =404;
    }

    location /admin/ {
        allow 192.0.2.10;
        allow 198.51.100.0/24;
        deny all;

        try_files $uri $uri/ =404;
    }
}

Остальная часть сайта останется публичной.

Ограничение административного API

location /api/admin/ {
    allow 192.0.2.10;
    deny all;

    proxy_pass http://127.0.0.1:3000;
}

Ограничение служебной страницы

location = /status {
    allow 127.0.0.1;
    allow 192.0.2.10;
    deny all;

    stub_status;
}

Знак:

=

означает точное совпадение URI.

Создание резервной копии

Перед изменением:

sudo cp   /etc/nginx/sites-available/example.com   /etc/nginx/sites-available/example.com.before-ip-restriction

Проверьте:

ls -l   /etc/nginx/sites-available/example.com*

Проверка конфигурации

sudo nginx -t

Ожидаемый результат:

syntax is ok
test is successful

Применение

sudo systemctl reload nginx

Проверьте:

systemctl status nginx --no-pager

Проверка с разрешённого IP

curl -I https://example.com/admin/

Ожидается обычный ответ приложения или сайта.

Проверка с запрещённого IP

С другой сети:

curl -I https://example.com/admin/

Ожидается:

HTTP/1.1 403 Forbidden

или:

HTTP/2 403

Проверка через локальный запрос

Если разрешён 127.0.0.1:

curl -I   -H 'Host: example.com'   http://127.0.0.1/admin/

Проверка через временное изменение IP невозможна

Заголовок:

X-Forwarded-For

не меняет реальный IP для обычного Nginx.

Команда:

curl   -H 'X-Forwarded-For: 192.0.2.10'   https://example.com

не должна использоваться как надёжная проверка, если Nginx не настроен доверять reverse proxy.

Порядок правил

Неправильный вариант:

deny all;
allow 192.0.2.10;

Первое совпавшее правило завершает проверку.

Правильный вариант:

allow 192.0.2.10;
deny all;

deny для отдельных адресов

Можно закрыть только конкретный IP:

deny 198.51.100.25;
allow all;

Но для административных страниц безопаснее whitelist-модель:

allow TRUSTED_IP;
deny all;

Использование include-файла

Если одинаковый список разрешённых IP используется в нескольких сайтах, вынесите его в отдельный файл.

Создайте:

sudo nano /etc/nginx/snippets/allowed-admin-ips.conf

Добавьте:

allow 192.0.2.10;
allow 198.51.100.0/24;
allow 2001:db8:100::/64;
deny all;

Подключите:

location /admin/ {
    include /etc/nginx/snippets/allowed-admin-ips.conf;

    proxy_pass http://127.0.0.1:3000;
}

Проверка include-файла

sudo nginx -t

Покажите итоговую конфигурацию:

sudo nginx -T |
grep -nE 'allowed-admin-ips|allow |deny '

Комментарии в правилах

# Рабочая станция администратора
allow 192.0.2.10;

# Корпоративная VPN-подсеть
allow 198.51.100.0/24;

deny all;

Комментарии упрощают сопровождение.

Не публикуйте внутренние IP и назначение адресов в открытых репозиториях без необходимости.

Динамический IP администратора

Если IP часто меняется, whitelist по одному адресу неудобен.

Подходящие варианты:

  • VPN со статической подсетью;
  • WireGuard;
  • корпоративный reverse proxy;
  • bastion host;
  • Zero Trust access;
  • Basic Auth как дополнительная защита.

Не разрешайте весь интернет только из-за динамического IP.

Ограничение по VPN-подсети

Пример:

allow 10.10.0.0/24;
deny all;

Пользователь сначала подключается к VPN, затем получает доступ к закрытому сайту.

Это более предсказуемо, чем whitelist домашнего динамического IP.

Nginx за внешним reverse proxy

Если перед Nginx находится:

  • CDN;
  • балансировщик;
  • WAF;
  • другой reverse proxy;

Nginx может видеть IP прокси вместо IP клиента.

В журнале будут адреса proxy-сервера.

В таком случае простые allow и deny будут проверять IP ближайшего proxy.

Real IP module

Для восстановления исходного IP клиента используются директивы:

set_real_ip_from PROXY_SUBNET;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Пример:

set_real_ip_from 192.0.2.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

После этого allow и deny будут работать с восстановленным адресом клиента.

Важность доверенного proxy

Нельзя использовать:

set_real_ip_from 0.0.0.0/0;

иначе любой клиент сможет подставить произвольный X-Forwarded-For.

Указывайте только реальные адреса доверенного reverse proxy.

Проверка real IP

Проверьте формат access log.

Пример:

log_format realip '$remote_addr - $http_x_forwarded_for - $request';

Создайте запрос через proxy и проверьте журнал.

Настройка логирования real IP является отдельной задачей, но важна для проверки whitelist.

Cloudflare и другие CDN

При использовании CDN нужно:

  • получить актуальные IP-сети провайдера;
  • настроить set_real_ip_from;
  • указать правильный real IP header;
  • регулярно обновлять список сетей.

Не копируйте устаревшие диапазоны из случайных источников.

Несколько уровней прокси

При цепочке:

Клиент → CDN → Load Balancer → Nginx

нужно доверять только известным узлам цепочки.

Используйте:

real_ip_recursive on;

только после корректного списка доверенных proxy.

Совмещение IP restriction и Basic Auth

Можно потребовать одновременно:

  • разрешённый IP;
  • корректный логин и пароль.

Пример логики:

location /admin/ {
    allow 192.0.2.10;
    deny all;

    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;

    proxy_pass http://127.0.0.1:3000;
}

Basic Auth рассматривается отдельно.

Директива satisfy

Nginx поддерживает:

satisfy all;

или:

satisfy any;

satisfy all

Требует выполнить все механизмы доступа.

satisfy any

Достаточно пройти хотя бы один.

Для строгой защиты административной панели обычно используют:

satisfy all;

Не добавляйте satisfy any без понимания, иначе пароль может открыть доступ с любого IP.

Журнал отказов

Проверьте error log:

sudo tail -50   /var/log/nginx/example.com.error.log

При блокировке может появиться сообщение:

access forbidden by rule

Поиск блокировок

sudo grep -i   'access forbidden by rule'   /var/log/nginx/example.com.error.log |
tail -20

Отдельный access log для закрытого location

Можно создать отдельный location и лог:

location /admin/ {
    access_log /var/log/nginx/admin-access.log;

    allow 192.0.2.10;
    deny all;

    proxy_pass http://127.0.0.1:3000;
}

Проверка:

sudo tail -f   /var/log/nginx/admin-access.log

Ошибка 403 после включения whitelist

Проверьте:

  • фактический IP клиента;
  • VPN;
  • IPv4 или IPv6;
  • порядок allow и deny;
  • real IP module;
  • CDN;
  • наличие правил в более широком server;
  • итоговую конфигурацию.

Команды:

sudo nginx -T |
grep -nE 'allow |deny |set_real_ip_from|real_ip_header'

IPv6 обходит IPv4-ограничение

Если клиент подключается по IPv6, правило только для IPv4 не сработает как ожидается.

Проверьте:

curl -4 -I https://example.com
curl -6 -I https://example.com

Добавьте соответствующие IPv6-правила либо отключите AAAA-запись только после анализа.

Проверка, какой IP видит Nginx

sudo tail -20   /var/log/nginx/example.com.access.log

Создайте новый запрос и сопоставьте время.

Это основной способ подтвердить фактический адрес.

Изменение разрешённого IP

Откройте include-файл или server block.

Замените:

allow OLD_IP;

на:

allow NEW_IP;

Проверьте:

sudo nginx -t

Примените:

sudo systemctl reload nginx

Не удаляйте старый IP до проверки доступа с нового адреса.

Временное разрешение второго IP

Безопасный порядок:

allow OLD_IP;
allow NEW_IP;
deny all;

Проверьте доступ с нового адреса.

После этого удалите старое правило.

Отключение ограничения

Удалите или закомментируйте:

allow ...;
deny all;

Проверьте:

sudo nginx -t

Примените:

sudo systemctl reload nginx

Восстановление резервной копии

sudo cp   /etc/nginx/sites-available/example.com.before-ip-restriction   /etc/nginx/sites-available/example.com

Проверьте и примените:

sudo nginx -t &&
sudo systemctl reload nginx

Типичные ошибки

deny all расположен первым

Исправьте порядок:

allow TRUSTED_IP;
deny all;

Разрешён внутренний IP вместо публичного

Если пользователь подключается через интернет, Nginx видит публичный IP или IP reverse proxy.

Проверьте access log.

Разрешён IP домашнего роутера, но включён VPN

При VPN внешний IP меняется.

Добавьте VPN-адрес или используйте VPN-подсеть.

Nginx видит только IP CDN

Настройте Real IP module и доверенные сети CDN.

После reload доступ пропал у всех

Используйте открытую SSH-сессию.

Восстановите резервную копию и выполните:

sudo nginx -t &&
sudo systemctl reload nginx

Безопасный порядок настройки

  1. Определить фактический IP по access log.
  2. Проверить IPv4 и IPv6.
  3. Создать резервную копию.
  4. Добавить allow.
  5. Добавить deny all.
  6. Выполнить nginx -t.
  7. Выполнить reload.
  8. Проверить доступ с разрешённого IP.
  9. Проверить блокировку с другой сети.
  10. Проверить журналы.
  11. Только после этого закрыть резервную сессию.

Быстрый набор команд

Проверить IP клиента:

sudo tail -20   /var/log/nginx/example.com.access.log

Правила:

allow 192.0.2.10;
deny all;

Проверка:

sudo nginx -t

Применение:

sudo systemctl reload nginx

Поиск отказов:

sudo grep -i   'access forbidden by rule'   /var/log/nginx/example.com.error.log |
tail

Итог

После выполнения инструкции:

  • определён фактический IP клиента;
  • настроен whitelist одного адреса или подсети;
  • закрыт весь сайт или отдельный location;
  • учтены IPv4 и IPv6;
  • рассмотрена работа за reverse proxy;
  • проверены разрешённые и запрещённые запросы;
  • показано безопасное изменение правил.

Для административных интерфейсов надёжнее сочетать IP whitelist с VPN и отдельной аутентификацией.

← Предыдущая статья Настройка reverse proxy в Nginx Следующая статья → Настройка заголовков безопасности в Nginx