Hairpin NAT на MikroTik — доступ к серверам изнутри
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-address | 192.168.88.50 |
| dst-address | 203.0.113.1 |
| dst-port | 80 |
Шаг 2: MikroTik выполняет dst-nat: заменяет dst-address на 192.168.88.10.
| Поле | Значение |
|---|---|
| src-address | 192.168.88.50 (не изменён!) |
| dst-address | 192.168.88.10 (после dst-nat) |
| dst-port | 80 |
Шаг 3: Сервер 192.168.88.10 получает пакет. Src-address — 192.168.88.50, это локальная сеть. Сервер отправляет ответ напрямую клиенту, минуя роутер.
| Поле | Значение |
|---|---|
| src-address | 192.168.88.10 |
| dst-address | 192.168.88.50 |
| src-port | 80 |
Шаг 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 NAT | Split 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.
Решение:
- Используйте Split DNS для снижения нагрузки — трафик пойдёт напрямую.
- Оптимизируйте правила — избегайте 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"
Сценарий: 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"