# 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` ядра создайте дополнительный файл: ```bash 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`, чтобы порт не пропал после пересоздания БД. Проверка: ```bash 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-пользователя сервера ядра: ```bash 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-сессию или консоль: ```bash # На сервере ядра: ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub ``` Не запускайте `ssh-keygen` повторно поверх существующего ключа. Если вход по SSH-паролю отключён, добавьте содержимое `id_ed25519.pub` в `~/.ssh/authorized_keys` выбранного пользователя через существующий доступ и выполните первое подключение вручную с параметром `UserKnownHostsFile` выше. На веб-сервере проверьте, что вход теперь работает без пароля: ```bash 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-данные и подключения через туннель: ```dotenv 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`: ```bash 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: ```bash 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 ```bash 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"; }' ``` Ожидаемый результат: ```text 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](https://man.openbsd.org/ssh), [OpenSSH keepalive](https://man.openbsd.org/ssh_config), [Docker published ports](https://docs.docker.com/engine/network/port-publishing/).