UFW придуман для того, чтобы фаервол настраивался тремя командами, и с этим он справляется. Проблема в другом: ufw status показывает намерения, а не результат. Правило может стоять в списке и при этом не закрывать ровно ничего — по трём разным причинам, и все три встречаются на реальных серверах регулярно.

Начало, при котором не запираешь себя

Порядок команд имеет значение. Сначала разрешить SSH, потом включать:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable

ufw enable до разрешения SSH обрывает вашу же сессию, и дальше только консоль хостера. Если сервер уже настроен и вы не уверены — держите открытым второе соединение, оно переживёт неудачную правку.

Смотреть надо подробный статус, короткий скрывает политику по умолчанию:

sudo ufw status verbose

Ошибка первая: правило есть, а порт открыт всему миру

Самая частая строка в чужих конфигурациях:

sudo ufw allow 3306

Так открывают MySQL «чтобы подключиться из дома» — и открывают его всему интернету. Правильных вариантов два, и оба лучше:

sudo ufw allow from 203.0.113.25 to any port 3306

или, что надёжнее, вообще не выпускать службу наружу: bind-address = 127.0.0.1 в конфиге MySQL, а доступ извне — через SSH-туннель. Фаервол — второй рубеж; первый в том, чтобы служба не слушала публичный адрес. Правило в UFW можно случайно удалить, а bind-address сам собой не поменяется.

Ошибка вторая: IPv6

Правило вида ufw allow from 203.0.113.25 относится только к IPv4. Если у сервера есть адрес IPv6 — а у большинства VPS он есть и включён — служба остаётся доступной по нему. Хостер выдал адрес, вы про него не помните, сканер про него знает.

Проверьте, что фильтрация v6 вообще включена (IPV6=yes в /etc/default/ufw) и что служба не слушает :: без нужды:

ss -tulpn | grep ':::'

Правила с явным указанием адреса нужно заводить для обеих версий протокола отдельно.

Ошибка третья: Docker

Самая обидная. Docker публикует порты, дописывая собственные правила в цепочки iptables раньше тех, куда пишет UFW. В результате контейнер, запущенный как -p 5432:5432, доступен из интернета, даже если UFW показывает Status: active и политику deny incoming. Фаервол при этом не сломан — до него просто не доходит очередь.

Лечится это не в UFW, а в том, как публикуется порт:

ports:
  - "127.0.0.1:5432:5432"

Привязка к локальному адресу — самое простое и надёжное решение. Наружу должно смотреть только то, что действительно обслуживает посетителей: обычно это порты 80 и 443 обратного прокси.

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

UFW применяет первое подходящее правило и на этом останавливается. Поэтому запрет, добавленный после разрешения, не сработает: до него дело не дойдёт. Смотрим нумерацию и вставляем в нужное место:

sudo ufw status numbered
sudo ufw insert 1 deny from 198.51.100.0/24
sudo ufw delete 7

Правила удаляются по номеру, но номера сдвигаются после каждого удаления — удаляйте по одному и перечитывайте список.

Проверка снаружи

Локальные команды показывают, что настроено. Что получилось на самом деле, видно только с другой машины:

nmap -Pn -p- 203.0.113.25
nc -zv 203.0.113.25 3306

Достаточно любого другого сервера или домашнего компьютера. Это единственная проверка, которая не врёт, и делать её стоит после каждой заметной перенастройки — особенно после установки чего-то, что «само настраивает сеть»: Docker, панели управления, VPN.

Логи

По умолчанию UFW почти ничего не пишет. Включается так:

sudo ufw logging low

Записи попадают в /var/log/ufw.log — но только если в системе есть rsyslog. На Debian 12 и Ubuntu 24.04 его может не быть, и тогда всё уходит в журнал systemd:

sudo journalctl -k | grep -i '\[UFW'

Пустой /var/log/ufw.log сам по себе ничего не означает — сначала посмотрите в журнал.

Чего ждать от фаервола

UFW закрывает то, что не должно быть доступно. Он не разбирает содержимое запросов к тому, что открыто: порт 443 открыт всем, и всё, что придёт на сайт, придёт беспрепятственно. Это работа других инструментов — WAF на уровне приложения, IDS на уровне трафика. Задача фаервола скромнее и важнее: чтобы список открытых портов совпадал с тем, что вы про него думаете. Как выглядит этот список вместе с активными правилами на одной странице — на демо ниже.