Удалённый доступ к базе данных: SSH-туннель и TLS
Открыть порт 5432 или 3306 наружу — самый быстрый способ поймать взлом. Базу данных нельзя выставлять в интернет напрямую. Правильные варианты — SSH-туннель и шифрование TLS. Разберём оба подхода на рабочих командах для PostgreSQL и MySQL.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Почему нельзя открывать порт БД наружу
Порты СУБД сканируются ботами непрерывно. Открытый 3306 или 5432 — это перебор паролей, попытки эксплойтов и утечка данных. Базу держат закрытой, а доступ дают через защищённый канал.
Первым делом убедитесь, что СУБД слушает только localhost, если внешний доступ не нужен приложениям на других серверах:
# PostgreSQL, postgresql.conf
listen_addresses = 'localhost'
# MySQL, my.cnf
bind-address = 127.0.0.1
И закройте порты фаерволом на всякий случай:
sudo ufw allow OpenSSH
sudo ufw deny 5432
sudo ufw deny 3306
sudo ufw enable
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
Арендовать VPS для базы данныхSSH-туннель: самый простой способ
SSH-туннель заворачивает трафик БД в уже зашифрованное SSH-соединение. Ничего дополнительно настраивать на сервере не нужно — только доступ по SSH.
Для PostgreSQL пробрасываем локальный порт 6432 на удалённый 5432:
ssh -N -L 6432:localhost:5432 user@SERVER_IP
# в другом терминале подключаемся как к локальной БД:
psql -h 127.0.0.1 -p 6432 -U dbuser dbname
Для MySQL всё аналогично:
ssh -N -L 3307:localhost:3306 user@SERVER_IP
mysql -h 127.0.0.1 -P 3307 -u dbuser -p dbname
Флаг -N означает «не выполнять команду, только пробросить порт». Пока сессия открыта, работает и туннель. Локальный порт (6432, 3307) выбирайте любой свободный — важно лишь, чтобы приложение обращалось именно к нему на 127.0.0.1, а не к реальному порту БД на удалённой машине.
Такой подход хорош тем, что не требует ни единой правки на стороне сервера БД: раз есть SSH-доступ, есть и защищённый канал к базе. Весь трафик уже зашифрован алгоритмами SSH, а аутентификация по ключу надёжнее пароля СУБД. Графические клиенты (DBeaver, TablePlus, pgAdmin) умеют поднимать такой туннель встроенными средствами — достаточно указать SSH-хост, пользователя и ключ в настройках подключения.
Постоянный туннель через autossh и systemd
Для приложения, которое должно держать соединение постоянно, ручной ssh не годится. Используем autossh, который переподнимает туннель при обрыве, и оборачиваем его в systemd.
sudo apt install -y autossh
sudo nano /etc/systemd/system/db-tunnel.service
[Unit]
Description=SSH tunnel to database
After=network.target
[Service]
User=appuser
ExecStart=/usr/bin/autossh -M 0 -N -o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 -L 6432:localhost:5432 user@SERVER_IP
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now db-tunnel
Для беспарольной авторизации заранее настройте ключи SSH (ssh-copy-id), иначе сервис зависнет на запросе пароля.
Вариант с TLS напрямую
Если БД должна принимать внешние подключения (например, реплика или BI-инструмент), включите TLS и разрешите только шифрованные соединения. Для PostgreSQL:
# postgresql.conf
ssl = on
ssl_cert_file = '/etc/postgresql/16/main/server.crt'
ssl_key_file = '/etc/postgresql/16/main/server.key'
В pg_hba.conf используйте hostssl вместо host, чтобы отклонять нешифрованные подключения:
hostssl dbname dbuser CLIENT_IP/32 scram-sha-256
Клиент подключается с требованием проверки сертификата:
psql "host=SERVER_IP dbname=dbname user=dbuser sslmode=verify-full sslrootcert=root.crt"
Режим verify-full здесь принципиален: он не только шифрует канал, но и сверяет сертификат сервера и его имя хоста, закрывая атаку «человек посередине». Даже при прямом TLS-доступе ограничьте круг разрешённых IP в pg_hba.conf или на фаерволе — шифрование защищает канал, но не отменяет необходимости фильтровать, кто вообще может стучаться в порт. Комбинация «список IP + hostssl + сильный пароль или клиентский сертификат» даёт практичный уровень безопасности для боевой базы.
Проверка и частые ошибки
Убедитесь, что снаружи порт БД действительно закрыт, — проверьте с другой машины:
nmap -p 5432,3306 SERVER_IP
# порты должны быть filtered/closed
- Открыли порт в интернет «на время» — боты найдут его за минуты.
- sslmode=require без verify-full — шифрование есть, но защиты от MITM нет.
- Туннель без autossh — оборвался, приложение потеряло БД.
- Пароль вместо ключа в systemd-туннеле — сервис виснет на старте.
Где держать защищённую БД
Root-доступ у MAATRIX позволяет настроить фаервол, SSH-ключи и TLS так, как нужно именно вам. Быстрый NVMe на AMD EPYC не создаёт узкого места при шифровании соединений, а локации UK, США и РФ подходят для доступа из разных стран. Оплата картой РФ, СБП, криптой или токеном MAAT удобна, когда зарубежные провайдеры недоступны, а ежедневные бэкапы страхуют данные.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
Арендовать VPS для базы данныхОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
SSH-туннель или TLS — что выбрать?
Для доступа администратора и разработчика проще SSH-туннель — не нужны сертификаты. Для постоянных подключений между сервисами удобнее прямой TLS с проверкой сертификата.
Чем sslmode=require хуже verify-full?
require только шифрует канал, но не проверяет подлинность сервера — возможна атака «человек посередине». verify-full сверяет сертификат и имя хоста, закрывая эту брешь.
Можно ли вообще не открывать порт БД?
Да, и это лучший вариант: слушайте только localhost, а весь внешний доступ давайте через SSH-туннель. Порт СУБД тогда недоступен из интернета в принципе.