#!/usr/bin/env bash # Debian 13+ one-line bootstrap for first install or safe source update. # Builds as an unprivileged user, then delegates host changes to install.sh/update.sh. set -euo pipefail REPO_URL="${RUSTPROXY_REPO_URL:-https://git.linuxiarz.pl/gru/RustProxy.git}" ADMIN_LISTEN="${RUSTPROXY_ADMIN_LISTEN:-127.0.0.1:9090}" ALLOW_REMOTE_ADMIN="${RUSTPROXY_ALLOW_REMOTE_ADMIN:-0}" PREFIX="${RUSTPROXY_PREFIX:-/opt/rustproxy}" MODE="${1:-auto}" case "$MODE" in auto|install|update) ;; --install) MODE=install ;; --update) MODE=update ;; -h|--help) cat <<'USAGE' Usage: install-debian13.sh [auto|install|update] auto Install when RustProxy is absent; update when /opt/rustproxy/install.json exists (default) install Require a fresh installation update Require an existing managed installation and perform a safe update Environment: RUSTPROXY_REPO_URL Git repository URL RUSTPROXY_ADMIN_LISTEN Admin bind used only on first install (default 127.0.0.1:9090) RUSTPROXY_ALLOW_REMOTE_ADMIN Set to 1 only to permit plain-HTTP non-loopback admin on first install RUSTPROXY_PREFIX Managed install prefix (default /opt/rustproxy) RUSTPROXY_BUILD_JOBS Cargo jobs for low-memory builds (default 1) USAGE exit 0 ;; *) echo "Unknown mode: $MODE (expected auto, install or update)." >&2 exit 2 ;; esac if [[ ${EUID:-$(id -u)} -ne 0 ]]; then echo "Run this bootstrap as root (for example: wget -qO- ... | bash)." >&2 exit 1 fi . /etc/os-release if [[ ${ID:-} != debian ]] || [[ ${VERSION_ID%%.*} -lt 13 ]]; then echo "This bootstrap supports Debian 13+. Detected: ${PRETTY_NAME:-unknown}." >&2 exit 1 fi install_record="$PREFIX/install.json" if [[ "$MODE" == auto ]]; then if [[ -f "$install_record" ]]; then MODE=update elif [[ -e "$PREFIX/current" || -e /etc/systemd/system/rustproxy.service ]]; then echo "RustProxy artifacts exist but $install_record is missing; refusing automatic overwrite." >&2 echo "Recover the managed install record or use the project migration/recovery procedure." >&2 exit 1 else MODE=install fi fi if [[ "$MODE" == update && ! -f "$install_record" ]]; then echo "Update requested, but managed installation record is missing: $install_record" >&2 exit 1 fi if [[ "$MODE" == install && -e "$install_record" ]]; then echo "Install requested, but RustProxy is already installed. Use update mode." >&2 exit 1 fi echo "RustProxy bootstrap mode: $MODE" export DEBIAN_FRONTEND=noninteractive apt-get update apt-get install -y build-essential gcc git ca-certificates python3 python3-venv python3-pip pkg-config wget sudo logrotate created_builder=0 if [[ -n ${SUDO_USER:-} && ${SUDO_USER} != root ]] && id "${SUDO_USER}" >/dev/null 2>&1; then builder=${SUDO_USER} builder_home=$(getent passwd "$builder" | cut -d: -f6) else builder=rustproxy-build builder_home=/var/tmp/rustproxy-build if ! id "$builder" >/dev/null 2>&1; then useradd --create-home --home-dir "$builder_home" --shell /bin/bash "$builder" created_builder=1 fi fi work=$(mktemp -d /var/tmp/rustproxy-source.XXXXXX) chown "$builder":"$(id -gn "$builder")" "$work" cleanup() { rm -rf "$work" if [[ $created_builder -eq 1 ]]; then userdel -r "$builder" >/dev/null 2>&1 || true fi } trap cleanup EXIT run_builder() { runuser -u "$builder" -- env HOME="$builder_home" PATH="$builder_home/.cargo/bin:/usr/local/bin:/usr/bin:/bin" "$@" } if ! run_builder bash -lc 'command -v cargo >/dev/null 2>&1'; then run_builder bash -lc "wget -qO- --https-only --secure-protocol=TLSv1_2 https://sh.rustup.rs | sh -s -- -y --profile minimal" fi run_builder git clone --depth 1 "$REPO_URL" "$work/RustProxy" # Keep source builds reliable on small Debian VPSes. The repository release # profile may use LTO/codegen settings that can make rustc exceed RAM limits. BUILD_JOBS="${RUSTPROXY_BUILD_JOBS:-1}" if ! [[ "$BUILD_JOBS" =~ ^[1-9][0-9]*$ ]]; then echo "RUSTPROXY_BUILD_JOBS must be a positive integer." >&2 exit 1 fi if [[ "$ALLOW_REMOTE_ADMIN" != "0" && "$ALLOW_REMOTE_ADMIN" != "1" ]]; then echo "RUSTPROXY_ALLOW_REMOTE_ADMIN must be 0 or 1." >&2 exit 1 fi run_builder bash -lc "cd '$work/RustProxy' && CARGO_BUILD_JOBS='$BUILD_JOBS' CARGO_PROFILE_RELEASE_LTO=false CARGO_PROFILE_RELEASE_CODEGEN_UNITS=8 cargo build --release --locked" cd "$work/RustProxy" if [[ "$MODE" == install ]]; then install_args=( --binary target/release/rust-proxy --prefix "$PREFIX" --admin "$ADMIN_LISTEN" ) if [[ "$ALLOW_REMOTE_ADMIN" == "1" ]]; then install_args+=(--allow-remote-admin) fi bash install.sh "${install_args[@]}" printf '\nRustProxy installed. Admin panel: http://%s\n' "$ADMIN_LISTEN" if [[ "$ALLOW_REMOTE_ADMIN" == "1" ]]; then printf 'WARNING: plain-HTTP remote administration was explicitly enabled. Restrict it to a trusted private network and migrate to Administration HTTPS.\n' else printf 'Administration is loopback-only by default. Use an SSH tunnel or enable Administration HTTPS before remote exposure.\n' fi else # update.sh reads the saved installation record and therefore preserves the # existing data directory, HTTP/TLS/admin binds and service account. bash update.sh \ --binary target/release/rust-proxy \ --prefix "$PREFIX" printf '\nRustProxy updated successfully. Existing configuration and data were preserved.\n' fi