#!/usr/bin/env bash # NetX Linux installer / updater. Ships at the root of netx--linux-x86_64.tar.gz. # # sudo ./install.sh # interactive install (or update when already installed) # sudo ./install.sh --yes --db bundled --port 8890 --pg-port 15432 # sudo ./install.sh --mode update --yes # what `netxctl update` runs # # Needs only bash, coreutils and useradd (tar to unpack it): Python, PostgreSQL # and the web UI are inside the package. set -euo pipefail PKG="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)" # shellcheck source=lib.sh . "${PKG}/packaging/linux/lib.sh" NETX_PY="${PKG}/python/bin/python3" NETX_ADMIN_PY="${PKG}/packaging/linux/netx_admin.py" PREFIX="/opt/netx" DATA="/var/lib/netx" MODE="" DB_MODE="" API_PORT="" BIND="" PG_PORT="" PG_PASSWORD="" DB_URL="" DB_HOST="" DB_PORT_EXT="" DB_USER="" DB_PASS="" DB_NAME="" CRED_KEY_FILE="" ADMIN_PASSWORD="" ADMIN_PW_GENERATED=0 NO_SERVICE=0 AUTO_UPDATE=0 OPEN_FIREWALL=0 NO_BACKUP=0 YES=0 usage() { cat < echo answer local a read -r -p "$1 [$2]: " a || true echo "${a:-$2}" } # ------------------------------------------------------------------ preflight preflight() { is_root || die "$(t "请用 root 运行:sudo ./install.sh" "run as root: sudo ./install.sh")" local arch arch="$(uname -m)" [[ "${arch}" == "x86_64" || "${arch}" == "amd64" ]] || die "$(t "本安装包仅支持 x86_64,当前" "this package is x86_64 only; this machine is") ${arch}" local glibc glibc="$(getconf GNU_LIBC_VERSION 2>/dev/null | awk '{print $2}')" || true [[ -n "${glibc}" ]] || die "$(t "未检测到 glibc(不支持 Alpine/musl)" "glibc not found (Alpine/musl is not supported)")" if [[ "$(printf '%s\n2.17\n' "${glibc}" | sort -V | head -n1)" != "2.17" ]]; then die "$(t "glibc 版本过低" "glibc too old"): ${glibc} (>= 2.17)" fi "${NETX_PY}" -c "import sys" 2>/dev/null || die "$(t "内置 Python 无法运行,安装包可能损坏" "bundled Python does not run; package may be corrupt")" [[ -f "${PKG}/version.json" ]] || die "version.json missing in ${PKG}" local parent avail parent="$(dirname "${PREFIX}")" mkdir -p "${parent}" avail="$(df -Pk "${parent}" | awk 'NR==2 {print $4}')" if [[ -n "${avail}" && "${avail}" -lt 1048576 ]]; then die "$(t "磁盘空间不足(至少 1GB)" "not enough disk space (need 1GB)"): ${parent}" fi } ensure_user() { if id "${NETX_USER}" >/dev/null 2>&1; then return 0; fi info "$(t "创建系统用户" "creating system user") ${NETX_USER}" local nologin=/sbin/nologin [[ -x "${nologin}" ]] || nologin=/usr/sbin/nologin [[ -x "${nologin}" ]] || nologin=/bin/false if command -v useradd >/dev/null 2>&1; then useradd -r -U -d "${DATA}" -M -s "${nologin}" "${NETX_USER}" 2>/dev/null || useradd -r -d "${DATA}" -M -s "${nologin}" "${NETX_USER}" elif command -v adduser >/dev/null 2>&1; then adduser -S -D -H -h "${DATA}" -s "${nologin}" "${NETX_USER}" 2>/dev/null || adduser --system --group --no-create-home --home "${DATA}" "${NETX_USER}" else die "$(t "缺少 useradd/adduser,无法创建用户" "useradd/adduser not found")" fi # Some useradd builds do not create a same-named group with -r. getent group "${NETX_USER}" >/dev/null 2>&1 || groupadd -r "${NETX_USER}" 2>/dev/null || true } # ------------------------------------------------------------------ prompts pick_port() { # pick_port