Введение / Зачем это нужно
Port forwarding (перенаправление портов) позволяет сделать локальный сервис, работающий на внутреннем IP-адресе и порту, доступным из внешней сети через публичный IP и порт вашего Linux-сервера. Это незаменимо, когда вы хотите, например, предоставить доступ к веб-серверу на порту 8080, базе данных или SSH-демону, находящимся за NAT, без изменения конфигурации самих сервисов.
После выполнения этого гайда вы сможете настроить перенаправление входящего трафика с порта 80 на внутренний сервер 192.168.1.100:8080, или с порта 2222 на внутренний SSH-сервер 192.168.1.100:22 — в зависимости от ваших задач.
Требования / Подготовка
Перед началом убедитесь, что:
- У вас есть доступ к Linux-системе (Ubuntu, CentOS, Debian, Fedora и т.д.) с правами sudo или root.
- На системе установлен и работает iptables (для классических дистрибутивов) или firewalld (для CentOS/RHEL/Fedora). Проверить можно командами:
sudo systemctl status iptables # для iptables sudo systemctl status firewalld # для firewalld - Вы знаете внутренний IP-адрес и порт сервиса, который хотите пробросить. Узнать можно через:
илиip addr showhostname -I - У вас есть публичный IP-адрес (или доменное имя), на который будет приходить входящий трафик. Если сервер находится в локальной сети, это IP вашего роутера, и на нём должен быть настроен проброс портов (port forwarding на роутере) на ваш Linux-сервер.
Шаг 1: Включение IP-форвардинга в ядре
По умолчанию в большинстве дистрибутивов Linux IP-форвардинг отключен. Это значит, что ядро не будет перенаправлять пакеты между сетевыми интерфейсами. Включите его временно:
sudo sysctl -w net.ipv4.ip_forward=1
Чтобы включить навсегда (чтобы настройка сохранилась после перезагрузки), отредактируйте файл /etc/sysctl.conf или создайте новый в /etc/sysctl.d/:
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-ipforward.conf
sudo sysctl -p /etc/sysctl.d/99-ipforward.conf
⚠️ Важно: Если вы используете IPv6, также включите форвардинг для него, добавив
net.ipv6.conf.all.forwarding=1в тот же файл.
Шаг 2: Настройка port forwarding с iptables
Этот способ подходит для дистрибутивов, где по умолчанию используется iptables (например, Ubuntu до 20.04, Debian, CentOS 6/7 без firewalld).
Предположим, вы хотите пробросить входящие подключения на порт 80 (HTTP) к внутреннему серверу с IP 192.168.1.100 на порт 8080.
- Добавьте правило DNAT (изменение адреса назначения) в таблицу
natдля цепочкиPREROUTING. Это правило сработает для входящих пакетов, предназначенных для порта 80:sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:8080-t nat— указывает таблицу NAT.-A PREROUTING— добавляет правило в конец цепочки PREROUTING (обрабатывает пакеты до маршрутизации).-p tcp— протокол TCP (для UDP замените наudp).--dport 80— целевой порт на внешнем интерфейсе.-j DNAT— цель — изменить адрес назначения.--to-destination 192.168.1.100:8080— новый адрес и порт.
- Разрешите проброс пакетов в цепочке
FORWARD. Это нужно, чтобы ядро не блокировало пересылку пакетов к внутреннему серверу:sudo iptables -A FORWARD -p tcp -d 192.168.1.100 --dport 8080 -j ACCEPT
Если у внутреннего сервера есть необходимость выходить в интернет через этот же шлюз, добавьте правило MASQUERADE (маскировка) для исходящего трафика:sudo iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.100 --dport 8080 -j MASQUERADE
Но для простого входящего port forwarding это часто не требуется, если внутренний сервер имеет правильный маршрут обратно клиенту.
Шаг 3: Настройка port forwarding с firewalld
Для дистрибутивов с firewalld (CentOS 7+, RHEL 7+, Fedora) используйте более простой синтаксис с зонами.
- Определите активную зону (например,
public):sudo firewall-cmd --get-default-zone
Обычно этоpublic. - Добавьте правило port forwarding в эту зону. Для проброса порта 80 на
192.168.1.100:8080:sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toaddr=192.168.1.100:toport=8080--add-forward-port— добавляет правило проброса порта.port=80— внешний порт.proto=tcp— протокол (можноudp).toaddr=192.168.1.100— внутренний IP.toport=8080— внутренний порт.
- Сделайте правило постоянным (чтобы оно сохранилось после перезагрузки):
sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toaddr=192.168.1.100:toport=8080 --permanent💡 Совет: Если ваш внутренний сервер должен иметь доступ в интернет через этот же шлюз, включите маскарадинг:
sudo firewall-cmd --zone=public --add-masquerade --permanent
Шаг 4: Сохранение правил
Правила iptables и firewalld по-разному сохраняются.
Для iptables
На большинстве дистрибутивов правила iptables не сохраняются автоматически после перезагрузки. Используйте:
- Ubuntu/Debian с пакетом
iptables-persistent:sudo netfilter-persistent save
Или вручную:sudo iptables-save > /etc/iptables/rules.v4 - CentOS 6/7 (если не используется firewalld):
sudo service iptables save
илиsudo /etc/init.d/iptables save
Для firewalld
Правила, добавленные с флагом --permanent, сохраняются в конфигурационных файлах (/etc/firewalld/). После добавления правил перезагрузите firewalld, чтобы убедиться, что они применены:
sudo firewall-cmd --reload
Шаг 5: Проверка работоспособности
- Просмотрите активные правила:
- Для iptables:
Вы должны увидеть правило в цепочкеsudo iptables -t nat -L -n -vPREROUTINGиFORWARD. - Для firewalld:
В выводе ищитеsudo firewall-cmd --list-allforward-ports.
- Для iptables:
- Проверьте, что порт открыт на внешнем интерфейсе. Обратите внимание: после DNAT порт 80 на публичном интерфейсе не слушается демоном, а перенаправляется. Поэтому команда
ss -tuln | grep :80может не показать ничего. Лучше проверить снаружи. - Протестируйте извне:
- С другого компьютера в сети или из интернета выполните:
илиcurl http://публичный_IP:80telnet публичный_IP 80 - Должны получить ответ от внутреннего сервера (например, веб-страницу с порта 8080).
Если сервис использует HTTPS, замените порт 80 на 443 и протокол наhttps. - С другого компьютера в сети или из интернета выполните:
Возможные проблемы
Правила не работают после перезагрузки
- iptables: Вы не сохранили правила. Выполните
sudo netfilter-persistent saveили аналогичную команду для вашего дистрибутива. - firewalld: Вы добавили правило без
--permanent. Исправьте:sudo firewall-cmd --zone=public --add-forward-port=... --permanentи перезагрузите.
Ошибка "Permission denied" или "Operation not permitted"
- Убедитесь, что вы выполняете команды с sudo или от root. Port forwarding требует прав администратора.
Порт уже занят
- На внешнем порту (например, 80) уже работает другой сервис (веб-сервер Apache/Nginx). Остановите его или выберите другой порт.
- Проверьте:
sudo ss -tuln | grep :80
Неверный внутренний IP
- Убедитесь, что IP
192.168.1.100корректен и сервис на нём запущен. Проверьте:ping 192.168.1.100иcurl http://192.168.1.100:8080с самого Linux-сервера.
Конфликт firewalld и iptables
- На системах с firewalld (CentOS 7+) не используйте iptables напрямую — firewalld управляет правилами через iptables. Вместо этого настраивайте всё через
firewall-cmd. Если вы случайно добавили правило iptables, оно может быть перезаписано firewalld.
Блокировка SELinux (для CentOS/RHEL/Fedora)
- SELinux по умолчанию может запрещать проброс портов. Временно отключите для теста:
Если это помогло, настройте политики SELinux правильно. Для firewalld обычно проблем нет, но для iptables может потребоваться:sudo setenforce 0sudo semanage port -a -t http_port_t -p tcp 80
Внутренний сервис не отвечает
- Проверьте, что сервис (например, веб-сервер) слушает на
0.0.0.0:8080или на внутреннем IP, а не только на127.0.0.1. Используйтеsudo ss -tuln | grep 8080. - Убедитесь, что на внутреннем сервере (если он отдельный) есть маршрут обратно к клиенту через ваш шлюз. Иногда требуется добавить статический маршрут или настроить NAT на шлюзе.
Проброс UDP-портов
- Для UDP используйте те же команды, но замените
tcpнаudpв iptables илиproto=udpв firewalld. Пример для firewalld:sudo firewall-cmd --zone=public --add-forward-port=port=53:proto=udp:toaddr=192.168.1.100:toport=53 --permanent