«Запереть дверь — ещё не значит обезопасить дом. Но оставить её открытой — значит, гарантированно потерять всё, что внутри. — Воланд»
Настоящее руководство описывает установку и настройку фаервола UFW (Uncomplicated Firewall) — фронтенда к iptables/nftables, который является стандартным средством защиты сетевого периметра в Ubuntu.
Мы начинаем с сервера, на котором уже выполнены предыдущие шаги: SSH работает (порт 22022, только ключи), пользователь uservpn имеет sudo без пароля, базовая система настроена (локаль, часовой пояс, hostname, swap).
Цель данного руководства — закрыть все входящие сетевые порты, кроме тех, которые действительно нужны, и настроить rate limiting для SSH.
Все шаги пронумерованы и должны выполняться в указанном порядке. Перескакивать не рекомендуется.
Входные данные: вы подключены к серверу по SSH пользователем
uservpnна порт 22022. Команды сsudoне запрашивают пароль.
Фаервол (брандмауэр, межсетевой экран) — компонент операционной системы, который фильтрует сетевой трафик по заданным правилам. Он решает, какие пакеты пропустить, какие заблокировать, а какие ограничить по частоте.
Без фаервола все порты сервера открыты для всего интернета. Любой сканер, ботнет или любопытный прохожий может попытаться подключиться к любому сервису. Это как оставить входную дверь квартиры открытой и надеяться, что никто не войдёт.
В Linux существует несколько уровней фильтрации:
| Уровень | Инструмент | Сложность |
|---|---|---|
| Ядро (netfilter) | iptables / nftables | Высокая — десятки параметров в одной команде |
| Обёртка | UFW | Низкая — понятные команды вида ufw allow 22/tcp |
| Обёртка над UFW | firewalld | Средняя — зоны, сервисы, динамические правила |
UFW — выбор по умолчанию для Ubuntu. Он не заменяет iptables, а упрощает работу с ним: за каждой командой ufw стоит набор правил iptables/nftables, которые UFW генерирует автоматически.
На нашем сервере работают следующие сервисы, требующие сетевого доступа:
| Порт | Протокол | Правило | Сервис | Назначение |
|---|---|---|---|---|
| 22022 | TCP | LIMIT | SSH | Удалённый доступ (rate limit — защита от брутфорса) |
| 80 | TCP | ALLOW | Nginx | HTTP — Let's Encrypt validation + редирект на HTTPS |
| 443 | TCP | ALLOW | Xray (VLESS + Reality) | VPN-туннель, маскируется под обычный HTTPS |
| 8443 | TCP | ALLOW | Nginx (Grav CMS) | Блог на psj-notes.ru |
| 4443 | TCP | ALLOW | Nginx (x-ui dashboard) | Панель управления VPN (Basic Auth) |
| 2096 | TCP | ALLOW | VLESS-Reality | Альтернативный порт VPN (резерв) |
Все остальные входящие соединения — заблокированы. Исходящие — разрешены без ограничений (сервер должен иметь возможность скачивать обновления, отправлять почту и т.д.).
Коровьев, разглядывая таблицу портов:
«Шесть открытых дверей из сотен возможных. Остальные — наглухо заперты. И заметьте, гражданин: даже в этих шести есть засовы, цепочки и глазок. Квартирный вопрос, как известно, испортил не только москвичей, но и всех, кто пытается зайти на сервер без приглашения.»
В некоторых образах Ubuntu UFW уже установлен. Проверим:
sudo ufw version
Если команда выводит версию (например, ufw 0.36.2) — пакет установлен. Если видите command not found — устанавливаем.
sudo apt install -y ufw
После установки проверьте, что UFW доступен:
sudo ufw status
Ожидаемый вывод:
Status: inactive
Важно: UFW не активен после установки. Это правильно — сначала настраиваем правила, потом включаем. Если включить фаервол без правил — он заблокирует всё, включая текущую SSH-сессию.
Политика по умолчанию (default policy) — правило, которое применяется к пакетам, не подошедшим ни под одно конкретное правило. UFW поддерживает две политики:
| Политика | Поведение |
|---|---|
allow |
Пропускать всё, что не запрещено явно |
deny |
Блокировать всё, что не разрешено явно |
Для сервера единственно правильный выбор — deny для входящих, allow для исходящих. Это называется «белый список»: разрешено только то, что мы явно указали.
sudo ufw default deny incoming
sudo ufw default allow outgoing
Ожидаемый вывод каждой команды:
Default incoming policy changed to 'deny'
(be sure to update your rules accordingly)
sudo ufw status verbose
Ожидаемый вывод (пока без правил):
Status: inactive
Default: deny (incoming), allow (outgoing), deny (routed)
Воланд кивнул:
«Теперь сервер по умолчанию глух и нем для внешнего мира. Всё, что мы разрешим — будет сделано осознанно. Это называется принцип наименьших привилегий, и он спас больше систем, чем все антивирусы вместе взятые.»
UFW может записывать в системный журнал информацию о заблокированных пакетах. Это полезно для диагностики: если что-то не работает, можно посмотреть, не блокирует ли фаервол нужный трафик.
sudo ufw logging low
Уровни логирования:
| Уровень | Что записывает | Когда использовать |
|---|---|---|
off |
Не записывает ничего | Никогда — вы останетесь слепыми |
low |
Только заблокированные пакеты | Рекомендуется для продакшена |
medium |
Заблокированные + разрешённые + rate limit | Для отладки |
high |
medium + дополнительная информация | Для глубокой диагностики |
full |
Всё, включая фрагментированные пакеты | Только при расследовании инцидентов |
Уровень low оптимален: он записывает только заблокированные соединения, не перегружая диск логами.
sudo ufw limit 22022/tcp
Что делает limit: разрешает подключения, но блокирует IP-адрес, если с него поступает более 6 новых соединений за 30 секунд. Это защита от брутфорса на уровне фаервола — дополнительный рубеж после Fail2ban.
Почему не
allow:allowпропускает всё без ограничений.limit— пропускает, но с защитой от флуда. Для SSH это критично, даже если порт изменён и вход только по ключам.
sudo ufw allow 80/tcp
Порт 80 нужен для двух вещей:
.well-known/acme-challenge/ и проверяет их доступность по HTTP. Без открытого 80-го порта продление сертификатов не работает.http://psj-notes.ru — получает https://psj-notes.ru.sudo ufw allow 443/tcp
Порт 443 — стандартный HTTPS. На нашем сервере его слушает Xray с протоколом VLESS + Reality. Для внешнего наблюдателя это выглядит как обычный HTTPS-сайт: трафик шифруется, SNI указывает на psj-notes.ru. Только клиент с правильным конфигурационным файлом получит доступ к VPN-туннелю.
sudo ufw allow 8443/tcp
Порт 8443 — HTTPS-виртуальный хост Nginx для блога Grav CMS. Доступен по адресу https://psj-notes.ru:8443.
sudo ufw allow 4443/tcp
Порт 4443 — HTTPS-виртуальный хост Nginx для дашборда и панели x-ui. Защищён Basic Auth (логин + пароль). Доступен по адресу https://consol.psj-notes.ru:4443.
sudo ufw allow 2096/tcp comment 'VLESS-Reality'
Порт 2096 — альтернативный порт для VPN-подключений. Полезен, если основной порт 443 по какой-то причине недоступен или занят другим сервисом.
Коровьев, подсчитывая правила на пальцах:
«Шесть правил — шесть дверей. Каждая с замком, каждая с охраной. И ни одной лишней. Заметьте: мы не открыли ни порта для базы данных, ни для FTP, ни для чего-нибудь экзотического. Если серверу это не нужно — дверь остаётся запертой.»
Перед включением убедитесь, что правило для SSH (порт 22022) добавлено:
sudo ufw status
Ожидаемый вывод:
Status: inactive
To Action From
-- ------ ----
22022/tcp LIMIT Anywhere
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
8443/tcp ALLOW Anywhere
4443/tcp ALLOW Anywhere
2096/tcp ALLOW Anywhere
Критично: если в списке нет правила для порта 22022 — не включайте фаервол. Вы потеряете SSH-доступ. Вернитесь к разделу 5.1 и добавьте правило.
sudo ufw --force enable
Флаг --force подашивает предупреждение о возможном разрыве SSH-соединения. Поскольку мы уже добавили правило для SSH, предупреждение нам не нужно.
Ожидаемый вывод:
Firewall is active and enabled on system startup
sudo ufw status verbose
Ожидаемый вывод:
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22022/tcp LIMIT IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
8443/tcp ALLOW IN Anywhere
4443/tcp ALLOW IN Anywhere
2096/tcp ALLOW IN Anywhere
22022/tcp (v6) LIMIT IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
8443/tcp (v6) ALLOW IN Anywhere (v6)
4443/tcp (v6) ALLOW IN Anywhere (v6)
2096/tcp (v6) ALLOW IN Anywhere (v6)
Обратите внимание: UFW автоматически создал правила и для IPv6 (строки с v6). Это правильно — если IPv6 включён, фаервол должен защищать оба стека.
После включения фаервола не закрывайте текущее SSH-подключение. Откройте новый терминал и попробуйте подключиться:
ssh -p 22022 uservpn@<IP-АДРЕС-СЕРВЕРА>
Если подключились — фаервол не блокирует SSH. Если нет — вернитесь в старую сессию и проверьте правила.
Попробуйте подключиться к порту, который не открыт (например, 3306 — MySQL):
nc -zv <IP-АДРЕС-СЕРВЕРА> 3306
Ожидаемый результат:
nc: connect to <IP-АДРЕС-СЕРВЕРА> port 3306 (tcp) failed: Connection refused
Или таймаут — это означает, что фаервол блокирует соединение.
Заблокированные попытки подключений записываются в системный журнал:
sudo dmesg | grep -i 'UFW BLOCK' | tail -5
Или через journalctl:
sudo journalctl -k | grep 'UFW BLOCK' | tail -5
Пример записи:
[UFW BLOCK] IN=eth0 OUT= MAC=... SRC=1.2.3.4 DST=194.50.94.224 ... DPT=3306 ...
Здесь SRC — IP-адрес источника (сканера), DPT — порт, к которому он пытался подключиться.
Воланд, просматривая логи:
«Вот видите — уже кто-то стучится в порт 3306. А MySQL у нас даже не установлен. Фаервол вежливо ответил: „Нет, сударь, здесь такого нет." И записал в журнал — для потомков. Через неделю таких записей будет тысячи. Это нормально. Интернет — место шумное.»
sudo ufw status numbered
Ожидаемый вывод:
Status: active
To Action From
-- ------ ----
[ 1] 22022/tcp LIMIT IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
[ 4] 8443/tcp ALLOW IN Anywhere
[ 5] 4443/tcp ALLOW IN Anywhere
[ 6] 2096/tcp ALLOW IN Anywhere
Номера правил нужны для удаления.
Чтобы удалить правило, укажите его номер:
sudo ufw delete <номер>
Например, удалить правило 6 (порт 2096):
sudo ufw delete 6
Система спросит подтверждение:
Deleting:
allow 2096/tcp comment 'VLESS-Reality'
Proceed with operation (y|n)? y
Альтернативный способ — указать правило текстом:
sudo ufw delete allow 2096/tcp
Если нужно начать заново:
sudo ufw reset
Это удалит все пользовательские правила и вернёт политики по умолчанию. Фаервол останется включённым.
Предупреждение: после
resetправило для SSH будет удалено. Перед повторным включением добавьте его заново.
| № | Порт | Протокол | Правило | Назначение | Комментарий |
|---|---|---|---|---|---|
| 1 | 22022 | TCP | LIMIT | SSH | Rate limit — макс. 6 соединений за 30 сек |
| 2 | 80 | TCP | ALLOW | HTTP | Let's Encrypt + редирект на HTTPS |
| 3 | 443 | TCP | ALLOW | VLESS + Reality | VPN-туннель (Xray) |
| 4 | 8443 | TCP | ALLOW | Grav CMS | Блог на psj-notes.ru |
| 5 | 4443 | TCP | ALLOW | x-ui dashboard | Панель управления (Basic Auth) |
| 6 | 2096 | TCP | ALLOW | VLESS-Reality | Резервный порт VPN |
Политики по умолчанию: входящие — deny, исходящие — allow.
Логирование: low (только заблокированные пакеты).
На данном этапе мы имеем:
| Что | Статус |
|---|---|
| UFW установлен | ✅ |
| Политика по умолчанию: deny incoming | ✅ |
| Политика по умолчанию: allow outgoing | ✅ |
| Логирование: low | ✅ |
| SSH (22022) — rate limit | ✅ |
| HTTP (80) — разрешён | ✅ |
| VLESS (443) — разрешён | ✅ |
| Grav CMS (8443) — разрешён | ✅ |
| x-ui dashboard (4443) — разрешён | ✅ |
| VLESS резерв (2096) — разрешён | ✅ |
| Фаервол активен | ✅ |
Следующее руководство: настройка Fail2ban — три тюрьмы для SSH:
sshd,sshd-ddos,recidive.
Конец документа. Настроившему — спокойный сон, забывшему правило SSH — да поможет ufw reset и веб-консоль провайдера.