mikrotik-wiki.ru
Главная
Загрузка...

Hairpin NAT на MikroTik — доступ к серверам изнутри

RouterOS 7.xIP11 мин330 мар. 2026 г.
TelegramVK

Hairpin NAT на MikroTik — доступ к серверам по внешнему IP изнутри сети

Hairpin NAT (NAT Loopback, NAT Reflection) — техника, позволяющая внутренним клиентам обращаться к локальному серверу по внешнему (публичному) IP-адресу или доменному имени. Без Hairpin NAT типичная ситуация выглядит так: проброс порта настроен, сервер доступен из интернета, но из локальной сети по внешнему IP — не работает. Это одна из самых частых проблем при настройке MikroTik, с которой сталкивается практически каждый администратор. В этом руководстве разберём причину проблемы, настроим Hairpin NAT, рассмотрим альтернативу через Split DNS и сравним оба подхода.

Описание

Проблема: проброс портов работает снаружи, но не изнутри

Типичный сценарий: администратор настроил проброс портов (dst-nat) для веб-сервера во внутренней сети. Из интернета всё работает, но когда сотрудник в офисе вводит в браузере публичный IP или доменное имя — страница не открывается.

code
Сценарий: dst-nat настроен (порт 80 → 192.168.88.10:80)

Из интернета (работает):
  [Клиент 5.5.5.5] → [MikroTik WAN 203.0.113.1:80] → dst-nat → [Сервер 192.168.88.10:80]
  Ответ: [Сервер] → [MikroTik] → NAT → [Клиент 5.5.5.5] ✓

Из LAN (НЕ работает):
  [Клиент 192.168.88.50] → [MikroTik 203.0.113.1:80] → dst-nat → [Сервер 192.168.88.10:80]
  Ответ: [Сервер 192.168.88.10] → [Клиент 192.168.88.50] напрямую (минуя MikroTik) ✗

Почему не работает — подробный анализ

Разберём пакет по шагам.

Шаг 1: Клиент 192.168.88.50 отправляет TCP SYN на 203.0.113.1:80.

ПолеЗначение
src-address192.168.88.50
dst-address203.0.113.1
dst-port80

Шаг 2: MikroTik выполняет dst-nat: заменяет dst-address на 192.168.88.10.

ПолеЗначение
src-address192.168.88.50 (не изменён!)
dst-address192.168.88.10 (после dst-nat)
dst-port80

Шаг 3: Сервер 192.168.88.10 получает пакет. Src-address — 192.168.88.50, это локальная сеть. Сервер отправляет ответ напрямую клиенту, минуя роутер.

ПолеЗначение
src-address192.168.88.10
dst-address192.168.88.50
src-port80

Шаг 4: Клиент получает пакет от 192.168.88.10:80, но ожидал ответ от 203.0.113.1:80. TCP-стек клиента отбрасывает пакет — src-address не совпадает.

Это называется asymmetric routing: запрос идёт через роутер, а ответ — напрямую. TCP-соединение не устанавливается.

Решение: Hairpin NAT

Hairpin NAT добавляет src-nat для внутренних запросов: заменяет src-address клиента на IP роутера. Теперь сервер видит запрос от роутера и отправляет ответ обратно через роутер. Роутер выполняет обратный NAT — и клиент получает ответ от ожидаемого IP.

code
С Hairpin NAT:
  [Клиент 192.168.88.50] → [MikroTik]
    dst-nat: dst 203.0.113.1 → 192.168.88.10
    src-nat: src 192.168.88.50 → 192.168.88.1 (IP роутера)
  → [Сервер 192.168.88.10:80]

  Ответ:
  [Сервер 192.168.88.10] → [MikroTik 192.168.88.1]
    reverse src-nat: dst 192.168.88.1 → 192.168.88.50
    reverse dst-nat: src 192.168.88.10 → 203.0.113.1
  → [Клиент 192.168.88.50] ✓

Hairpin NAT vs Split DNS

КритерийHairpin NATSplit DNS
ПринципДополнительное NAT-правилоDNS возвращает локальный IP для внутренних клиентов
СложностьОдно правило NATСтатическая DNS-запись на роутере
Нагрузка на роутерКаждый пакет проходит через NAT (CPU)Только DNS-запрос, далее трафик напрямую
Работает по IPДаНет (только по доменному имени)
Несколько серверовОтдельное правило для каждогоОтдельная DNS-запись для каждого
Видимость src-IPСервер видит IP роутера (теряется реальный src)Сервер видит реальный IP клиента
ПроизводительностьНиже (двойной NAT)Выше (прямое соединение)

Рекомендация: если клиенты обращаются к серверу по доменному имени — используйте Split DNS. Если нужен доступ по IP-адресу — Hairpin NAT.

Настройка

Исходная конфигурация

Допустим, у нас уже настроен проброс порта.

[admin@MikroTik] >
# Проверяем существующие dst-nat правила
/ip/firewall/nat print where chain=dstnat

# Типичный проброс порта 80 → веб-сервер
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10 to-ports=80 \
    comment="Port forward: HTTP → web server"

# Типичный src-nat для выхода в интернет
/ip/firewall/nat add chain=srcnat \
    out-interface=ether1-wan \
    action=masquerade \
    comment="Default masquerade"

Способ 1: Hairpin NAT через masquerade (простой)

Самый простой способ — добавить masquerade-правило для внутренних запросов.

[admin@MikroTik] >
# Hairpin NAT — masquerade для трафика из LAN в LAN через dst-nat
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 \
    protocol=tcp dst-port=80 \
    action=masquerade \
    comment="Hairpin NAT: HTTP to web server"

Это правило говорит: «Если пакет пришёл из LAN (192.168.88.0/24) и после dst-nat направляется на сервер 192.168.88.10:80, замени src-address на IP исходящего интерфейса (masquerade)».

Важно: правило Hairpin NAT должно стоять перед общим masquerade-правилом.

[admin@MikroTik] >
# Проверяем порядок правил
/ip/firewall/nat print

# Если Hairpin NAT не первое — перемещаем
/ip/firewall/nat move [find where comment="Hairpin NAT: HTTP to web server"] destination=0

Способ 2: Hairpin NAT через src-nat (рекомендуемый)

Более явный и предсказуемый способ — использовать src-nat с конкретным to-addresses.

[admin@MikroTik] >
# Hairpin NAT — src-nat с конкретным адресом
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 \
    protocol=tcp dst-port=80 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin NAT: HTTP to web server"

Разница: masquerade использует IP исходящего интерфейса (может меняться), а src-nat фиксирует адрес 192.168.88.1. Для внутренних правил src-nat надёжнее.

Способ 3: Универсальное правило для всех dst-nat

Если у вас много проброшенных портов, можно создать одно универсальное Hairpin NAT-правило.

[admin@MikroTik] >
# Универсальный Hairpin NAT для всей подсети
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.0/24 \
    action=masquerade \
    comment="Hairpin NAT: universal for all port forwards"

Это правило говорит: «Любой трафик из LAN в LAN — masquerade». Оно покрывает все dst-nat правила одним правилом.

Плюсы: одно правило на все порт-форварды. Минусы: masquerade для всего LAN↔LAN трафика, потенциально маскирует src-IP там, где это не нужно. Используйте с осторожностью.

Способ 4: Split DNS (альтернатива Hairpin NAT)

Если клиенты обращаются к серверу по доменному имени (например, myserver.example.com), можно использовать Split DNS — DNS-сервер MikroTik вернёт локальный IP вместо внешнего.

[admin@MikroTik] >
# Включаем DNS-сервер на MikroTik (если не включён)
/ip/dns set allow-remote-requests=yes

# Статическая DNS-запись: домен → локальный IP
/ip/dns/static add name=myserver.example.com address=192.168.88.10 \
    comment="Split DNS: internal access to web server"

# Если несколько доменов
/ip/dns/static add name=mail.example.com address=192.168.88.11 \
    comment="Split DNS: internal access to mail server"
/ip/dns/static add name=vpn.example.com address=192.168.88.12 \
    comment="Split DNS: internal access to VPN server"

Важно: клиенты должны использовать MikroTik как DNS-сервер (DHCP должен выдавать IP роутера как DNS).

[admin@MikroTik] >
# Проверяем DHCP-настройки
/ip/dhcp-server/network print

# DNS должен указывать на роутер
/ip/dhcp-server/network set [find where address=192.168.88.0/24] dns-server=192.168.88.1

Настройка Hairpin NAT для нескольких серверов

Типичный сценарий: проброшено несколько сервисов на разные серверы.

[admin@MikroTik] >
# === dst-nat правила (проброс портов) ===
# Веб-сервер
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=tcp dst-port=80,443 \
    action=dst-nat to-addresses=192.168.88.10 \
    comment="DNAT: HTTP/HTTPS → web server"

# Почтовый сервер
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=tcp dst-port=25,465,587,993 \
    action=dst-nat to-addresses=192.168.88.11 \
    comment="DNAT: Mail → mail server"

# Игровой сервер
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=tcp dst-port=27015 \
    action=dst-nat to-addresses=192.168.88.12 \
    comment="DNAT: Game → game server"

/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=udp dst-port=27015 \
    action=dst-nat to-addresses=192.168.88.12 \
    comment="DNAT: Game UDP → game server"

# === Hairpin NAT для каждого сервера ===
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 \
    protocol=tcp dst-port=80,443 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin: web server"

/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.11 \
    protocol=tcp dst-port=25,465,587,993 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin: mail server"

/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.12 \
    protocol=tcp dst-port=27015 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin: game server TCP"

/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.12 \
    protocol=udp dst-port=27015 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin: game server UDP"

# === Общий masquerade для интернета (в конце!) ===
/ip/firewall/nat add chain=srcnat \
    out-interface=ether1-wan \
    action=masquerade \
    comment="Default masquerade"

Настройка при динамическом WAN IP (PPPoE, DHCP)

Если внешний IP динамический, dst-nat настраивается без указания dst-address (или с привязкой к интерфейсу).

[admin@MikroTik] >
# dst-nat без dst-address — привязка к WAN-интерфейсу
/ip/firewall/nat add chain=dstnat \
    in-interface=ether1-wan protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10 to-ports=80 \
    comment="DNAT: HTTP → web server (dynamic WAN)"

# Hairpin NAT — не зависит от WAN IP, работает одинаково
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 \
    protocol=tcp dst-port=80 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin NAT: HTTP"

Проверка

Проверка NAT-правил

[admin@MikroTik] >
# Вывод всех NAT-правил с счётчиками
/ip/firewall/nat print stats

# Проверяем порядок — Hairpin src-nat должен быть ПЕРЕД общим masquerade
/ip/firewall/nat print chain=srcnat

# Ожидаемый порядок:
#  0  srcnat  src=192.168.88.0/24 dst=192.168.88.10 tcp:80  src-nat 192.168.88.1  (Hairpin)
#  1  srcnat  out-interface=ether1-wan  masquerade  (Default)

Тестирование из LAN

[admin@MikroTik] >
# С клиентского ПК в LAN (192.168.88.50):
# Открываем браузер → http://203.0.113.1 → должен открыться сайт

# Проверка через torch на роутере
/tool/torch interface=bridge-lan src-address=192.168.88.50 \
    dst-address=192.168.88.10 protocol=tcp port=80 duration=10

# Проверка через connection tracking
/ip/firewall/connection print where dst-address~"192.168.88.10" and dst-port=80

Проверка счётчиков правил

[admin@MikroTik] >
# Если Hairpin NAT работает, счётчик правила увеличивается
/ip/firewall/nat print stats where comment~"Hairpin"

# Ожидаемый вывод:
#  0  chain=srcnat ... packets=142 bytes=8520  (числа растут при обращении)

Проверка Split DNS

[admin@MikroTik] >
# Проверяем статические DNS-записи
/ip/dns/static print

# Тестируем резолвинг с роутера
:resolve myserver.example.com
# Должен вернуть 192.168.88.10 (локальный IP)

# Проверяем DNS cache
/ip/dns/cache print where name~"myserver"

Диагностика через packet sniffer

[admin@MikroTik] >
# Захват пакетов между клиентом и сервером
/tool/sniffer set filter-address=192.168.88.50 filter-protocol=tcp filter-port=80 \
    streaming-enabled=no

/tool/sniffer start
# Делаем запрос из браузера клиента
/tool/sniffer stop

/tool/sniffer/packet print detail
# Проверяем: src-address в пакетах к серверу должен быть 192.168.88.1 (после Hairpin NAT)

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

Ошибка 1: Hairpin NAT не работает — забыт src-address в правиле

Проблема: правило srcnat создано без указания src-address, и оно применяется к трафику из интернета, вызывая проблемы.

[admin@MikroTik] >
# НЕПРАВИЛЬНО — нет src-address
/ip/firewall/nat add chain=srcnat \
    dst-address=192.168.88.10 protocol=tcp dst-port=80 \
    action=masquerade

# ПРАВИЛЬНО — указан src-address=LAN
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 protocol=tcp dst-port=80 \
    action=masquerade \
    comment="Hairpin NAT: HTTP"

Без src-address правило будет masquerade-ить трафик из интернета, и сервер потеряет реальный src-IP внешних клиентов.

Ошибка 2: Неправильный порядок NAT-правил

Проблема: Hairpin NAT-правило стоит после общего masquerade. NAT chain обрабатывается сверху вниз, и общее правило срабатывает первым.

Решение:

[admin@MikroTik] >
# Проверяем порядок
/ip/firewall/nat print chain=srcnat

# Перемещаем Hairpin перед masquerade
/ip/firewall/nat move [find where comment~"Hairpin"] destination=0

# Правильный порядок:
# 1. Hairpin NAT (конкретные правила)
# 2. Default masquerade (общее правило — последнее)

Ошибка 3: dst-nat правило привязано к in-interface, а Hairpin-запрос приходит с другого интерфейса

Проблема: dst-nat указан с in-interface=ether1-wan. Запрос из LAN приходит через bridge-lan, и dst-nat не срабатывает.

[admin@MikroTik] >
# НЕПРАВИЛЬНО для Hairpin — привязка к WAN-интерфейсу
/ip/firewall/nat add chain=dstnat \
    in-interface=ether1-wan \
    protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10

# ПРАВИЛЬНО — используем dst-address вместо in-interface
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 \
    protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10 \
    comment="DNAT: HTTP (works for Hairpin too)"

Если нужно сохранить привязку к интерфейсу для безопасности, создайте два правила.

[admin@MikroTik] >
# Правило для трафика из интернета
/ip/firewall/nat add chain=dstnat \
    in-interface=ether1-wan \
    protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10 \
    comment="DNAT: HTTP from WAN"

# Правило для трафика из LAN (Hairpin)
/ip/firewall/nat add chain=dstnat \
    src-address=192.168.88.0/24 \
    dst-address=203.0.113.1 \
    protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10 \
    comment="DNAT: HTTP from LAN (Hairpin)"

Ошибка 4: Сервер теряет реальный IP клиента

Проблема: после настройки Hairpin NAT сервер видит все внутренние запросы от 192.168.88.1 (IP роутера), а не от реальных клиентов. Это проблема для логирования и ACL.

Решение: это неизбежное следствие Hairpin NAT. Если нужен реальный src-IP — используйте Split DNS.

[admin@MikroTik] >
# Split DNS — клиенты обращаются к серверу напрямую по локальному IP
/ip/dns/static add name=myserver.example.com address=192.168.88.10
# Сервер видит реальный src-IP клиента

Если нужен и Hairpin NAT, и реальный IP — для HTTP-серверов можно использовать заголовок X-Forwarded-For, но MikroTik его не добавляет (это задача reverse proxy: nginx, HAProxy).

Ошибка 5: Hairpin NAT для HTTPS не работает с сертификатом

Проблема: при обращении по HTTPS через Hairpin NAT браузер показывает ошибку сертификата.

Причина: сертификат выдан на доменное имя (myserver.example.com), а клиент обращается по IP-адресу (203.0.113.1). Сертификат не совпадает.

Решение: используйте Split DNS, чтобы клиент обращался по доменному имени.

[admin@MikroTik] >
# Split DNS — браузер использует доменное имя, сертификат совпадает
/ip/dns/static add name=myserver.example.com address=192.168.88.10

# Если нужен wildcard
/ip/dns/static add name=*.example.com address=192.168.88.10

Ошибка 6: Hairpin NAT увеличивает нагрузку на CPU

Проблема: при большом количестве внутренних обращений к серверу через Hairpin NAT нагрузка на CPU роутера растёт, так как каждый пакет проходит двойной NAT (dst-nat + src-nat) и не попадает в FastTrack.

Решение:

  1. Используйте Split DNS для снижения нагрузки — трафик пойдёт напрямую.
  2. Оптимизируйте правила — избегайте masquerade, используйте src-nat с конкретным адресом.
[admin@MikroTik] >
# masquerade медленнее (lookup на каждый пакет)
# src-nat быстрее (фиксированный адрес)
/ip/firewall/nat set [find where comment~"Hairpin" and action=masquerade] \
    action=src-nat to-addresses=192.168.88.1

Итоговая конфигурация

[admin@MikroTik] >
# === Hairpin NAT — полная настройка ===

# dst-nat (проброс портов)
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=tcp dst-port=80,443 \
    action=dst-nat to-addresses=192.168.88.10 \
    comment="DNAT: HTTP/HTTPS → web server"

# Hairpin NAT (src-nat для внутренних запросов)
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 \
    protocol=tcp dst-port=80,443 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin NAT: web server"

# Split DNS (дополнительно, для обращения по имени)
/ip/dns set allow-remote-requests=yes
/ip/dns/static add name=myserver.example.com address=192.168.88.10 \
    comment="Split DNS: internal access"

# Общий masquerade (в конце!)
/ip/firewall/nat add chain=srcnat \
    out-interface=ether1-wan \
    action=masquerade \
    comment="Default masquerade"
[admin@MikroTik] >
Сценарий: dst-nat настроен (порт 80 → 192.168.88.10:80)

Из интернета (работает):
  [Клиент 5.5.5.5] → [MikroTik WAN 203.0.113.1:80] → dst-nat → [Сервер 192.168.88.10:80]
  Ответ: [Сервер] → [MikroTik] → NAT → [Клиент 5.5.5.5] ✓

Из LAN (НЕ работает):
  [Клиент 192.168.88.50] → [MikroTik 203.0.113.1:80] → dst-nat → [Сервер 192.168.88.10:80]
  Ответ: [Сервер 192.168.88.10] → [Клиент 192.168.88.50] напрямую (минуя MikroTik) ✗
С Hairpin NAT:
  [Клиент 192.168.88.50] → [MikroTik]
    dst-nat: dst 203.0.113.1 → 192.168.88.10
    src-nat: src 192.168.88.50 → 192.168.88.1 (IP роутера)
  → [Сервер 192.168.88.10:80]

  Ответ:
  [Сервер 192.168.88.10] → [MikroTik 192.168.88.1]
    reverse src-nat: dst 192.168.88.1 → 192.168.88.50
    reverse dst-nat: src 192.168.88.10 → 203.0.113.1
  → [Клиент 192.168.88.50] ✓
# Проверяем существующие dst-nat правила
/ip/firewall/nat print where chain=dstnat

# Типичный проброс порта 80 → веб-сервер
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10 to-ports=80 \
    comment="Port forward: HTTP → web server"

# Типичный src-nat для выхода в интернет
/ip/firewall/nat add chain=srcnat \
    out-interface=ether1-wan \
    action=masquerade \
    comment="Default masquerade"
# Hairpin NAT — masquerade для трафика из LAN в LAN через dst-nat
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 \
    protocol=tcp dst-port=80 \
    action=masquerade \
    comment="Hairpin NAT: HTTP to web server"
# Проверяем порядок правил
/ip/firewall/nat print

# Если Hairpin NAT не первое — перемещаем
/ip/firewall/nat move [find where comment="Hairpin NAT: HTTP to web server"] destination=0
# Hairpin NAT — src-nat с конкретным адресом
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 \
    protocol=tcp dst-port=80 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin NAT: HTTP to web server"
# Универсальный Hairpin NAT для всей подсети
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.0/24 \
    action=masquerade \
    comment="Hairpin NAT: universal for all port forwards"
# Включаем DNS-сервер на MikroTik (если не включён)
/ip/dns set allow-remote-requests=yes

# Статическая DNS-запись: домен → локальный IP
/ip/dns/static add name=myserver.example.com address=192.168.88.10 \
    comment="Split DNS: internal access to web server"

# Если несколько доменов
/ip/dns/static add name=mail.example.com address=192.168.88.11 \
    comment="Split DNS: internal access to mail server"
/ip/dns/static add name=vpn.example.com address=192.168.88.12 \
    comment="Split DNS: internal access to VPN server"
# Проверяем DHCP-настройки
/ip/dhcp-server/network print

# DNS должен указывать на роутер
/ip/dhcp-server/network set [find where address=192.168.88.0/24] dns-server=192.168.88.1
# === dst-nat правила (проброс портов) ===
# Веб-сервер
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=tcp dst-port=80,443 \
    action=dst-nat to-addresses=192.168.88.10 \
    comment="DNAT: HTTP/HTTPS → web server"

# Почтовый сервер
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=tcp dst-port=25,465,587,993 \
    action=dst-nat to-addresses=192.168.88.11 \
    comment="DNAT: Mail → mail server"

# Игровой сервер
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=tcp dst-port=27015 \
    action=dst-nat to-addresses=192.168.88.12 \
    comment="DNAT: Game → game server"

/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=udp dst-port=27015 \
    action=dst-nat to-addresses=192.168.88.12 \
    comment="DNAT: Game UDP → game server"

# === Hairpin NAT для каждого сервера ===
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 \
    protocol=tcp dst-port=80,443 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin: web server"

/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.11 \
    protocol=tcp dst-port=25,465,587,993 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin: mail server"

/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.12 \
    protocol=tcp dst-port=27015 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin: game server TCP"

/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.12 \
    protocol=udp dst-port=27015 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin: game server UDP"

# === Общий masquerade для интернета (в конце!) ===
/ip/firewall/nat add chain=srcnat \
    out-interface=ether1-wan \
    action=masquerade \
    comment="Default masquerade"
# dst-nat без dst-address — привязка к WAN-интерфейсу
/ip/firewall/nat add chain=dstnat \
    in-interface=ether1-wan protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10 to-ports=80 \
    comment="DNAT: HTTP → web server (dynamic WAN)"

# Hairpin NAT — не зависит от WAN IP, работает одинаково
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 \
    protocol=tcp dst-port=80 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin NAT: HTTP"
# Вывод всех NAT-правил с счётчиками
/ip/firewall/nat print stats

# Проверяем порядок — Hairpin src-nat должен быть ПЕРЕД общим masquerade
/ip/firewall/nat print chain=srcnat

# Ожидаемый порядок:
#  0  srcnat  src=192.168.88.0/24 dst=192.168.88.10 tcp:80  src-nat 192.168.88.1  (Hairpin)
#  1  srcnat  out-interface=ether1-wan  masquerade  (Default)
# С клиентского ПК в LAN (192.168.88.50):
# Открываем браузер → http://203.0.113.1 → должен открыться сайт

# Проверка через torch на роутере
/tool/torch interface=bridge-lan src-address=192.168.88.50 \
    dst-address=192.168.88.10 protocol=tcp port=80 duration=10

# Проверка через connection tracking
/ip/firewall/connection print where dst-address~"192.168.88.10" and dst-port=80
# Если Hairpin NAT работает, счётчик правила увеличивается
/ip/firewall/nat print stats where comment~"Hairpin"

# Ожидаемый вывод:
#  0  chain=srcnat ... packets=142 bytes=8520  (числа растут при обращении)
# Проверяем статические DNS-записи
/ip/dns/static print

# Тестируем резолвинг с роутера
:resolve myserver.example.com
# Должен вернуть 192.168.88.10 (локальный IP)

# Проверяем DNS cache
/ip/dns/cache print where name~"myserver"
# Захват пакетов между клиентом и сервером
/tool/sniffer set filter-address=192.168.88.50 filter-protocol=tcp filter-port=80 \
    streaming-enabled=no

/tool/sniffer start
# Делаем запрос из браузера клиента
/tool/sniffer stop

/tool/sniffer/packet print detail
# Проверяем: src-address в пакетах к серверу должен быть 192.168.88.1 (после Hairpin NAT)
# НЕПРАВИЛЬНО — нет src-address
/ip/firewall/nat add chain=srcnat \
    dst-address=192.168.88.10 protocol=tcp dst-port=80 \
    action=masquerade

# ПРАВИЛЬНО — указан src-address=LAN
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 protocol=tcp dst-port=80 \
    action=masquerade \
    comment="Hairpin NAT: HTTP"
# Проверяем порядок
/ip/firewall/nat print chain=srcnat

# Перемещаем Hairpin перед masquerade
/ip/firewall/nat move [find where comment~"Hairpin"] destination=0

# Правильный порядок:
# 1. Hairpin NAT (конкретные правила)
# 2. Default masquerade (общее правило — последнее)
# НЕПРАВИЛЬНО для Hairpin — привязка к WAN-интерфейсу
/ip/firewall/nat add chain=dstnat \
    in-interface=ether1-wan \
    protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10

# ПРАВИЛЬНО — используем dst-address вместо in-interface
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 \
    protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10 \
    comment="DNAT: HTTP (works for Hairpin too)"
# Правило для трафика из интернета
/ip/firewall/nat add chain=dstnat \
    in-interface=ether1-wan \
    protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10 \
    comment="DNAT: HTTP from WAN"

# Правило для трафика из LAN (Hairpin)
/ip/firewall/nat add chain=dstnat \
    src-address=192.168.88.0/24 \
    dst-address=203.0.113.1 \
    protocol=tcp dst-port=80 \
    action=dst-nat to-addresses=192.168.88.10 \
    comment="DNAT: HTTP from LAN (Hairpin)"
# Split DNS — клиенты обращаются к серверу напрямую по локальному IP
/ip/dns/static add name=myserver.example.com address=192.168.88.10
# Сервер видит реальный src-IP клиента
# Split DNS — браузер использует доменное имя, сертификат совпадает
/ip/dns/static add name=myserver.example.com address=192.168.88.10

# Если нужен wildcard
/ip/dns/static add name=*.example.com address=192.168.88.10
# masquerade медленнее (lookup на каждый пакет)
# src-nat быстрее (фиксированный адрес)
/ip/firewall/nat set [find where comment~"Hairpin" and action=masquerade] \
    action=src-nat to-addresses=192.168.88.1
# === Hairpin NAT — полная настройка ===

# dst-nat (проброс портов)
/ip/firewall/nat add chain=dstnat \
    dst-address=203.0.113.1 protocol=tcp dst-port=80,443 \
    action=dst-nat to-addresses=192.168.88.10 \
    comment="DNAT: HTTP/HTTPS → web server"

# Hairpin NAT (src-nat для внутренних запросов)
/ip/firewall/nat add chain=srcnat \
    src-address=192.168.88.0/24 \
    dst-address=192.168.88.10 \
    protocol=tcp dst-port=80,443 \
    action=src-nat to-addresses=192.168.88.1 \
    comment="Hairpin NAT: web server"

# Split DNS (дополнительно, для обращения по имени)
/ip/dns set allow-remote-requests=yes
/ip/dns/static add name=myserver.example.com address=192.168.88.10 \
    comment="Split DNS: internal access"

# Общий masquerade (в конце!)
/ip/firewall/nat add chain=srcnat \
    out-interface=ether1-wan \
    action=masquerade \
    comment="Default masquerade"
IP / Hairpin NAT на MikroTik — доступ к серверам изнутри