ssh туннель

This commit is contained in:
2026-10-04 13:36:43 +04:00
parent 5952e966d2
commit 22cb56e52f
7 changed files with 328 additions and 5 deletions
+55 -1
View File
@@ -19,7 +19,61 @@ VMANGOS_CHARACTERS_DB_USERNAME=vmangos
MOONWELL_CLIENT_VERSION=1.12.1
```
Для PHP, запущенного прямо на хосте, укажите `127.0.0.1:13306` вместо `db:3306`. В продакшене настройте `VMANGOS_DOCKER_NETWORK=vmangos_default` и учётные данные продакшен-БД vMaNGOS. Контейнер приложения присоединяется к указанной сети автоматически.
Для PHP, запущенного прямо на хосте, укажите `127.0.0.1:13306` вместо `db:3306`.
## Production с удалённым ядром
Для соединения через SSH используйте [пошаговую инструкцию](docs/ssh-core-tunnel.md)
и `compose.prod.ssh-tunnel.yaml`.
`compose.prod.yaml` подключает приложение только к сети веба `sail`.
Внешняя Docker-сеть vMaNGOS не требуется. `VMANGOS_DOCKER_NETWORK`
в `.env` не влияет на этот режим; `DB_*` остаются настройками MySQL самого сайта.
Production Compose читает `.env`, а не `.env.production`.
Укажите доступный из контейнера приложения адрес и порт MariaDB ядра
(прямое соединение, VPN или туннель), базы и учётные данные:
```dotenv
VMANGOS_AUTH_DB_HOST=CORE_DB_HOST
VMANGOS_AUTH_DB_PORT=CORE_DB_PORT
VMANGOS_AUTH_DB_DATABASE=realmd
VMANGOS_AUTH_DB_USERNAME=WEB_DB_USER
VMANGOS_AUTH_DB_PASSWORD=WEB_DB_PASSWORD
VMANGOS_CHARACTERS_DB_HOST=CORE_DB_HOST
VMANGOS_CHARACTERS_DB_PORT=CORE_DB_PORT
VMANGOS_CHARACTERS_DB_DATABASE=characters
VMANGOS_CHARACTERS_DB_USERNAME=WEB_DB_USER
VMANGOS_CHARACTERS_DB_PASSWORD=WEB_DB_PASSWORD
MOONWELL_REALM_STATUS_HOST=CORE_GAME_HOST
```
Замените значения-заполнители своими. Порт игрового сервера `3724` не является
портом MariaDB. Адрес `db` используется только внутри сети Docker ядра;
`127.0.0.1` внутри контейнера приложения означает сам контейнер.
Если заданы `VMANGOS_AUTH_DB_URL` или `VMANGOS_CHARACTERS_DB_URL`,
обновите их либо удалите, чтобы Laravel использовал отдельные `*_DB_*` значения.
Учётной записи БД и сетевому доступу должны быть разрешены соединения с веб-сервера.
После изменения `.env` пересоздайте контейнеры и обновите кеш:
```bash
docker compose -f compose.prod.yaml up -d --no-deps --force-recreate app web
docker compose -f compose.prod.yaml exec -T --user app app php artisan config:cache
```
Проверка обеих БД из контейнера (только `SELECT 1`, без изменения аккаунтов):
```bash
docker compose -f compose.prod.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"; }'
```
Для production-ядра на том же Docker-хосте добавьте
`-f compose.prod.local-core.yaml` во все production-команды Compose,
укажите `VMANGOS_DOCKER_NETWORK=vmangos_default` (либо фактическую сеть ядра)
и адрес БД `db:3306`. В локальном Sail `compose.yaml` подключение к сети
`vmangos-local_default` сохранено.
## Запуск сайта
+12
View File
@@ -0,0 +1,12 @@
# Optional connection to a vMaNGOS database on the same Docker host.
# docker compose -f compose.prod.yaml -f compose.prod.local-core.yaml up -d
services:
app:
networks:
- sail
- vmangos
networks:
vmangos:
external: true
name: '${VMANGOS_DOCKER_NETWORK:-vmangos_default}'
+48
View File
@@ -0,0 +1,48 @@
# Use together with compose.prod.yaml. No database port is published on the web host.
services:
core-db-tunnel:
build:
context: .
dockerfile: docker/ssh-tunnel/Dockerfile
image: moonwell-core-db-tunnel:local
restart: unless-stopped
init: true
environment:
CORE_SSH_HOST: '${CORE_SSH_HOST:?Set CORE_SSH_HOST in .env}'
CORE_SSH_PORT: '${CORE_SSH_PORT:-22}'
CORE_SSH_USER: '${CORE_SSH_USER:?Set CORE_SSH_USER in .env}'
CORE_DB_HOST: '${CORE_DB_HOST:-127.0.0.1}'
CORE_DB_PORT: '${CORE_DB_PORT:-13306}'
volumes:
- type: bind
source: '${CORE_SSH_KEY_PATH:-/etc/moonwell/ssh-tunnel/id_ed25519}'
target: /run/ssh/id_ed25519
read_only: true
bind:
create_host_path: false
- type: bind
source: '${CORE_SSH_KNOWN_HOSTS_PATH:-/etc/moonwell/ssh-tunnel/known_hosts}'
target: /run/ssh/known_hosts
read_only: true
bind:
create_host_path: false
networks:
- sail
healthcheck:
test: ['CMD', 'nc', '-z', '-w', '2', '127.0.0.1', '3306']
interval: 10s
timeout: 3s
retries: 3
start_period: 15s
read_only: true
tmpfs:
- /tmp
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
app:
depends_on:
core-db-tunnel:
condition: service_healthy
-4
View File
@@ -23,7 +23,6 @@ services:
- '/var/www/html/bootstrap/cache:uid=${WWWUSER:-1000},gid=${WWWGROUP:-1000},mode=0770'
networks:
- sail
- vmangos
depends_on:
mysql:
condition: service_healthy
@@ -100,9 +99,6 @@ services:
networks:
sail:
driver: bridge
vmangos:
external: true
name: '${VMANGOS_DOCKER_NETWORK:-vmangos_default}'
volumes:
sail-mysql:
+10
View File
@@ -0,0 +1,10 @@
FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends openssh-client ca-certificates netcat-openbsd \
&& rm -rf /var/lib/apt/lists/*
COPY docker/ssh-tunnel/start.sh /usr/local/bin/moonwell-core-tunnel
RUN chmod 0755 /usr/local/bin/moonwell-core-tunnel
ENTRYPOINT ["/usr/local/bin/moonwell-core-tunnel"]
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
set -eu
: "${CORE_SSH_HOST:?Set CORE_SSH_HOST}"
: "${CORE_SSH_USER:?Set CORE_SSH_USER}"
exec ssh -NT \
-p "${CORE_SSH_PORT:-22}" \
-i /run/ssh/id_ed25519 \
-o BatchMode=yes \
-o IdentitiesOnly=yes \
-o StrictHostKeyChecking=yes \
-o UserKnownHostsFile=/run/ssh/known_hosts \
-o GlobalKnownHostsFile=/dev/null \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-o ConnectTimeout=10 \
-L "0.0.0.0:3306:${CORE_DB_HOST:-127.0.0.1}:${CORE_DB_PORT:-13306}" \
"${CORE_SSH_USER}@${CORE_SSH_HOST}"
+183
View File
@@ -0,0 +1,183 @@
# 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/).