mirror of
https://github.com/masterking32/MasterHttpRelayVPN.git
synced 2026-05-17 21:24:37 +03:00
230 lines
10 KiB
Bash
230 lines
10 KiB
Bash
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# MasterHttpRelayVPN — VPS Exit Node Installer
|
|
# =============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
GITHUB_RAW="https://raw.githubusercontent.com/masterking32/MasterHttpRelayVPN/python_testing/apps_script"
|
|
|
|
# ── Colours ──────────────────────────────────────────────────────────────────
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
|
|
|
|
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
|
header() { echo -e "\n${BOLD}${CYAN}$*${NC}"; }
|
|
|
|
# ── Platform check ────────────────────────────────────────────────────────────
|
|
if [[ "$(uname -s)" != "Linux" ]]; then
|
|
error "This installer only supports Linux. Detected: $(uname -s)"
|
|
exit 1
|
|
fi
|
|
|
|
# ── Root / sudo check ─────────────────────────────────────────────────────────
|
|
if [[ $EUID -ne 0 ]]; then
|
|
error "Please run as root or with sudo:"
|
|
echo " sudo bash $0"
|
|
exit 1
|
|
fi
|
|
|
|
# ── Download vps_exit_node.py from GitHub ────────────────────────────────────
|
|
PYTHON_SCRIPT="/tmp/vps_exit_node.py"
|
|
info "Fetching vps_exit_node.py from GitHub..."
|
|
if command -v curl &>/dev/null; then
|
|
curl -fsSL "$GITHUB_RAW/vps_exit_node.py" -o "$PYTHON_SCRIPT"
|
|
elif command -v wget &>/dev/null; then
|
|
wget -qO "$PYTHON_SCRIPT" "$GITHUB_RAW/vps_exit_node.py"
|
|
else
|
|
error "Neither curl nor wget is available. Install one and retry."
|
|
exit 1
|
|
fi
|
|
info "Downloaded vps_exit_node.py to $PYTHON_SCRIPT"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
header "Step 1/7 — Checking Python 3"
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
PYTHON_BIN=""
|
|
for candidate in python3 python3.12 python3.11 python3.10; do
|
|
if command -v "$candidate" &>/dev/null; then
|
|
VER=$("$candidate" -c 'import sys; print("%d%d" % sys.version_info[:2])')
|
|
if [[ "$VER" -ge 310 ]]; then
|
|
PYTHON_BIN=$(command -v "$candidate")
|
|
info "Found $PYTHON_BIN ($($PYTHON_BIN --version 2>&1))"
|
|
break
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [[ -z "$PYTHON_BIN" ]]; then
|
|
info "Python 3.10+ not found — attempting install..."
|
|
if command -v apt-get &>/dev/null; then
|
|
apt-get update -qq
|
|
apt-get install -y python3 python3-minimal
|
|
elif command -v dnf &>/dev/null; then
|
|
dnf install -y python3
|
|
elif command -v yum &>/dev/null; then
|
|
yum install -y python3
|
|
elif command -v pacman &>/dev/null; then
|
|
pacman -Sy --noconfirm python
|
|
else
|
|
error "Cannot determine package manager. Please install Python 3.10+ manually."
|
|
exit 1
|
|
fi
|
|
PYTHON_BIN=$(command -v python3)
|
|
info "Installed: $PYTHON_BIN"
|
|
fi
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
header "Step 2/7 — Collecting configuration"
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
# Port
|
|
echo ""
|
|
read -rp "Listen port [default: 8181]: " INPUT_PORT </dev/tty || INPUT_PORT=""
|
|
PORT="${INPUT_PORT:-8181}"
|
|
if ! [[ "$PORT" =~ ^[0-9]+$ ]] || [[ "$PORT" -lt 1 ]] || [[ "$PORT" -gt 65535 ]]; then
|
|
error "Invalid port: $PORT"
|
|
exit 1
|
|
fi
|
|
info "Port: $PORT"
|
|
|
|
# PSK
|
|
echo ""
|
|
read -rp "Pre-shared key (leave empty to auto-generate): " INPUT_PSK </dev/tty || INPUT_PSK=""
|
|
if [[ -z "$INPUT_PSK" ]]; then
|
|
PSK=$("$PYTHON_BIN" -c "import secrets; print(secrets.token_hex(32))")
|
|
info "Auto-generated PSK: ${BOLD}${PSK}${NC}"
|
|
warn "Save this PSK — you will need it in config.json on your client."
|
|
else
|
|
PSK="$INPUT_PSK"
|
|
info "Using provided PSK."
|
|
fi
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
header "Step 3/7 — Installing server files"
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
INSTALL_DIR="/opt/exit-node"
|
|
mkdir -p "$INSTALL_DIR"
|
|
cp "$PYTHON_SCRIPT" "$INSTALL_DIR/vps_exit_node.py"
|
|
chmod 700 "$INSTALL_DIR/vps_exit_node.py"
|
|
info "Installed to $INSTALL_DIR/vps_exit_node.py"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
header "Step 4/7 — Writing environment file"
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
ENV_FILE="/etc/exit-node.env"
|
|
cat > "$ENV_FILE" <<EOF
|
|
# MasterHttpRelayVPN VPS exit node — environment configuration
|
|
# Generated by setup_vps_exit_node.sh
|
|
EXIT_NODE_PSK=${PSK}
|
|
EOF
|
|
chmod 600 "$ENV_FILE"
|
|
info "Environment file written to $ENV_FILE (mode 600)"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
header "Step 5/7 — Installing systemd service"
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
SERVICE_FILE="/etc/systemd/system/exit-node.service"
|
|
cat > "$SERVICE_FILE" <<EOF
|
|
[Unit]
|
|
Description=MasterHttpRelayVPN Exit Node
|
|
Documentation=https://github.com/masterking32/MasterHttpRelayVPN
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
EnvironmentFile=/etc/exit-node.env
|
|
ExecStart=${PYTHON_BIN} ${INSTALL_DIR}/vps_exit_node.py --port ${PORT}
|
|
Restart=always
|
|
RestartSec=5
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
# Security hardening
|
|
NoNewPrivileges=yes
|
|
PrivateTmp=yes
|
|
ProtectSystem=strict
|
|
ReadWritePaths=/var/log
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
systemctl enable exit-node
|
|
systemctl restart exit-node
|
|
info "Service installed and started."
|
|
|
|
# Give it a moment to confirm it really started.
|
|
sleep 2
|
|
if systemctl is-active --quiet exit-node; then
|
|
info "Service is ${GREEN}running${NC}."
|
|
else
|
|
warn "Service may not have started. Check: journalctl -u exit-node -n 30"
|
|
fi
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
header "Step 6/7 — Firewall"
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
if command -v ufw &>/dev/null; then
|
|
ufw allow "$PORT"/tcp comment "exit-node" || true
|
|
info "ufw rule added for port $PORT/tcp"
|
|
elif command -v firewall-cmd &>/dev/null; then
|
|
firewall-cmd --permanent --add-port="$PORT"/tcp || true
|
|
firewall-cmd --reload || true
|
|
info "firewalld rule added for port $PORT/tcp"
|
|
else
|
|
warn "No ufw or firewalld found. Make sure port $PORT/tcp is open in your VPS firewall panel."
|
|
fi
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
header "Step 7/7 — Health check"
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
HEALTH_URL="http://127.0.0.1:${PORT}/"
|
|
if command -v curl &>/dev/null; then
|
|
HEALTH=$(curl -sf --max-time 5 "$HEALTH_URL" 2>/dev/null || echo "")
|
|
if echo "$HEALTH" | grep -q '"ok"'; then
|
|
info "Health check OK: $HEALTH"
|
|
else
|
|
warn "Health check returned unexpected response. Check: journalctl -u exit-node -n 30"
|
|
fi
|
|
else
|
|
warn "curl not found — skipping health check. You can test manually:"
|
|
echo " curl http://127.0.0.1:${PORT}/"
|
|
fi
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
PUBLIC_IP=$(curl -sf --max-time 5 https://ipv4.ifconfig.me 2>/dev/null || echo "YOUR-VPS-IP")
|
|
|
|
echo ""
|
|
echo -e "${BOLD}${GREEN}============================================================${NC}"
|
|
echo -e "${BOLD} Installation complete!${NC}"
|
|
echo -e "${BOLD}${GREEN}============================================================${NC}"
|
|
echo ""
|
|
echo -e " Service status : ${CYAN}systemctl status exit-node${NC}"
|
|
echo -e " Live logs : ${CYAN}journalctl -fu exit-node${NC}"
|
|
echo -e " Uninstall : ${CYAN}systemctl disable --now exit-node && rm $SERVICE_FILE $ENV_FILE${NC}"
|
|
echo ""
|
|
echo -e "${BOLD}Add this to config.json on your client machine:${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}"
|
|
cat <<JSON
|
|
"exit_node": {
|
|
"enabled": true,
|
|
"provider": "vps",
|
|
"url": "http://${PUBLIC_IP}:${PORT}",
|
|
"psk": "${PSK}",
|
|
"mode": "full",
|
|
"hosts": []
|
|
}
|
|
JSON
|
|
echo -e "${NC}"
|