From 802e6805f1698295c000fdf4bf39faeac646106d Mon Sep 17 00:00:00 2001 From: demassimo <87481244+demassimo@users.noreply.github.com> Date: Sun, 19 Oct 2025 22:04:24 +0200 Subject: [PATCH] Ensure installer provisions SteamCMD dependencies --- README.md | 88 +++++----------- scripts/install_panel.sh | 214 +++++++++++++++++++++++++++++++++------ 2 files changed, 212 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 5779134..c6ef794 100644 --- a/README.md +++ b/README.md @@ -21,74 +21,42 @@ You can change these in the helper scripts under `scripts/`, via the new web con ## Install -### 1) Create the helper scripts (as root) -``` -install -Dm755 scripts/rust_install.sh /usr/local/bin/rust_install.sh -install -Dm755 scripts/rust_update.sh /usr/local/bin/rust_update.sh -install -Dm755 scripts/oxide_update.sh /usr/local/bin/oxide_update.sh -``` +### Automated Ubuntu install (recommended) + +Run the interactive installer as root. It will ask for the panel service user, +Rust service name, Steam account paths, and the initial web login credentials. +The script enables the multiverse repository, installs SteamCMD and the 32-bit +runtime libraries it needs, installs the required Python packages system-wide, +copies the web application into `/opt/rust-panel/app` (by default), configures +sudo rules for the panel user, installs the helper scripts into +`/usr/local/bin`, and enables a `systemd` service so the panel starts +automatically. -### 2) Sudoers (limit panel privileges) -Allow the `rustpanel` service user to run just these commands without a password: ``` -/etc/sudoers.d/rustpanel ---------------------------------------- -rustpanel ALL=NOPASSWD: /bin/systemctl start rust-server -rustpanel ALL=NOPASSWD: /bin/systemctl stop rust-server -rustpanel ALL=NOPASSWD: /bin/systemctl restart rust-server -rustpanel ALL=NOPASSWD: /bin/systemctl status rust-server -rustpanel ALL=NOPASSWD: /bin/journalctl -u rust-server -rustpanel ALL=NOPASSWD: /usr/local/bin/rust_install.sh -rustpanel ALL=NOPASSWD: /usr/local/bin/rust_update.sh -rustpanel ALL=NOPASSWD: /usr/local/bin/oxide_update.sh * ---------------------------------------- +sudo ./scripts/install_panel.sh ``` -> The `*` after `oxide_update.sh` allows passing a single URL argument. +After the prompts complete you can visit the panel on port 8080 immediately. +All environment settings are stored in `/etc/rust-panel/panel.env`; edit that +file and restart the `rustpanel` service if you ever need to change the +defaults. -### 3) Python app -Deploy `app.py` and `templates/index.html` to e.g. `/home/rustpanel/rust-panel/`. -Create a venv and install Flask: -``` -sudo -u rustpanel bash -lc ' - cd ~/rust-panel - python3 -m venv ../venv - ../venv/bin/pip install --upgrade pip Flask -' -``` +### Manual install (advanced) -### 4) Systemd unit for the panel -``` -/etc/systemd/system/rustpanel.service ---------------------------------------- -[Unit] -Description=Flask Rust Panel -After=network.target +If you would like to perform the setup yourself, follow the high level steps +below as a reference: -[Service] -User=rustpanel -WorkingDirectory=/home/rustpanel/rust-panel -Environment=RUST_SERVICE=rust-server -# Optional: override login credentials (defaults admin/rustpanel) -# Environment=RUSTPANEL_USER=rustpanel -# Environment=RUSTPANEL_PASSWORD=ChangeMeNow -# Or provide a pre-hashed password (pbkdf2:sha256) -# Environment=RUSTPANEL_PASSWORD_HASH=... -# Optional auth token for API callers (still works in addition to UI login) -# Environment=RUSTPANEL_TOKEN=YourStrongTokenHere -ExecStart=/home/rustpanel/venv/bin/python /home/rustpanel/rust-panel/app.py -Restart=on-failure -RestartSec=5 +1. Copy the helper scripts from `scripts/` into `/usr/local/bin` and make them + executable. +2. Grant the panel service user password-less sudo access to the helper scripts + and to the `systemctl`/`journalctl` commands for your Rust server unit. +3. Deploy the Flask app somewhere (for example `/opt/rust-panel/app.py` and the + `templates/` directory) and install the Python dependencies globally. +4. Create a `systemd` unit that launches `/usr/bin/python3 /path/to/app.py` with + the appropriate environment variables for credentials and paths. +5. Enable and start the unit. -[Install] -WantedBy=multi-user.target ---------------------------------------- -``` -Enable: -``` -systemctl daemon-reload -systemctl enable --now rustpanel -``` +The automated installer performs these steps for you using safe defaults. ## Using the panel - Visit: `http://:8080` diff --git a/scripts/install_panel.sh b/scripts/install_panel.sh index 3c6f5c1..2d5879d 100755 --- a/scripts/install_panel.sh +++ b/scripts/install_panel.sh @@ -5,15 +5,20 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" INSTALL_DIR="${1:-/opt/rust-panel}" APP_DIR="${INSTALL_DIR}/app" -VENV_DIR="${INSTALL_DIR}/venv" -PYTHON_BIN="${PYTHON_BIN:-python3}" +CONFIG_DIR="/etc/rust-panel" +ENV_FILE="${CONFIG_DIR}/panel.env" +DEFAULT_SERVICE_NAME="rustpanel" +DEFAULT_RUST_SERVICE="rust-server" usage() { cat <<'USAGE' Usage: install_panel.sh [INSTALL_DIR] -Installs the Rust-La-Panel application into INSTALL_DIR (default: /opt/rust-panel) -and copies the helper scripts into /usr/local/bin. Requires Python 3 and pip. +Interactive installer for the Rust-La-Panel application. Copies the +application into INSTALL_DIR (default: /opt/rust-panel), installs Python +dependencies system-wide, sets up a systemd service, configures sudoers +rules for the panel service user, and installs the helper scripts needed to +manage the Rust server. Run this script as root on Ubuntu. USAGE } @@ -22,12 +27,102 @@ if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then exit 0 fi -if ! command -v "${PYTHON_BIN}" >/dev/null 2>&1; then - echo "[ERROR] Python interpreter '${PYTHON_BIN}' not found." >&2 +if [[ "${EUID}" -ne 0 ]]; then + echo "[ERROR] This installer must be run as root." >&2 exit 1 fi -mkdir -p "${APP_DIR}" +echo "[INFO] Preparing APT repositories for Steam installation..." +export DEBIAN_FRONTEND=noninteractive +if ! dpkg --print-foreign-architectures | grep -qx 'i386'; then + dpkg --add-architecture i386 +fi + +apt-get update >/dev/null + +if ! command -v add-apt-repository >/dev/null 2>&1; then + apt-get install -y --no-install-recommends software-properties-common lsb-release >/dev/null +fi + +if ! add-apt-repository -yn multiverse >/dev/null; then + echo "[WARN] Unable to enable the multiverse repository automatically. Please ensure it is enabled." >&2 +fi + +apt-get update >/dev/null + +echo "[INFO] Installing required system packages, including SteamCMD..." +apt-get install -y --no-install-recommends \ + python3 python3-flask python3-dotenv sudo \ + steamcmd lib32gcc-s1 lib32stdc++6 ca-certificates >/dev/null + +read -rp "Enter the systemd service name for the panel [${DEFAULT_SERVICE_NAME}]: " input_service +PANEL_SERVICE_NAME="${input_service:-${DEFAULT_SERVICE_NAME}}" +SERVICE_FILE="/etc/systemd/system/${PANEL_SERVICE_NAME}.service" +SUDOERS_FILE="/etc/sudoers.d/${PANEL_SERVICE_NAME}" + +read -rp "Enter the Linux user to run the panel service [${PANEL_SERVICE_NAME}]: " input_user +PANEL_SERVICE_USER="${input_user:-${PANEL_SERVICE_NAME}}" + +read -rp "Enter the systemd service name that manages the Rust server [${DEFAULT_RUST_SERVICE}]: " input_rust_service +RUST_SERVER_SERVICE="${input_rust_service:-${DEFAULT_RUST_SERVICE}}" + +read -rp "Enter the Steam user that owns the Rust server [steam]: " input_steam_user +STEAM_USER="${input_steam_user:-steam}" + +default_steam_home="/home/${STEAM_USER}" +read -rp "Enter the Steam home directory [${default_steam_home}]: " input_steam_home +STEAM_HOME="${input_steam_home:-${default_steam_home}}" + +default_steamcmd="${STEAM_HOME}/steamcmd/steamcmd.sh" +if command -v steamcmd >/dev/null 2>&1; then + default_steamcmd="$(command -v steamcmd)" +fi +read -rp "Enter the SteamCMD path [${default_steamcmd}]: " input_steamcmd +STEAMCMD="${input_steamcmd:-${default_steamcmd}}" + +default_rust_dir="${STEAM_HOME}/rust-server" +read -rp "Enter the Rust server directory [${default_rust_dir}]: " input_rust_dir +RUST_DIR="${input_rust_dir:-${default_rust_dir}}" + +read -rp "Enter the panel login username [admin]: " input_panel_user +PANEL_LOGIN_USER="${input_panel_user:-admin}" + +while true; do + read -srp "Enter the panel login password: " PANEL_LOGIN_PASSWORD + echo + read -srp "Confirm the panel login password: " PANEL_LOGIN_PASSWORD_CONFIRM + echo + if [[ -z "${PANEL_LOGIN_PASSWORD}" ]]; then + echo "[WARN] Password cannot be empty. Please try again." + continue + fi + if [[ "${PANEL_LOGIN_PASSWORD}" != "${PANEL_LOGIN_PASSWORD_CONFIRM}" ]]; then + echo "[WARN] Passwords do not match. Please try again." + continue + fi + break +done + +echo "[INFO] Hashing panel password..." +PANEL_PASSWORD_HASH="$( + PANEL_PASSWORD="${PANEL_LOGIN_PASSWORD}" python3 - <<'PY' +import os +from werkzeug.security import generate_password_hash + +password = os.environ["PANEL_PASSWORD"] +print(generate_password_hash(password)) +PY +)" +unset PANEL_LOGIN_PASSWORD PANEL_LOGIN_PASSWORD_CONFIRM PANEL_PASSWORD + +mkdir -p "${INSTALL_DIR}" "${APP_DIR}" "${CONFIG_DIR}" + +if ! id "${PANEL_SERVICE_USER}" >/dev/null 2>&1; then + echo "[INFO] Creating service user '${PANEL_SERVICE_USER}'." + useradd --system --create-home --home-dir "${INSTALL_DIR}" --shell /usr/sbin/nologin "${PANEL_SERVICE_USER}" +fi + +PANEL_SERVICE_GROUP="$(id -gn "${PANEL_SERVICE_USER}")" copy_path() { local source_path="${1}" destination_path="${2}" @@ -36,38 +131,97 @@ copy_path() { mkdir -p "${destination_path}" cp -a "${source_path}/." "${destination_path}/" else - cp -a "${source_path}" "${destination_path}" + install -Dm644 "${source_path}" "${destination_path}" fi } +echo "[INFO] Copying application files to ${APP_DIR}" copy_path "${REPO_ROOT}/app.py" "${APP_DIR}/app.py" copy_path "${REPO_ROOT}/templates" "${APP_DIR}/templates" -copy_path "${REPO_ROOT}/.env" "${APP_DIR}/.env" -copy_path "${REPO_ROOT}/requirements.txt" "${APP_DIR}/requirements.txt" - -"${PYTHON_BIN}" -m venv "${VENV_DIR}" -"${VENV_DIR}/bin/pip" install --upgrade pip -"${VENV_DIR}/bin/pip" install -r "${APP_DIR}/requirements.txt" - -if [[ "${EUID}" -eq 0 ]]; then - echo "Installing helper scripts into /usr/local/bin" - install -Dm755 "${REPO_ROOT}/scripts/rust_install.sh" /usr/local/bin/rust_install.sh - install -Dm755 "${REPO_ROOT}/scripts/rust_update.sh" /usr/local/bin/rust_update.sh - install -Dm755 "${REPO_ROOT}/scripts/oxide_update.sh" /usr/local/bin/oxide_update.sh + +if [[ -d "${REPO_ROOT}/static" ]]; then + copy_path "${REPO_ROOT}/static" "${APP_DIR}/static" +fi + +install -Dm644 "${REPO_ROOT}/requirements.txt" "${APP_DIR}/requirements.txt" + +echo "[INFO] Installing helper scripts into /usr/local/bin" +install -Dm755 "${REPO_ROOT}/scripts/rust_install.sh" /usr/local/bin/rust_install.sh +install -Dm755 "${REPO_ROOT}/scripts/rust_update.sh" /usr/local/bin/rust_update.sh +install -Dm755 "${REPO_ROOT}/scripts/oxide_update.sh" /usr/local/bin/oxide_update.sh + +cat >"${ENV_FILE}" <"${SERVICE_FILE}" <"${SUDOERS_FILE}" </dev/null 2>&1; then + visudo -cf "${SUDOERS_FILE}" >/dev/null +fi + +chown -R "${PANEL_SERVICE_USER}:${PANEL_SERVICE_GROUP}" "${INSTALL_DIR}" + +if command -v systemctl >/dev/null 2>&1; then + echo "[INFO] Enabling and starting ${PANEL_SERVICE_NAME}.service" + systemctl daemon-reload + systemctl enable --now "${PANEL_SERVICE_NAME}.service" else - cat <<'MSG' -[INFO] Run this script as root (or re-run with sudo) to install the helper scripts -into /usr/local/bin. They remain available under scripts/ in the repository. -MSG + echo "[WARN] systemctl not found. Skipping automatic service enable." fi cat <