// заметки
Установка и настройка PostgreSQL
Установка PostgreSQL через apt и Docker: кластер, initdb, pg_hba, доступы и параметры под нагрузку. Пошаговые команды с проверкой на каждом шаге
PostgreSQL после установки по умолчанию слушает только localhost и использует настройки под слабую машину. Ниже: два способа поставить сервер (пакет дистрибутива и Docker), создать кластер, настроить доступы через pg_hba.conf и выставить базовые параметры под нагрузку с проверкой каждого шага
Контекст: Debian или Ubuntu, одна машина, PostgreSQL ставится и как системный пакет, и как контейнер. Команды других дистрибутивов отличаются, различия отмечены отдельно
Симптом
Свежий инстанс отвечает на psql под локальным пользователем postgres, но приложение с другого хоста получает отказ. Под нагрузкой картина другая: сортировки уходят на диск, а число соединений упирается в лимит. Оба симптома растут из дефолтов: конфигурация рассчитана на минимальную машину и локальный доступ
$ sudo -u postgres psql -Atc "show listen_addresses;"
localhost
$ sudo -u postgres psql -Atc "show shared_buffers;"
128MBПриложение с другого хоста к такому серверу не подключится, а на машине с 16 ГБ памяти 128 МБ под кеш страниц почти ничего не значат. Это не ошибка установки, а заводские значения
Диагностика
Сначала проверьте, что сервер установлен и какой кластер обслуживается
psql --version
pg_lsclusters
systemctl status postgresql --no-pagerpg_lsclusters есть только в пакетах postgresql-common (Debian, Ubuntu). Он показывает версию, имя кластера, порт, статус, владельца, каталог данных и лог. В RHEL и производных команды другие: кластер создаёт postgresql-setup --initdb, а состояние смотрят через systemctl status postgresql
Если pg_lsclusters не найден, это отдельный сценарий: linux: «команда не найдена»
Дальше выясните, какой конфиг читает работающий сервер. Путь зависит от способа установки, поэтому его не угадывают, а спрашивают у самого сервера
sudo -u postgres psql -Atc "show config_file;"
sudo -u postgres psql -Atc "show hba_file;"
sudo -u postgres psql -Atc "show data_directory;"config_file — это postgresql.conf, hba_file — pg_hba.conf, data_directory — каталог с самими базами. В Debian и Ubuntu конфиги обычно лежат в /etc/postgresql/<version>/main/, в Docker — внутри каталога данных
Что сервер реально слушает, показывает ss
sudo ss -ltnp | grep postgresЕсли в выводе только 127.0.0.1:5432 или [::1]:5432, TCP-доступ ограничен локальной машиной. Если строки нет вообще, сервер может работать только через Unix-сокет
Причина
apt-пакет создаёт кластер автоматически при установке, а initdb задаёт минимальные дефолты. listen_addresses = 'localhost' привязывает сервер к петлевому интерфейсу, потому что открытый наружу PostgreSQL без настроенных правил доступа был бы дырой
Второй слой — pg_hba.conf (host-based authentication, правила доступа по типу подключения). Файл читается сверху вниз, и срабатывает первое подходящее правило. Методы аутентификации: peer сверяет имя ОС-пользователя с именем роли и работает только через Unix-сокет, md5 проверяет пароль по MD5-хешу, scram-sha-256 — по современной схеме SCRAM. В PostgreSQL 14 и новее scram-sha-256 используется по умолчанию
Третий слой — параметры памяти. shared_buffers задаёт кеш страниц самого сервера и по умолчанию мал. max_connections ограничивает число соединений, а каждое соединение в PostgreSQL — отдельный процесс со своей памятью. Поэтому инстанс с дефолтами не разгоняется под нагрузкой, хотя формально работает
Решение
Сначала установка через apt в Debian и Ubuntu
sudo apt update
sudo apt install -y postgresql postgresql-contribПакет postgresql-contrib добавляет расширения, например pg_stat_statements и pgcrypto. Установка сразу создаёт кластер и запускает службу
Проверьте результат
pg_lsclustersВ выводе должна быть строка с версией, именем main, портом 5432 и статусом online. Если кластера нет, создайте его вручную
sudo pg_createcluster <version> main --startВторой путь — Docker
docker run -d --name pg \
-e POSTGRES_USER=app \
-e POSTGRES_DB=app \
-e POSTGRES_PASSWORD='<password>' \
-p 127.0.0.1:5432:5432 \
-v pgdata:/var/lib/postgresql/data \
postgres:16Официальный образ при первом запуске сам вызывает initdb, создаёт пользователя, базу и файлы доступа. Публикация порта через -p 127.0.0.1:5432:5432 оставляет базу доступной только с хоста, для внешнего доступа адрес меняют осознанно
Кластер можно создать и вручную, через initdb
sudo -u postgres initdb -D /var/lib/postgresql/data
sudo -u postgres pg_ctl -D /var/lib/postgresql/data -l logfile startinitdb создаёт каталог данных и базовые конфиги. Запускать его от root нельзя, поэтому команда идёт через sudo -u postgres
Сетевые параметры и порт задайте в postgresql.conf по пути из show config_file. Дефолтный listen_addresses = 'localhost' и есть причина отказа для клиента с другого хоста, поэтому для внешнего доступа его меняют на конкретный интерфейс или на все адреса:
# postgresql.conf
listen_addresses = '*' # дефолт 'localhost' слушает только петлевой интерфейс
port = 5432listen_addresses — список интерфейсов, на которых сервер принимает TCP-соединения. Значение 'localhost' оставляет только петлевой интерфейс, '*' слушает все адреса. Открывать '*' безопасно только за файрволом или в приватной сети: сам параметр не ограничивает, кто может подключиться. Внешний доступ дополнительно разрешают в pg_hba.conf строкой host для подсети приложения и отдельным правилом файрвола
port меняют, если 5432 занят другим инстансом. После правки listen_addresses и port нужен перезапуск, а не перечитывание конфига
sudo systemctl restart postgresqlПравила доступа задайте в pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
local all all peer
host app app 127.0.0.1/32 scram-sha-256
host app app ::1/128 scram-sha-256Порядок строк важен: сервер идёт по файлу сверху вниз и останавливается на первом совпадении, поэтому широкая строка выше узкой перекроет её. Метод trust пускает без пароля и в продакшене недопустим. peer удобен для локального администрирования: sudo -u postgres psql работает без пароля, потому что имя ОС-пользователя совпадает с именем роли
После правки pg_hba.conf достаточно перечитать конфигурацию
sudo systemctl reload postgresqlПерезапуск не нужен: правила доступа перечитываются на лету
Дальше создайте отдельную роль и базу
sudo -u postgres psqlCREATE ROLE app LOGIN PASSWORD '<password>';
CREATE DATABASE app OWNER app;Пароль не оседает в открытом виде в psql_history, если использовать \password app: команда запросит пароль и применит password_encryption из конфига. Для приложения пароль хранят в менеджере секретов или в ~/.pgpass с правами 600
Проверьте подключение под новой ролью
psql "postgresql://app@127.0.0.1:5432/app" -c "select current_user, current_database();"Строка подключения postgresql:// состоит из роли, хоста, порта и базы. Пароль запрашивается отдельно или берётся из ~/.pgpass
Параметры под нагрузку начинают с памяти
shared_buffers — примерно 25% от RAM, effective_cache_size — оценка доступного кеша (порядка 50–75% RAM) для планировщика, work_mem — память на одну операцию сортировки или хеширования в одном соединении
# postgresql.conf, пример для машины с 16 ГБ RAM
shared_buffers = 4GB
effective_cache_size = 12GB
work_mem = 8MB
maintenance_work_mem = 512MB
max_connections = 200effective_cache_size не выделяет память: это подсказка планировщику, сколько данных помещается в кеш сервера и ОС. work_mem выделяется на каждую операцию сортировки или хеша, а соединений может быть много, поэтому верхняя граница потребления — это max_connections × work_mem × число одновременных операций. maintenance_work_mem используют VACUUM, CREATE INDEX и другие служебные операции
shared_buffers, max_connections и port требуют перезапуска, work_mem, effective_cache_size и maintenance_work_mem применяются при перечитывании
sudo systemctl reload postgresqlЛогическая копия делается через pg_dump и не блокирует чтение
pg_dump -Fc -f /backup/app.dump "postgresql://app@127.0.0.1:5432/app"Ключ -Fc пишет архив в сжатом формате, который распаковывает pg_restore
pg_restore -d app /backup/app.dumpРоли и права уровня кластера в одну базу не входят, для них нужен pg_dumpall --globals-only. Копировать каталог данных на работающем сервере нельзя: получится несогласованный снимок
Проверка
pg_isready -h 127.0.0.1 -p 5432pg_isready показывает, принимает ли сервер соединения. Ответ accepting connections — рабочий вариант
sudo -u postgres psql -c "show shared_buffers; show max_connections;"Убедитесь, что параметры применились и вернулись заданные значения
psql "postgresql://app@127.0.0.1:5432/app" -c "\conninfo"\conninfo печатает роль, базу, хост и порт текущего подключения. Если приложение в контейнере не видит базу, проверьте, что публикация порта и listen_addresses согласованы
Восстановление копии проверяют на отдельной базе, а не поверх рабочей
createdb app_restore && pg_restore -d app_restore /backup/app.dumpПодводные камни
- Широкая строка
pg_hba.confперекрывает узкую. Первое совпадение выигрывает, поэтому правилоhost all all 0.0.0.0/0 md5выше прикладного отключает проверку, которую вы настроили ниже listen_addresses = '*'без файрвола открывает базу в сеть. Параметр не фильтрует клиентов, от этого защищает толькоpg_hba.confв связке с сетевой политикойpeerне работает по TCP. Метод сверяет ОС-пользователя, а у сетевого соединения его нет, поэтому для удалённых клиентов нуженscram-sha-256- Пароль роли не меняется сменой
POSTGRES_PASSWORDв контейнере. Переменная обрабатывается только при первомinitdb, для существующего кластера выполняйтеALTER ROLE ... PASSWORD work_memумножается на соединения. Большое значение на сервере с сотнями соединений приводит к нехватке памяти, ограничивайте через пул соединений, например PgBouncerpg_dumpне заменяет WAL-архивирование. Для восстановления на момент времени нужен поток физических копий, логическая копия даёт снимок на момент запуска- Различия дистрибутивов.
pg_lsclustersиpg_createclusterесть в Debian и Ubuntu, в RHEL кластер создаётpostgresql-setup --initdb
Итог
Установка PostgreSQL сводится к трём слоям: пакет или контейнер создаёт кластер и службу, listen_addresses и pg_hba.conf определяют, кто и как подключается, а параметры памяти и соединений определяют поведение под нагрузкой. Состояние проверяйте через pg_lsclusters и pg_isready, а копии делайте через pg_dump
Если сервер запущен, но соединения отклоняются, это отдельный сценарий: postgresql: connection refused
Для настройки под конкретную нагрузку и аудита запросов есть услуги консалтинга по PostgreSQL и разработки backend
Похожие заметки
PostgreSQL: connection refused — не подключается
Connection refused и no pg_hba.conf entry выглядят похоже, но лежат на разных уровнях. Разбираю диагностику, причины и фиксы для локального PostgreSQL и Docker
pkill -f убивает сам себя: шаблон совпадает с командой
pkill -f и pgrep -f сопоставляют шаблон со всей командной строкой, включая обёртку bash -c. Разбираю, почему команда убивает себя, и какие фильтры помогают
Nix на CachyOS: установка невозможна — rootless-запуск
Nix не ставится, если корень read-only, sudo сломан, а путь /nix зашит в ELF. Разбор трёх ограничений и rootless-запуск через mount-namespace и chroot