Погодин Евгений — ИТ Заметки
🐧Linux Обновлено 04.11.2026

Linux для админа Windows 13. PostgreSQL и MySQL: установка, роли, резервные копии

Note

Материал сверен с официальной документацией (Ubuntu Server, man-страницы и документация проектов; ссылки — в конце статьи). Примеры вывода — иллюстрации: на вашем сервере значения и формат могут отличаться. Перед работой на боевом сервере проверьте команды на тестовой машине.

Почти любое приложение хранит данные в базе. В Windows-среде это чаще всего SQL Server с консолью SSMS (SQL Server Management Studio), а на Linux администратор работает с PostgreSQL или MySQL из терминала. В этой статье вы:

  • установите PostgreSQL и MySQL и поймёте, чем сокет отличается от сетевого порта;
  • создадите пользователя и базу для приложения и зададите пароль так, чтобы он не попал в историю команд;
  • оставите сервер доступным только локально и узнаете, как безопасно открыть доступ другому серверу;
  • сделаете копию базы и, главное, проверите, что из неё можно восстановить данные.
Задача SQL Server PostgreSQL MySQL
Консоль управления SSMS, sqlcmd psql mysql
Администратор сервера sa роль postgres root@localhost
Вход без пароля Windows-аутентификация peer auth_socket
Вход с паролем SQL Server authentication scram-sha-256 caching_sha2_password
Копия базы BACKUP DATABASE, файл .bak pg_dump mysqldump
Восстановление RESTORE DATABASE pg_restore, psql mysql
Расписание задания SQL Server Agent cron, таймеры systemd то же

Что нужно знать заранее

Warning

Адреса этой серии учебные (192.168.10.20 для lnx1, 192.168.10.21 для lnx2): подставляйте адреса своей сети. Примеры меняют конфигурацию баз и брандмауэра и создают тестовые базы. Выполняйте их на тестовой виртуальной машине (ВМ), держите её консоль открытой и не работайте на базе с настоящими данными.

Как клиенты попадают в базу

СУБД (система управления базами данных) — серверная программа, которая хранит данные в базах и выполняет запросы на языке SQL (Structured Query Language). Клиентом выступает приложение или консоль администратора. Подключиться можно двумя способами:

  • Unix-сокет — специальный файл, через который программы одного компьютера общаются без сети. Порт не нужен, а сервер узнаёт у ядра, какой пользователь операционной системы (ОС) подключился.
  • TCP-порт — как у любой сетевой службы: PostgreSQL по умолчанию слушает 5432, MySQL — 3306.

Из первого способа вытекает метод входа peer (в MySQL он называется auth_socket): сервер сверяет имя пользователя ОС с именем в базе и пускает без пароля. Это похоже на Windows-аутентификацию: вас уже проверила система. По сети peer недоступен, там нужен пароль. Ubuntu настраивает PostgreSQL именно так: по сокету peer, по TCP scram-sha-256 (проверка пароля по схеме «вызов-ответ», сам пароль по сети не передаётся). MySQL по умолчанию пускает локального root через auth_socket.

В документации Ubuntu Server есть руководства по PostgreSQL и MySQL, их мы и разбираем. Номер версии зависит от выпуска Ubuntu: на 24.04 LTS клиент PostgreSQL — версии 16 (так указано в man-странице psql для 24.04). Свои версии покажут psql --version и mysql --version. Ссылки в конце статьи ведут на документацию PostgreSQL 16 и ветки MySQL 8.0. Для Ubuntu 24.04 LTS; в 26.04 LTS пакеты новее: проверьте apt policy postgresql, apt policy mysql-server и документацию выпуска.

PostgreSQL

Установка и проверка

sudo apt install postgresql
systemctl status postgresql
pg_lsclusters
sudo ss -tlnp | grep postgres

Служба называется postgresql. Кластер — один экземпляр PostgreSQL со своим каталогом данных и портом; при установке создаётся кластер main, а pg_lsclusters показывает версию, имя, порт и состояние кластеров. Служба postgresql управляет всеми кластерами сразу. Настройки кластера лежат в /etc/postgresql/<ВЕРСИЯ>/main/: файлы postgresql.conf и pg_hba.conf; вместо <ВЕРСИЯ> подставьте номер из ls /etc/postgresql. Последняя команда должна показать порт 5432 только на 127.0.0.1 (возможно, и на [::1]): по умолчанию PostgreSQL слушает только локальный адрес.

Если PostgreSQL на сервере уже есть (например, для Zabbix), пропустите установку и не трогайте чужие базы: перезапуск службы в разделе про доступ из сети остановит и их.

Роль и база для приложения

В системе есть пользователь ОС postgres и одноимённая роль-суперпользователь (суперпользователь обходит все ограничения доступа). Войти в консоль psql под ним можно без пароля, через сокет и peer:

sudo -u postgres psql

Если psql (или другая команда от имени postgres) пишет could not change directory to ...: Permission denied, это предупреждение: пользователь postgres не может войти в ваш домашний каталог, а сама команда выполняется. Чтобы не видеть его, сначала перейдите в общий каталог: cd /tmp.

В приглашении postgres=# создайте роль и базу:

CREATE ROLE appuser LOGIN;
\password appuser
CREATE DATABASE appdb OWNER appuser;
\l
\du
\q

Что здесь происходит:

  • Роль (role) в PostgreSQL — и пользователь, и группа. Войти может только роль с атрибутом LOGIN; команда CREATE USER — то же самое, что CREATE ROLE ... LOGIN.
  • \password запрашивает пароль у вас, шифрует его на стороне клиента и отправляет серверу. Пароль не попадает ни в историю команд, ни в журнал сервера. Форма CREATE ROLE ... PASSWORD 'секрет' отправляет пароль открытым текстом, и он может остаться и в истории клиента, и в журнале.
  • OWNER appuser делает роль владельцем базы. В PostgreSQL 16 схемой public (пространством имён, куда по умолчанию попадают таблицы) распоряжается владелец базы, поэтому приложению больше ничего выдавать не нужно.
  • \l показывает базы, \du — роли, \q выходит из консоли.

Если роль или база уже есть (вы повторяете шаги), сервер ответит ошибкой «уже существует»: это безопасно.

Подключение и файл ~/.pgpass

Приложение будет подключаться как appuser. Для peer нужен пользователь ОС с тем же именем, а такого нет, поэтому подключаемся по TCP к локальному адресу:

psql -h 127.0.0.1 -U appuser appdb

Пароль спросят. Создайте тестовую таблицу, чтобы потом было что копировать:

CREATE TABLE notes (id integer PRIMARY KEY, body text NOT NULL);
INSERT INTO notes VALUES (1, 'first'), (2, 'second');
SELECT * FROM notes;
\q

Чтобы скрипты не спрашивали пароль, используют файл ~/.pgpass: одна строка вида хост:порт:база:роль:пароль. На Unix права должны запрещать любой доступ группе и остальным (0600), иначе файл игнорируется. Создайте файл сразу с правами 600 и только потом впишите пароль редактором (не echo: пароль остался бы в истории). Если ~/.pgpass у вас уже есть, не затирайте его: первая команда создаёт файл только при его отсутствии, вторая закрывает права:

[ -e ~/.pgpass ] || install -m 600 /dev/null ~/.pgpass
chmod 600 ~/.pgpass
nano ~/.pgpass
127.0.0.1:5432:appdb:appuser:<ПАРОЛЬ>

Проверка без запроса пароля (-w запрещает его спрашивать):

psql -h 127.0.0.1 -U appuser -w appdb -c '\dt'

Кто и откуда: pg_hba.conf

Правила входа хранятся в pg_hba.conf (HBA — host-based authentication). Строка состоит из типа подключения (local — сокет, host — TCP, hostssl — TCP только с шифрованием TLS, Transport Layer Security), базы, роли, адреса клиента и метода. Пример записей в этом формате:

# TYPE   DATABASE  USER     ADDRESS        METHOD
local    all       postgres                peer
host     appdb     appuser  127.0.0.1/32   scram-sha-256

Сервер проходит строки сверху вниз и применяет первую подходящую. Если она отказала, остальные не проверяются; если не подошла ни одна, доступ закрыт. Поэтому узкие правила ставят выше широких. Файл читается при запуске и при перечитывании настроек. Разбор файла проверяют запросом к представлению pg_hba_file_rules (в консоли psql под postgres): оно показывает разбор файла на диске, ещё не применённого сервером, а в столбце error видны проблемные строки.

SELECT line_number, type, database, user_name, address, auth_method, error
FROM pg_hba_file_rules;
SELECT pg_reload_conf();

Второй запрос заставляет сервер перечитать настройки.

MySQL

Установка и проверка

sudo apt install mysql-server
sudo systemctl status mysql
sudo ss -tap | grep mysql

Служба называется mysql. Пример вывода последней команды из документации Ubuntu:

LISTEN 0 151 127.0.0.1:mysql 0.0.0.0:* users:(("mysqld",pid=149190,fd=29))
LISTEN 0 70  *:33060         *:*       users:(("mysqld",pid=149190,fd=32))

Первая строка — порт 3306 только на 127.0.0.1: адрес задаёт директива bind-address в /etc/mysql/mysql.conf.d/mysqld.cnf. Вторая строка примера — порт 33060 (дополнительный протокол X) на всех адресах. Но в mysqld.cnf пакета Ubuntu 24.04 стоит и mysqlx-bind-address = 127.0.0.1, поэтому у вас, скорее всего, будет 127.0.0.1:33060. Проверьте: grep bind-address /etc/mysql/mysql.conf.d/mysqld.cnf. В любом случае порт 33060 в брандмауэре не открывайте.

Локальный root входит через auth_socket, а пользователей приложений создают командами SQL; в этом сценарии скрипт mysql_secure_installation, который советуют многие инструкции, не обязателен.

База, пользователь и права

Консоль администратора открывается без пароля, потому что вы входите как root ОС:

sudo mysql
CREATE DATABASE appdb;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY RANDOM PASSWORD;
GRANT ALL ON appdb.* TO 'appuser'@'localhost';
SHOW GRANTS FOR 'appuser'@'localhost';
  • Учётная запись в MySQL — пара «имя@хост»: 'appuser'@'localhost' — пользователь, подключающийся с этого же сервера. Если хост не указать, подразумевается %, то есть любой адрес, поэтому всегда пишите его явно.
  • RANDOM PASSWORD (MySQL 8.0.18 и новее) заставляет сервер придумать пароль и один раз показать его в результате команды. Скопируйте его в файл с паролем (ниже). Если задавать пароль вручную (IDENTIFIED BY '<ПАРОЛЬ>'), он окажется в тексте команды, а значит, может остаться в истории клиента. По умолчанию пароль хранит плагин caching_sha2_password.
  • Новая запись не имеет прав. GRANT ALL ON appdb.* даёт все права на одну базу. Приложению, которое не меняет структуру таблиц, хватит и SELECT, INSERT, UPDATE, DELETE.

Подключение и файл с паролем

mysql -u appuser -p appdb

Опция -p без значения запрашивает пароль. Писать -pПАРОЛЬ нельзя: на некоторых системах команда с паролем видна другим пользователям в списке процессов (ps). Для скриптов пароль кладут в раздел [client] файла параметров с правами 600. Файл ~/.my.cnf читают все клиентские программы, а мы ходим в базу и под root, и под appuser, поэтому заведём отдельный файл и укажем его опцией --defaults-extra-file (она должна стоять первой; путь пишите полностью, без ~). Сначала создайте файл с правами 600:

[ -e ~/appuser.cnf ] || install -m 600 /dev/null ~/appuser.cnf
chmod 600 ~/appuser.cnf
nano ~/appuser.cnf

Содержимое файла:

[client]
user=appuser
password=<ПАРОЛЬ>

Подключение:

mysql --defaults-extra-file=/home/admin-lab/appuser.cnf appdb

В приглашении mysql> создайте тестовую таблицу:

CREATE TABLE notes (id INT PRIMARY KEY, body VARCHAR(100) NOT NULL);
INSERT INTO notes VALUES (1, 'first'), (2, 'second');
SELECT * FROM notes;

А MariaDB?

В документации Ubuntu Server MariaDB не описана, поэтому команды выше для неё не сверены с документацией. По документации проекта, клиент для выгрузки дампов называется mariadb-dump; прежнее имя mysqldump остаётся ссылкой на него, но с версии 11.0 оно считается устаревшим, поэтому в новых скриптах пишите mariadb-dump. Если выберете MariaDB, ставьте пакет mariadb-server, смотрите версию в apt policy mariadb-server и сверяйте каждую команду с документацией MariaDB.

Доступ с другого сервера: только если это нужно

Лучший вариант — вообще не открывать порт. Приложение на том же сервере ходит через сокет или 127.0.0.1, а администратор с PC1 подключается через туннель SSH из статьи про SSH:

ssh -N -L 15432:127.0.0.1:5432 lnx1

Порт 15432 на вашем компьютере теперь ведёт к порту 5432 сервера lnx1; клиент подключается к localhost:15432. Окно с туннелем оставьте открытым. Алиас lnx1 взят из файла config статьи про SSH; без него команда выглядит так: ssh -N -L 15432:127.0.0.1:5432 admin-lab@192.168.10.20.

Если приложению на lnx2 необходимо ходить на базу по сети, нужны три независимых ограничения: адрес прослушивания, правило входа и брандмауэр. Для PostgreSQL порядок такой.

Шаг 1. Копии файлов. Это точка отката; <ВЕРСИЯ> — номер из ls /etc/postgresql:

sudo cp -a /etc/postgresql/<ВЕРСИЯ>/main/postgresql.conf{,.bak}
sudo cp -a /etc/postgresql/<ВЕРСИЯ>/main/pg_hba.conf{,.bak}

Шаг 2. Адрес прослушивания. В postgresql.conf замените строку #listen_addresses = 'localhost' списком конкретных адресов, а не '*':

listen_addresses = 'localhost,192.168.10.20'

Шаг 3. Правило входа. В конец pg_hba.conf добавьте строку для одной роли, одной базы и одного клиента. hostssl отклонит подключение без шифрования:

hostssl  appdb  appuser  192.168.10.21/32  scram-sha-256

Шаг 4. Проверка и перезапуск. Проверьте разбор файла запросом к pg_hba_file_rules (см. выше). Затем перезапустите службу: смена listen_addresses требует перезапуска, перечитывания мало.

sudo systemctl restart postgresql.service

Шаг 5. Брандмауэр. На lnx1 ufw включён по статье про сеть (общее состояние стенда описано во врезке «Состояние стенда» в статье про Ansible); проверьте sudo ufw status. Откройте порт только для этого клиента:

sudo ufw allow proto tcp from 192.168.10.21 to any port 5432

Шаг 6. Проверка с клиента. На lnx2 (там нужен пакет postgresql-client) выполните psql -h 192.168.10.20 -U appuser appdb; на lnx1 убедитесь по sudo ss -tlnp, что порт слушает только указанные адреса.

Откат. Верните файлы из копий (sudo cp -a /etc/postgresql/<ВЕРСИЯ>/main/pg_hba.conf.bak /etc/postgresql/<ВЕРСИЯ>/main/pg_hba.conf, то же для postgresql.conf), перезапустите службу и повторите правило ufw с delete: sudo ufw delete allow proto tcp from 192.168.10.21 to any port 5432.

Сертификат для TLS создаётся при установке (пакетом ssl-cert), и по документации Ubuntu он подходит для тестов; для боевого сервера нужен сертификат доверенного центра сертификации.

В MySQL те же три слоя, но в других местах. Сначала скопируйте файл настроек: sudo cp -a /etc/mysql/mysql.conf.d/mysqld.cnf{,.bak}. Затем задайте в нём список адресов bind-address = 127.0.0.1,192.168.10.20, перезапустите службу (sudo systemctl restart mysql.service) и создайте отдельную запись для адреса клиента с обязательным шифрованием:

CREATE USER 'appuser'@'192.168.10.21' IDENTIFIED BY RANDOM PASSWORD REQUIRE SSL;
GRANT ALL ON appdb.* TO 'appuser'@'192.168.10.21';

Откройте порт 3306 только для этого клиента (sudo ufw allow proto tcp from 192.168.10.21 to any port 3306) и проверьте по sudo ss -tlnp | grep mysqld, что сервер слушает только нужные адреса. Проверки файла перед перезапуском, как sshd -t, в руководстве Ubuntu для MySQL нет: держите консоль ВМ открытой, а при неудачном запуске смотрите sudo journalctl -u mysql. Откат: верните mysqld.cnf из копии, перезапустите службу, удалите запись командой DROP USER 'appuser'@'192.168.10.21'; и правило ufw.

Порты 5432, 3306 и 33060 в интернет не публикуют ни при каких условиях: открытый порт базы быстро находят сканеры. Порт, опубликованный контейнером Docker, обходит ufw (статья про Docker).

Резервные копии

Копия, которую не пробовали восстановить, — только надежда. Мы сделаем дамп и загрузим его в соседнюю базу. Дамп содержит данные, поэтому ручные копии кладём в закрытый каталог (повторный запуск команды безопасен):

mkdir -p -m 700 ~/dumps

Это каталог для проверки и разовых копий; плановые дампы держат в /var/backups/db (об этом ниже). Дамп — не копия файлов данных, как .bak в SQL Server, а логическое описание: команды, воссоздающие базу. Его можно загрузить и в другую версию сервера. Копирование каталога данных работающего сервера дамп не заменяет: такая копия привязана к версии и бывает несогласованной.

PostgreSQL

Запускаем программы от имени postgres через peer: пароль не нужен.

sudo -u postgres pg_dump -Fc appdb > ~/dumps/appdb.dump
sudo -u postgres pg_dumpall --globals-only > ~/dumps/globals.sql
chmod 600 ~/dumps/*
  • pg_dump делает согласованный снимок одной базы и не блокирует работу других клиентов. Он пишет в стандартный вывод, поэтому результат перенаправляют в файл.
  • Формат -Fc (custom) — сжатый архив для pg_restore, из которого можно восстановить отдельные части. Без -F получится текстовый SQL-скрипт для psql. Формат directory (-Fd -f каталог) умеет выгружать в несколько потоков (-j).
  • pg_dump не сохраняет роли: они общие для всего сервера. Их выгружает pg_dumpall --globals-only; в файле лежат хеши паролей, поэтому права 600.

Проверим, что архив читается, и восстановим его в новую базу, не трогая рабочую:

pg_restore --list ~/dumps/appdb.dump | head
sudo -u postgres createdb -T template0 appdb_restore
sudo -u postgres pg_restore -d appdb_restore --exit-on-error \
  < ~/dumps/appdb.dump
sudo -u postgres psql -d appdb_restore -c 'SELECT count(*) FROM notes;'

Пустую базу создают из template0, чтобы в неё не попало ничего лишнего из template1. Опция --exit-on-error останавливает восстановление на первой ошибке: по умолчанию pg_restore продолжает работу. Ожидаемый результат — две строки в notes. Тестовую базу после проверки удалите, сверив имя:

sudo -u postgres psql -c 'DROP DATABASE appdb_restore;'

DROP DATABASE необратима. Перед настоящим восстановлением остановите приложение, убедитесь, что роли-владельцы уже существуют (иначе объекты не получат прежних владельцев), создайте пустую базу из template0 и загрузите архив. Текстовый дамп загружают так: psql -X --set ON_ERROR_STOP=on -1 имя_базы < файл. После загрузки полезно выполнить ANALYZE, чтобы планировщик запросов получил статистику.

MySQL

sudo mysqldump --single-transaction --routines --events appdb \
  > ~/dumps/appdb-mysql.sql
chmod 600 ~/dumps/appdb-mysql.sql
  • --single-transaction берёт согласованный снимок без блокировки приложений, но только для таблиц InnoDB (это основной движок хранения MySQL с поддержкой транзакций; о движках рассказывает документация Ubuntu).
  • --routines и --events добавляют хранимые процедуры и события: по умолчанию их в дамп не кладут.
  • Без опции --databases в файле нет команды CREATE DATABASE, поэтому базу создают заранее. Учётные записи хранятся в системной базе mysql и в дамп одной базы не попадают: запишите команды CREATE USER и GRANT отдельно.

Восстановление в тестовую базу и проверка:

sudo mysql -e 'CREATE DATABASE appdb_restore'
sudo mysql appdb_restore < ~/dumps/appdb-mysql.sql
sudo mysql -e 'SELECT COUNT(*) FROM appdb_restore.notes'
sudo mysql -e 'DROP DATABASE appdb_restore'

Для больших баз Ubuntu советует физическое копирование Percona XtraBackup; это отдельная тема.

Когда и куда

Ручные дампы в ~/dumps годятся для проверки. Боевую копию запускают по расписанию (cron или таймер systemd), кладут в /var/backups/db (владелец root, права 700) и отправляют на другой сервер: готовые команды плановой выгрузки, ротацию и оповещение о сбое даёт статья про резервное копирование: tar, rsync и restic. Правило хранения «3-2-1» описано в статье Резервное копирование 3-2-1.

Типичные ошибки и недоразумения

  • Роль не входит. Роль создана без LOGIN, либо вы подключаетесь по сокету под ОС-пользователем с другим именем: peer требует совпадения имён. Подключайтесь по TCP (-h 127.0.0.1) или используйте sudo -u.
  • Пароль в командной строке. mysql -pПАРОЛЬ виден в списке процессов, а CREATE ROLE ... PASSWORD оставляет пароль в истории. Используйте \password, запрос -p, RANDOM PASSWORD и файлы с паролем (~/.pgpass, файл параметров MySQL) с правами 600.
  • *`listen_addresses = ''илиbind-address = 0.0.0.0` без других мер.** Сервер принимает подключения на всех интерфейсах. Перечислите нужные адреса, ограничьте правило входа и откройте порт в ufw только для одного клиента.
  • Слишком широкое правило в pg_hba.conf. Строка с 0.0.0.0/0 или методом trust выше узкого правила отменит его: действует первая подходящая строка.
  • 'appuser'@'%' по забывчивости. Запись без хоста в MySQL разрешает подключение с любого адреса.
  • Дамп сделали, но не проверили. Единственная проверка копии — восстановление: в тестовую базу, с проверкой данных.
  • Загрузка чужого дампа. Восстановление выполняет команды, которые выбрал автор дампа, с правами восстанавливающего. Просматривайте дампы из недоверенных источников до загрузки.

Проверьте себя

  1. Почему psql -U appuser appdb на сервере может отказать, а psql -h 127.0.0.1 -U appuser appdb работает? Без -h клиент идёт по сокету, где действует peer: имя пользователя ОС должно совпасть с ролью, а ОС-пользователя appuser нет. С -h подключение идёт по TCP, где проверяется пароль.
  2. Что произойдёт, если в pg_hba.conf выше узкого правила стоит строка, разрешающая всем trust? Сервер применяет первую подходящую строку и дальше не смотрит, поэтому узкое правило не сработает, а доступ получат все, кто подходит под широкую строку.
  3. Как задать пароль роли так, чтобы он не остался в истории команд и журналах? В psql командой \password роль (в MySQL — IDENTIFIED BY RANDOM PASSWORD); для скриптов — файл ~/.pgpass или файл параметров MySQL с правами 600.
  4. Какие три ограничения нужны, прежде чем разрешить подключение с другого сервера? Адрес прослушивания (listen_addresses или bind-address) только для нужного интерфейса, правило входа для одной роли и клиента (pg_hba.conf или запись 'роль'@'хост') и правило брандмауэра, открывающее порт только этому клиенту.
  5. Как убедиться, что дамп пригоден? Восстановить его в отдельную тестовую базу, сравнить данные и после проверки удалить тестовую базу.

Что дальше

Источники

Ещё по теме «Linux»