Сборка REDL: панель на PHP 8, капча-тумблер, закрытые уязвимости, установщики в один клик

- панель работает на PHP 8.4 (оригинал под PHP 7.0): elFinder utf8_encode, apache_get_modules, warnings
- капча выключена и управляется из админки (флаг captcha_enable + блок настроек)
- закрыты две SQL-инъекции без авторизации (createAuthLog: пароль из POST и CF-Connecting-IP)
- убрано хранение паролей в открытом виде в authlog, XSS в поле ref
- установщики install-panel.sh и install-node.sh (оригинальный затирал sources.list репозиториями Debian 9)
- современный Dockerfile (оригинальный на debian:stretch больше не собирается)
- планировщик и автозапуск работают без systemd
- брендинг REDL.IO, год 2026, ссылки на redl.io
- документация на русском: ИЗМЕНЕНИЯ, БЕЗОПАСНОСТЬ, ИНСТРУКЦИЯ
This commit is contained in:
2026-07-30 02:00:01 +00:00
commit 6ee2744e3a
492 changed files with 354172 additions and 0 deletions
+252
View File
@@ -0,0 +1,252 @@
#!/usr/bin/env bash
#
# Установка игровой ноды (локации) в один клик.
# Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом.
#
# Нода — это машина, на которой реально крутятся игровые сервера.
# Панель подключается к ней по SSH и создаёт docker-контейнер на каждый сервер.
#
# Что делает скрипт:
# 1. Проверяет, что docker здесь вообще может работать (в контейнерных VPS — не может)
# 2. Ставит docker, собирает образ debian:stretch (имя ждёт панель)
# 3. Создаёт раскладку /home/cp/gameservers/files и группу gameservers
# 4. Ставит MariaDB для баз игровых серверов и SteamCMD
# 5. Настраивает SSH и ProFTPD так, как ожидает панель
# 6. Печатает данные для подключения локации в админке
#
# Запуск: sudo bash install-node.sh
#
set -euo pipefail
C_OK=$'\033[1;32m'; C_ERR=$'\033[1;31m'; C_INF=$'\033[1;36m'; C_W=$'\033[1;33m'; C_0=$'\033[0m'
step() { printf '%s»%s %s\n' "$C_INF" "$C_0" "$1"; }
ok() { printf ' %s✓%s %s\n' "$C_OK" "$C_0" "$1"; }
warn() { printf ' %s!%s %s\n' "$C_W" "$C_0" "$1"; }
die() { printf '%s✗ %s%s\n' "$C_ERR" "$1" "$C_0" >&2; exit 1; }
[[ $EUID -eq 0 ]] || die "Запустите скрипт от root: sudo bash $0"
SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
printf '\n%s=== Игровая нода · установка ===%s\n' "$C_INF" "$C_0"
printf 'Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом\n\n'
# ── 0. проверка пригодности машины ───────────────────────────────────────────
step "Проверяю, может ли эта машина запускать docker…"
CAPFAIL=0
if ! unshare -Ur true 2>/dev/null; then
CAPFAIL=1
warn "Ядро запрещает вложенные namespace (unshare не работает)"
fi
if [[ ! -e /dev/fuse && $CAPFAIL -eq 1 ]]; then
warn "Нет /dev/fuse"
fi
if [[ $CAPFAIL -eq 1 ]]; then
printf '\n%sЭТА МАШИНА НЕ ПОДХОДИТ ПОД ИГРОВУЮ НОДУ.%s\n' "$C_ERR" "$C_0"
printf 'Панель разворачивает каждый игровой сервер отдельным docker-контейнером,\n'
printf 'а здесь docker не запустится: это контейнерный VPS (LXC/OpenVZ или\n'
printf 'аналог) без CAP_SYS_ADMIN. Rootless podman тоже не поможет — ядро\n'
printf 'запрещает вложенные user namespace.\n\n'
printf 'Нужен сервер с полным доступом к ядру: выделенный сервер (dedicated)\n'
printf 'или KVM/VMware-виртуализация. Панель при этом может жить где угодно,\n'
printf 'включая контейнерный VPS — ей docker не нужен.\n\n'
read -rp "Всё равно продолжить установку? (yes/no): " GO
[[ "$GO" == "yes" ]] || exit 1
else
ok "Namespace доступны, docker будет работать"
fi
read -rp "IP этой ноды (как её увидит панель): " NODEIP
[[ -n "$NODEIP" ]] || die "IP не может быть пустым"
read -rp "Разрешить панели вход по SSH под root с паролем? (yes/no): " SSHROOT
. /etc/os-release 2>/dev/null || true
CODENAME="${VERSION_CODENAME:-bookworm}"
DISTRO_ID="${ID:-debian}"
step "Система: ${PRETTY_NAME:-неизвестна}"
export DEBIAN_FRONTEND=noninteractive
# ── 1. базовые пакеты ────────────────────────────────────────────────────────
step "Ставлю базовые пакеты…"
apt-get update -qq
apt-get install -y -qq curl wget ca-certificates gnupg unzip tar sudo pwgen htop \
openssh-server mariadb-server proftpd-basic lib32stdc++6 >/dev/null 2>&1 || \
apt-get install -y -qq curl wget ca-certificates gnupg unzip tar sudo pwgen htop \
openssh-server mariadb-server proftpd lib32stdc++6 >/dev/null
ok "Пакеты установлены"
# ── 2. docker ────────────────────────────────────────────────────────────────
step "Ставлю Docker…"
if command -v docker >/dev/null 2>&1; then
ok "Docker уже установлен: $(docker --version 2>/dev/null | head -1)"
else
install -m 0755 -d /etc/apt/keyrings
curl -fsSL "https://download.docker.com/linux/$DISTRO_ID/gpg" -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$DISTRO_ID $CODENAME stable" \
> /etc/apt/sources.list.d/docker.list
apt-get update -qq
apt-get install -y -qq docker-ce docker-ce-cli containerd.io >/dev/null
ok "Docker установлен из официального репозитория"
fi
service docker start >/dev/null 2>&1 || /etc/init.d/docker start >/dev/null 2>&1 || true
sleep 3
docker info >/dev/null 2>&1 || die "Docker-демон не поднялся. Без него нода не заработает"
ok "Docker-демон отвечает"
# ── 3. образ игровых серверов ────────────────────────────────────────────────
step "Собираю образ для игровых серверов (тег debian:stretch — его ждёт панель)…"
if docker image inspect debian:stretch >/dev/null 2>&1; then
ok "Образ debian:stretch уже собран"
else
DF="$SRC/docker/Dockerfile"
[[ -f "$DF" ]] || die "Не найден $DF — распакуйте репозиторий целиком"
docker build -t debian:stretch -f "$DF" "$SRC/docker" >/tmp/redl-docker-build.log 2>&1 \
|| { tail -25 /tmp/redl-docker-build.log; die "Сборка образа не удалась, полный лог: /tmp/redl-docker-build.log"; }
ok "Образ собран (Debian 12 + 32-битные библиотеки + Java + Node.js + screen)"
fi
# ── 4. раскладка каталогов ───────────────────────────────────────────────────
step "Создаю раскладку каталогов…"
groupadd -f gameservers
mkdir -p /home/cp/backups /home/cp/gameservers/files
chown -R root:root /home
chmod 755 /home /home/cp /home/cp/gameservers /home/cp/gameservers/files
chmod 700 /home/cp/backups
ok "/home/cp/gameservers/files — сюда кладутся сборки игр, /home/gs<id> — сами сервера"
# ── 5. база для игровых серверов ─────────────────────────────────────────────
step "Настраиваю MariaDB для баз игровых серверов…"
mkdir -p /run/mysqld && chown mysql:mysql /run/mysqld
if ! mysqladmin ping >/dev/null 2>&1; then
service mariadb start >/dev/null 2>&1 || /etc/init.d/mariadb start >/dev/null 2>&1 || true
for _ in $(seq 1 45); do mysqladmin ping >/dev/null 2>&1 && break; sleep 2; done
fi
mysqladmin ping >/dev/null 2>&1 || die "MariaDB не поднялась"
SQLCNF=/etc/mysql/mariadb.conf.d/50-server.cnf
if [[ -f "$SQLCNF" ]]; then
sed -i 's/^bind-address.*/bind-address = 0.0.0.0/' "$SQLCNF"
grep -q '^max_connections' "$SQLCNF" || sed -i '/^\[mysqld\]/a max_connections = 1000' "$SQLCNF"
fi
DBADMPASS="$(pwgen -cns -1 20)"
mysql -e "CREATE USER IF NOT EXISTS 'gsadmin'@'%' IDENTIFIED BY '$DBADMPASS';
ALTER USER 'gsadmin'@'%' IDENTIFIED BY '$DBADMPASS';
GRANT ALL PRIVILEGES ON *.* TO 'gsadmin'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;"
service mariadb restart >/dev/null 2>&1 || /etc/init.d/mariadb restart >/dev/null 2>&1 || true
sleep 3
umask 077; printf 'mysql_user=gsadmin\nmysql_pass=%s\n' "$DBADMPASS" > /root/.redl-node-credentials
warn "MariaDB слушает 0.0.0.0:3306 — так требует панель. ОБЯЗАТЕЛЬНО ограничьте порт файрволом (см. конец вывода)"
ok "Пользователь gsadmin создан, пароль в /root/.redl-node-credentials"
# ── 6. SSH ───────────────────────────────────────────────────────────────────
step "Настраиваю SSH…"
SSHD=/etc/ssh/sshd_config
cp -n "$SSHD" "$SSHD.bak-redl" 2>/dev/null || true
grep -q '^DenyGroups gameservers' "$SSHD" || echo 'DenyGroups gameservers' >> "$SSHD"
if [[ "$SSHROOT" == "yes" ]]; then
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/' "$SSHD"
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/' "$SSHD"
ROOTPASS="$(pwgen -cns -1 24)"
echo "root:$ROOTPASS" | chpasswd
printf 'ssh_user=root\nssh_pass=%s\n' "$ROOTPASS" >> /root/.redl-node-credentials
ok "Вход root по паролю разрешён, пароль сгенерирован (в /root/.redl-node-credentials)"
warn "Панель хранит этот пароль в своей базе в открытом виде — таково её устройство"
else
ROOTPASS=""
warn "Вход root по паролю не менялся. Панель умеет подключаться ТОЛЬКО по логину и паролю,"
warn "и её команды требуют прав root — иначе создание серверов не заработает"
fi
if ! sshd -t 2>/dev/null; then
cp "$SSHD.bak-redl" "$SSHD"
die "Конфиг sshd не прошёл проверку — откатил, ничего не сломано"
fi
service ssh restart >/dev/null 2>&1 || service sshd restart >/dev/null 2>&1 || /etc/init.d/ssh restart >/dev/null 2>&1 || true
ok "Группе gameservers вход по SSH запрещён (игровые пользователи не зайдут в шелл)"
# ── 7. FTP ───────────────────────────────────────────────────────────────────
step "Настраиваю ProFTPD (доступ клиента к файлам сервера)…"
PFTP=/etc/proftpd/proftpd.conf
if [[ -f "$PFTP" ]]; then
grep -q '^DefaultRoot ~' "$PFTP" || echo 'DefaultRoot ~' >> "$PFTP"
grep -q '^RequireValidShell off' "$PFTP" || echo 'RequireValidShell off' >> "$PFTP"
service proftpd restart >/dev/null 2>&1 || /etc/init.d/proftpd restart >/dev/null 2>&1 || true
ok "Клиент видит только свой каталог (DefaultRoot ~)"
else
warn "Конфиг ProFTPD не найден — FTP не настроен, файловый менеджер панели работать не будет"
fi
# ── 8. SteamCMD ──────────────────────────────────────────────────────────────
step "Ставлю SteamCMD (нужен для CS 1.6 / CS:S и других игр Steam)…"
if [[ -x /root/steamcmd/steamcmd.sh ]]; then
ok "SteamCMD уже установлен"
else
mkdir -p /root/steamcmd && cd /root/steamcmd
if curl -fsSL -o steamcmd_linux.tar.gz https://media.steampowered.com/client/steamcmd_linux.tar.gz; then
tar xzf steamcmd_linux.tar.gz && rm -f steamcmd_linux.tar.gz
ok "SteamCMD в /root/steamcmd"
else
warn "Не удалось скачать SteamCMD — поставьте позже вручную"
fi
cd "$SRC"
fi
# ── 9. сторож docker ─────────────────────────────────────────────────────────
step "Ставлю сторож docker…"
cat > /usr/local/bin/gamenode-guard <<'GUARD'
#!/bin/sh
# Поднимает docker и MariaDB, если упали или машина перезагрузилась.
docker info >/dev/null 2>&1 || service docker start >/dev/null 2>&1
mysqladmin ping >/dev/null 2>&1 || service mariadb start >/dev/null 2>&1
# запускаем контейнеры серверов, помеченных как работающие
for c in $(docker ps -a --filter "name=^gs" --filter "status=exited" --format '{{.Names}}' 2>/dev/null); do
docker start "$c" >/dev/null 2>&1
done
GUARD
chmod +x /usr/local/bin/gamenode-guard
cat > /etc/cron.d/gamenode-guard <<'G'
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
*/2 * * * * root /usr/local/bin/gamenode-guard >/dev/null 2>&1
@reboot root sleep 30; /usr/local/bin/gamenode-guard >/dev/null 2>&1
G
chmod 644 /etc/cron.d/gamenode-guard
service cron start >/dev/null 2>&1 || /etc/init.d/cron start >/dev/null 2>&1 || true
ok "Проверка раз в 2 минуты + подъём после перезагрузки"
# ── 10. проверка ─────────────────────────────────────────────────────────────
step "Финальная проверка…"
docker image inspect debian:stretch >/dev/null 2>&1 && ok "образ debian:stretch на месте" || warn "образа debian:stretch НЕТ"
[[ -d /home/cp/gameservers/files ]] && ok "каталоги на месте"
getent group gameservers >/dev/null && ok "группа gameservers создана"
mysqladmin ping >/dev/null 2>&1 && ok "MariaDB отвечает"
# проверяем, что контейнер реально создаётся и стартует
if docker run --rm debian:stretch /bin/echo test >/dev/null 2>&1; then
ok "Тестовый контейнер запускается — нода готова принимать игровые сервера"
else
warn "Тестовый контейнер НЕ запустился — проверьте docker вручную"
fi
CPU="$(nproc)"; RAM="$(free -m | awk '/^Mem:/{print $2}')"; HDD="$(df -BG --output=size / | tail -1 | tr -dc '0-9')"
printf '\n%s=== Нода установлена ===%s\n\n' "$C_OK" "$C_0"
printf '%sПодключение локации в панели (Админка → Локации → Добавить):%s\n' "$C_INF" "$C_0"
printf ' IP : %s\n' "$NODEIP"
printf ' Пользователь SSH: root\n'
if [[ -n "$ROOTPASS" ]]; then
printf ' Пароль SSH : %s\n' "$ROOTPASS"
else
printf ' Пароль SSH : (вы отказались менять — укажите действующий пароль root)\n'
fi
printf ' Ресурсы : %s ядер, %s МБ ОЗУ, %s ГБ диска\n\n' "$CPU" "$RAM" "$HDD"
printf ' Данные MySQL для баз игровых серверов — в /root/.redl-node-credentials\n\n'
printf '%sОБЯЗАТЕЛЬНО закройте порты файрволом (замените IP_ПАНЕЛИ на адрес панели):%s\n' "$C_W" "$C_0"
printf ' ufw allow from IP_ПАНЕЛИ to any port 22 proto tcp\n'
printf ' ufw allow from IP_ПАНЕЛИ to any port 3306 proto tcp\n'
printf ' ufw deny 3306\n'
printf ' # порты игровых серверов (например 7777, 22005, 25565) оставьте открытыми\n\n'
printf '%sСборки игр%s кладите в /home/cp/gameservers/files/<код_игры>/\n' "$C_INF" "$C_0"
printf ' Коды игр берите в Админка → Игры. Оригинальные ссылки на сборки в\n'
printf ' установщике вели на сторонние сайты по HTTP — мы их не используем,\n'
printf ' подробности в БЕЗОПАСНОСТЬ.md\n\n'
printf 'Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом\n\n'