Новинка Виртуальный VDS сервер в Нидерландах от 390р
Выберите продукт

PostgreSQL на VDS: pg_hba.conf, SCRAM и TLS для безопасного доступа

PostgreSQL удобно держать на VDS, но открывать порт 5432 «как есть» нельзя. Разберём, как включить сетевые подключения, описать правила pg_hba.conf, перейти на SCRAM и заставить клиентов использовать TLS.
PostgreSQL на VDS: pg_hba.conf, SCRAM и TLS для безопасного доступа

PostgreSQL на отдельной Linux VDS — хороший вариант для проектов, которым уже тесно в рамках локальной базы на том же сервере: нужны отдельные ресурсы, понятные бэкапы, контроль над версиями и независимое обслуживание. Но как только база начинает слушать сеть, её безопасность перестаёт быть «внутренним делом» приложения.

Неправильная строка в pg_hba.conf, слишком широкий listen_addresses, старый метод паролей или отсутствие TLS могут превратить аккуратный сервер в публичную точку атаки. В этой инструкции разберём практичную схему: PostgreSQL слушает только нужные адреса, доступ разрешён точечно, пароли работают через SCRAM, а сетевые подключения идут по TLS.

Главная идея: PostgreSQL не должен быть «открыт в интернет». Он должен быть доступен только тем клиентам, которым это действительно нужно, с понятной аутентификацией и шифрованием канала.

Что именно защищаем

У PostgreSQL есть несколько уровней допуска. Их часто смешивают, из-за чего возникают ошибки вроде «порт открыт, но не пускает», «пароль верный, но SSL required», «локально работает, с приложения нет». Для нормальной настройки полезно разделять эти уровни.

  • listen_addresses в postgresql.conf отвечает за то, на каких IP-адресах сервер PostgreSQL принимает TCP-подключения.
  • Системный firewall решает, кто может достучаться до порта 5432 на уровне сети.
  • pg_hba.conf определяет, какие пользователи, к каким базам и с каких адресов могут проходить аутентификацию.
  • Метод аутентификации, например scram-sha-256, определяет, как проверяется пароль.
  • TLS в PostgreSQL шифрует соединение и, при правильном sslmode, позволяет клиенту проверить, что он подключился к нужному серверу.

Безопасная конфигурация получается только при совпадении всех слоёв. Если в pg_hba.conf разрешён доступ одному IP, но firewall открыт для всего мира, это всё ещё лишняя поверхность атаки. Если firewall строгий, но в pg_hba.conf стоит широкое правило 0.0.0.0/0, вы оставляете риск на случай будущих изменений сети.

Где лежат конфиги PostgreSQL

Пути зависят от способа установки. В пакетах Debian и Ubuntu обычно используется каталог вида /etc/postgresql/16/main/. В RHEL-based дистрибутивах — AlmaLinux, Rocky Linux, CentOS Stream, Oracle Linux — конфиги часто лежат в /var/lib/pgsql/16/data/, если PostgreSQL установлен из PGDG-пакетов, или в другом каталоге для системных пакетов.

Поэтому лучше не угадывать путь, а спросить сам 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;'

Эти команды покажут точные файлы postgresql.conf и pg_hba.conf. Если на сервере несколько кластеров или версий PostgreSQL, это особенно важно: можно отредактировать один файл, а работать будет другой.

Проверка версии и сервиса

Перед правками полезно понять, какая версия запущена и как называется systemd-unit. На Debian/Ubuntu часто используется агрегирующий сервис postgresql, а также кластеры, управляемые утилитами pg_ctlcluster. На RHEL-based системах unit обычно содержит версию.

psql --version
systemctl list-units 'postgresql*' --type=service

Схема уровней доступа PostgreSQL: listen_addresses, firewall, pg_hba.conf и TLS

Шаг 1. Настраиваем listen_addresses

Параметр listen_addresses определяет, на каких IP-адресах PostgreSQL открывает порт. Значение localhost означает только локальные подключения. Значение * означает все адреса, включая публичный IPv4 и IPv6, если они есть. Для production лучше указывать конкретный адрес: приватный IP VDS, адрес внутренней сети, VPN-интерфейс или loopback, если база нужна только локальному приложению.

Типовые варианты:

  • приложение и PostgreSQL на одном сервере: listen_addresses = '127.0.0.1,::1';
  • приложение на другой VDS во внутренней сети: listen_addresses = '10.10.0.5,127.0.0.1';
  • доступ только через VPN: укажите IP VPN-интерфейса, например 10.8.0.1;
  • временная диагностика: не используйте * без одновременного строгого firewall и pg_hba.conf.

Откройте файл postgresql.conf, путь к которому мы нашли через SHOW config_file;, и задайте параметр:

listen_addresses = '10.10.0.5,127.0.0.1'
port = 5432

Изменение listen_addresses требует перезапуска PostgreSQL, обычного reload недостаточно: сервер должен заново открыть сокеты.

Перезапуск PostgreSQL

Для Debian/Ubuntu можно использовать общий сервис или кластерные команды. Если у вас один кластер, чаще всего достаточно:

sudo systemctl restart postgresql
sudo systemctl status postgresql --no-pager

Если нужно управлять конкретным кластером:

pg_lsclusters
sudo pg_ctlcluster 16 main restart

Для RHEL-based дистрибутивов название сервиса зависит от версии и репозитория. Проверьте его через systemctl list-units, затем перезапустите нужный unit:

sudo systemctl restart postgresql-16
sudo systemctl status postgresql-16 --no-pager

После перезапуска проверьте, на каких адресах слушает PostgreSQL:

sudo ss -ltnp | grep ':5432'

Если вы видите 0.0.0.0:5432 или [::]:5432, сервер слушает все адреса. Иногда это допустимо при строгих сетевых фильтрах, но для обычной VDS безопаснее сузить listen_addresses.

Шаг 2. Включаем SCRAM вместо md5

SCRAM — современный механизм парольной аутентификации в PostgreSQL. В конфигурации он обозначается как scram-sha-256. Старый метод md5 всё ещё встречается в унаследованных установках, но для новых ролей и новых подключений лучше использовать SCRAM.

Важно: параметр password_encryption влияет на то, как PostgreSQL будет сохранять новые или изменённые пароли. Он не переписывает уже существующие пароли автоматически. Поэтому переход на SCRAM состоит из двух частей: включить 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();'

Дальше задайте пароль роли заново. Делайте это для прикладных пользователей, а не для системной роли postgres, если она не используется приложением.

sudo -u postgres psql
ALTER ROLE appuser WITH PASSWORD 'use-a-long-random-password-here';
\q

В реальной эксплуатации пароль не стоит оставлять в истории shell. Безопаснее выполнить ALTER ROLE внутри интерактивного psql, использовать менеджер секретов или временно отключить запись истории. Для CI/CD и приложений храните пароль вне репозитория: в переменных окружения, защищённых секретах раннера или отдельном хранилище.

Как понять, что пароль уже SCRAM

Проверить формат сохранённого секрета можно из-под суперпользователя PostgreSQL. Не публикуйте вывод этой команды: в нём есть хеши паролей.

sudo -u postgres psql -c "SELECT rolname, CASE WHEN rolpassword LIKE 'SCRAM-SHA-256%' THEN 'scram' WHEN rolpassword IS NULL THEN 'no password' ELSE 'legacy or other' END AS password_type FROM pg_authid ORDER BY rolname;"

Если у прикладной роли отображается legacy or other, задайте пароль заново после включения password_encryption.

Шаг 3. Разбираем pg_hba.conf без магии

pg_hba.conf — это список правил доступа. PostgreSQL читает его сверху вниз и применяет первое подходящее правило. Это принципиально: если сверху стоит широкое разрешение, более строгие строки ниже уже не сработают. Поэтому файл стоит вести как firewall: сначала специальные правила, затем более общие, а в конце можно оставить явные запреты.

Формат строки для TCP-подключений обычно такой:

type database user address auth-method auth-options

Ключевые типы:

  • local — Unix socket, без IP-адреса;
  • host — TCP-подключение без требования TLS;
  • hostssl — TCP-подключение только с TLS;
  • hostnossl — TCP-подключение только без TLS, чаще полезно для явного запрета или диагностики.

Для production, где база доступна по сети, лучше использовать hostssl. Тогда клиент без TLS не пройдёт даже при правильном пароле.

Пример минимального pg_hba.conf для приложения

Допустим, база appdb, пользователь appuser, приложение подключается с приватного IP 10.10.0.20, администратор — с VPN-подсети 10.8.0.0/24. Тогда фрагмент pg_hba.conf может выглядеть так:

local   all             postgres                                peer
local   all             all                                     peer
hostssl appdb           appuser         10.10.0.20/32            scram-sha-256
hostssl all             adminuser       10.8.0.0/24              scram-sha-256
hostnossl all           all             0.0.0.0/0                reject
hostnossl all           all             ::/0                     reject

Здесь локальные подключения через Unix socket используют peer: системный пользователь сопоставляется с пользователем PostgreSQL. Сетевые подключения для приложения и администратора разрешены только по TLS и только через SCRAM. В конце добавлены явные запреты для TCP без TLS. Они не заменяют firewall, но делают поведение понятнее.

Если у вас приложение и PostgreSQL находятся на одном сервере, сетевое правило для приложения может вообще не понадобиться: используйте локальный socket или 127.0.0.1. Чем меньше сетевых правил, тем проще сопровождать безопасность.

Чего не стоит писать в pg_hba.conf

Самая частая опасная строка выглядит так:

host    all             all             0.0.0.0/0                md5

Она разрешает всем IPv4-адресам пытаться подобрать пароль ко всем базам и пользователям, а ещё использует старый метод. Даже если пароль сильный, это создаёт лишнюю нагрузку, шум в логах и риск при утечке учётных данных. Для IPv6 аналогичная широкая строка — ::/0.

Если вам нужен доступ с динамического домашнего IP, лучше не расширять правило до всего интернета. Практичнее использовать VPN, bastion-хост, SSH-туннель или временно добавлять конкретный адрес с обязательным удалением после работ. Для постоянной эксплуатации база должна быть доступна только из предсказуемых сетей; для VPN-сценариев пригодится инструкция по site-to-site WireGuard на VDS.

FastFox VDS
Облачный VDS-сервер
Виртуальные серверы с быстрым запуском и гибкой конфигурацией от 390₽ / мес
Доступные локации
Россия Нидерланды

Шаг 4. Включаем TLS в PostgreSQL

PostgreSQL использует параметры ssl, ssl_cert_file, ssl_key_file и, при необходимости, ssl_ca_file. Сертификат сервера нужен не только для шифрования. При режиме клиента verify-full он ещё подтверждает имя сервера, к которому подключается приложение.

Для внутренней базы можно использовать сертификат от собственной CA. Для публичного DNS-имени удобно использовать обычный серверный сертификат, если ваша модель доступа допускает проверку по доменному имени. Важно, чтобы имя в строке подключения совпадало с SAN сертификата: если клиент подключается к db.example.local, это имя должно быть в сертификате. Если нужен сертификат от доверенного центра, посмотрите раздел SSL-сертификаты.

Права на ключи

Закрытый ключ должен быть доступен пользователю PostgreSQL и недоступен всем остальным. Иначе сервер откажется запускаться или вы получите небезопасную конфигурацию.

Пример расположения файлов:

/etc/postgresql/tls/server.crt
/etc/postgresql/tls/server.key
/etc/postgresql/tls/ca.crt

Создайте каталог и выставьте права. На Debian/Ubuntu и RHEL-based системах пользователь обычно называется postgres.

sudo install -d -m 0750 -o postgres -g postgres /etc/postgresql/tls
sudo chown postgres:postgres /etc/postgresql/tls/server.crt /etc/postgresql/tls/server.key /etc/postgresql/tls/ca.crt
sudo chmod 0644 /etc/postgresql/tls/server.crt /etc/postgresql/tls/ca.crt
sudo chmod 0600 /etc/postgresql/tls/server.key

В postgresql.conf включите TLS:

ssl = on
ssl_cert_file = '/etc/postgresql/tls/server.crt'
ssl_key_file = '/etc/postgresql/tls/server.key'
ssl_ca_file = '/etc/postgresql/tls/ca.crt'
ssl_min_protocol_version = 'TLSv1.2'

Если все клиенты поддерживают TLS 1.3, можно рассмотреть более строгую политику, но TLS 1.2 остаётся практичным минимумом совместимости для многих драйверов и библиотек. Не включайте старые протоколы ради «на всякий случай»: если клиент настолько старый, лучше обновить клиентскую библиотеку.

Перезапуск после TLS

После изменения путей к сертификатам и ключам надёжнее перезапустить PostgreSQL. Если вы только меняете часть параметров, иногда хватает reload, но при TLS-правках перезапуск проще и предсказуемее.

sudo systemctl restart postgresql
sudo -u postgres psql -c 'SHOW ssl;'
sudo -u postgres psql -c 'SHOW ssl_cert_file;'

Для RHEL-based систем замените имя сервиса на фактическое, например postgresql-16:

sudo systemctl restart postgresql-16
sudo -u postgres psql -c 'SHOW ssl;'

Шаг 5. Требуем TLS через hostssl

Само по себе ssl = on не запрещает незашифрованные подключения. Оно разрешает PostgreSQL принимать TLS, но решение о допуске всё равно принимает pg_hba.conf. Поэтому для сетевых клиентов используйте hostssl, а не просто host.

hostssl appdb           appuser         10.10.0.20/32            scram-sha-256
hostssl all             adminuser       10.8.0.0/24              scram-sha-256
hostnossl all           all             0.0.0.0/0                reject
hostnossl all           all             ::/0                     reject

После изменения pg_hba.conf достаточно перезагрузить конфигурацию:

sudo -u postgres psql -c 'SELECT pg_reload_conf();'

Если вы не можете подключиться к базе из-за ошибки в pg_hba.conf, используйте локальный доступ на сервере под пользователем postgres. Поэтому не удаляйте бездумно локальные строки local, пока не убедились, что есть рабочий административный канал.

Шаг 6. Firewall: не полагайтесь только на PostgreSQL

Даже идеальный pg_hba.conf не отменяет сетевой фильтр. На VDS порт 5432 должен быть закрыт для всех, кроме доверенных адресов. Если приложение находится на соседней VDS во внутренней сети, разрешайте именно её приватный IP. Если администраторы подключаются через VPN, разрешайте VPN-подсеть. Если база нужна только локально, порт не должен быть доступен извне вообще.

UFW на Debian/Ubuntu

sudo ufw allow from 10.10.0.20 to any port 5432 proto tcp
sudo ufw allow from 10.8.0.0/24 to any port 5432 proto tcp
sudo ufw status verbose

firewalld на RHEL-based системах

sudo firewall-cmd --permanent --new-zone=postgresql-clients
sudo firewall-cmd --permanent --zone=postgresql-clients --add-source=10.10.0.20/32
sudo firewall-cmd --permanent --zone=postgresql-clients --add-source=10.8.0.0/24
sudo firewall-cmd --permanent --zone=postgresql-clients --add-port=5432/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --zone=postgresql-clients --list-all

nftables, если вы ведёте правила вручную

Если на сервере используется собственная nftables-конфигурация, логика такая же: разрешить порт только от нужных источников и запретить остальное. Фрагмент ниже — пример, его нужно адаптировать к вашей таблице и цепочке. Если хотите глубже разобраться в взаимодействии контейнеров и firewall, пригодится материал про Docker, iptables и nftables.

table inet filter {
  set pg_clients_v4 {
    type ipv4_addr
    flags interval
    elements = { 10.10.0.20, 10.8.0.0/24 }
  }

  chain input {
    type filter hook input priority 0; policy drop;
    ct state established,related accept
    iif lo accept
    ip saddr @pg_clients_v4 tcp dport 5432 accept
  }
}

Перед применением firewall-правил всегда сохраняйте активную SSH-сессию и имейте доступ к консоли VDS. Ошибка в firewall может отрезать не только PostgreSQL, но и администрирование сервера.

Проверка TLS-подключения клиента к PostgreSQL через psql

Шаг 7. Проверяем подключение клиента

Для проверки используйте psql с явным sslmode. Режим require шифрует канал, но не проверяет имя сервера. Для production лучше стремиться к verify-full: клиент проверяет цепочку доверия и соответствие имени сервера сертификату.

psql 'host=db.example.local port=5432 dbname=appdb user=appuser sslmode=verify-full sslrootcert=/path/to/ca.crt'

После подключения проверьте, что TLS действительно используется:

SELECT ssl, version, cipher FROM pg_stat_ssl WHERE pid = pg_backend_pid();

Если результат показывает ssl = t, соединение зашифровано. Если строка пустая или ssl = f, проверьте pg_hba.conf, строку подключения и клиентскую библиотеку.

Полезно также посмотреть, какое правило pg_hba.conf сработало. В свежих версиях PostgreSQL есть представление pg_hba_file_rules, которое помогает найти синтаксические ошибки и оценить порядок правил.

sudo -u postgres psql -c 'SELECT line_number, type, database, user_name, address, auth_method, error FROM pg_hba_file_rules ORDER BY line_number;'

Если в колонке error есть текст, PostgreSQL не сможет корректно применить это правило. Исправьте файл и выполните SELECT pg_reload_conf();.

Типовые ошибки и быстрые диагностики

Connection refused

Ошибка connection refused означает, что TCP-соединение не принято. Обычно PostgreSQL не слушает нужный адрес, сервис не запущен или firewall отклоняет соединение. Проверьте listen_addresses, порт и список слушающих сокетов.

sudo systemctl status postgresql --no-pager
sudo ss -ltnp | grep ':5432'
sudo -u postgres psql -c 'SHOW listen_addresses;'

No pg_hba.conf entry

Ошибка no pg_hba.conf entry означает, что клиент дошёл до PostgreSQL, но ни одно правило не подошло. В тексте ошибки обычно указаны пользователь, база, IP-адрес клиента и наличие или отсутствие SSL. Это почти готовая подсказка для новой строки pg_hba.conf, но не копируйте её механически: сначала проверьте, должен ли этот клиент вообще иметь доступ.

Password authentication failed

Если правило найдено, но пароль не подходит, проверьте, что приложение использует актуальный секрет, роль не заблокирована, а пароль был переустановлен после перехода на SCRAM. Иногда проблема не в PostgreSQL, а в старой переменной окружения, кэше deployment-системы или секретах контейнера.

sudo -u postgres psql -c "SELECT rolname, rolcanlogin, rolvaliduntil FROM pg_roles WHERE rolname = 'appuser';"

SSL error или certificate verify failed

Ошибки проверки сертификата чаще всего связаны с несовпадением имени хоста и SAN сертификата, неправильным sslrootcert на клиенте или неполной цепочкой CA. Если вы подключаетесь по IP, а сертификат выписан на DNS-имя, verify-full ожидаемо завершится ошибкой. Используйте стабильное DNS-имя для базы или добавляйте IP в SAN, если это действительно нужно.

Рекомендованная базовая схема для VDS

Для большинства небольших production-проектов хорошо работает такая модель: PostgreSQL слушает приватный адрес VDS и localhost, firewall разрешает 5432 только от приложения и VPN, pg_hba.conf использует hostssl и scram-sha-256, клиенты подключаются с sslmode=verify-full, а пароли хранятся в секретах, а не в репозитории.

listen_addresses = '10.10.0.5,127.0.0.1'
password_encryption = 'scram-sha-256'
ssl = on
ssl_cert_file = '/etc/postgresql/tls/server.crt'
ssl_key_file = '/etc/postgresql/tls/server.key'
ssl_ca_file = '/etc/postgresql/tls/ca.crt'
ssl_min_protocol_version = 'TLSv1.2'
local   all             postgres                                peer
local   all             all                                     peer
hostssl appdb           appuser         10.10.0.20/32            scram-sha-256
hostssl all             adminuser       10.8.0.0/24              scram-sha-256
hostnossl all           all             0.0.0.0/0                reject
hostnossl all           all             ::/0                     reject

Эта схема не претендует на универсальность. Для репликации понадобятся отдельные правила для пользователя репликации и адресов standby-серверов. Для клиентских сертификатов можно усилить правила через clientcert=verify-full. Для highload-систем стоит дополнительно настраивать пулер соединений, лимиты ролей, аудит и мониторинг. Но как безопасная отправная точка для PostgreSQL на Linux VDS она закрывает главные риски.

Чек-лист перед вводом в production

  • listen_addresses не содержит * без необходимости.
  • Порт 5432 закрыт firewall для всех, кроме доверенных адресов.
  • В pg_hba.conf нет широких правил 0.0.0.0/0 и ::/0 с разрешающей аутентификацией.
  • Сетевые правила используют hostssl, а не обычный host.
  • Для прикладных пользователей задан scram-sha-256, пароли переустановлены после включения password_encryption.
  • TLS-сертификат соответствует имени, по которому подключаются клиенты.
  • Клиенты используют sslmode=verify-full там, где это возможно.
  • Локальный административный доступ сохранён, чтобы можно было исправить ошибку в pg_hba.conf.
  • После правок выполнены проверки через ss, pg_hba_file_rules и pg_stat_ssl.

Если идти по этому чек-листу, настройка PostgreSQL перестаёт быть набором разрозненных параметров. Вы получаете понятную модель доступа: сеть пускает только нужных клиентов, PostgreSQL принимает только ожидаемые роли и базы, пароли проверяются современным SCRAM, а TLS защищает канал и помогает клиенту убедиться, что перед ним правильный сервер.

Поделиться статьей

Вам будет интересно

PostgreSQL pg_hba.conf на VDS: почему trust 0.0.0.0/0 опасен и как открыть доступ правильно OpenAI Статья написана AI (GPT 5)

PostgreSQL pg_hba.conf на VDS: почему trust 0.0.0.0/0 опасен и как открыть доступ правильно

PostgreSQL не подключается извне, и хочется поставить trust для всех адресов? Разбираем безопасный путь: listen_addresses, точные ...
Ansible на VDS: inventory, become, SSH-ключи и первый playbook OpenAI Статья написана AI (GPT 5)

Ansible на VDS: inventory, become, SSH-ключи и первый playbook

Разберём, как подготовить Ansible для управления VDS: собрать inventory, настроить SSH-ключи, проверить доступ, аккуратно включить ...
systemd-tmpfiles: безопасная очистка /tmp и кэшей вместо cron rm -rf OpenAI Статья написана AI (GPT 5)

systemd-tmpfiles: безопасная очистка /tmp и кэшей вместо cron rm -rf

Когда /tmp разрастается, рука тянется к cron и rm -rf. Разбираем, почему это рискованно, как работает systemd-tmpfiles, где лежат ...