Simple update
This commit is contained in:
82
README.md
82
README.md
@@ -98,6 +98,8 @@ Admin token
|
|||||||
/opt/sshpanel/xray_config.json
|
/opt/sshpanel/xray_config.json
|
||||||
/opt/sshpanel/admin/
|
/opt/sshpanel/admin/
|
||||||
/opt/sshpanel/logs/panel.log
|
/opt/sshpanel/logs/panel.log
|
||||||
|
/opt/sshpanel/update.sh
|
||||||
|
/opt/sshpanel/change_admin_password.sh
|
||||||
/etc/systemd/system/sshpanel.service
|
/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.
|
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
|
```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
|
### API pública CheckUser
|
||||||
|
|
||||||
@@ -385,6 +418,8 @@ Admin token
|
|||||||
/opt/sshpanel/xray_config.json
|
/opt/sshpanel/xray_config.json
|
||||||
/opt/sshpanel/admin/
|
/opt/sshpanel/admin/
|
||||||
/opt/sshpanel/logs/panel.log
|
/opt/sshpanel/logs/panel.log
|
||||||
|
/opt/sshpanel/update.sh
|
||||||
|
/opt/sshpanel/change_admin_password.sh
|
||||||
/etc/systemd/system/sshpanel.service
|
/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.
|
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
|
```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
|
### Public CheckUser API
|
||||||
|
|
||||||
|
|||||||
13
install.sh
13
install.sh
@@ -35,23 +35,23 @@ case "$OS_ID" in
|
|||||||
ubuntu|debian|linuxmint)
|
ubuntu|debian|linuxmint)
|
||||||
PKG_UPDATE="apt-get update -qq"
|
PKG_UPDATE="apt-get update -qq"
|
||||||
PKG_INSTALL="DEBIAN_FRONTEND=noninteractive apt-get install -y"
|
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)
|
centos|rhel|rocky|almalinux)
|
||||||
PKG_UPDATE="yum makecache -q"
|
PKG_UPDATE="yum makecache -q"
|
||||||
PKG_INSTALL="yum install -y"
|
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)
|
fedora)
|
||||||
PKG_UPDATE="dnf makecache -q"
|
PKG_UPDATE="dnf makecache -q"
|
||||||
PKG_INSTALL="dnf install -y"
|
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…"
|
warn "Unknown OS '$OS_ID' — attempting apt-get…"
|
||||||
PKG_UPDATE="apt-get update -qq"
|
PKG_UPDATE="apt-get update -qq"
|
||||||
PKG_INSTALL="DEBIAN_FRONTEND=noninteractive apt-get install -y"
|
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
|
esac
|
||||||
info " OS: $OS_ID"
|
info " OS: $OS_ID"
|
||||||
@@ -107,6 +107,11 @@ go build -ldflags="-s -w" -o "$INSTALL_DIR/sshpanel" .
|
|||||||
info " Binary: $INSTALL_DIR/sshpanel"
|
info " Binary: $INSTALL_DIR/sshpanel"
|
||||||
cp -r "$SCRIPT_DIR/admin/"* "$INSTALL_DIR/admin/"
|
cp -r "$SCRIPT_DIR/admin/"* "$INSTALL_DIR/admin/"
|
||||||
info " Admin panel copied"
|
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
|
if [[ -f "$SCRIPT_DIR/change_admin_password.sh" ]]; then
|
||||||
cp "$SCRIPT_DIR/change_admin_password.sh" "$INSTALL_DIR/change_admin_password.sh"
|
cp "$SCRIPT_DIR/change_admin_password.sh" "$INSTALL_DIR/change_admin_password.sh"
|
||||||
chmod 700 "$INSTALL_DIR/change_admin_password.sh"
|
chmod 700 "$INSTALL_DIR/change_admin_password.sh"
|
||||||
|
|||||||
484
update.sh
484
update.sh
@@ -1,7 +1,21 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Update script for SSH Panel — updates the binary and admin panel in place.
|
# Update script for DragonCoreSSH / SSH Panel.
|
||||||
# Preserves: .env, config.json, xray_config.json, SSH keys, database, certs.
|
# Pulls the newest source from Git, builds the new binary, and updates the
|
||||||
# Usage: sudo bash update.sh
|
# 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
|
set -euo pipefail
|
||||||
|
|
||||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
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} $*"; }
|
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
|
||||||
error() { echo -e "${RED}[x]${NC} $*"; exit 1; }
|
error() { echo -e "${RED}[x]${NC} $*"; exit 1; }
|
||||||
|
|
||||||
# ── config ────────────────────────────────────────────────────────────────────
|
# Config
|
||||||
INSTALL_DIR="/opt/sshpanel"
|
INSTALL_DIR="${INSTALL_DIR:-/opt/sshpanel}"
|
||||||
SERVICE_NAME="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)"
|
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"
|
[[ $EUID -ne 0 ]] && error "Run as root: sudo bash $0"
|
||||||
|
|
||||||
echo -e "\n${GREEN}══════════════════════════════════════════${NC}"
|
echo -e "\n${GREEN}==========================================${NC}"
|
||||||
echo -e "${GREEN} SSH Panel · Updater ${NC}"
|
echo -e "${GREEN} DragonCoreSSH / SSH Panel Updater ${NC}"
|
||||||
echo -e "${GREEN}══════════════════════════════════════════${NC}\n"
|
echo -e "${GREEN}==========================================${NC}\n"
|
||||||
|
|
||||||
# ── 1. Pre-flight checks ──────────────────────────────────────────────────────
|
# Helpers
|
||||||
info "[1/6] Pre-flight checks…"
|
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."
|
install_git_if_missing() {
|
||||||
[[ -f "$INSTALL_DIR/.env" ]] || error "$INSTALL_DIR/.env not found — run install.sh first."
|
if command -v git >/dev/null 2>&1; then
|
||||||
[[ -f "$SCRIPT_DIR/go.mod" ]] || error "go.mod not found — run this script from the source directory."
|
return 0
|
||||||
|
|
||||||
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
|
|
||||||
fi
|
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
|
remote_default_branch() {
|
||||||
MACHINE=$(uname -m)
|
local branch
|
||||||
case "$MACHINE" in
|
branch="$(git ls-remote --symref "$REPO_URL" HEAD 2>/dev/null | awk '/^ref:/ {sub("refs/heads/", "", $2); print $2; exit}')"
|
||||||
x86_64) GOARCH="amd64" ;;
|
if [[ -n "$branch" ]]; then
|
||||||
aarch64) GOARCH="arm64" ;;
|
printf '%s\n' "$branch"
|
||||||
armv7l) GOARCH="armv6l" ;;
|
else
|
||||||
*) GOARCH="amd64" ;;
|
printf 'main\n'
|
||||||
esac
|
fi
|
||||||
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
|
|
||||||
|
|
||||||
export PATH=$PATH:/usr/local/go/bin
|
prepare_source_from_git() {
|
||||||
go version
|
install_git_if_missing
|
||||||
|
|
||||||
# ── 3. Build new binary ───────────────────────────────────────────────────────
|
if [[ -z "$UPDATE_REF" ]]; then
|
||||||
info "[3/6] Building new sshpanel binary…"
|
UPDATE_REF="$(remote_default_branch)"
|
||||||
|
fi
|
||||||
|
|
||||||
cd "$SCRIPT_DIR"
|
info "[1/7] Fetching latest files from Git..."
|
||||||
export GOPATH=/tmp/gopath_sshpanel
|
info " Repo : $REPO_URL"
|
||||||
export GOCACHE=/tmp/gocache_sshpanel
|
info " Ref : $UPDATE_REF"
|
||||||
go mod download
|
|
||||||
go build -ldflags="-s -w" -o /tmp/sshpanel_new .
|
|
||||||
info " Build complete."
|
|
||||||
|
|
||||||
# ── 4. Apply update ───────────────────────────────────────────────────────────
|
# If update.sh is being run from a real clone of this repo, update that folder.
|
||||||
info "[4/6] Applying update…"
|
# 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
|
# Normal installed-server path: keep a local Git cache under /opt/sshpanel/source.
|
||||||
if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
|
mkdir -p "$(dirname "$SOURCE_CACHE_DIR")"
|
||||||
info " Stopping $SERVICE_NAME…"
|
if [[ -d "$SOURCE_CACHE_DIR/.git" ]]; then
|
||||||
systemctl stop "$SERVICE_NAME"
|
SOURCE_DIR="$SOURCE_CACHE_DIR"
|
||||||
RESTART_NEEDED=true
|
info " Updating cached source folder: $SOURCE_DIR"
|
||||||
else
|
git -C "$SOURCE_DIR" remote set-url origin "$REPO_URL" >/dev/null 2>&1 || true
|
||||||
RESTART_NEEDED=false
|
git -C "$SOURCE_DIR" fetch --prune origin
|
||||||
fi
|
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
|
[[ -f "$SOURCE_DIR/go.mod" ]] || error "Downloaded source is invalid: go.mod not found in $SOURCE_DIR"
|
||||||
if [[ -f "$INSTALL_DIR/sshpanel" ]]; then
|
[[ -d "$SOURCE_DIR/admin" ]] || error "Downloaded source is invalid: admin folder not found in $SOURCE_DIR"
|
||||||
cp "$INSTALL_DIR/sshpanel" "$INSTALL_DIR/sshpanel.bak"
|
}
|
||||||
info " Old binary backed up to sshpanel.bak"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Replace binary
|
install_go_if_needed() {
|
||||||
mv /tmp/sshpanel_new "$INSTALL_DIR/sshpanel"
|
local go_version machine goarch go_url current_go need_go
|
||||||
chmod +x "$INSTALL_DIR/sshpanel"
|
go_version="$(awk '$1 == "go" {print $2; exit}' "$SOURCE_DIR/go.mod" 2>/dev/null || echo "1.22.5")"
|
||||||
info " Binary updated."
|
need_go=true
|
||||||
|
|
||||||
# Update admin panel files
|
info "[2/7] Checking Go toolchain..."
|
||||||
mkdir -p "$INSTALL_DIR/admin"
|
info " Required Go: $go_version"
|
||||||
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
|
|
||||||
|
|
||||||
# Ensure banner file exists (new in this version)
|
if command -v go >/dev/null 2>&1; then
|
||||||
if [[ ! -f "$INSTALL_DIR/banner.txt" ]]; then
|
current_go="$(go version 2>/dev/null | awk '{print $3}' | sed 's/go//')"
|
||||||
touch "$INSTALL_DIR/banner.txt"
|
if [[ "$(printf '%s\n' "$go_version" "$current_go" | sort -V | head -1)" == "$go_version" ]]; then
|
||||||
info " Created banner.txt"
|
info " Go $current_go already installed."
|
||||||
fi
|
need_go=false
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Ensure certs directory exists (new in this version)
|
if $need_go; then
|
||||||
mkdir -p "$INSTALL_DIR/certs"
|
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
|
export PATH=$PATH:/usr/local/go/bin
|
||||||
# without overwriting user-configured values.
|
go version
|
||||||
CFG="$INSTALL_DIR/config.json"
|
}
|
||||||
if [[ -f "$CFG" ]]; then
|
|
||||||
# Add banner_file if not present
|
build_binary() {
|
||||||
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
|
info "[3/7] Building new sshpanel binary..."
|
||||||
python3 - "$CFG" << 'PYEOF'
|
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
|
import json, sys
|
||||||
path = sys.argv[1]
|
path = sys.argv[1]
|
||||||
with open(path) as f:
|
try:
|
||||||
d = json.load(f)
|
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:
|
if 'banner_file' not in d:
|
||||||
d['banner_file'] = '/opt/sshpanel/banner.txt'
|
d['banner_file'] = '/opt/sshpanel/banner.txt'
|
||||||
with open(path, 'w') as f:
|
changed = True
|
||||||
json.dump(d, f, indent=2)
|
if 'local_ssh_listen' in d:
|
||||||
PYEOF
|
d.pop('local_ssh_listen', None)
|
||||||
info " Added banner_file to config.json"
|
changed = True
|
||||||
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
|
|
||||||
if changed:
|
if changed:
|
||||||
with open(path, 'w') as f:
|
with open(path, 'w') as f:
|
||||||
json.dump(d, f, indent=2)
|
json.dump(d, f, indent=2)
|
||||||
|
f.write('\n')
|
||||||
PYEOF
|
PYEOF
|
||||||
|
info " config.json checked."
|
||||||
|
fi
|
||||||
|
|
||||||
# Fix routing: remove geoip:private rules that require geoip.dat from xray_config.json
|
if [[ -f "$xcfg" ]] && grep -q '"geoip:private"' "$xcfg" 2>/dev/null; then
|
||||||
XCFG="$INSTALL_DIR/xray_config.json"
|
python3 - "$xcfg" <<'PYEOF'
|
||||||
if [[ -f "$XCFG" ]]; then
|
|
||||||
if grep -q '"geoip:private"' "$XCFG" 2>/dev/null; then
|
|
||||||
python3 - "$XCFG" << 'PYEOF'
|
|
||||||
import json, sys
|
import json, sys
|
||||||
path = sys.argv[1]
|
path = sys.argv[1]
|
||||||
with open(path) as f:
|
try:
|
||||||
d = json.load(f)
|
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', {})
|
routing = d.get('routing', {})
|
||||||
rules = routing.get('rules', [])
|
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', [])]
|
new_rules = [r for r in rules if 'geoip:private' not in r.get('ip', [])]
|
||||||
if new_rules != rules:
|
if new_rules != rules:
|
||||||
if new_rules:
|
if new_rules:
|
||||||
d['routing']['rules'] = new_rules
|
d.setdefault('routing', {})['rules'] = new_rules
|
||||||
else:
|
else:
|
||||||
d.pop('routing', None)
|
d.pop('routing', None)
|
||||||
with open(path, 'w') as f:
|
with open(path, 'w') as f:
|
||||||
json.dump(d, f, indent=2)
|
json.dump(d, f, indent=2)
|
||||||
|
f.write('\n')
|
||||||
PYEOF
|
PYEOF
|
||||||
info " Removed geoip:private routing rule from xray_config.json"
|
info " Removed geoip:private routing rule from xray_config.json"
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
fi
|
}
|
||||||
|
|
||||||
# ── 5. DNSTT DNS/53 redirect ─────────────────────────────────────────────────
|
ensure_dnstt_redirect() {
|
||||||
info "[5/6] Ensuring DNSTT DNS redirect (UDP 53 -> 5300)…"
|
info " Ensuring DNSTT DNS redirect service exists..."
|
||||||
cat > /usr/local/sbin/sshpanel-dnstt-redirect.sh <<'EOS'
|
cat > /usr/local/sbin/sshpanel-dnstt-redirect.sh <<'EOS'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
DNS_UPSTREAM="${DNS_UPSTREAM:-1.1.1.1}"
|
DNS_UPSTREAM="${DNS_UPSTREAM:-1.1.1.1}"
|
||||||
DNSTT_PORT="${DNSTT_PORT:-5300}"
|
DNSTT_PORT="${DNSTT_PORT:-5300}"
|
||||||
|
|
||||||
if command -v systemctl >/dev/null 2>&1; then
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
systemctl disable --now systemd-resolved.service >/dev/null 2>&1 || true
|
systemctl disable --now systemd-resolved.service >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
rm -f /etc/resolv.conf
|
rm -f /etc/resolv.conf
|
||||||
printf 'nameserver %s\n' "$DNS_UPSTREAM" > /etc/resolv.conf
|
printf 'nameserver %s\n' "$DNS_UPSTREAM" > /etc/resolv.conf
|
||||||
|
|
||||||
if command -v ufw >/dev/null 2>&1; then
|
if command -v ufw >/dev/null 2>&1; then
|
||||||
ufw allow 53/udp >/dev/null 2>&1 || true
|
ufw allow 53/udp >/dev/null 2>&1 || true
|
||||||
fi
|
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 --permanent --add-port=53/udp >/dev/null 2>&1 || true
|
||||||
firewall-cmd --reload >/dev/null 2>&1 || true
|
firewall-cmd --reload >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
add_iptables_rule() {
|
add_iptables_rule() {
|
||||||
local bin="$1" chain="$2"
|
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 -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"
|
|| "$bin" -t nat -A "$chain" -p udp --dport 53 -j REDIRECT --to-ports "$DNSTT_PORT"
|
||||||
}
|
}
|
||||||
|
|
||||||
if command -v iptables >/dev/null 2>&1; then
|
if command -v iptables >/dev/null 2>&1; then
|
||||||
add_iptables_rule iptables PREROUTING
|
add_iptables_rule iptables PREROUTING
|
||||||
fi
|
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"
|
|| nft add rule inet sshpanel_nat prerouting udp dport 53 redirect to :"$DNSTT_PORT"
|
||||||
fi
|
fi
|
||||||
EOS
|
EOS
|
||||||
chmod +x /usr/local/sbin/sshpanel-dnstt-redirect.sh
|
chmod +x /usr/local/sbin/sshpanel-dnstt-redirect.sh
|
||||||
cat > /etc/systemd/system/sshpanel-dnstt-redirect.service <<'EOF'
|
|
||||||
|
cat > /etc/systemd/system/sshpanel-dnstt-redirect.service <<'EOF2'
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=SSH Panel DNSTT DNS redirect (UDP 53 to 5300)
|
Description=SSH Panel DNSTT DNS redirect (UDP 53 to 5300)
|
||||||
After=network.target
|
After=network.target
|
||||||
@@ -226,55 +338,95 @@ RemainAfterExit=yes
|
|||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOF
|
EOF2
|
||||||
mkdir -p /etc/systemd/system/sshpanel.service.d
|
|
||||||
cat > /etc/systemd/system/sshpanel.service.d/override.conf <<EOF
|
mkdir -p /etc/systemd/system/sshpanel.service.d
|
||||||
|
cat > /etc/systemd/system/sshpanel.service.d/override.conf <<EOF2
|
||||||
[Unit]
|
[Unit]
|
||||||
Wants=sshpanel-dnstt-redirect.service
|
Wants=sshpanel-dnstt-redirect.service
|
||||||
After=sshpanel-dnstt-redirect.service
|
After=sshpanel-dnstt-redirect.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Environment=PANEL_LOG_FILE=${INSTALL_DIR}/logs/panel.log
|
Environment=PANEL_LOG_FILE=${INSTALL_DIR}/logs/panel.log
|
||||||
EOF
|
EOF2
|
||||||
systemctl daemon-reload
|
|
||||||
systemctl enable --now sshpanel-dnstt-redirect.service || warn "DNSTT DNS redirect service failed; check: journalctl -u sshpanel-dnstt-redirect -e"
|
|
||||||
|
|
||||||
# ── 6. Restart service ────────────────────────────────────────────────────────
|
systemctl daemon-reload
|
||||||
info "[6/6] Restarting service…"
|
systemctl enable --now sshpanel-dnstt-redirect.service || warn "DNSTT redirect service failed. Check: journalctl -u sshpanel-dnstt-redirect -e"
|
||||||
|
}
|
||||||
|
|
||||||
if $RESTART_NEEDED; then
|
restart_service() {
|
||||||
systemctl start "$SERVICE_NAME"
|
info "[7/7] Restarting service..."
|
||||||
sleep 2
|
ensure_dnstt_redirect
|
||||||
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
|
||||||
info " $SERVICE_NAME is running."
|
if $RESTART_NEEDED; then
|
||||||
|
systemctl start "$SERVICE_NAME"
|
||||||
|
sleep 2
|
||||||
|
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||||
|
info " $SERVICE_NAME is running."
|
||||||
|
else
|
||||||
|
warn " $SERVICE_NAME failed to start. Check logs:"
|
||||||
|
warn " journalctl -u $SERVICE_NAME -n 50 --no-pager"
|
||||||
|
if [[ -f "$INSTALL_DIR/sshpanel.bak" ]]; then
|
||||||
|
warn " Restore command:"
|
||||||
|
warn " cp $INSTALL_DIR/sshpanel.bak $INSTALL_DIR/sshpanel && systemctl start $SERVICE_NAME"
|
||||||
|
fi
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
warn " $SERVICE_NAME failed to start — check logs:"
|
warn " Service was not running. Start it with: systemctl start $SERVICE_NAME"
|
||||||
warn " journalctl -u $SERVICE_NAME -n 30 --no-pager"
|
fi
|
||||||
warn " You can restore the old binary:"
|
}
|
||||||
warn " mv $INSTALL_DIR/sshpanel.bak $INSTALL_DIR/sshpanel && systemctl start $SERVICE_NAME"
|
|
||||||
exit 1
|
# Pre-flight
|
||||||
|
info "[0/7] Pre-flight checks..."
|
||||||
|
[[ -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."
|
||||||
|
need_cmd python3
|
||||||
|
if ! command -v rsync >/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
|
fi
|
||||||
else
|
|
||||||
warn " Service was not running; start it with: systemctl start $SERVICE_NAME"
|
|
||||||
fi
|
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 ""
|
||||||
echo -e "${GREEN}══════════════════════════════════════════${NC}"
|
echo -e "${GREEN}==========================================${NC}"
|
||||||
echo -e "${GREEN} Update complete! ${NC}"
|
echo -e "${GREEN} Update complete! ${NC}"
|
||||||
echo -e "${GREEN}══════════════════════════════════════════${NC}"
|
echo -e "${GREEN}==========================================${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " Logs: ${YELLOW}journalctl -u ${SERVICE_NAME} -f${NC}"
|
echo -e " Updated from: ${YELLOW}${REPO_URL}${NC}"
|
||||||
echo -e " ${YELLOW}tail -f ${INSTALL_DIR}/logs/panel.log${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 ""
|
||||||
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 ""
|
||||||
echo -e "${YELLOW}What was updated:${NC}"
|
echo -e "${YELLOW}Preserved:${NC}"
|
||||||
echo -e " • sshpanel binary"
|
echo -e " - .env"
|
||||||
echo -e " • Admin panel (admin/index.html)"
|
echo -e " - config.json"
|
||||||
echo -e "${YELLOW}What was preserved:${NC}"
|
echo -e " - xray_config.json"
|
||||||
echo -e " • .env (DB credentials, tokens)"
|
echo -e " - SSH keys, certs, logs, database and users"
|
||||||
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 ""
|
echo ""
|
||||||
|
|||||||
Reference in New Issue
Block a user