Сборка 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
+256
View File
@@ -0,0 +1,256 @@
#!/usr/bin/env bash
#
# Установка панели игрового хостинга в один клик.
# Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом.
#
# Что делает скрипт:
# 1. Ставит nginx, PHP 8.x (FPM), MariaDB
# 2. Разворачивает код панели в /var/www/hostinpl
# 3. Создаёт базу, пользователя и загружает схему
# 4. Прописывает конфиг (пароль БД, адрес, токен планировщика)
# 5. Настраивает планировщик (9 заданий) и сторож автозапуска
# 6. Создаёт администратора панели
#
# Запуск: sudo bash install-panel.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)"
[[ -d "$SRC/panel" ]] || die "Рядом со скриптом нет каталога panel/ — распакуйте репозиторий целиком"
WEBROOT=/var/www/hostinpl
DBNAME=hostin
DBUSER=hostinpl
PORT="${PORT:-80}"
printf '\n%s=== Панель игрового хостинга · установка ===%s\n' "$C_INF" "$C_0"
printf 'Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом\n\n'
# ── 0. вопросы ───────────────────────────────────────────────────────────────
read -rp "Домен или IP панели (например panel.example.com): " DOMAIN
[[ -n "$DOMAIN" ]] || die "Адрес не может быть пустым"
read -rp "E-Mail администратора (он же логин в панель): " ADMMAIL
[[ "$ADMMAIL" == *@*.* ]] || die "Похоже, это не e-mail"
read -rsp "Пароль администратора (минимум 6 символов): " ADMPASS; echo
[[ ${#ADMPASS} -ge 6 ]] || die "Пароль короче 6 символов"
if [[ -e "$WEBROOT" ]]; then
read -rp "Каталог $WEBROOT уже существует. Перезаписать код панели? (yes/no): " OW
[[ "$OW" == "yes" ]] || die "Отменено пользователем"
fi
. /etc/os-release 2>/dev/null || true
step "Система: ${PRETTY_NAME:-неизвестна}"
# ── 1. пакеты ────────────────────────────────────────────────────────────────
step "Устанавливаю пакеты (nginx, PHP-FPM, MariaDB)…"
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq nginx mariadb-server unzip curl cron pwgen \
php-fpm php-mysql php-mbstring php-curl php-gd php-xml php-zip php-ssh2 >/dev/null
PHPV="$(ls -1 /etc/php/ 2>/dev/null | sort -V | tail -1)"
[[ -n "$PHPV" ]] || die "PHP не установился"
ok "PHP $PHPV, $(nginx -v 2>&1 | sed 's/.*nginx\///')"
# ── 2. службы (в контейнерах systemd может отсутствовать) ────────────────────
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 не поднялась — проверьте /var/log/mysql/"
ok "MariaDB отвечает"
# ── 3. база ──────────────────────────────────────────────────────────────────
step "Создаю базу данных…"
DBPASS="$(pwgen -cns -1 20)"
mysql -e "CREATE DATABASE IF NOT EXISTS \`$DBNAME\` DEFAULT CHARSET utf8;"
mysql -e "CREATE USER IF NOT EXISTS '$DBUSER'@'localhost' IDENTIFIED BY '$DBPASS';
ALTER USER '$DBUSER'@'localhost' IDENTIFIED BY '$DBPASS';
GRANT ALL PRIVILEGES ON \`$DBNAME\`.* TO '$DBUSER'@'localhost';
FLUSH PRIVILEGES;"
ok "База $DBNAME, пользователь $DBUSER (права только на свою базу)"
# ── 4. файлы ─────────────────────────────────────────────────────────────────
step "Копирую код панели в $WEBROOT"
mkdir -p "$WEBROOT"
cp -a "$SRC/panel/." "$WEBROOT/"
if [[ -f "$WEBROOT/hostinpl.sql" ]]; then
TABLES="$(mysql -N -B -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$DBNAME'")"
if [[ "$TABLES" -lt 5 ]]; then
mysql "$DBNAME" < "$WEBROOT/hostinpl.sql"
ok "Схема загружена: $(mysql -N -B -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$DBNAME'") таблиц"
else
warn "В базе уже $TABLES таблиц — схему не перезаписываю"
fi
rm -f "$WEBROOT/hostinpl.sql"
fi
# ── 5. конфиг ────────────────────────────────────────────────────────────────
step "Настраиваю конфигурацию…"
CRONTOKEN="$(pwgen -cns -1 24)"
CFG="$WEBROOT/application/config.php"
PROTO=http; [[ "$PORT" == "443" ]] && PROTO=https
URL="$PROTO://$DOMAIN/"; [[ "$PORT" != "80" && "$PORT" != "443" ]] && URL="http://$DOMAIN:$PORT/"
# Значения подставляются через callback, а не строкой замены: иначе символы вида $1
# в сгенерированном пароле PHP принял бы за обратную ссылку и записал бы мусор.
php -r '
$f=$argv[1];$s=file_get_contents($f);
$set=function($s,$key,$val,$anchor=false){
$re="~".($anchor?"^":"")."\x27".preg_quote($key,"~")."\x27(\s*)=>(\s*)\x27[^\x27]*\x27~u".($anchor?"m":"");
return preg_replace_callback($re,function($m)use($key,$val){
return "\x27".$key."\x27".$m[1]."=>".$m[2]."\x27".$val."\x27";
},$s,1);
};
$s=$set($s,"db_username",$argv[2]);
$s=$set($s,"db_password",$argv[3]);
$s=$set($s,"url",$argv[4]);
$s=$set($s,"token",$argv[5],true);
file_put_contents($f,$s);' "$CFG" "$DBUSER" "$DBPASS" "$URL" "$CRONTOKEN"
php -l "$CFG" >/dev/null || die "Конфиг повреждён — установка прервана"
grep -q "'db_password' => *'$DBPASS'" "$CFG" || grep -q "$DBPASS" "$CFG" || die "Пароль БД не попал в конфиг"
umask 077; printf 'db_user=%s\ndb_pass=%s\ncron_token=%s\n' "$DBUSER" "$DBPASS" "$CRONTOKEN" > /root/.redl-panel-credentials
ok "Конфиг записан, креды сохранены в /root/.redl-panel-credentials"
# ── 6. права ─────────────────────────────────────────────────────────────────
step "Выставляю права…"
chown -R www-data:www-data "$WEBROOT"
find "$WEBROOT" -type d -exec chmod 750 {} +
find "$WEBROOT" -type f -exec chmod 640 {} +
chmod -R 770 "$WEBROOT/tmp"
ok "Владелец www-data, конфиг недоступен извне"
# ── 7. PHP ───────────────────────────────────────────────────────────────────
step "Настраиваю PHP $PHPV"
INI="/etc/php/$PHPV/fpm/php.ini"
sed -i 's/^short_open_tag = Off/short_open_tag = On/' "$INI"
sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 90M/' "$INI"
sed -i 's/^post_max_size = .*/post_max_size = 360M/' "$INI"
sed -i 's|^;\?date.timezone =.*|date.timezone = Europe/Moscow|' "$INI"
mkdir -p /run/php
service "php$PHPV-fpm" restart >/dev/null 2>&1 || /etc/init.d/"php$PHPV-fpm" restart >/dev/null 2>&1 || true
sleep 2
[[ -S "/run/php/php$PHPV-fpm.sock" ]] || die "PHP-FPM сокет не создан"
ok "short_open_tag включён (панель использует <? ?>), загрузка до 90 МБ"
# ── 8. nginx ─────────────────────────────────────────────────────────────────
step "Настраиваю nginx (порт $PORT)…"
cat > /etc/nginx/sites-available/hostinpl <<NGINX
server {
listen 0.0.0.0:$PORT default_server;
server_name $DOMAIN _;
root $WEBROOT;
index index.php;
client_max_body_size 360M;
# редиректы без хоста и порта — иначе за обратным прокси уводит на :$PORT
absolute_redirect off;
port_in_redirect off;
location / { try_files \$uri \$uri/ /index.php\$is_args\$args; }
location ~ \.php\$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php$PHPV-fpm.sock;
fastcgi_read_timeout 300;
}
# закрываем служебное
location ~ /\.(ht|git) { deny all; }
location ~* \.(sql|log)\$ { deny all; }
location ^~ /application/config.php { deny all; }
}
NGINX
ln -sfn /etc/nginx/sites-available/hostinpl /etc/nginx/sites-enabled/hostinpl
rm -f /etc/nginx/sites-enabled/default
nginx -t >/dev/null 2>&1 || { nginx -t; die "Конфиг nginx не прошёл проверку"; }
service nginx restart >/dev/null 2>&1 || /etc/init.d/nginx restart >/dev/null 2>&1 || nginx
sleep 1
ok "Сайт слушает 0.0.0.0:$PORT"
# ── 9. планировщик ───────────────────────────────────────────────────────────
step "Настраиваю планировщик…"
B="http://127.0.0.1:$PORT/main/cron"
{
echo 'SHELL=/bin/sh'
echo 'PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin'
echo "0 0 * * * root curl -s -m 300 '$B/index?token=$CRONTOKEN' >/dev/null 2>&1"
echo "* * * * * root curl -s -m 55 '$B/gameServers?token=$CRONTOKEN' >/dev/null 2>&1"
echo "* * * * * root curl -s -m 55 '$B/tasks?token=$CRONTOKEN' >/dev/null 2>&1"
echo "*/10 * * * * root curl -s -m 300 '$B/serverReloader?token=$CRONTOKEN' >/dev/null 2>&1"
echo "*/30 * * * * root curl -s -m 300 '$B/stopServers?token=$CRONTOKEN' >/dev/null 2>&1"
echo "*/30 * * * * root curl -s -m 300 '$B/stopServersQuery?token=$CRONTOKEN' >/dev/null 2>&1"
echo "0 * * * * root curl -s -m 300 '$B/updateStats?token=$CRONTOKEN' >/dev/null 2>&1"
echo "0 * * * * root curl -s -m 300 '$B/updateStatsLocations?token=$CRONTOKEN' >/dev/null 2>&1"
echo "0 3 * * 0 root curl -s -m 300 '$B/clearLogs?token=$CRONTOKEN' >/dev/null 2>&1"
} > /etc/cron.d/hostinpl
chmod 644 /etc/cron.d/hostinpl
service cron start >/dev/null 2>&1 || /etc/init.d/cron start >/dev/null 2>&1 || true
ok "9 заданий панели (статистика, задачи, автоотключение просрочки)"
# ── 10. сторож автозапуска (нужен там, где нет systemd) ──────────────────────
step "Ставлю сторож автозапуска…"
cat > /usr/local/bin/hostinpl-guard <<GUARD
#!/bin/sh
# Поднимает стек панели, если что-то упало или машина перезагрузилась.
pgrep -x mariadbd >/dev/null 2>&1 || pgrep -x mysqld >/dev/null 2>&1 || {
mkdir -p /run/mysqld; chown mysql:mysql /run/mysqld
service mariadb start >/dev/null 2>&1 || /etc/init.d/mariadb start >/dev/null 2>&1
}
pgrep -f "^php-fpm$PHPV: master" >/dev/null 2>&1 || service php$PHPV-fpm start >/dev/null 2>&1
curl -sf -o /dev/null http://127.0.0.1:$PORT/account/login || service nginx start >/dev/null 2>&1
pgrep -x cron >/dev/null 2>&1 || service cron start >/dev/null 2>&1
GUARD
chmod +x /usr/local/bin/hostinpl-guard
cat > /etc/cron.d/hostinpl-guard <<'G'
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
* * * * * root /usr/local/bin/hostinpl-guard >/dev/null 2>&1
@reboot root sleep 20; /usr/local/bin/hostinpl-guard >/dev/null 2>&1
G
chmod 644 /etc/cron.d/hostinpl-guard
ok "Проверка раз в минуту и подъём после перезагрузки"
# ── 11. администратор ────────────────────────────────────────────────────────
step "Создаю администратора панели…"
HASH="$(php -r 'echo md5($argv[1]);' "$ADMPASS")"
mysql "$DBNAME" <<SQL
DELETE FROM users WHERE user_email='$ADMMAIL';
INSERT INTO users
(user_email,user_password,user_firstname,user_lastname,user_status,user_balance,
user_access_level,user_date_reg,user_online_date,user_promo_date,user_activate,
key_activate,ref,rmoney,bonuses,test_server,user_last_date)
VALUES
('$ADMMAIL','$HASH','Администратор','Панели',1,0.00,3,NOW(),UNIX_TIMESTAMP(),
CURDATE(),1,'',0,0.00,0.00,'2',NOW());
SQL
ok "Логин $ADMMAIL, уровень доступа 3 (полный)"
# ── 12. проверка ─────────────────────────────────────────────────────────────
step "Проверяю работу панели…"
sleep 2
CODE="$(curl -s -o /tmp/redl-check.html -w '%{http_code}' -L "http://127.0.0.1:$PORT/account/login" || true)"
[[ "$CODE" == "200" ]] || die "Страница входа вернула $CODE (ожидался 200). Смотрите /var/log/nginx/error.log"
grep -q 'kt_login_signin_form' /tmp/redl-check.html || die "Страница входа отдалась без формы"
rm -f /tmp/redl-check.html
ok "Страница входа отвечает, форма на месте"
printf '\n%s=== Установка завершена ===%s\n\n' "$C_OK" "$C_0"
printf ' Адрес панели : %s\n' "$URL"
printf ' Логин : %s\n' "$ADMMAIL"
printf ' Пароль : тот, что вы ввели при установке\n'
printf ' Креды БД : /root/.redl-panel-credentials\n\n'
printf '%sДальше:%s\n' "$C_INF" "$C_0"
printf ' 1. Капча выключена. Включить: Админка → Настройки → Прочие настройки → «Защита от ботов»\n'
printf ' (сначала впишите оба ключа с google.com/recaptcha, потом переключайте)\n'
printf ' 2. Платёжные системы: Админка → Настройки → Платёжные системы\n'
printf ' 3. Игровую ноду ставьте скриптом install-node.sh и подключайте в Админка → Локации\n\n'
printf 'Поддерживается и развивается с помощью REDL.IO — Хостинг с искусственным интеллектом\n\n'