Установка и настройка PostgreSQL на Debian и Ubuntu
Установка из пакета дистрибутива или из репозитория PGDG, первый вход через пользователя postgres, создание базы и роли, разбор pg_hba.conf и резервная копия, которая действительно выручает.
PostgreSQL ставится на Debian и Ubuntu за две минуты. Оставшиеся два часа обычно уходят на то, что подключиться потом не может никто. Эта статья доводит установку до конца: выбор пакета, первый вход, база данных и пользователь, правила доступа в pg_hba.conf и резервная копия, про которую точно известно, что она восстанавливается.
Все команды выполняются от имени root. Если вы работаете под обычным пользователем, добавляйте впереди sudo. Номер версии 17 в путях замените на ту версию, которая действительно установлена в вашей системе.
Какая версия PostgreSQL входит в какой дистрибутив
Главное различие между четырьмя распространёнными системами: основная версия, которая приходит из репозитория дистрибутива. Она жёстко привязана к релизу и в течение всего срока жизни дистрибутива уже не меняется.
| Дистрибутив | PostgreSQL из репозитория дистрибутива |
| Debian 13 (trixie) | 17 |
| Debian 12 (bookworm) | 15 |
| Ubuntu 24.04 LTS (noble) | 16 |
| Ubuntu 22.04 LTS (jammy) | 14 |
У такого разброса есть практические последствия. Дамп из Debian 13 не получится просто так залить в Ubuntu 22.04. А тем, кто работает на Ubuntu 22.04, стоит знать: согласно политике версионирования PostgreSQL Global Development Group поддержка PostgreSQL 14 со стороны сообщества прекращается 12 ноября 2026 года. Обновления безопасности для 22.04 Ubuntu продолжит выпускать в рамках цикла LTS, но исправления из upstream в них больше поступать не будут. Для новых проектов на 22.04 это весомый аргумент сразу взять репозиторий PGDG.
Что доступно именно в вашей системе, покажет запрос к базе пакетов, ещё до того как вы что-либо установите:
apt update
apt-cache policy postgresql
Строка Кандидат, в англоязычной локали Candidate, показывает номер вида 17+283. Число перед плюсом означает основную версию PostgreSQL, всё остальное относится к номеру версии метапакета Debian.
Установка из пакета дистрибутива
Для большинства задач пакет дистрибутива и есть правильный выбор. Он включён в поток обновлений безопасности дистрибутива, работает с системными библиотеками и не создаёт проблем при переходе на следующий релиз.
apt install -y postgresql postgresql-contrib
postgresql-contrib приносит штатные расширения, в том числе pgcrypto, uuid-ossp и pg_stat_statements. Без этого пакета многие приложения позже спотыкаются об ERROR: could not open extension control file, а поиск причины занимает больше времени, чем сама установка.
Debian и Ubuntu при установке автоматически создают первый кластер с именем main и запускают его. Кластер здесь — это работающий экземпляр со своим каталогом данных, своим портом и своей конфигурацией. Получилось ли это, отвечает не код возврата apt, а вот что:
pg_lsclusters
В колонке Status вывод должен показывать online:
Ver Cluster Port Status Owner Data directory Log file
17 main 5432 online postgres /var/lib/postgresql/17/main /var/log/postgresql/postgresql-17-main.log
Если там стоит down, запустите службу вручную. service postgresql start работает на всех четырёх системах, в том числе в контейнерах без systemd. На обычном сервере с тем же успехом подойдёт systemctl start postgresql.
service postgresql start
pg_isready
pg_isready отвечает строкой /var/run/postgresql:5432 - accepting connections и возвращает код 0. Это первое твёрдое доказательство того, что сервер доступен, и его удобно использовать дальше в скриптах мониторинга.
Когда нужен репозиторий PGDG и как подключить его аккуратно
Официальный репозиторий на apt.postgresql.org отдаёт все поддерживаемые основные версии параллельно, для trixie, bookworm, noble и jammy. Он нужен тогда, когда приложению требуется конкретная основная версия, когда нужны расширения, которых нет в пакетах Debian, или когда версия из дистрибутива скоро останется без поддержки.
Ключ должен лежать в отдельном файле, а не в устаревшей связке apt-key. Debian 13 и Ubuntu 24.04 к тому же предпочитают формат deb822 с расширением .sources, который при этом работает и на Debian 12, и на Ubuntu 22.04:
apt install -y curl ca-certificates
install -d /usr/share/postgresql-common/pgdg
curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
cat > /etc/apt/sources.list.d/pgdg.sources <<EOF
Types: deb
URIs: https://apt.postgresql.org/pub/repos/apt
Suites: $(. /etc/os-release && echo $VERSION_CODENAME)-pgdg
Components: main
Signed-By: /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
EOF
Строка с $(. /etc/os-release ...) автоматически подставляет trixie-pgdg, bookworm-pgdg, noble-pgdg или jammy-pgdg. Дальше:
apt update
apt-cache policy postgresql-18
Для той же задачи пакет postgresql-common содержит готовый скрипт /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh. Это альтернатива ключу и файлу pgdg.sources из примера выше, а не дополнение к ним. Если выполнить и то и другое, скрипт дополнительно создаст /etc/apt/sources.list.d/pgdg.list, и apt после этого при каждом запуске будет предупреждать: W: Target Packages (main/binary-amd64/Packages) is configured multiple times in /etc/apt/sources.list.d/pgdg.list:1 and /etc/apt/sources.list.d/pgdg.sources:1. Кто предпочитает скрипт ручным действиям выше, пусть заранее поставит gnupg, то есть apt install -y curl ca-certificates gnupg. Дело в том, что более старая версия скрипта на Ubuntu 22.04 всё ещё импортирует ключ через apt-key и без gnupg прерывается сообщением E: gnupg, gnupg2 and gnupg1 do not seem to be installed, but one of them is required for this operation с кодом возврата 255. На Debian 13, Debian 12 и Ubuntu 24.04 более новая версия кладёт ключ сразу как .asc и отрабатывает без дополнительного пакета.
Ловушка: два кластера, два порта
Если в системе уже установлен пакет дистрибутива и вы ставите новую основную версию, появляется второй кластер. Порт 5432 ему не достанется, он получит следующий свободный, то есть 5433. Приложения по-прежнему подключаются к старой версии, и никакого сообщения об ошибке при этом нет. Это самая частая причина фразы «я же установил PostgreSQL 18, а SELECT version() показывает 15».
apt install -y postgresql-18
pg_lsclusters
Теперь в выводе две строки с разными портами. Если данные нужно перенести в новую версию, правильный инструмент это pg_upgradecluster, а не дамп руками. Он требует, чтобы были установлены оба серверных пакета, и оставляет старый кластер остановленным, а не удаляет его:
pg_upgradecluster 15 main
После этого проверьте через pg_lsclusters, какой кластер занял порт 5432, и протестируйте приложение, прежде чем окончательно удалять старый кластер командой pg_dropcluster --stop 15 main. Эта команда стирает каталог данных без дополнительных вопросов.
Первый вход, и почему root не может запустить psql
Классическая заминка сразу после установки:
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "root" does not exist
Это не поломка, а ожидаемое поведение. Debian и Ubuntu настраивают локальные соединения через сокет методом peer. PostgreSQL при этом спрашивает у ядра, от имени какого системного пользователя открыто соединение, и требует, чтобы существовала роль базы данных с тем же именем. Существует только роль postgres, поэтому сначала нужно переключиться в этого системного пользователя.
su - postgres
После этого psql запускается без аргументов. Выйти из оболочки можно командой exit. Для отдельных команд из скрипта удобнее переключать пользователя на каждую команду:
runuser -u postgres -- psql -c "SELECT version();"
Если sudo установлен, то же самое пишется как sudo -u postgres psql -c "SELECT version();". Оба варианта равноценны. При использовании sudo часто появляется предупреждение could not change directory to "/root": Permission denied. Оно ни на что не влияет: пользователю postgres нельзя заходить в рабочий каталог root, но команда всё равно выполняется.
Эти три запроса показывают, с чем именно вы имеете дело, и при любом разборе проблем это первый шаг:
runuser -u postgres -- psql -c "SHOW server_version;"
runuser -u postgres -- psql -c "SHOW config_file;"
runuser -u postgres -- psql -c "SHOW hba_file;"
Последняя команда особенно полезна. Она называет путь, который работающий сервер действительно читает, обычно /etc/postgresql/17/main/pg_hba.conf. Если вы правите файл, а ничего не меняется, почти всегда перед вами конфигурация другого кластера.
Внутри psql помогают мета-команды: \l выводит список баз данных, \du список ролей, \dt таблицы текущей базы, \conninfo показывает, под кем и куда вы подключены, а \q завершает сеанс.
Создание базы данных и пользователя
Для каждого приложения следует заводить отдельную роль и отдельную базу данных. Порядок здесь важен, потому что база должна сразу принадлежать этой роли.
runuser -u postgres -- psql -c "CREATE ROLE appuser LOGIN PASSWORD 'ВашНадёжныйПароль';"
runuser -u postgres -- psql -c "CREATE DATABASE appdb OWNER appuser;"
Начиная с PostgreSQL 14 пароли по умолчанию хранятся в формате scram-sha-256, то есть на всех четырёх рассматриваемых здесь системах. В базу пароль при этом попадает не открытым текстом, зато он остаётся в истории вашей командной оболочки. Чтобы этого избежать, используйте в psql команду \password appuser, которая спрашивает пароль интерактивно.
Ловушка начиная с PostgreSQL 15: permission denied for schema public
Поведение, о котором многие старые руководства ещё не знают: начиная с PostgreSQL 15 создавать объекты в схеме public может уже не каждый пользователь. Это касается Debian 12, Debian 13 и Ubuntu 24.04. Только Ubuntu 22.04 с PostgreSQL 14 ведёт себя по-старому. Ошибка выглядит так:
ERROR: permission denied for schema public
LINE 1: CREATE TABLE clients (id serial primary key);
Правильный путь показан выше: база данных принадлежит роли. Схема public начиная с версии 15 принадлежит роли pg_database_owner, а владелец конкретной базы неявно входит в эту роль. Если база создана без OWNER, права нужно выдать отдельно. Учтите, что этот запрос должен выполняться в нужной базе данных, а не в postgres:
runuser -u postgres -- psql -d appdb -c "GRANT ALL ON SCHEMA public TO appuser;"
Доказательство, что права действительно работают
CREATE ROLE без ошибок ещё не означает, что приложение сможет подключиться. Доказательством служит настоящий вход по TCP с последующей записью. PGPASSWORD здесь нужен только для теста, для постоянной работы смотрите раздел ниже:
PGPASSWORD='ВашНадёжныйПароль' psql -h 127.0.0.1 -U appuser -d appdb -c "SELECT current_user, current_database();"
PGPASSWORD='ВашНадёжныйПароль' psql -h 127.0.0.1 -U appuser -d appdb -c "CREATE TABLE probe (id int);"
Если обе команды отработали, связка из роли, пароля, базы данных и прав на схему полностью рабочая. Таблицу probe мы сознательно оставляем на месте: тесту резервной копии ниже нужен хотя бы один объект в базе, иначе он проверит пустоту. Для контроля выведите список объектов:
runuser -u postgres -- psql -c "\du"
runuser -u postgres -- psql -c "\l"
Пара слов о кодировке: если на момент создания кластера системная локаль не была UTF-8, шаблонная база может оказаться в SQL_ASCII. Тогда CREATE DATABASE ... ENCODING 'UTF8' завершится ошибкой ERROR: new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII). Обходной путь: указать TEMPLATE template0 при создании. Чистое решение: система с локалью UTF-8.
Как устроен pg_hba.conf, самый частый источник ошибок
Файл pg_hba.conf (host-based authentication) ещё до проверки пароля решает, будет ли соединение вообще разрешено. Он читается сверху вниз, и побеждает первая подходящая строка. Если не подходит ни одна, соединение отклоняется. Разрешающее правило ниже по файлу вам не поможет, если более строгое правило выше сработает раньше. Это с большим отрывом самая частая ошибка в конфигурации.
В поставке Debian и Ubuntu файл выглядит так:
# TYPE DATABASE USER ADDRESS METHOD
local all postgres peer
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
Именно так это выглядит на четырёх рассматриваемых здесь системах. На более старых, например на Debian 11 с PostgreSQL 13, в обеих строках host ещё стоит md5 вместо scram-sha-256. Вход по TCP работает в обоих случаях, но полагаться на md5 больше не стоит.
Значение столбцов: local обозначает Unix-сокет, host подключение по TCP с TLS или без него, hostssl только TLS-соединения. Далее идут база данных, роль, сеть в нотации CIDR и метод. Важны четыре метода. peer сверяет системного пользователя и работает только через сокет. scram-sha-256 это современный парольный метод и правильный выбор для всего, что идёт по TCP. md5 объявлен устаревшим и в новых конфигурациях появляться не должен. trust пускает любого без проверки, и на доступном извне сервере ему делать нечего.
Сообщения об ошибках дословно
Если научиться их различать, гадать больше не придётся:
FATAL: Peer authentication failed for user "appuser"
Вы подключены через сокет, но имя вашего системного пользователя отличается от имени роли. Либо смените пользователя, либо подключайтесь через -h 127.0.0.1, чтобы сработала строка host.
FATAL: no pg_hba.conf entry for host "198.51.100.4", user "appuser", database "appdb", no encryption
Сервер доступен, но ни одно правило не подходит под эту комбинацию исходного адреса, роли и базы данных. Либо строки нет вовсе, либо сеть в существующей строке не покрывает этот адрес.
FATAL: password authentication failed for user "appuser"
Правило сработало, но пароль не подходит. Частая причина: роль создана без LOGIN или пароль остался от предыдущей установки.
psql: error: connection to server at "203.0.113.10", port 5432 failed: Connection refused
Здесь pg_hba.conf вообще не участвовал. Либо сервер не запущен, либо он не слушает на этом адресе, либо соединение режет файрвол. Об этом чуть ниже.
Проверка изменений до перечитывания конфигурации
В PostgreSQL есть системное представление, которое показывает разобранные правила вместе с номерами строк и синтаксическими ошибками. Оно отвечает на вопрос, какое правило сервер видит на самом деле, а не какое вам кажется написанным:
runuser -u postgres -- psql -c "SELECT line_number, type, database, user_name, address, auth_method FROM pg_hba_file_rules;"
Изменения в pg_hba.conf не требуют перезапуска, достаточно перечитать конфигурацию, при этом существующие соединения не разрываются:
runuser -u postgres -- psql -c "SELECT pg_reload_conf();"
Как вариант, service postgresql reload. Настоящий перезапуск нужен только тогда, когда изменены параметры вроде listen_addresses, port или shared_buffers.
Как открыть доступ извне
По умолчанию PostgreSQL слушает только localhost. Это хорошая настройка, и отказываться от неё стоит лишь тогда, когда это действительно необходимо. Совпасть должны две вещи: сервер должен слушать на нужном адресе, а pg_hba.conf должен разрешать источник. Нет первого, получите Connection refused, нет второго, получите no pg_hba.conf entry.
Конфигурация лежит в /etc/postgresql/17/main/postgresql.conf. Debian поставляет для неё инструмент pg_conftool, который правит файл надёжнее, чем поиск с заменой в редакторе:
pg_conftool 17 main show listen_addresses
pg_conftool 17 main set listen_addresses '10.0.0.5,127.0.0.1'
Указывайте конкретные адреса вместо *. На сервере с публичным и внутренним адресом так вы привяжете службу только к внутренней сети. После этого добавьте в pg_hba.conf правило, сформулированное настолько узко, насколько возможно:
host appdb appuser 10.0.0.0/24 scram-sha-256
После перезапуска командой service postgresql restart первым делом проверьте, что процесс слушает в действительности. ss -lntp | grep 5432 показывает привязанные адреса. Если там только 127.0.0.1:5432, изменение не подействовало, чаще всего потому, что правился другой кластер или значение перекрывает файл в каталоге conf.d.
Файрволу тоже нужно правило, причём с указанием источника. Порт 5432, открытый в интернет без ограничений, просканируют в течение нескольких часов:
ufw allow from 10.0.0.0/24 to any port 5432 proto tcp
Честный совет: в большинстве случаев лучшее решение это вообще не открывать порт. Для доступа во время обслуживания вполне хватит SSH-туннеля вида ssh -L 5432:127.0.0.1:5432 user@server. Для постоянных соединений между несколькими серверами чище выглядит сеть WireGuard, потому что база при этом продолжает слушать только на приватном адресе. Кстати, Debian и Ubuntu по умолчанию включают TLS с самоподписанным сертификатом, поэтому sslmode=require работает сразу. Но настоящую защиту от злоумышленника на линии даёт только sslmode=verify-full с сертификатом, которому доверяет клиент.
Резервное копирование через pg_dump и доказательство, что копия рабочая
Для отдельных баз данных лучший выбор это формат custom. Он сжат, из него можно восстанавливать выборочно, и загружать его можно параллельно:
runuser -u postgres -- pg_dump -Fc -d appdb -f /var/lib/postgresql/appdb.dump
Момент, который часто упускают: pg_dump не сохраняет ни роли, ни пароли. Они хранятся на уровне всего кластера, и копировать их нужно отдельно, иначе после восстановления не окажется именно тех пользователей, которые нужны приложению:
runuser -u postgres -- pg_dumpall --globals-only -f /var/lib/postgresql/globals.sql
Когда версии не совпадают
pg_dump: error: server version: 17.5; pg_dump version: 15.10
pg_dump: error: aborting because of server version mismatch
Правило такое: pg_dump может быть новее сервера, но никогда не старше. На Debian и Ubuntu это решается легко, потому что /usr/bin/pg_dump это всего лишь обёртка, которая выбирает подходящую версию программы. Установите пакет postgresql-client-18, и более новая версия будет наготове. А расширением Debian --cluster можно направить обёртку на конкретный кластер, здесь на версию 17, кластер main:
pg_dump --version
runuser -u postgres -- pg_dump --cluster 17/main -Fc -d appdb -f /var/lib/postgresql/appdb.dump
Как убрать пароль из скрипта
Для автоматических резервных копий пароль следует положить в файл .pgpass в формате хост:порт:база:пользователь:пароль. Если права на файл слишком широкие, PostgreSQL молча его игнорирует. Не менее важно, в чьём домашнем каталоге он лежит, потому что читается всегда файл того пользователя, от имени которого команда действительно выполняется. Файл ~/.pgpass от root останется без эффекта, пока резервное копирование, как в этой статье, идёт через runuser -u postgres. В этом случае учитывается домашний каталог пользователя postgres:
touch /var/lib/postgresql/.pgpass
chown postgres:postgres /var/lib/postgresql/.pgpass
chmod 0600 /var/lib/postgresql/.pgpass
Пустой файл тоже ничего не даёт. Внесите по одной строке на каждое соединение, например 127.0.0.1:5432:appdb:appuser:ВашНадёжныйПароль. Если же задание резервного копирования выполняется напрямую от root без смены пользователя, тот же файл должен лежать в /root/.pgpass.
Проверка резервной копии
Файл резервной копии, который ни разу не восстанавливали, это всего лишь предположение. Проверка занимает минуту. Сначала посмотрите оглавление, затем загрузите копию во временную базу и пересчитайте таблицы:
runuser -u postgres -- pg_restore -l /var/lib/postgresql/appdb.dump | head -n 20
runuser -u postgres -- createdb appdb_restore_test
runuser -u postgres -- pg_restore -d appdb_restore_test /var/lib/postgresql/appdb.dump
runuser -u postgres -- psql -d appdb_restore_test -c "\dt"
runuser -u postgres -- dropdb appdb_restore_test
Если \dt показывает те же таблицы, что и в оригинале, то есть как минимум таблицу probe, копия пригодна. Если же команда сообщает Did not find any relations., значит скопированная база была пустой и тест ничего не доказывает. В appdb тестовую таблицу потом можно убрать командой runuser -u postgres -- psql -d appdb -c "DROP TABLE probe;". Для повседневной работы достаточно записи в /etc/cron.d, которая складывает оба файла с датой в имени и удаляет старые. Важно, чтобы файлы затем покидали сервер. Копия на том же накопителе спасёт от случайного DROP TABLE, но не от отказа оборудования.
Если кластер не запускается
Если служба не стартует, её статус обычно сообщает лишь то, что что-то не удалось. Настоящая причина записана в журнале кластера:
tail -n 30 /var/log/postgresql/postgresql-*-main.log
Одну строку при этом можно спокойно пропустить. Знакомое по первому разделу сообщение FATAL: role "root" does not exist чаще всего оставляет pg_isready: инструмент выполняет попытку подключения от имени текущего системного пользователя, то есть от root, и сервер записывает в журнал неизвестную роль. Код возврата при этом всё равно 0, вывод остаётся accepting connections, и с кластером всё в полном порядке.
На системах с systemd те же строки выдаёт journalctl -u postgresql@17-main --no-pager -n 50. Обратите внимание на юнит с номером версии: postgresql.service это лишь оболочка, которая запускает все кластеры, и она рапортует об успехе даже тогда, когда отдельный кластер не поднялся. Поэтому pg_lsclusters надёжнее как способ проверки.
Три сообщения покрывают большинство случаев. could not bind IPv4 address "0.0.0.0": Address already in use означает, что порт занят другим кластером, смотрите раздел про два кластера. Сообщение No space left on device при записи postmaster.pid означает попросту заполненный накопитель, что подтверждается командой df -h. А ошибки о некорректных правах на каталог данных появляются после необдуманных запусков chmod или chown: каталог /var/lib/postgresql/17/main должен принадлежать пользователю postgres и иметь режим 0700.
И напоследок замечание об эксплуатации: в настройках по умолчанию PostgreSQL работает консервативно и далеко не использует всю оперативную память сервера. Прежде чем крутить shared_buffers и work_mem, включите pg_stat_statements из пакета contrib и посмотрите, какие запросы действительно съедают время. На практике узкое место почти всегда в отсутствующем индексе, а не в параметрах памяти.
Частые вопросы
Какую версию PostgreSQL я получу в своём дистрибутиве?
Почему при запуске psql появляется сообщение «role root does not exist»?
Что означает «no pg_hba.conf entry for host» и как это исправить?
Почему пользователь не может создавать таблицы, хотя доступ к базе данных у него есть?
Нужно ли перезапускать PostgreSQL после изменения pg_hba.conf?
Достаточно ли pg_dump для полной резервной копии?
2026 KernelHost GmbH. Все права защищены. Эта инструкция охраняется авторским правом. Публикация на других сайтах, в том числе частично или в изменённом виде, без нашего письменного согласия не разрешается. Цитирование с указанием источника и активной ссылкой мы приветствуем.

