Типичная ситуация на VDS: PostgreSQL установлен, приложение на другом сервере или рабочая машина администратора пытается подключиться к базе, а в ответ — connection refused, timeout или no pg_hba.conf entry. В поиске быстрых решений часто всплывает строка вида host all all 0.0.0.0/0 trust. Она действительно может «починить» подключение, но делает это самым опасным способом: любой, кто достучится до порта PostgreSQL, сможет войти без пароля под разрешенным пользователем.
В этой статье разберем, как устроен pg_hba.conf, чем отличаются trust, scram-sha-256 и другие методы, зачем нужен listen_addresses, как правильно включить доступ к PostgreSQL на VDS и где должен стоять firewall. Цель — не просто заставить порт 5432 отвечать, а сделать это контролируемо и безопасно.
Короткое правило:
trustне должен использоваться для удаленного доступа. Строка0.0.0.0/0 trustна публичном интерфейсе VDS — это фактически вход без ключа в серверную комнату.
Что именно настраивает pg_hba.conf
Файл pg_hba.conf отвечает не за то, слушает ли PostgreSQL сеть, а за то, кому и каким способом разрешено аутентифицироваться. Аббревиатура HBA расшифровывается как host-based authentication: правила доступа по типу соединения, базе, пользователю, адресу клиента и методу проверки.
Каждая значимая строка в pg_hba.conf читается слева направо и обычно имеет такую структуру:
TYPE DATABASE USER ADDRESS METHOD
Для локальных Unix-сокетов поле ADDRESS отсутствует:
local all postgres peer
Для TCP/IP-подключений адрес указывается в CIDR-формате:
host appdb appuser 203.0.113.10/32 scram-sha-256
Ключевой нюанс: PostgreSQL применяет первое подходящее правило. Если выше стоит широкое правило host all all 0.0.0.0/0 trust, то более строгие строки ниже могут никогда не сработать. Поэтому порядок в pg_hba.conf так же важен, как и сами методы аутентификации.
Почему trust 0.0.0.0/0 почти всегда ошибка
Метод trust означает: «доверять клиенту без проверки пароля». Для локального одноразового стенда это иногда удобно: например, в тестовом контейнере, который живет несколько минут и не публикует порт наружу. Но на VDS с публичным IP-адресом такая настройка превращается в критическую дыру.
Строка ниже разрешает подключение к любой базе любому пользователю с любого IPv4-адреса без пароля:
host all all 0.0.0.0/0 trust
Если дополнительно PostgreSQL слушает внешний интерфейс через listen_addresses = '*', а порт 5432 открыт в firewall, база становится доступной всему интернету. Даже если кажется, что «имя пользователя никто не знает», это слабая защита: стандартные роли, утечки конфигов приложений, старые бэкапы, логи деплоя и перебор имен быстро превращают такую настройку в инцидент.
Для IPv6 аналогичная проблема выглядит так:
host all all ::/0 trust
Иногда администратор открывает только IPv4 и забывает, что на VDS уже включен IPv6. В результате PostgreSQL может оказаться доступен через адрес, который не проверяли. Поэтому при аудите смотрите оба семейства адресов: IPv4 и IPv6.
Три слоя доступа: listen_addresses, pg_hba.conf и firewall
Чтобы удаленное подключение к PostgreSQL заработало, должны совпасть три условия. Первое — сам PostgreSQL должен слушать нужный адрес. За это отвечает параметр listen_addresses в postgresql.conf. Второе — в pg_hba.conf должно быть правило, которое разрешает клиенту аутентификацию. Третье — сетевой экран на VDS и, если используется, внешний firewall провайдера должны пропускать TCP-порт 5432 только от нужных источников.
Важно не путать эти уровни. Если listen_addresses оставлен равным localhost, PostgreSQL не будет принимать подключения на публичный IP, даже если в pg_hba.conf прописан весь интернет. Если pg_hba.conf не содержит подходящего правила, клиент увидит отказ после установления TCP-соединения. Если firewall закрыт, подключение обычно будет зависать по таймауту или сразу получать отказ на сетевом уровне.

Как найти реальные пути к конфигам
Пути к файлам зависят от дистрибутива, версии PostgreSQL и способа установки. Не угадывайте — спросите сам сервер PostgreSQL.
sudo -u postgres psql -c 'SHOW config_file;'
sudo -u postgres psql -c 'SHOW hba_file;'
sudo -u postgres psql -c 'SHOW data_directory;'
На Debian и Ubuntu при пакетной установке часто используются пути вида:
/etc/postgresql/16/main/postgresql.conf
/etc/postgresql/16/main/pg_hba.conf
Посмотреть кластеры PostgreSQL в Debian/Ubuntu удобно так:
pg_lsclusters
В RHEL-based дистрибутивах — AlmaLinux, Rocky Linux, CentOS Stream, Oracle Linux — и в Fedora путь часто находится в каталоге данных, например:
/var/lib/pgsql/16/data/postgresql.conf
/var/lib/pgsql/16/data/pg_hba.conf
Но для системных пакетов без PGDG-репозитория путь может отличаться, поэтому команды SHOW config_file; и SHOW hba_file; надежнее любых шпаргалок.
Настраиваем listen_addresses без лишнего расширения поверхности атаки
Параметр listen_addresses определяет, на каких IP-адресах PostgreSQL будет принимать TCP-подключения. Значение localhost безопасно по умолчанию: база доступна только с того же сервера. Значение * заставляет PostgreSQL слушать все доступные интерфейсы, включая публичный IPv4, IPv6 и приватные адреса.
Для продакшена лучше указывать конкретный адрес, если архитектура это позволяет. Например, если приложение подключается к PostgreSQL по приватной сети, слушайте приватный IP, а не все интерфейсы:
listen_addresses = '127.0.0.1,10.10.0.5'
Если отдельной приватной сети нет и подключение идет через публичный адрес VDS, можно указать публичный IP явно:
listen_addresses = '127.0.0.1,198.51.100.5'
Временное значение * допустимо для диагностики, но после проверки лучше заменить его на конкретный список адресов:
listen_addresses = '*'
Изменение listen_addresses требует перезапуска PostgreSQL, потому что это параметр уровня postmaster. Обычного reload недостаточно.
Перезапуск PostgreSQL
Debian/Ubuntu:
sudo systemctl restart postgresql
RHEL-based и Fedora при установке PostgreSQL из PGDG-пакетов часто используют unit с версией:
sudo systemctl restart postgresql-16
Если не уверены в имени сервиса, посмотрите доступные unit-файлы:
systemctl list-units 'postgresql*'
Безопасный pg_hba.conf: минимально нужные правила
Хороший pg_hba.conf начинается с принципа минимальных прав. Разрешайте не «всем ко всему», а конкретному пользователю доступ к конкретной базе с конкретного адреса или подсети. Для приложения это обычно выглядит так:
# Локальный администратор PostgreSQL через Unix-сокет
local all postgres peer
# Локальные TCP-подключения
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
# Приложение с одного внешнего IP
host appdb appuser 203.0.113.10/32 scram-sha-256
Если приложение находится в приватной сети VDS, лучше разрешить именно приватную подсеть:
host appdb appuser 10.10.0.0/24 scram-sha-256
Если вы включили SSL в PostgreSQL и хотите принимать удаленные подключения только по TLS, используйте hostssl. Тогда обычные незашифрованные TCP-подключения не подойдут под это правило:
hostssl appdb appuser 203.0.113.10/32 scram-sha-256
Для hostssl в postgresql.conf должен быть включен параметр ssl, а серверу нужны корректные сертификат и ключ. Если TLS пока не настроен, используйте host вместе со строгим firewall, но запланируйте включение шифрования, особенно если трафик идет не по приватному каналу.
Что делать с широкими правилами
Иногда в старых инструкциях встречается компромиссный вариант:
host all all 0.0.0.0/0 md5
Он лучше, чем trust, потому что требует пароль, но все равно слишком широк для VDS. Любой внешний адрес сможет пытаться пройти аутентификацию. Это увеличивает шум в логах, поверхность атаки и риск подбора слабого пароля. Если нужен доступ с динамического домашнего IP, лучше использовать VPN, bastion-host, SSH-туннель или регулярно обновляемый allowlist, а не открывать 0.0.0.0/0. Для постоянных связок между серверами можно посмотреть подход с site-to-site VPN на WireGuard.
Включаем scram-sha-256 и обновляем пароль роли
Для современных PostgreSQL предпочтительный метод парольной аутентификации — scram-sha-256. Он безопаснее старого md5 и должен быть стандартом для новых инсталляций. Но есть нюанс: если роль уже имела пароль, сохраненный в старом формате, простая замена метода в pg_hba.conf может привести к ошибкам подключения. Нужно убедиться, что новые пароли сохраняются как SCRAM, и переустановить пароль роли.
Проверьте текущий режим:
sudo -u postgres psql -c 'SHOW password_encryption;'
Установите scram-sha-256 как режим для новых паролей:
sudo -u postgres psql -c "ALTER SYSTEM SET password_encryption = 'scram-sha-256';"
sudo -u postgres psql -c 'SELECT pg_reload_conf();'
Теперь задайте новый пароль приложению. Используйте длинный случайный пароль из менеджера секретов, а не пример из статьи:
sudo -u postgres psql -c "ALTER ROLE appuser WITH PASSWORD 'replace_with_long_random_password';"
После этого строка в pg_hba.conf с методом scram-sha-256 будет работать корректно для этой роли. Если у вас старые клиенты или драйверы PostgreSQL, проверьте их совместимость с SCRAM заранее: очень старые библиотеки могут поддерживать только md5.
Reload pg_hba.conf и проверка синтаксиса
После изменения pg_hba.conf обычно достаточно reload, перезапуск не нужен. PostgreSQL перечитает правила доступа без разрыва уже установленных соединений.
Debian/Ubuntu:
sudo systemctl reload postgresql
RHEL-based и Fedora для PGDG-пакетов:
sudo systemctl reload postgresql-16
Также можно выполнить reload из SQL:
sudo -u postgres psql -c 'SELECT pg_reload_conf();'
Если в pg_hba.conf есть синтаксическая ошибка, PostgreSQL обычно оставит старые правила активными и запишет проблему в журнал. Поэтому после изменения сразу смотрите логи.
Debian/Ubuntu с systemd:
journalctl -u postgresql -n 100 --no-pager
RHEL-based и Fedora:
journalctl -u postgresql-16 -n 100 --no-pager
Внутри PostgreSQL можно проверить, применились ли настройки:
sudo -u postgres psql -c "SELECT name, setting, context FROM pg_settings WHERE name IN ('listen_addresses', 'password_encryption');"
Firewall PostgreSQL: открываем порт только нужным адресам
Даже идеально настроенный pg_hba.conf не заменяет firewall. Сетевой экран должен отсекать лишние подключения до того, как они попадут в PostgreSQL. На VDS это особенно важно: публичный IP регулярно сканируется автоматическими ботами, и открытый 5432 быстро окажется в их списках.
Если используете UFW на Debian/Ubuntu, разрешите порт только от IP приложения или администратора:
sudo ufw allow from 203.0.113.10 to any port 5432 proto tcp
sudo ufw status verbose
Если у вас firewalld на AlmaLinux, Rocky Linux, CentOS Stream, Oracle Linux или Fedora, можно добавить rich rule:
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=203.0.113.10 port port=5432 protocol=tcp accept'
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
Для nftables правило зависит от вашей базовой структуры таблиц и цепочек. Пример для таблицы inet filter и цепочки input:
sudo nft add rule inet filter input ip saddr 203.0.113.10 tcp dport 5432 accept
Если на сервере параллельно работают контейнеры, проверьте, не меняет ли Docker ожидаемую логику фильтрации. Подробно этот нюанс разобран в статье про Docker, iptables и nftables на VDS.
Если у провайдера есть отдельный облачный firewall или security group, продублируйте ограничение там. Лучшая схема — когда порт 5432 закрыт для всего интернета и открыт только для конкретных IP или приватной сети. Тогда даже ошибка в pg_hba.conf не сразу становится доступной извне.
Проверяем, что PostgreSQL слушает нужный адрес
После изменения listen_addresses и перезапуска проверьте, на каких адресах открыт порт 5432:
ss -lntp | grep 5432
Если видите только 127.0.0.1:5432, удаленный клиент не подключится. Если видите 0.0.0.0:5432, PostgreSQL слушает все IPv4-интерфейсы. Это не всегда ошибка, но тогда firewall и pg_hba.conf должны быть особенно строгими. Если видите [::]:5432, проверьте IPv6-правила тоже.
С клиентской машины проверьте подключение:
psql -h 198.51.100.5 -p 5432 -U appuser -d appdb -c 'select current_user, inet_client_addr();'
Если подключение успешно, команда покажет текущего пользователя и адрес клиента, который видит PostgreSQL. Это полезно для проверки, совпадает ли реальный исходящий IP клиента с тем, что вы прописали в allowlist.

Разбор частых ошибок
connection refused
Ошибка connection refused означает, что TCP-соединение отвергнуто: PostgreSQL не слушает указанный адрес и порт, сервис не запущен или локальный firewall активно отклоняет соединение. Начинайте с проверки сервиса и сокетов:
systemctl status postgresql
ss -lntp | grep 5432
Для RHEL-based систем с версионным unit используйте имя своего сервиса, например postgresql-16.
timeout
Таймаут чаще всего связан с firewall, внешней security group, маршрутизацией или попыткой подключиться не к тому IP. На сервере проверьте, приходят ли пакеты на порт 5432:
sudo tcpdump -ni any tcp port 5432
Если пакеты не приходят, проблема до сервера: адрес, маршрут, внешний firewall, NAT или правило у клиента. Если приходят, но ответа нет, смотрите локальный firewall и состояние PostgreSQL.
no pg_hba.conf entry
Сообщение no pg_hba.conf entry означает, что TCP-соединение дошло до PostgreSQL, но ни одно правило pg_hba.conf не подошло по базе, пользователю, адресу, SSL-режиму или типу соединения. Проверьте реальный IP клиента, имя базы, имя роли и порядок строк. Часто проблема в том, что у клиента NAT, и PostgreSQL видит не тот адрес, который ожидал администратор.
password authentication failed
Если правило найдено, но пароль не принят, проверьте пароль роли, метод scram-sha-256, совместимость клиента и то, к той ли базе идет подключение. Для приложений также проверьте переменные окружения и секреты в systemd unit, Docker Compose или CI/CD: старый пароль часто остается именно там.
Практический безопасный сценарий для VDS
Соберем все в один понятный сценарий. Допустим, PostgreSQL работает на VDS с адресом 198.51.100.5, приложение подключается с адреса 203.0.113.10, база называется appdb, роль — appuser.
В postgresql.conf указываем адреса, которые должен слушать PostgreSQL:
listen_addresses = '127.0.0.1,198.51.100.5'
password_encryption = 'scram-sha-256'
В pg_hba.conf оставляем локальный доступ и добавляем точечное правило для приложения:
local all postgres peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
host appdb appuser 203.0.113.10/32 scram-sha-256
Открываем firewall только для IP приложения:
sudo ufw allow from 203.0.113.10 to any port 5432 proto tcp
Перезапускаем PostgreSQL, потому что меняли listen_addresses:
sudo systemctl restart postgresql
Задаем роли новый пароль в SCRAM-формате:
sudo -u postgres psql -c "ALTER ROLE appuser WITH PASSWORD 'replace_with_long_random_password';"
Проверяем с клиентской стороны:
psql -h 198.51.100.5 -U appuser -d appdb -c 'select current_user, inet_client_addr();'
Такой вариант не полагается на один-единственный барьер. Даже если пароль случайно утечет, подключиться сможет только разрешенный источник. Даже если firewall временно станет шире, pg_hba.conf не пустит произвольных пользователей ко всем базам. Именно многослойность делает настройку устойчивой.
Когда trust все-таки допустим
Метод trust не является «запрещенной командой», но у него очень узкая зона применения. Его можно встретить в локальной разработке, изолированных CI-контейнерах, одноразовых тестовых окружениях или при аварийном восстановлении доступа, когда порт PostgreSQL не опубликован наружу и сервер изолирован сетевыми правилами.
Даже в таких случаях лучше ограничивать trust локальным сокетом или loopback-адресом:
local all postgres peer
host all all 127.0.0.1/32 trust
Но для постоянной работы PostgreSQL на VDS, особенно если база доступна с других серверов, используйте scram-sha-256, точные CIDR-адреса, отдельные роли для приложений и firewall. А строку host all all 0.0.0.0/0 trust лучше воспринимать как временный диагностический костыль, который нельзя оставлять после проверки.
Итоговый чек-лист
- Не используйте
host all all 0.0.0.0/0 trustиhost all all ::/0 trustна VDS с публичным доступом. - Проверьте реальные пути к
postgresql.confиpg_hba.confкомандамиSHOW config_file;иSHOW hba_file;. - Настройте
listen_addressesна конкретные IP-адреса, а не на*, если это возможно. - В
pg_hba.confразрешайте конкретную базу, конкретную роль и конкретный IP или подсеть. - Используйте
scram-sha-256и переустановите пароли ролей после включенияpassword_encryption. - Ограничьте порт 5432 на уровне firewall: UFW, firewalld, nftables и внешний firewall провайдера должны пропускать только нужные источники.
- После изменения
listen_addressesперезапускайте PostgreSQL, после измененияpg_hba.confобычно достаточно reload. - Проверяйте результат с обеих сторон:
ssна сервере иpsqlс клиентской машины.
Главная мысль простая: удаленный доступ к PostgreSQL должен быть осознанным, а не «открытым на всякий случай». Настройте listen_addresses, pg_hba.conf, scram-sha-256 и firewall как одну систему — и база будет доступна приложению, но не всему интернету.


