База данных на VPS: MySQL или PostgreSQL без утечек в интернет
Как поставить MySQL или PostgreSQL на VPS, оставить базу доступной только локально, не попасть в ловушку Docker с портами и настроить резервные копии дампом.
Содержание 19
- Коротко
- Почему база опасна наружу
- PostgreSQL: шаги
- MySQL: шаги
- Ловушка Docker
- Доступ с компьютера: туннель вместо открытого порта
- Резервные копии дампом
- Примеры
- Как восстановить из дампа
- Симптом → причина → решение
- Пример: отдельный пользователь с правом только чтения
- Как сделать в кабинете EGN
- Частые ошибки
- Итог
- Вопросы и ответы
- Какую базу выбрать: PostgreSQL или MySQL?
- Можно ли открыть порт базы только для своего IP?
- Нужен ли отдельный пользователь для каждого приложения?
- Как часто делать дамп?
База данных на VPS — самая частая причина утечек в игровых и веб-проектах. Люди ставят PostgreSQL или MySQL, открывают порт, чтобы подключиться с компьютера, и забывают закрыть его. Через несколько дней в логах появляются сотни попыток входа. Правило простое: база слушает только свой сервер, а доступ извне, если он нужен, идёт через туннель.
Коротко
Поставьте PostgreSQL или MySQL из репозитория Ubuntu, оставьте адрес прослушивания 127.0.0.1 и не открывайте порт 5432 или 3306 в фаерволе. Если базу запускаете в Docker, публикуйте порт с адресом 127.0.0.1:5432:5432, иначе Docker обойдёт правила ufw. Дампы делайте по расписанию командами pg_dump или mysqldump.
Почему база опасна наружу
Базы данных рассчитаны на доверенную сеть, а не на интернет. У них есть логины и пароли, но автоматические сканеры каждый день перебирают стандартные учётные записи. Если пароль слабый или его вообще нет, база попадает в ботнеты за часы.
Опасность не в том, что база открыта, а в том, что её не видно владельцу. Поэтому проверка порта — обязательный шаг после установки.
PostgreSQL: шаги
- Установите сервер:
sudo apt update
sudo apt install -y postgresql- Проверьте, на каких адресах слушает PostgreSQL. По умолчанию в Ubuntu это только localhost, поэтому строка
listen_addressesв конфиге закомментирована (значение по умолчаниюlocalhost). Если она раскомментирована и содержит'*', база слушает все адреса:
sudo grep -n "listen_addresses" /etc/postgresql/*/main/postgresql.conf
sudo ss -tlnp | grep 5432Ожидаемый результат — адрес 127.0.0.1:5432 или [::1]:5432. Если там 0.0.0.0:5432, исправьте listen_addresses и перезапустите сервер.
- Создайте пользователя и базу. Пароль замените на свой длинный, в примере он условный:
CREATE USER app WITH PASSWORD 'замените-на-длинный-пароль';
CREATE DATABASE app OWNER app;Выполняется от имени пользователя postgres: sudo -u postgres psql.
- Приложение подключается по строке вида:
DATABASE_URL=postgresql://app:замените-на-длинный-пароль@127.0.0.1:5432/appMySQL: шаги
- Установите сервер:
sudo apt update
sudo apt install -y mysql-server- Проверьте адрес прослушивания в конфиге. Откройте
/etc/mysql/mysql.conf.d/mysqld.cnfи найдите строкуbind-address. Для локальной базы она должна быть127.0.0.1. Затем перезапустите сервер:
sudo systemctl restart mysql
sudo ss -tlnp | grep 3306- Создайте базу и пользователя, которому доступ разрешён только с localhost:
CREATE DATABASE app;
CREATE USER 'app'@'localhost' IDENTIFIED BY 'замените-на-длинный-пароль';
GRANT ALL PRIVILEGES ON app.* TO 'app'@'localhost';Ловушка Docker
Docker записывает свои правила в iptables раньше, чем их применяет ufw. Поэтому правило ufw deny 3306 не спасает, если контейнер опубликовал порт командой -p 3306:3306. Порт открывается на всех адресах, и база оказывается в интернете.
Исправление одно: указывать адрес в публикации портов. В docker-compose.yml это выглядит так:
services:
db:
image: postgres:16
ports:
- "127.0.0.1:5432:5432"Тогда порт доступен только с самого VPS, а приложение, которое живёт в той же сети Docker, подключается по имени сервиса. Подробнее про связку контейнеров в статье Docker Compose на VPS для нескольких сервисов.
Если базе снаружи не нужен доступ, лучше не публиковать порт вовсе. Уберите блок ports полностью. В режиме «Свои правила» облачного фаервола (вкладка «Фаервол» карточки VPS) порт базы тоже не нужно разрешать, но не полагайтесь только на него и проверяйте ss -tlnp.
Доступ с компьютера: туннель вместо открытого порта
Если нужно подключиться к базе со своего компьютера, не открывайте порт. Используйте SSH-туннель:
ssh -L 5432:127.0.0.1:5432 user@ваш-vpsПосле этого в клиенте БД подключайтесь к 127.0.0.1:5432 на своём компьютере. Трафик пойдёт через защищённое SSH-соединение.
Резервные копии дампом
Сначала определите, что вы защищаете: данные или структуру. Для ежедневных копий подойдёт дамп:
sudo -u postgres pg_dump app | gzip | sudo tee /var/backups/db/app-$(date +%F).sql.gz > /dev/nullДля MySQL используйте --single-transaction, чтобы дамп InnoDB-таблиц был согласованным без остановки записи:
sudo mysqldump --single-transaction app | gzip | sudo tee /var/backups/db/app-$(date +%F).sql.gz > /dev/nullКаталог для дампов заранее создайте и закройте от чужих (sudo mkdir -p /var/backups/db && sudo chmod 700 /var/backups/db). Перенаправление > выполняет ваша оболочка, а не sudo, поэтому запись идёт через sudo tee. Копии храните не на том же диске, а в S3 или через restic, как описано в статье Бэкапы VPS: снапшоты, S3 и restic.
Снапшот VPS тоже защищает базу, но он снимается на работающем сервере, как после внезапного отключения питания. Для баз данных надёжнее ненадолго остановить запись или использовать дамп: об этом прямо сказано в подсказке на вкладке «Бэкапы» кабинета EGN (ниже).
Примеры
Приложение и база на одном VPS. Самый частый вариант. База слушает 127.0.0.1, приложение подключается локально, снаружи открыты только 80 и 443.
Статистика игрового сервера. Плагин или скрипт пишет данные в базу локально, а сайт статистики читает их через то же приложение. Порт базы не нужен наружу.
Разработчик хочет работать с базой. Используйте SSH-туннель, как описано выше, и не открывайте порт для всех.
Как восстановить из дампа
Копия без проверки восстановления — это не резерв. Восстановите дамп на отдельной базе и сравните количество строк в главных таблицах. Для PostgreSQL:
sudo -u postgres createdb app_test
gunzip -c /var/backups/db/app-2026-11-13.sql.gz | sudo -u postgres psql app_test
sudo -u postgres psql -d app_test -c "SELECT count(*) FROM users;"Для MySQL:
sudo mysql -e "CREATE DATABASE app_test;"
gunzip -c /var/backups/db/app-2026-11-13.sql.gz | sudo mysql app_test
sudo mysql -e "SELECT COUNT(*) FROM app_test.users;"Имя таблицы users подставьте своё. Если числа совпадают с основной базой на момент дампа, копия пригодна. После проверки удалите тестовую базу, чтобы не занимать место.
Симптом → причина → решение
| Симптом | Частая причина | Что сделать |
|---|---|---|
FATAL: password authentication failed |
Неверный пароль или пользователь не имеет доступа к базе | Проверьте строку DATABASE_URL, при необходимости задайте пароль через ALTER USER |
Connection refused на 5432 или 3306 |
Сервер не запущен или слушает другой адрес | systemctl status postgresql или mysql, затем ss -tlnp |
| База работает медленно после роста данных | Нет индексов или таблица без ограничения выборки | Смотрите медленные запросы в журнале и добавляйте индексы |
| Диск заполнился | Логи и дампы хранятся на системном диске | Перенесите дампы в S3 и настройте ротацию логов |
| Docker-контейнер базы не виден извне, хотя должен | Порт опубликован только на 127.0.0.1 | Это правильная схема: подключайтесь через туннель или из той же сети Docker |
| После перезагрузки база не стартует | Служба не включена в автозапуск | sudo systemctl enable postgresql или mysql |
Пример: отдельный пользователь с правом только чтения
Для отчётов или аналитики создайте отдельного пользователя, который не может менять данные. В PostgreSQL это выглядит так:
CREATE USER reporter WITH PASSWORD 'замените-на-длинный-пароль';
GRANT CONNECT ON DATABASE app TO reporter;
GRANT USAGE ON SCHEMA public TO reporter;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO reporter;Такой пользователь подключается через SSH-туннель и не может удалить данные, даже если его строка подключения утекла.
Как сделать в кабинете EGN
Резервные копии VPS в кабинете EGN находятся на вкладке «Бэкапы» карточки сервера. Там есть два вида копий: «Горячее» с быстрым восстановлением и «Холодное», которое дешевле, но восстанавливается медленнее. Ниже указано, что копия снимается на работающем сервере и поэтому для базы лучше дополнительно сделать дамп.
На этой же вкладке есть блок «Копии по расписанию». Пока он выключен, копии делаются только вручную, о них легко забыть. Проверьте этот пункт сразу после заказа, а не через месяц.
Частые ошибки
- Порт 5432 или 3306 открыт в ufw. Закройте его:
sudo ufw statusпокажет правила. Если доступ нужен одному IP, разрешайте только его. - Слабый или пустой пароль пользователя базы. Задайте длинный пароль и ограничьте пользователя только его базой, не выдавайте
ALL PRIVILEGESна всё. -p 3306:3306в Docker. Порт публикуется на все адреса и обходит ufw. Указывайте127.0.0.1:.- Дамп без проверки. Раз в неделю восстанавливайте копию на тестовой базе. Непроверенный дамп — это надежда, а не резерв.
- Дамп хранится на том же VPS. При потере сервера он пропадает вместе с базой.
- Пароль в git. Держите строку подключения в файле окружения с правами 600.
Итог
База данных на VPS работает безопасно, если слушает только локальный адрес, порт не публикуется наружу, а дампы уходят за пределы сервера. Проверяйте ss -tlnp после каждой установки и каждой правки Docker-файла. Если база нужна вашим друзьям или внешнему сервису, используйте туннель или отдельный VPS с ограниченным доступом, а не открытый порт.
Вопросы и ответы
Какую базу выбрать: PostgreSQL или MySQL?
Для нового проекта чаще берут PostgreSQL за строгость типов и расширения. MySQL подходит, если приложение или хостинг уже ориентированы на него.
Можно ли открыть порт базы только для своего IP?
Можно правилом ufw с указанием адреса, например sudo ufw allow from 203.0.113.10 to any port 5432 proto tcp. Но проще и безопаснее SSH-туннель.
Нужен ли отдельный пользователь для каждого приложения?
Да. Каждому приложению выдавайте свою учётную запись с правами только на свою базу.
Как часто делать дамп?
Для активного проекта раз в сутки, для редко меняющихся данных раз в неделю. Частоту выбирайте так, чтобы потеря одного дня не была катастрофой.
Сервер под игры за пару минут — egnetwork.ru
Читать далее
Вся рубрика →Мониторинг ресурсов VPS: htop, iotop и vnstat
Как за несколько минут понять, что тормозит VPS: процессор, память, диск или сеть. Команды htop, iotop, vnstat, free и df с примерами вывода и таблицей симптомов.
Трафик VPS: как посчитать объём и не получить сюрприз в конце месяца
Что считается трафиком, как перевести скорость канала в терабайты за месяц, как читать счётчик входящего и исходящего трафика в кабинете EGN и что делать, если лимит закончился.
IPv6 на VPS: как пользоваться префиксом /64
Что значит /64, как проверить адрес на сервере, назначить дополнительные адреса, настроить ufw для IPv6 и не выпасть из сети. Примеры команд и типичные ошибки.