diff --git a/README.md b/README.md index d126620..d4c80af 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,8 @@ Admin token /opt/sshpanel/xray_config.json /opt/sshpanel/admin/ /opt/sshpanel/logs/panel.log +/opt/sshpanel/update.sh +/opt/sshpanel/change_admin_password.sh /etc/systemd/system/sshpanel.service ``` @@ -195,15 +197,46 @@ sudo bash /opt/sshpanel/change_admin_password.sh --user admin --generate O script atualiza o usuário `admin` no PostgreSQL, ativa ele como `superadmin`, salva `ADMIN_PASSWORD` em `/opt/sshpanel/.env` e reinicia o serviço `sshpanel` para recarregar o cache interno de admins. -### Atualização +### Atualização automática pelo Git -Entre na pasta do projeto atualizado e execute: +Depois da instalação, o `update.sh` fica salvo em `/opt/sshpanel/update.sh`. Para atualizar o servidor, o dono só precisa executar: ```bash -sudo bash update.sh +sudo bash /opt/sshpanel/update.sh ``` -O update recompila o binário e atualiza os arquivos do painel web, mantendo as configurações e dados existentes. +O script baixa automaticamente os arquivos mais recentes do Git: + +```text +https://git.dr2.site/penguinehis/DragonCoreSSH-NewWEB.git +``` + +Depois ele recompila o binário e atualiza o painel web e os scripts auxiliares, mantendo as configurações e dados existentes. + +O update preserva: + +```text +/opt/sshpanel/.env +/opt/sshpanel/config.json +/opt/sshpanel/xray_config.json +Banco de dados PostgreSQL +Usuários SSH/Xray +Chaves SSH +Certificados +Logs +``` + +Se quiser forçar uma branch/ref específica: + +```bash +sudo UPDATE_REF=main bash /opt/sshpanel/update.sh +``` + +Se quiser usar outro repositório: + +```bash +sudo REPO_URL=https://git.dr2.site/penguinehis/DragonCoreSSH-NewWEB.git bash /opt/sshpanel/update.sh +``` ### API pública CheckUser @@ -385,6 +418,8 @@ Admin token /opt/sshpanel/xray_config.json /opt/sshpanel/admin/ /opt/sshpanel/logs/panel.log +/opt/sshpanel/update.sh +/opt/sshpanel/change_admin_password.sh /etc/systemd/system/sshpanel.service ``` @@ -482,15 +517,46 @@ sudo bash /opt/sshpanel/change_admin_password.sh --user admin --generate The script updates the `admin` user in PostgreSQL, enables it as `superadmin`, saves `ADMIN_PASSWORD` in `/opt/sshpanel/.env`, and restarts `sshpanel` so the in-memory admin cache is reloaded. -### Update +### Automatic Git update -Enter the updated source-code folder and run: +After installation, `update.sh` is saved at `/opt/sshpanel/update.sh`. To update the server, the owner only needs to run: ```bash -sudo bash update.sh +sudo bash /opt/sshpanel/update.sh ``` -The update script rebuilds the binary and updates the web panel files while keeping existing configuration and user data. +The script automatically downloads the latest files from Git: + +```text +https://git.dr2.site/penguinehis/DragonCoreSSH-NewWEB.git +``` + +Then it rebuilds the binary and updates the web panel and helper scripts while keeping existing configuration and user data. + +The update preserves: + +```text +/opt/sshpanel/.env +/opt/sshpanel/config.json +/opt/sshpanel/xray_config.json +PostgreSQL database +SSH/Xray users +SSH keys +Certificates +Logs +``` + +To force a specific branch/ref: + +```bash +sudo UPDATE_REF=main bash /opt/sshpanel/update.sh +``` + +To use another repository: + +```bash +sudo REPO_URL=https://git.dr2.site/penguinehis/DragonCoreSSH-NewWEB.git bash /opt/sshpanel/update.sh +``` ### Public CheckUser API diff --git a/install.sh b/install.sh index ce7ab3c..06e370b 100644 --- a/install.sh +++ b/install.sh @@ -35,23 +35,23 @@ case "$OS_ID" in ubuntu|debian|linuxmint) PKG_UPDATE="apt-get update -qq" PKG_INSTALL="DEBIAN_FRONTEND=noninteractive apt-get install -y" - PKG_DEPS="curl wget git build-essential postgresql postgresql-contrib ca-certificates unzip openssh-client openssl iptables nftables" + PKG_DEPS="curl wget git rsync build-essential postgresql postgresql-contrib ca-certificates unzip openssh-client openssl iptables nftables" ;; centos|rhel|rocky|almalinux) PKG_UPDATE="yum makecache -q" PKG_INSTALL="yum install -y" - PKG_DEPS="curl wget git gcc make postgresql-server postgresql-contrib ca-certificates unzip openssh-clients openssl iptables nftables" + PKG_DEPS="curl wget git rsync gcc make postgresql-server postgresql-contrib ca-certificates unzip openssh-clients openssl iptables nftables" ;; fedora) PKG_UPDATE="dnf makecache -q" PKG_INSTALL="dnf install -y" - PKG_DEPS="curl wget git gcc make postgresql-server postgresql-contrib ca-certificates unzip openssh-clients openssl iptables nftables" + PKG_DEPS="curl wget git rsync gcc make postgresql-server postgresql-contrib ca-certificates unzip openssh-clients openssl iptables nftables" ;; *) warn "Unknown OS '$OS_ID' — attempting apt-get…" PKG_UPDATE="apt-get update -qq" PKG_INSTALL="DEBIAN_FRONTEND=noninteractive apt-get install -y" - PKG_DEPS="curl wget git build-essential postgresql postgresql-contrib ca-certificates unzip openssh-client openssl iptables nftables" + PKG_DEPS="curl wget git rsync build-essential postgresql postgresql-contrib ca-certificates unzip openssh-client openssl iptables nftables" ;; esac info " OS: $OS_ID" @@ -107,6 +107,11 @@ go build -ldflags="-s -w" -o "$INSTALL_DIR/sshpanel" . info " Binary: $INSTALL_DIR/sshpanel" cp -r "$SCRIPT_DIR/admin/"* "$INSTALL_DIR/admin/" info " Admin panel copied" +if [[ -f "$SCRIPT_DIR/update.sh" ]]; then + cp "$SCRIPT_DIR/update.sh" "$INSTALL_DIR/update.sh" + chmod 700 "$INSTALL_DIR/update.sh" + info " Git updater copied" +fi if [[ -f "$SCRIPT_DIR/change_admin_password.sh" ]]; then cp "$SCRIPT_DIR/change_admin_password.sh" "$INSTALL_DIR/change_admin_password.sh" chmod 700 "$INSTALL_DIR/change_admin_password.sh" diff --git a/update.sh b/update.sh index dc33908..29bd510 100644 --- a/update.sh +++ b/update.sh @@ -1,7 +1,21 @@ #!/bin/bash -# Update script for SSH Panel — updates the binary and admin panel in place. -# Preserves: .env, config.json, xray_config.json, SSH keys, database, certs. -# Usage: sudo bash update.sh +# Update script for DragonCoreSSH / SSH Panel. +# Pulls the newest source from Git, builds the new binary, and updates the +# installed files in place. +# +# Preserved: +# - /opt/sshpanel/.env +# - /opt/sshpanel/config.json +# - /opt/sshpanel/xray_config.json +# - SSH keys, certs, logs, database, users +# +# Usage: +# sudo bash /opt/sshpanel/update.sh +# sudo bash update.sh +# +# Optional: +# sudo UPDATE_REF=main bash /opt/sshpanel/update.sh +# sudo REPO_URL=https://git.dr2.site/penguinehis/DragonCoreSSH-NewWEB.git bash /opt/sshpanel/update.sh set -euo pipefail RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' @@ -9,184 +23,279 @@ info() { echo -e "${GREEN}[+]${NC} $*"; } warn() { echo -e "${YELLOW}[!]${NC} $*"; } error() { echo -e "${RED}[x]${NC} $*"; exit 1; } -# ── config ──────────────────────────────────────────────────────────────────── -INSTALL_DIR="/opt/sshpanel" -SERVICE_NAME="sshpanel" +# Config +INSTALL_DIR="${INSTALL_DIR:-/opt/sshpanel}" +SERVICE_NAME="${SERVICE_NAME:-sshpanel}" +REPO_URL="${REPO_URL:-https://git.dr2.site/penguinehis/DragonCoreSSH-NewWEB.git}" +UPDATE_REF="${UPDATE_REF:-}" +SOURCE_CACHE_DIR="${SOURCE_CACHE_DIR:-${INSTALL_DIR}/source}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -GO_VERSION="${GO_VERSION:-$(awk '$1 == "go" {print $2; exit}' "$SCRIPT_DIR/go.mod" 2>/dev/null || echo "1.22.5")}" -# ───────────────────────────────────────────────────────────────────────────── +SOURCE_DIR="" +RESTART_NEEDED=false [[ $EUID -ne 0 ]] && error "Run as root: sudo bash $0" -echo -e "\n${GREEN}══════════════════════════════════════════${NC}" -echo -e "${GREEN} SSH Panel · Updater ${NC}" -echo -e "${GREEN}══════════════════════════════════════════${NC}\n" +echo -e "\n${GREEN}==========================================${NC}" +echo -e "${GREEN} DragonCoreSSH / SSH Panel Updater ${NC}" +echo -e "${GREEN}==========================================${NC}\n" -# ── 1. Pre-flight checks ────────────────────────────────────────────────────── -info "[1/6] Pre-flight checks…" +# Helpers +need_cmd() { + command -v "$1" >/dev/null 2>&1 || error "Required command not found: $1" +} -[[ -d "$INSTALL_DIR" ]] || error "Install dir $INSTALL_DIR not found — run install.sh first." -[[ -f "$INSTALL_DIR/.env" ]] || error "$INSTALL_DIR/.env not found — run install.sh first." -[[ -f "$SCRIPT_DIR/go.mod" ]] || error "go.mod not found — run this script from the source directory." - -info " Install dir : $INSTALL_DIR" -info " Source dir : $SCRIPT_DIR" -info " Go version : $GO_VERSION" - -# ── 2. Go toolchain ─────────────────────────────────────────────────────────── -info "[2/6] Checking Go toolchain…" - -NEED_GO=true -if command -v go &>/dev/null; then - CURRENT_GO=$(go version 2>/dev/null | awk '{print $3}' | sed 's/go//') - if [[ "$(printf '%s\n' "$GO_VERSION" "$CURRENT_GO" | sort -V | head -1)" == "$GO_VERSION" ]]; then - info " Go $CURRENT_GO already installed — skipping" - NEED_GO=false +install_git_if_missing() { + if command -v git >/dev/null 2>&1; then + return 0 fi -fi + warn "git is not installed. Trying to install it..." + if command -v apt-get >/dev/null 2>&1; then + apt-get update -qq + DEBIAN_FRONTEND=noninteractive apt-get install -y git ca-certificates + elif command -v dnf >/dev/null 2>&1; then + dnf install -y git ca-certificates + elif command -v yum >/dev/null 2>&1; then + yum install -y git ca-certificates + else + error "git is required. Install git first, then run this updater again." + fi +} -if $NEED_GO; then - MACHINE=$(uname -m) - case "$MACHINE" in - x86_64) GOARCH="amd64" ;; - aarch64) GOARCH="arm64" ;; - armv7l) GOARCH="armv6l" ;; - *) GOARCH="amd64" ;; - esac - GO_URL="https://go.dev/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz" - info " Downloading Go ${GO_VERSION} (${GOARCH})…" - wget -q --show-progress -O /tmp/go.tar.gz "$GO_URL" - rm -rf /usr/local/go - tar -C /usr/local -xzf /tmp/go.tar.gz - rm -f /tmp/go.tar.gz - echo 'export PATH=$PATH:/usr/local/go/bin' > /etc/profile.d/go.sh - chmod +x /etc/profile.d/go.sh -fi +remote_default_branch() { + local branch + branch="$(git ls-remote --symref "$REPO_URL" HEAD 2>/dev/null | awk '/^ref:/ {sub("refs/heads/", "", $2); print $2; exit}')" + if [[ -n "$branch" ]]; then + printf '%s\n' "$branch" + else + printf 'main\n' + fi +} -export PATH=$PATH:/usr/local/go/bin -go version +prepare_source_from_git() { + install_git_if_missing -# ── 3. Build new binary ─────────────────────────────────────────────────────── -info "[3/6] Building new sshpanel binary…" + if [[ -z "$UPDATE_REF" ]]; then + UPDATE_REF="$(remote_default_branch)" + fi -cd "$SCRIPT_DIR" -export GOPATH=/tmp/gopath_sshpanel -export GOCACHE=/tmp/gocache_sshpanel -go mod download -go build -ldflags="-s -w" -o /tmp/sshpanel_new . -info " Build complete." + info "[1/7] Fetching latest files from Git..." + info " Repo : $REPO_URL" + info " Ref : $UPDATE_REF" -# ── 4. Apply update ─────────────────────────────────────────────────────────── -info "[4/6] Applying update…" + # If update.sh is being run from a real clone of this repo, update that folder. + # This is useful for developers who run the updater from the cloned project. + if [[ -d "$SCRIPT_DIR/.git" && -f "$SCRIPT_DIR/go.mod" ]]; then + SOURCE_DIR="$SCRIPT_DIR" + info " Updating existing source folder: $SOURCE_DIR" + git -C "$SOURCE_DIR" remote set-url origin "$REPO_URL" >/dev/null 2>&1 || true + git -C "$SOURCE_DIR" fetch --prune origin + git -C "$SOURCE_DIR" checkout "$UPDATE_REF" >/dev/null 2>&1 || true + git -C "$SOURCE_DIR" reset --hard "origin/$UPDATE_REF" + git -C "$SOURCE_DIR" clean -fd + return 0 + fi -# Stop the service -if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then - info " Stopping $SERVICE_NAME…" - systemctl stop "$SERVICE_NAME" - RESTART_NEEDED=true -else - RESTART_NEEDED=false -fi + # Normal installed-server path: keep a local Git cache under /opt/sshpanel/source. + mkdir -p "$(dirname "$SOURCE_CACHE_DIR")" + if [[ -d "$SOURCE_CACHE_DIR/.git" ]]; then + SOURCE_DIR="$SOURCE_CACHE_DIR" + info " Updating cached source folder: $SOURCE_DIR" + git -C "$SOURCE_DIR" remote set-url origin "$REPO_URL" >/dev/null 2>&1 || true + git -C "$SOURCE_DIR" fetch --prune origin + git -C "$SOURCE_DIR" checkout "$UPDATE_REF" >/dev/null 2>&1 || true + git -C "$SOURCE_DIR" reset --hard "origin/$UPDATE_REF" + git -C "$SOURCE_DIR" clean -fd + else + rm -rf "$SOURCE_CACHE_DIR" + info " Cloning source folder to: $SOURCE_CACHE_DIR" + git clone --depth 1 --branch "$UPDATE_REF" "$REPO_URL" "$SOURCE_CACHE_DIR" || { + warn "Clone with ref '$UPDATE_REF' failed. Trying default clone..." + rm -rf "$SOURCE_CACHE_DIR" + git clone --depth 1 "$REPO_URL" "$SOURCE_CACHE_DIR" + } + SOURCE_DIR="$SOURCE_CACHE_DIR" + fi -# Backup old binary -if [[ -f "$INSTALL_DIR/sshpanel" ]]; then - cp "$INSTALL_DIR/sshpanel" "$INSTALL_DIR/sshpanel.bak" - info " Old binary backed up to sshpanel.bak" -fi + [[ -f "$SOURCE_DIR/go.mod" ]] || error "Downloaded source is invalid: go.mod not found in $SOURCE_DIR" + [[ -d "$SOURCE_DIR/admin" ]] || error "Downloaded source is invalid: admin folder not found in $SOURCE_DIR" +} -# Replace binary -mv /tmp/sshpanel_new "$INSTALL_DIR/sshpanel" -chmod +x "$INSTALL_DIR/sshpanel" -info " Binary updated." +install_go_if_needed() { + local go_version machine goarch go_url current_go need_go + go_version="$(awk '$1 == "go" {print $2; exit}' "$SOURCE_DIR/go.mod" 2>/dev/null || echo "1.22.5")" + need_go=true -# Update admin panel files -mkdir -p "$INSTALL_DIR/admin" -cp -r "$SCRIPT_DIR/admin/"* "$INSTALL_DIR/admin/" -info " Admin panel updated." -if [[ -f "$SCRIPT_DIR/change_admin_password.sh" ]]; then - cp "$SCRIPT_DIR/change_admin_password.sh" "$INSTALL_DIR/change_admin_password.sh" - chmod 700 "$INSTALL_DIR/change_admin_password.sh" - info " Admin password recovery script updated." -fi + info "[2/7] Checking Go toolchain..." + info " Required Go: $go_version" -# Ensure banner file exists (new in this version) -if [[ ! -f "$INSTALL_DIR/banner.txt" ]]; then - touch "$INSTALL_DIR/banner.txt" - info " Created banner.txt" -fi + if command -v go >/dev/null 2>&1; then + current_go="$(go version 2>/dev/null | awk '{print $3}' | sed 's/go//')" + if [[ "$(printf '%s\n' "$go_version" "$current_go" | sort -V | head -1)" == "$go_version" ]]; then + info " Go $current_go already installed." + need_go=false + fi + fi -# Ensure certs directory exists (new in this version) -mkdir -p "$INSTALL_DIR/certs" + if $need_go; then + machine="$(uname -m)" + case "$machine" in + x86_64) goarch="amd64" ;; + aarch64) goarch="arm64" ;; + armv7l) goarch="armv6l" ;; + *) goarch="amd64" ;; + esac + go_url="https://go.dev/dl/go${go_version}.linux-${goarch}.tar.gz" + info " Downloading Go ${go_version} (${goarch})..." + need_cmd wget + wget -q --show-progress -O /tmp/go.tar.gz "$go_url" + rm -rf /usr/local/go + tar -C /usr/local -xzf /tmp/go.tar.gz + rm -f /tmp/go.tar.gz + echo 'export PATH=$PATH:/usr/local/go/bin' > /etc/profile.d/go.sh + chmod +x /etc/profile.d/go.sh + fi -# Patch config.json to add missing fields introduced in this version -# without overwriting user-configured values. -CFG="$INSTALL_DIR/config.json" -if [[ -f "$CFG" ]]; then - # Add banner_file if not present - if ! python3 -c "import json,sys; d=json.load(open('$CFG')); sys.exit(0 if 'banner_file' in d else 1)" 2>/dev/null; then - python3 - "$CFG" << 'PYEOF' + export PATH=$PATH:/usr/local/go/bin + go version +} + +build_binary() { + info "[3/7] Building new sshpanel binary..." + cd "$SOURCE_DIR" + export GOPATH=/tmp/gopath_sshpanel + export GOCACHE=/tmp/gocache_sshpanel + go mod download + go build -ldflags="-s -w" -o /tmp/sshpanel_new . + info " Build complete." +} + +stop_service() { + info "[4/7] Stopping service..." + if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then + systemctl stop "$SERVICE_NAME" + RESTART_NEEDED=true + info " $SERVICE_NAME stopped." + else + RESTART_NEEDED=false + warn " $SERVICE_NAME was not running." + fi +} + +copy_optional_script() { + local name mode + name="$1" + mode="$2" + if [[ -f "$SOURCE_DIR/$name" ]]; then + cp "$SOURCE_DIR/$name" "$INSTALL_DIR/$name" + chmod "$mode" "$INSTALL_DIR/$name" + info " Updated $name" + fi +} + +apply_update() { + info "[5/7] Applying update..." + + mkdir -p "$INSTALL_DIR/admin" "$INSTALL_DIR/logs" "$INSTALL_DIR/certs" + + if [[ -f "$INSTALL_DIR/sshpanel" ]]; then + cp "$INSTALL_DIR/sshpanel" "$INSTALL_DIR/sshpanel.bak" + info " Old binary backed up to $INSTALL_DIR/sshpanel.bak" + fi + + mv /tmp/sshpanel_new "$INSTALL_DIR/sshpanel" + chmod 755 "$INSTALL_DIR/sshpanel" + info " Binary updated." + + rsync -a --delete "$SOURCE_DIR/admin/" "$INSTALL_DIR/admin/" + info " Admin panel updated." + + copy_optional_script "update.sh" 700 + copy_optional_script "install.sh" 700 + copy_optional_script "change_admin_password.sh" 700 + + # Keep a local copy of the latest source for easier support and future updates. + if [[ "$SOURCE_DIR" != "$SOURCE_CACHE_DIR" ]]; then + rm -rf "$SOURCE_CACHE_DIR" + mkdir -p "$SOURCE_CACHE_DIR" + rsync -a --delete --exclude '.git' "$SOURCE_DIR/" "$SOURCE_CACHE_DIR/" + info " Source files copied to $SOURCE_CACHE_DIR" + fi + + [[ -f "$INSTALL_DIR/banner.txt" ]] || touch "$INSTALL_DIR/banner.txt" +} + +patch_configs() { + info "[6/7] Patching config files without overwriting user settings..." + + local cfg xcfg + cfg="$INSTALL_DIR/config.json" + xcfg="$INSTALL_DIR/xray_config.json" + + if [[ -f "$cfg" ]]; then + python3 - "$cfg" <<'PYEOF' import json, sys path = sys.argv[1] -with open(path) as f: - d = json.load(f) +try: + with open(path) as f: + d = json.load(f) +except Exception as e: + print(f"[!] Could not parse {path}: {e}") + sys.exit(0) +changed = False if 'banner_file' not in d: d['banner_file'] = '/opt/sshpanel/banner.txt' -with open(path, 'w') as f: - json.dump(d, f, indent=2) -PYEOF - info " Added banner_file to config.json" - fi - - # Remove legacy local_ssh_listen. DragonCore now handles DNSTT in-process. - python3 - "$CFG" << 'PYEOF' -import json, sys -path = sys.argv[1] -with open(path) as f: - d = json.load(f) -changed = d.pop('local_ssh_listen', None) is not None + changed = True +if 'local_ssh_listen' in d: + d.pop('local_ssh_listen', None) + changed = True if changed: with open(path, 'w') as f: json.dump(d, f, indent=2) + f.write('\n') PYEOF + info " config.json checked." + fi - # Fix routing: remove geoip:private rules that require geoip.dat from xray_config.json - XCFG="$INSTALL_DIR/xray_config.json" - if [[ -f "$XCFG" ]]; then - if grep -q '"geoip:private"' "$XCFG" 2>/dev/null; then - python3 - "$XCFG" << 'PYEOF' + if [[ -f "$xcfg" ]] && grep -q '"geoip:private"' "$xcfg" 2>/dev/null; then + python3 - "$xcfg" <<'PYEOF' import json, sys path = sys.argv[1] -with open(path) as f: - d = json.load(f) +try: + with open(path) as f: + d = json.load(f) +except Exception as e: + print(f"[!] Could not parse {path}: {e}") + sys.exit(0) routing = d.get('routing', {}) rules = routing.get('rules', []) -# Remove rules that reference geoip:private new_rules = [r for r in rules if 'geoip:private' not in r.get('ip', [])] if new_rules != rules: if new_rules: - d['routing']['rules'] = new_rules + d.setdefault('routing', {})['rules'] = new_rules else: d.pop('routing', None) with open(path, 'w') as f: json.dump(d, f, indent=2) + f.write('\n') PYEOF - info " Removed geoip:private routing rule from xray_config.json" - fi + info " Removed geoip:private routing rule from xray_config.json" fi -fi +} -# ── 5. DNSTT DNS/53 redirect ───────────────────────────────────────────────── -info "[5/6] Ensuring DNSTT DNS redirect (UDP 53 -> 5300)…" -cat > /usr/local/sbin/sshpanel-dnstt-redirect.sh <<'EOS' +ensure_dnstt_redirect() { + info " Ensuring DNSTT DNS redirect service exists..." + cat > /usr/local/sbin/sshpanel-dnstt-redirect.sh <<'EOS' #!/bin/bash set -euo pipefail DNS_UPSTREAM="${DNS_UPSTREAM:-1.1.1.1}" DNSTT_PORT="${DNSTT_PORT:-5300}" + if command -v systemctl >/dev/null 2>&1; then systemctl disable --now systemd-resolved.service >/dev/null 2>&1 || true fi rm -f /etc/resolv.conf printf 'nameserver %s\n' "$DNS_UPSTREAM" > /etc/resolv.conf + if command -v ufw >/dev/null 2>&1; then ufw allow 53/udp >/dev/null 2>&1 || true fi @@ -194,11 +303,13 @@ if command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2> firewall-cmd --permanent --add-port=53/udp >/dev/null 2>&1 || true firewall-cmd --reload >/dev/null 2>&1 || true fi + add_iptables_rule() { local bin="$1" chain="$2" "$bin" -t nat -C "$chain" -p udp --dport 53 -j REDIRECT --to-ports "$DNSTT_PORT" 2>/dev/null \ || "$bin" -t nat -A "$chain" -p udp --dport 53 -j REDIRECT --to-ports "$DNSTT_PORT" } + if command -v iptables >/dev/null 2>&1; then add_iptables_rule iptables PREROUTING fi @@ -212,8 +323,9 @@ if ! command -v iptables >/dev/null 2>&1 && command -v nft >/dev/null 2>&1; then || nft add rule inet sshpanel_nat prerouting udp dport 53 redirect to :"$DNSTT_PORT" fi EOS -chmod +x /usr/local/sbin/sshpanel-dnstt-redirect.sh -cat > /etc/systemd/system/sshpanel-dnstt-redirect.service <<'EOF' + chmod +x /usr/local/sbin/sshpanel-dnstt-redirect.sh + + cat > /etc/systemd/system/sshpanel-dnstt-redirect.service <<'EOF2' [Unit] Description=SSH Panel DNSTT DNS redirect (UDP 53 to 5300) After=network.target @@ -226,55 +338,95 @@ RemainAfterExit=yes [Install] WantedBy=multi-user.target -EOF -mkdir -p /etc/systemd/system/sshpanel.service.d -cat > /etc/systemd/system/sshpanel.service.d/override.conf < /etc/systemd/system/sshpanel.service.d/override.conf </dev/null 2>&1; then + warn "rsync is not installed. Trying to install it..." + if command -v apt-get >/dev/null 2>&1; then + apt-get update -qq + DEBIAN_FRONTEND=noninteractive apt-get install -y rsync + elif command -v dnf >/dev/null 2>&1; then + dnf install -y rsync + elif command -v yum >/dev/null 2>&1; then + yum install -y rsync + else + error "rsync is required. Install rsync first, then run this updater again." fi -else - warn " Service was not running; start it with: systemctl start $SERVICE_NAME" fi +info " Install dir : $INSTALL_DIR" +info " Cache dir : $SOURCE_CACHE_DIR" + +prepare_source_from_git +install_go_if_needed +build_binary +stop_service +apply_update +patch_configs +restart_service + echo "" -echo -e "${GREEN}══════════════════════════════════════════${NC}" +echo -e "${GREEN}==========================================${NC}" echo -e "${GREEN} Update complete! ${NC}" -echo -e "${GREEN}══════════════════════════════════════════${NC}" +echo -e "${GREEN}==========================================${NC}" echo "" -echo -e " Logs: ${YELLOW}journalctl -u ${SERVICE_NAME} -f${NC}" -echo -e " ${YELLOW}tail -f ${INSTALL_DIR}/logs/panel.log${NC}" +echo -e " Updated from: ${YELLOW}${REPO_URL}${NC}" +echo -e " Source ref : ${YELLOW}${UPDATE_REF}${NC}" +echo -e " Source cache: ${YELLOW}${SOURCE_CACHE_DIR}${NC}" +echo -e " Logs : ${YELLOW}journalctl -u ${SERVICE_NAME} -f${NC}" +echo -e " ${YELLOW}tail -f ${INSTALL_DIR}/logs/panel.log${NC}" +echo -e " Backup : ${YELLOW}${INSTALL_DIR}/sshpanel.bak${NC}" echo "" -echo -e " Backup: ${YELLOW}${INSTALL_DIR}/sshpanel.bak${NC}" +echo -e "${YELLOW}Updated:${NC}" +echo -e " - sshpanel binary" +echo -e " - Admin panel" +echo -e " - update.sh / install.sh / helper scripts when available" echo "" -echo -e "${YELLOW}What was updated:${NC}" -echo -e " • sshpanel binary" -echo -e " • Admin panel (admin/index.html)" -echo -e "${YELLOW}What was preserved:${NC}" -echo -e " • .env (DB credentials, tokens)" -echo -e " • config.json (your server settings)" -echo -e " • xray_config.json (your Xray settings)" -echo -e " • SSH host keys" -echo -e " • All user data in PostgreSQL" +echo -e "${YELLOW}Preserved:${NC}" +echo -e " - .env" +echo -e " - config.json" +echo -e " - xray_config.json" +echo -e " - SSH keys, certs, logs, database and users" echo ""