Files
redl 6ee2744e3a Сборка 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
- документация на русском: ИЗМЕНЕНИЯ, БЕЗОПАСНОСТЬ, ИНСТРУКЦИЯ
2026-07-30 02:00:01 +00:00

257 lines
16 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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'