Files
moonwell-web/docs/ssh-core-tunnel.md
T
2026-10-04 13:36:43 +04:00

9.2 KiB
Raw Blame History

SSH-туннель от веба к БД ядра

Для Ubuntu/Debian и production Compose этого проекта. Адрес сервера ядра, SSH-порт и SSH-пользователь заменяются вашими значениями. Настройка выполняется на двух серверах. SSH-пароль и пароль MariaDB — разные данные.

Схема: app → core-db-tunnel:3306 → SSH → 127.0.0.1:13306 → MariaDB ядра. Порт 3306 туннеля доступен только в сети контейнеров веба; на хост он не публикуется. Ключ хранится вне репозитория в /etc/moonwell/ssh-tunnel, в образ он не копируется.

1. На сервере ядра: доступ к MariaDB через localhost

В папке с production compose.yaml ядра создайте дополнительный файл:

cat > compose.ssh-db.yaml <<'YAML'
services:
  db:
    ports:
      - "127.0.0.1:13306:3306"
YAML

docker compose -f compose.yaml -f compose.ssh-db.yaml up -d --no-deps db

Этот шаг пересоздаёт контейнер MariaDB, сохраняя его volume; соединения с БД прервутся на время перезапуска. Выполните его в подходящее для этого время. Если MariaDB уже доступна на localhost сервера ядра, используйте существующий порт и пропустите этот шаг. В будущих командах управления ядром сохраняйте -f compose.ssh-db.yaml, чтобы порт не пропал после пересоздания БД.

Проверка:

ss -lnt | grep ':13306'
docker compose -f compose.yaml -f compose.ssh-db.yaml ps db

При использовании другого имени сервиса замените db на имя MariaDB вашего ядра. На сервере ядра SSH должен разрешать локальный TCP forwarding (AllowTcpForwarding yes или local); ограничения пользователя и ключа должны разрешать 127.0.0.1:13306.

2. На сервере веба: отдельный SSH-ключ

Выполняйте команды от root, как в текущем сеансе. Подставьте адрес, SSH-порт и существующего SSH-пользователя сервера ядра:

CORE_HOST=IP_ИЛИ_ДОМЕН_ЯДРА
CORE_PORT=22
CORE_USER=SSH_ПОЛЬЗОВАТЕЛЬ

apt-get update
apt-get install -y openssh-client
install -d -m 700 /etc/moonwell/ssh-tunnel
ssh-keygen -t ed25519 -N '' \
  -C moonwell-web-db-tunnel \
  -f /etc/moonwell/ssh-tunnel/id_ed25519

ssh-copy-id -p "$CORE_PORT" \
  -i /etc/moonwell/ssh-tunnel/id_ed25519.pub \
  -o UserKnownHostsFile=/etc/moonwell/ssh-tunnel/known_hosts \
  "$CORE_USER@$CORE_HOST"

ssh-copy-id запросит SSH-пароль выбранного пользователя и сохранит публичный ключ. При первом подключении сверьте показанный fingerprint с ключом сервера ядра, проверенным через его существующую SSH-сессию или консоль:

# На сервере ядра:
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

Не запускайте ssh-keygen повторно поверх существующего ключа. Если вход по SSH-паролю отключён, добавьте содержимое id_ed25519.pub в ~/.ssh/authorized_keys выбранного пользователя через существующий доступ и выполните первое подключение вручную с параметром UserKnownHostsFile выше.

На веб-сервере проверьте, что вход теперь работает без пароля:

chmod 600 /etc/moonwell/ssh-tunnel/id_ed25519 /etc/moonwell/ssh-tunnel/known_hosts
ssh -p "$CORE_PORT" \
  -i /etc/moonwell/ssh-tunnel/id_ed25519 \
  -o IdentitiesOnly=yes -o BatchMode=yes -o StrictHostKeyChecking=yes \
  -o UserKnownHostsFile=/etc/moonwell/ssh-tunnel/known_hosts \
  "$CORE_USER@$CORE_HOST" true

3. Настройки веба

Перенесите обновлённый compose.prod.yaml и новые файлы этого проекта на веб-сервер:

  • compose.prod.ssh-tunnel.yaml;
  • docker/ssh-tunnel/Dockerfile;
  • docker/ssh-tunnel/start.sh.

В .env веба укажите фактические SSH-данные и подключения через туннель:

CORE_SSH_HOST=IP_ИЛИ_ДОМЕН_ЯДРА
CORE_SSH_PORT=22
CORE_SSH_USER=SSH_ПОЛЬЗОВАТЕЛЬ
CORE_DB_HOST=127.0.0.1
CORE_DB_PORT=13306

VMANGOS_AUTH_DB_HOST=core-db-tunnel
VMANGOS_AUTH_DB_PORT=3306
VMANGOS_AUTH_DB_DATABASE=realmd
VMANGOS_AUTH_DB_USERNAME=vmangos
VMANGOS_AUTH_DB_PASSWORD="ПАРОЛЬ_БД_ЯДРА"

VMANGOS_CHARACTERS_DB_HOST=core-db-tunnel
VMANGOS_CHARACTERS_DB_PORT=3306
VMANGOS_CHARACTERS_DB_DATABASE=characters
VMANGOS_CHARACTERS_DB_USERNAME=vmangos
VMANGOS_CHARACTERS_DB_PASSWORD="ПАРОЛЬ_БД_ЯДРА"

Здесь CORE_DB_HOST=127.0.0.1 означает localhost сервера ядра, а не веба. Порты 13306 (MariaDB на сервере ядра) и 3306 (туннель в сети веба) различаются. CORE_SSH_PORT — SSH-порт, он может отличаться от 22. Настройки DB_* MySQL самого веба и AWS_* S3 остаются прежними. Удалите старые VMANGOS_AUTH_DB_URL и VMANGOS_CHARACTERS_DB_URL, если они указаны: иначе Laravel может использовать адреса из URL вместо настроек выше. VMANGOS_DOCKER_NETWORK для production с удалённым ядром не используется. Для проверки статуса игрового сервера укажите MOONWELL_REALM_STATUS_HOST равным доступному с веба адресу игрового сервера, а не mangosd из локального Docker.

4. Запуск на веб-сервере

Из папки moonwell-web:

docker compose -f compose.prod.yaml -f compose.prod.ssh-tunnel.yaml up -d --build core-db-tunnel
docker compose -f compose.prod.yaml -f compose.prod.ssh-tunnel.yaml ps core-db-tunnel
docker compose -f compose.prod.yaml -f compose.prod.ssh-tunnel.yaml logs --tail=30 core-db-tunnel

После состояния healthy пересоздайте приложение и nginx:

docker compose -f compose.prod.yaml -f compose.prod.ssh-tunnel.yaml up -d --no-deps --force-recreate app web
docker compose -f compose.prod.yaml -f compose.prod.ssh-tunnel.yaml exec -T --user app app php artisan config:cache

Docker запускает туннель после перезагрузки и перезапускает завершившийся SSH-процесс. SSH keepalive обнаруживает обрыв соединения. healthy подтверждает, что SSH создал локальный слушающий порт; доступность самой MariaDB проверяется следующим шагом.

5. Проверка из Laravel

docker compose -f compose.prod.yaml -f compose.prod.ssh-tunnel.yaml exec -T --user app app php artisan tinker --execute='foreach (["vmangos_auth", "vmangos_characters"] as $name) { DB::connection($name)->select("SELECT 1"); echo $name." OK\n"; }'

Ожидаемый результат:

vmangos_auth OK
vmangos_characters OK

Команда выполняет только SELECT 1, игровые аккаунты не меняются. Если tinker не установлен в вашей production-сборке, проверьте наличие laravel/tinker в production-зависимостях перед запуском этой команды.

Ошибки:

  • Permission denied (publickey): SSH-пользователь, публичный ключ или права файла ключа.
  • Host key verification failed: известный ключ не соответствует адресу/порту; сверьте fingerprint и обновите файл known_hosts через подтверждённое подключение.
  • administratively prohibited: сервер SSH запретил forwarding или цель туннеля.
  • connect failed: Connection refused: MariaDB не слушает на адресе/порту CORE_DB_HOST:CORE_DB_PORT на сервере ядра.
  • Access denied for user: туннель работает, но неверны учётные данные или MariaDB не разрешает этому пользователю подключение с адреса хоста Docker.

Документация: OpenSSH forwarding, OpenSSH keepalive, Docker published ports.