# База данных на VPS: MySQL или PostgreSQL без утечек в интернет

> Как поставить MySQL или PostgreSQL на VPS, оставить базу доступной только локально, не попасть в ловушку Docker с портами и настроить резервные копии дампом.

- Рубрика: Гайды по играм
- Игра: VPS
- Опубликовано: 2026-11-13T18:40:00+03:00
- Обновлено: 2026-11-13T18:40:00+03:00
- Адрес: https://blog.egnetwork.ru/vps-baza-dannykh-mysql-postgresql
- Автор: Команда EGN

База данных на 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: шаги

1. Установите сервер:

```bash
sudo apt update
sudo apt install -y postgresql
```

2. Проверьте, на каких адресах слушает PostgreSQL. По умолчанию в Ubuntu это только localhost, поэтому строка `listen_addresses` в конфиге закомментирована (значение по умолчанию `localhost`). Если она раскомментирована и содержит `'*'`, база слушает все адреса:

```bash
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` и перезапустите сервер.

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

```sql
CREATE USER app WITH PASSWORD 'замените-на-длинный-пароль';
CREATE DATABASE app OWNER app;
```

Выполняется от имени пользователя postgres: `sudo -u postgres psql`.

4. Приложение подключается по строке вида:

```properties
DATABASE_URL=postgresql://app:замените-на-длинный-пароль@127.0.0.1:5432/app
```

## MySQL: шаги

1. Установите сервер:

```bash
sudo apt update
sudo apt install -y mysql-server
```

2. Проверьте адрес прослушивания в конфиге. Откройте `/etc/mysql/mysql.conf.d/mysqld.cnf` и найдите строку `bind-address`. Для локальной базы она должна быть `127.0.0.1`. Затем перезапустите сервер:

```bash
sudo systemctl restart mysql
sudo ss -tlnp | grep 3306
```

3. Создайте базу и пользователя, которому доступ разрешён только с localhost:

```sql
CREATE DATABASE app;
CREATE USER 'app'@'localhost' IDENTIFIED BY 'замените-на-длинный-пароль';
GRANT ALL PRIVILEGES ON app.* TO 'app'@'localhost';
```

![Схема: база доступна только локально, опубликованный порт Docker обходит ufw](https://blog.egnetwork.ru/media/600)

## Ловушка Docker

Docker записывает свои правила в iptables раньше, чем их применяет ufw. Поэтому правило `ufw deny 3306` не спасает, если контейнер опубликовал порт командой `-p 3306:3306`. Порт открывается на всех адресах, и база оказывается в интернете.

Исправление одно: указывать адрес в публикации портов. В `docker-compose.yml` это выглядит так:

```yaml
services:
  db:
    image: postgres:16
    ports:
      - "127.0.0.1:5432:5432"
```

Тогда порт доступен только с самого VPS, а приложение, которое живёт в той же сети Docker, подключается по имени сервиса. Подробнее про связку контейнеров в статье [Docker Compose на VPS для нескольких сервисов](https://blog.egnetwork.ru/vps-docker-compose-neskolko-servisov).

Если базе снаружи не нужен доступ, лучше не публиковать порт вовсе. Уберите блок `ports` полностью. В режиме «Свои правила» облачного фаервола (вкладка «Фаервол» карточки VPS) порт базы тоже не нужно разрешать, но не полагайтесь только на него и проверяйте `ss -tlnp`.

## Доступ с компьютера: туннель вместо открытого порта

Если нужно подключиться к базе со своего компьютера, не открывайте порт. Используйте SSH-туннель:

```bash
ssh -L 5432:127.0.0.1:5432 user@ваш-vps
```

После этого в клиенте БД подключайтесь к `127.0.0.1:5432` на своём компьютере. Трафик пойдёт через защищённое SSH-соединение.

## Резервные копии дампом

Сначала определите, что вы защищаете: данные или структуру. Для ежедневных копий подойдёт дамп:

```bash
sudo -u postgres pg_dump app | gzip | sudo tee /var/backups/db/app-$(date +%F).sql.gz > /dev/null
```

Для MySQL используйте `--single-transaction`, чтобы дамп InnoDB-таблиц был согласованным без остановки записи:

```bash
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](https://blog.egnetwork.ru/vps-bekapy-snapshot-restic).

Снапшот VPS тоже защищает базу, но он снимается на работающем сервере, как после внезапного отключения питания. Для баз данных надёжнее ненадолго остановить запись или использовать дамп: об этом прямо сказано в подсказке на вкладке «Бэкапы» кабинета EGN (ниже).

## Примеры

**Приложение и база на одном VPS.** Самый частый вариант. База слушает 127.0.0.1, приложение подключается локально, снаружи открыты только 80 и 443.

**Статистика игрового сервера.** Плагин или скрипт пишет данные в базу локально, а сайт статистики читает их через то же приложение. Порт базы не нужен наружу.

**Разработчик хочет работать с базой.** Используйте SSH-туннель, как описано выше, и не открывайте порт для всех.

## Как восстановить из дампа

Копия без проверки восстановления — это не резерв. Восстановите дамп на отдельной базе и сравните количество строк в главных таблицах. Для PostgreSQL:

```bash
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:

```bash
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 это выглядит так:

```sql
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 находятся на вкладке «Бэкапы» карточки сервера. Там есть два вида копий: «Горячее» с быстрым восстановлением и «Холодное», которое дешевле, но восстанавливается медленнее. Ниже указано, что копия снимается на работающем сервере и поэтому для базы лучше дополнительно сделать дамп.

![Вкладка «Бэкапы» в кабинете: горячее и холодное хранение копий](https://blog.egnetwork.ru/media/598)

На этой же вкладке есть блок «Копии по расписанию». Пока он выключен, копии делаются только вручную, о них легко забыть. Проверьте этот пункт сразу после заказа, а не через месяц.

## Частые ошибки

- **Порт 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](https://egnetwork.ru/)

---

Материал EGN (blog.egnetwork.ru), обновлено 13 ноября 2026; при цитировании указывайте ссылку.
