From 2bd07f0e2a0ac6529050cc6fb6959e67b8db5634 Mon Sep 17 00:00:00 2001 From: eddy <1036636139@qq.com> Date: Thu, 6 Nov 2025 20:17:23 +0800 Subject: [PATCH] Init --- .gitignore | 160 +++ LICENSE | 21 + README.md | 111 ++ init/00-disable-password.sh | 44 + init/01-sysUpdate.sh | 15 + init/02-sysCleanup.sh | 14 + init/03-docker.sh | 31 + init/ddns-go.sh | 782 ++++++++++++++ init/vps_init.sh | 675 ++++++++++++ init/xray-manager.sh | 1935 +++++++++++++++++++++++++++++++++++ install/01-Nginx.sh | 50 + install/02-NginxProxy.sh | 51 + install/03-X-UI.sh | 50 + install/04-FRP.sh | 75 ++ install/05-ZeroTier.sh | 69 ++ install/06-Rustdesk.sh | 76 ++ install/07-Alist.sh | 51 + install/08-Duplicati.sh | 53 + install/09-Syncthing.sh | 57 ++ install/10-Vaultwarden.sh | 59 ++ install/11-EasyImage.sh | 52 + install/12-Wordpress.sh | 85 ++ install/13-Nextcloud.sh | 68 ++ install/14-Joplin.sh | 67 ++ 24 files changed, 4651 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 init/00-disable-password.sh create mode 100644 init/01-sysUpdate.sh create mode 100644 init/02-sysCleanup.sh create mode 100644 init/03-docker.sh create mode 100644 init/ddns-go.sh create mode 100644 init/vps_init.sh create mode 100644 init/xray-manager.sh create mode 100644 install/01-Nginx.sh create mode 100644 install/02-NginxProxy.sh create mode 100644 install/03-X-UI.sh create mode 100644 install/04-FRP.sh create mode 100644 install/05-ZeroTier.sh create mode 100644 install/06-Rustdesk.sh create mode 100644 install/07-Alist.sh create mode 100644 install/08-Duplicati.sh create mode 100644 install/09-Syncthing.sh create mode 100644 install/10-Vaultwarden.sh create mode 100644 install/11-EasyImage.sh create mode 100644 install/12-Wordpress.sh create mode 100644 install/13-Nextcloud.sh create mode 100644 install/14-Joplin.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68bc17f --- /dev/null +++ b/.gitignore @@ -0,0 +1,160 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..29f9d29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 ghuang.top + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3579b48 --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +# vps +vps脚本 + +## 初始化脚本 (init) + +- 00-disable-password +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/00-disable-password.sh && chmod +x 00-disable-password.sh && ./00-disable-password.sh +``` + +- 01-sysUpdate +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/01-sysUpdate.sh && chmod +x 01-sysUpdate.sh && ./01-sysUpdate.sh +``` + +- 02-sysCleanup +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/02-sysCleanup.sh && chmod +x 02-sysCleanup.sh && ./02-sysCleanup.sh +``` + +- 03-docker +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/03-docker.sh && chmod +x 03-docker.sh && ./03-docker.sh +``` + +- ddns-go +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/ddns-go.sh && chmod +x ddns-go.sh && ./ddns-go.sh +``` + +- vps_init +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/vps_init.sh && chmod +x vps_init.sh && ./vps_init.sh +``` + +- xray-manager +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/xray-manager.sh && chmod +x xray-manager.sh && ./xray-manager.sh +``` + +## 安装脚本 (install) + +- 01-Nginx +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/01-Nginx.sh && chmod +x 01-Nginx.sh && ./01-Nginx.sh +``` + +- 02-NginxProxy +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/02-NginxProxy.sh && chmod +x 02-NginxProxy.sh && ./02-NginxProxy.sh +``` + +- 03-X-UI +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/03-X-UI.sh && chmod +x 03-X-UI.sh && ./03-X-UI.sh +``` + +- 04-FRP +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/04-FRP.sh && chmod +x 04-FRP.sh && ./04-FRP.sh +``` + +- 05-ZeroTier +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/05-ZeroTier.sh && chmod +x 05-ZeroTier.sh && ./05-ZeroTier.sh +``` + +- 06-Rustdesk +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/06-Rustdesk.sh && chmod +x 06-Rustdesk.sh && ./06-Rustdesk.sh +``` + +- 07-Alist +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/07-Alist.sh && chmod +x 07-Alist.sh && ./07-Alist.sh +``` + +- 08-Duplicati +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/08-Duplicati.sh && chmod +x 08-Duplicati.sh && ./08-Duplicati.sh +``` + +- 09-Syncthing +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/09-Syncthing.sh && chmod +x 09-Syncthing.sh && ./09-Syncthing.sh +``` + +- 10-Vaultwarden +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/10-Vaultwarden.sh && chmod +x 10-Vaultwarden.sh && ./10-Vaultwarden.sh +``` + +- 11-EasyImage +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/11-EasyImage.sh && chmod +x 11-EasyImage.sh && ./11-EasyImage.sh +``` + +- 12-Wordpress +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/12-Wordpress.sh && chmod +x 12-Wordpress.sh && ./12-Wordpress.sh +``` + +- 13-Nextcloud +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/13-Nextcloud.sh && chmod +x 13-Nextcloud.sh && ./13-Nextcloud.sh +``` + +- 14-Joplin +```sh +curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/14-Joplin.sh && chmod +x 14-Joplin.sh && ./14-Joplin.sh +``` diff --git a/init/00-disable-password.sh b/init/00-disable-password.sh new file mode 100644 index 0000000..6eceaf4 --- /dev/null +++ b/init/00-disable-password.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# chmod +x 00-disable-password.sh && ./00-disable-password.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/00-disable-password.sh && chmod +x 00-disable-password.sh && ./00-disable-password.sh + + +# 用户设置 +new_ssh_port="4399" # 根据需求修改端口 + +echo "1、关闭 SSH 密码登录并启用密钥认证" +disablePasswordLogin() { + # 备份 SSH 配置文件 + cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak + + # 修改 SSH 配置文件 + sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/g' /etc/ssh/sshd_config + sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/g' /etc/ssh/sshd_config + + # 确保 PubkeyAuthentication 开启 + sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/g' /etc/ssh/sshd_config + + # 修改端口 + sed -i 's/^#\?Port [0-9]\+/Port '$new_ssh_port'/g' /etc/ssh/sshd_config + + # 重启 SSH 服务 + service sshd restart +} +disablePasswordLogin + +echo "2、开启防火墙并允许新的 SSH 端口" +openUfwPort() { + echo "开启防火墙并允许新的SSH端口: $new_ssh_port" + apt update -y && apt install -y ufw + ufw --force enable + ufw allow $new_ssh_port + ufw status +} +openUfwPort + +echo "------------------------" +echo "修改后的信息:" +echo "端口: $new_ssh_port" +echo "SSH 密码登录: 已关闭" +echo "请确保您的公钥已正确上传到服务器的 ~/.ssh/authorized_keys 文件中。" +echo "------------------------" diff --git a/init/01-sysUpdate.sh b/init/01-sysUpdate.sh new file mode 100644 index 0000000..36f3de9 --- /dev/null +++ b/init/01-sysUpdate.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# chmod +x 01-sysUpdate.sh && ./01-sysUpdate.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/01-sysUpdate.sh && chmod +x 01-sysUpdate.sh && ./01-sysUpdate.sh + +echo "系统更新" + +if [ -f "/etc/debian_version" ]; then + apt update -y && DEBIAN_FRONTEND=noninteractive apt full-upgrade -y +fi + +# 1、VPS Initialization +apt update -y && apt upgrade -y # 更新一下包 +apt install -y wget curl sudo vim git ufw # Debian系统比较干净,安装常用的软件 +sudo usermod -aG sudo root + diff --git a/init/02-sysCleanup.sh b/init/02-sysCleanup.sh new file mode 100644 index 0000000..5080a62 --- /dev/null +++ b/init/02-sysCleanup.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# chmod +x 02-sysCleanup.sh && ./02-sysCleanup.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/02-sysCleanup.sh && chmod +x 02-sysCleanup.sh && ./02-sysCleanup.sh + +echo "系统清理" + +apt autoremove --purge -y +apt clean -y +apt autoclean -y +apt remove --purge $(dpkg -l | awk '/^rc/ {print $2}') -y +journalctl --rotate +journalctl --vacuum-time=1s +journalctl --vacuum-size=50M +apt remove --purge $(dpkg -l | awk '/^ii linux-(image|headers)-[^ ]+/{print $2}' | grep -v $(uname -r | sed 's/-.*//') | xargs) -y diff --git a/init/03-docker.sh b/init/03-docker.sh new file mode 100644 index 0000000..2c9b4ad --- /dev/null +++ b/init/03-docker.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# chmod +x 03-docker.sh && ./03-docker.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/03-docker.sh && chmod +x 03-docker.sh && ./03-docker.sh + +echo "初始化vps" + +# 检查 Docker 是否已安装 +if ! command -v docker &> /dev/null; then + # 如果 Docker 未安装,则安装它 + echo "安装 Docker..." + curl -fsSL https://get.docker.com | sudo sh +else + echo "Docker 已经安装." +fi + +# 安装 Docker Compose +if ! command -v docker-compose &> /dev/null; then + # 如果 Docker Compose 未安装,则安装它 + echo "安装 Docker Compose..." + #apt install -y docker-compose + curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + chmod +x /usr/local/bin/docker-compose +else + echo "Docker Compose 已经安装." +fi + +echo "------------------------" +echo "Docker的版本" +docker --version +docker-compose --version +echo "------------------------" diff --git a/init/ddns-go.sh b/init/ddns-go.sh new file mode 100644 index 0000000..1236eb3 --- /dev/null +++ b/init/ddns-go.sh @@ -0,0 +1,782 @@ +#!/bin/bash +# ddns-go 自动安装脚本 +# 使用方法: chmod +x ddns-go.sh && ./ddns-go.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/ddns-go.sh && chmod +x ddns-go.sh && ./ddns-go.sh + +# 彩色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# 全局变量 +DDNS_VERSION="" # 当前指定的 ddns-go 版本 +DDNS_PATH="/root/ddns" +SCRIPT_VERSION="1.0.0" + +# 日志函数 +log_info() { + echo -e "${GREEN}[信息]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[警告]${NC} $1" +} + +log_error() { + echo -e "${RED}[错误]${NC} $1" +} + +# 获取最新版本号 +get_latest_version() { + local version="" + + # 方法1:利用GitHub重定向特性获取最新版本 + local redirect_url=$(curl -s -L -o /dev/null -w '%{url_effective}' https://github.com/jeessy2/ddns-go/releases/latest 2>/dev/null) + version=$(echo "$redirect_url" | grep -o 'tag/v[0-9.]*' | cut -d/ -f2 2>/dev/null) + + # 如果获取失败,尝试备用方法 + if [[ -z "$version" ]]; then + # 方法2: 通过API获取 + version=$(curl -s https://api.github.com/repos/jeessy2/ddns-go/releases/latest | grep -o '"tag_name": "v[0-9.]*"' | cut -d'"' -f4 2>/dev/null) + fi + + # 如果还是失败,返回默认版本 + if [[ -z "$version" ]]; then + version="v6.9.1" # 默认版本 + fi + + # 直接返回版本号,不打印任何日志 + echo "$version" +} + +# 检测系统架构 +detect_arch() { + # 获取架构 + local arch=$(uname -m) + local arch_type="" + + # 转换架构名称为ddns-go使用的格式 + case "$arch" in + x86_64) + arch_type="linux_x86_64" + ;; + i386|i686) + arch_type="linux_x86" + ;; + aarch64|arm64) + arch_type="linux_arm64" + ;; + armv7*|armv6*) + arch_type="linux_armv7" + ;; + armv8*) + arch_type="linux_arm64" + ;; + *) + log_warn "未知架构: $arch,将尝试使用x86_64版本" + arch_type="linux_x86_64" + ;; + esac + + # 直接返回结果而不是写入临时文件 + echo "$arch_type" +} + +# 获取IP地址信息 +get_ip_info() { + local ipv4=$(curl -s ipv4.ip.sb) + local ipv6=$(curl -s ipv6.ip.sb 2>/dev/null || echo "无") + + echo "$ipv4|$ipv6" +} + +# 配置防火墙 - 仅处理 UFW +configure_firewall() { + local port=$1 + log_info "配置防火墙" + + # 检查是否安装了 ufw + if command -v ufw &>/dev/null; then + # 检查ufw是否启用 + local ufw_status=$(ufw status | grep -o "Status: active" 2>/dev/null) + + if [[ -z "$ufw_status" ]]; then + log_warn "UFW 防火墙未启用,可能需要手动配置防火墙规则" + log_info "您可以运行 'sudo ufw enable' 启用 UFW 防火墙" + return 0 + fi + + # 检查端口是否已经开放 + if ufw status | grep -q "$port/tcp"; then + log_info "端口 $port 已经开放,跳过" + return 0 + fi + + # 开放端口 + echo -n "配置 UFW 防火墙,开放端口 $port... " + if ufw allow "$port/tcp" &>/dev/null; then + echo -e "${GREEN}完成${NC}" + log_info "已在 UFW 防火墙开放端口: $port" + else + echo -e "${RED}失败${NC}" + log_warn "无法开放端口 $port" + fi + else + log_warn "未检测到 UFW 防火墙,跳过防火墙配置" + log_info "如需管理防火墙规则,请安装 UFW: sudo apt install ufw" + fi + + return 0 +} + +# 关闭防火墙端口 - 仅处理 UFW +close_firewall_port() { + local port=$1 + log_info "关闭防火墙端口" + + # 检查是否安装了 ufw + if command -v ufw &>/dev/null; then + # 检查ufw是否启用 + local ufw_status=$(ufw status | grep -o "Status: active" 2>/dev/null) + + if [[ -z "$ufw_status" ]]; then + log_warn "UFW 防火墙未启用,跳过防火墙配置" + return 0 + fi + + # 检查端口是否已开放在UFW中 + if ! ufw status | grep -q "$port/tcp"; then + log_info "端口 $port 未在 UFW 中开放,跳过" + return 0 + fi + + # 关闭端口 + echo -n "关闭 UFW 防火墙端口 $port... " + if ufw delete allow "$port/tcp" &>/dev/null; then + echo -e "${GREEN}完成${NC}" + log_info "已关闭 UFW 防火墙端口: $port" + else + echo -e "${RED}失败${NC}" + log_warn "无法关闭端口 $port" + fi + else + log_warn "未检测到 UFW 防火墙,跳过防火墙配置" + fi + + return 0 +} + +# 安装 ddns-go +install_ddns_go() { + clear + echo "==================================================" + echo -e "${GREEN}开始安装 ddns-go${NC}" + echo "==================================================" + + log_info "开始安装 ddns-go..." + + # 询问用户是否自定义端口 + local web_port="9876" # 默认端口 + read -rp "是否自定义web访问端口? [y/N] " custom_port + if [[ "$custom_port" =~ ^[yY]$ ]]; then + while true; do + read -rp "请输入端口号 (1-65535): " web_port + if [[ "$web_port" =~ ^[0-9]+$ ]] && [ "$web_port" -ge 1 ] && [ "$web_port" -le 65535 ]; then + log_info "将使用端口: $web_port" + break + else + log_error "无效的端口号,请输入1-65535之间的数字" + fi + done + else + log_info "将使用默认端口: $web_port" + fi + + # 更新软件包 + log_info "更新软件包..." + apt update -y && apt upgrade -y + + # 安装必要工具 + log_info "安装必要工具..." + apt install -y wget curl sudo vim git + + # 创建安装目录 + mkdir -p $DDNS_PATH + + # 1. 获取版本 - 先获取所有必要变量,不输出日志 + local version="" + if [[ -n "$DDNS_VERSION" ]]; then + version="$DDNS_VERSION" + else + version=$(get_latest_version) + fi + + # 2. 移除版本号前的 'v' + local version_num=${version#v} + + # 3. 检测系统架构 - 使用改进后的函数,直接返回结果 + local arch_suffix=$(detect_arch) + + # 4. 构建下载URL - 使用纯文本变量 + local download_file="ddns-go_${version_num}_${arch_suffix}.tar.gz" + local download_path="${DDNS_PATH}/${download_file}" + local download_url="https://github.com/jeessy2/ddns-go/releases/download/${version}/${download_file}" + + # 5. 现在安全地输出日志 + log_info "获取到最新版本:$version" + log_info "检测到系统架构: $(uname -m) (使用: $arch_suffix)" + log_info "下载链接: $download_url" + + # 6. 下载文件 - 统一使用curl下载 + log_info "正在下载 ddns-go..." + + if curl -s -L -o "$download_path" "$download_url"; then + log_info "下载成功" + else + log_error "下载失败,请检查网络连接" + read -rp "按回车键返回主菜单..." temp + show_menu + return 1 + fi + + # 7. 解压文件 + log_info "正在解压文件..." + if tar -zxf "$download_path" -C $DDNS_PATH; then + log_info "解压成功" + else + log_error "解压失败" + read -rp "按回车键返回主菜单..." temp + show_menu + return 1 + fi + + # 8. 设置权限 + chmod +x $DDNS_PATH/ddns-go + + # 9. 验证可执行文件 + log_info "验证 ddns-go 二进制文件..." + if [ ! -f $DDNS_PATH/ddns-go ]; then + log_error "未找到 ddns-go 可执行文件" + read -rp "按回车键返回主菜单..." temp + show_menu + return 1 + fi + + # 10. 测试运行 + if ! $DDNS_PATH/ddns-go -h > /dev/null 2>&1; then + log_error "ddns-go 可执行文件无法运行,可能是架构不匹配" + log_info "尝试检查更多架构版本..." + + # 清理之前的文件 + rm -rf $DDNS_PATH/* + + # 尝试其他架构版本 + local try_arch_list=("linux_arm64" "linux_armv7" "linux_x86" "linux_x86_64") + local success=false + + for try_arch in "${try_arch_list[@]}"; do + if [ "$try_arch" != "$arch_suffix" ]; then + log_info "尝试 $try_arch 架构版本..." + + # 构建下载信息 + local try_file="ddns-go_${version_num}_${try_arch}.tar.gz" + local try_path="${DDNS_PATH}/${try_file}" + local try_url="https://github.com/jeessy2/ddns-go/releases/download/${version}/${try_file}" + + # 下载并解压 - 统一使用curl + if curl -s -L -o "$try_path" "$try_url" && + tar -zxf "$try_path" -C $DDNS_PATH && + chmod +x $DDNS_PATH/ddns-go; then + + # 测试是否可运行 + if $DDNS_PATH/ddns-go -h > /dev/null 2>&1; then + log_info "$try_arch 架构版本可以运行" + success=true + break + else + log_warn "$try_arch 架构版本不兼容" + fi + else + log_warn "$try_arch 架构版本下载或解压失败" + fi + fi + done + + # 如果所有架构都尝试失败 + if [ "$success" = false ]; then + log_error "无法找到合适的版本,安装失败" + read -rp "按回车键返回主菜单..." temp + show_menu + return 1 + fi + fi + + # 11. 安装服务 + log_info "安装系统服务..." + cd $DDNS_PATH + ./ddns-go -s install -l 0.0.0.0:$web_port + + # 12. 验证服务 + if systemctl status ddns-go > /dev/null 2>&1; then + log_info "ddns-go 服务已成功安装并运行" + else + log_warn "ddns-go 服务可能未正确启动,请手动检查: systemctl status ddns-go" + fi + + # 13. 获取IP信息 + local ip_info=$(get_ip_info) + local ipv4=$(echo "$ip_info" | cut -d'|' -f1) + + # 14. 配置防火墙 + configure_firewall $web_port + + log_info "ddns-go 安装完成!" + echo "==================================================" + echo -e "${GREEN}安装成功!${NC}" + echo -e "${CYAN}Web管理界面访问地址: http://$ipv4:$web_port${NC}" + echo -e "请在浏览器中打开上述地址进行配置" + echo "==================================================" + + # 清理下载文件 + rm -f "$download_path" + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 卸载服务 +uninstall_ddns_go() { + clear + echo "==================================================" + echo -e "${RED}开始卸载 ddns-go${NC}" + echo "==================================================" + + # 确认卸载 + echo -e "${YELLOW}警告: 这将卸载 ddns-go 并删除相关文件${NC}" + read -rp "是否继续? [Y/n] " confirm + if [[ "$confirm" =~ ^[nN]$ ]]; then + log_info "卸载已取消" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + + log_info "正在卸载 ddns-go 服务..." + + # 获取端口信息用于关闭防火墙 + local port="" + if [ -d "$DDNS_PATH" ] && [ -f "$DDNS_PATH/config.yaml" ]; then + port=$(grep -o 'listen: 0.0.0.0:[0-9]*' "$DDNS_PATH/config.yaml" 2>/dev/null | grep -o '[0-9]*$' | head -n 1) + fi + + if [[ -z "$port" ]]; then + port=$(systemctl status ddns-go 2>/dev/null | grep -o '\-l 0.0.0.0:[0-9]*' | grep -o '[0-9]*$' | head -n 1) + fi + + if [ -d "$DDNS_PATH" ]; then + cd $DDNS_PATH + if [ -f "./ddns-go" ]; then + ./ddns-go -s uninstall + log_info "服务已卸载" + else + log_error "找不到 ddns-go 可执行文件" + fi + + # 询问是否删除文件 + read -rp "是否删除所有 ddns-go 文件? [Y/n] " delete_confirm + if [[ ! "$delete_confirm" =~ ^[nN]$ ]]; then + rm -rf $DDNS_PATH + log_info "所有文件已删除" + else + log_info "文件已保留" + fi + else + log_error "找不到 ddns-go 安装目录" + fi + + # 关闭防火墙端口 + if [[ -n "$port" ]]; then + close_firewall_port $port + fi + + log_info "ddns-go 卸载完成!" + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 更新 ddns-go +update_ddns_go() { + clear + echo "==================================================" + echo -e "${YELLOW}更新 ddns-go${NC}" + echo "==================================================" + + # 检查是否已安装 + if [ ! -d "$DDNS_PATH" ] || [ ! -f "$DDNS_PATH/ddns-go" ]; then + log_error "ddns-go 未安装,请先安装" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + + # 获取当前版本 + local current_version="" + current_version=$($DDNS_PATH/ddns-go -v 2>&1 | grep -o 'v[0-9.]*' | head -n 1) + + if [[ -z "$current_version" ]]; then + log_warn "无法获取当前版本信息" + current_version="未知" + fi + + log_info "当前版本: $current_version" + + # 获取最新版本 + local latest_version=$(get_latest_version) + log_info "最新版本: $latest_version" + + # 比较版本 + if [[ "$current_version" == "$latest_version" ]]; then + log_info "已经是最新版本" + read -rp "是否强制更新? [y/N] " force_update + if [[ ! "$force_update" =~ ^[yY]$ ]]; then + log_info "更新已取消" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + fi + + # 备份配置 + local config_backup="$DDNS_PATH/config.yaml.bak" + if [ -f "$DDNS_PATH/config.yaml" ]; then + log_info "备份配置文件..." + cp "$DDNS_PATH/config.yaml" "$config_backup" + fi + + # 停止服务 + log_info "停止 ddns-go 服务..." + cd $DDNS_PATH + ./ddns-go -s uninstall + + # 下载新版本 + log_info "下载新版本..." + + # 检测系统架构 - 使用改进后的函数,直接返回结果 + local arch_suffix=$(detect_arch) + local version_num=${latest_version#v} + + # 构建下载URL + local download_file="ddns-go_${version_num}_${arch_suffix}.tar.gz" + local download_path="${DDNS_PATH}/${download_file}" + local download_url="https://github.com/jeessy2/ddns-go/releases/download/${latest_version}/${download_file}" + + log_info "下载链接: $download_url" + + # 删除原来的二进制文件 + rm -f $DDNS_PATH/ddns-go + + # 下载文件 - 统一使用curl下载 + if curl -s -L -o "$download_path" "$download_url"; then + log_info "下载成功" + else + log_error "下载失败,请检查网络连接" + log_warn "将恢复服务" + if [ -f "$config_backup" ]; then + cp "$config_backup" "$DDNS_PATH/config.yaml" + fi + cd $DDNS_PATH + ./ddns-go -s install -l 0.0.0.0:9876 + read -rp "按回车键返回主菜单..." temp + show_menu + return 1 + fi + + # 解压文件 + log_info "解压新版本..." + if tar -zxf "$download_path" -C $DDNS_PATH; then + log_info "解压成功" + else + log_error "解压失败" + log_warn "将恢复服务" + if [ -f "$config_backup" ]; then + cp "$config_backup" "$DDNS_PATH/config.yaml" + fi + cd $DDNS_PATH + ./ddns-go -s install -l 0.0.0.0:9876 + read -rp "按回车键返回主菜单..." temp + show_menu + return 1 + fi + + # 设置权限 + chmod +x $DDNS_PATH/ddns-go + + # 恢复配置 + if [ -f "$config_backup" ]; then + log_info "恢复配置文件..." + cp "$config_backup" "$DDNS_PATH/config.yaml" + fi + + # 获取当前配置的端口 + local port="9876" + if [ -f "$DDNS_PATH/config.yaml" ]; then + local config_port=$(grep -o 'listen: 0.0.0.0:[0-9]*' "$DDNS_PATH/config.yaml" 2>/dev/null | grep -o '[0-9]*$' | head -n 1) + if [[ -n "$config_port" ]]; then + port="$config_port" + fi + fi + + # 安装服务 + log_info "重新安装服务..." + cd $DDNS_PATH + ./ddns-go -s install -l 0.0.0.0:$port + + # 验证更新 + local new_version=$($DDNS_PATH/ddns-go -v 2>&1 | grep -o 'v[0-9.]*' | head -n 1) + if [[ -z "$new_version" ]]; then + new_version="未知" + fi + log_info "更新完成,当前版本: $new_version" + + # 清理下载文件 + rm -f "$download_path" + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 查看状态 +check_status() { + clear + echo "==================================================" + echo -e "${BLUE}ddns-go 状态检查${NC}" + echo "==================================================" + + # 检查是否安装 + if [ ! -d "$DDNS_PATH" ] || [ ! -f "$DDNS_PATH/ddns-go" ]; then + echo -e "${RED}ddns-go 未安装${NC}" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + + # 检查版本 + local version=$($DDNS_PATH/ddns-go -v 2>&1 | grep -o 'v[0-9.]*' | head -n 1) + if [[ -z "$version" ]]; then + version="未知" + fi + echo -e "ddns-go 版本: ${GREEN}$version${NC}" + + # 检查服务状态 + echo -n "服务状态: " + if systemctl is-active ddns-go &>/dev/null; then + echo -e "${GREEN}运行中${NC}" + else + echo -e "${RED}未运行${NC}" + fi + + echo -n "自启动状态: " + if systemctl is-enabled ddns-go &>/dev/null; then + echo -e "${GREEN}已启用${NC}" + else + echo -e "${RED}未启用${NC}" + fi + + # 检查配置文件 + echo -n "配置文件: " + if [ -f "$DDNS_PATH/config.yaml" ]; then + echo -e "${GREEN}存在${NC}" + else + echo -e "${RED}不存在${NC}" + fi + + # 获取内存和 CPU 使用情况 + echo "资源使用情况:" + ps -aux | grep ddns-go | grep -v grep | awk '{print "内存使用: " $4 "%, CPU使用: " $3 "%"}' + + # 获取端口信息 + echo -n "端口状态: " + local port=$(grep -o 'listen: 0.0.0.0:[0-9]*' "$DDNS_PATH/config.yaml" 2>/dev/null | grep -o '[0-9]*$' | head -n 1) + if [[ -z "$port" ]]; then + port=$(systemctl status ddns-go 2>/dev/null | grep -o '\-l 0.0.0.0:[0-9]*' | grep -o '[0-9]*$' | head -n 1) + fi + + if [[ -n "$port" ]]; then + if command -v ss &>/dev/null; then + if ss -tuln | grep -q ":$port "; then + echo -e "${GREEN}端口 $port 已开放${NC}" + else + echo -e "${RED}端口 $port 未开放${NC}" + fi + elif command -v netstat &>/dev/null; then + if netstat -tuln | grep -q ":$port "; then + echo -e "${GREEN}端口 $port 已开放${NC}" + else + echo -e "${RED}端口 $port 未开放${NC}" + fi + else + echo -e "${YELLOW}无法检查端口状态${NC}" + fi + else + echo -e "${YELLOW}未找到端口信息${NC}" + fi + + # 检查DNS解析记录 + echo -e "\n上次DNS更新信息:" + if [ -f "$DDNS_PATH/config.yaml" ]; then + grep -A 10 'ipv4' "$DDNS_PATH/config.yaml" | head -n 10 + else + echo "未找到配置文件,无法获取DNS更新信息" + fi + + # 显示日志 + echo -e "\n最近日志:" + if command -v journalctl &>/dev/null; then + journalctl -u ddns-go --no-pager -n 10 + else + echo "找不到日志信息" + fi + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 重启服务 +restart_service() { + clear + echo "==================================================" + echo -e "${GREEN}重启 ddns-go 服务${NC}" + echo "==================================================" + + # 检查是否已安装 + if [ ! -d "$DDNS_PATH" ] || [ ! -f "$DDNS_PATH/ddns-go" ]; then + log_error "ddns-go 未安装,请先安装" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + + log_info "正在重启 ddns-go 服务..." + + # 尝试使用systemctl重启 + if systemctl restart ddns-go; then + log_info "服务已重启" + else + log_warn "systemctl重启失败,尝试手动重启..." + cd $DDNS_PATH + ./ddns-go -s uninstall + sleep 1 + + # 获取当前配置的端口 + local web_port="9876" + if [ -f "$DDNS_PATH/config.yaml" ]; then + local config_port=$(grep -o 'listen: 0.0.0.0:[0-9]*' "$DDNS_PATH/config.yaml" 2>/dev/null | grep -o '[0-9]*$' | head -n 1) + if [[ -n "$config_port" ]]; then + web_port="$config_port" + fi + fi + + ./ddns-go -s install -l 0.0.0.0:$web_port + log_info "服务已手动重启" + fi + + # 获取IP信息 + local ip_info=$(get_ip_info) + local ipv4=$(echo "$ip_info" | cut -d'|' -f1) + + log_info "服务已重启,Web管理界面: http://$ipv4:$web_port" + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 显示帮助 +show_help() { + echo "ddns-go 管理脚本 v${SCRIPT_VERSION}" + echo "用法: $0 [选项]" + echo "" + echo "选项:" + echo " install 直接安装 ddns-go" + echo " uninstall 直接卸载 ddns-go" + echo " restart 重启 ddns-go 服务" + echo " status 查看 ddns-go 状态" + echo " update 更新 ddns-go" + echo " ip 显示当前公网IP地址" + echo " help 显示此帮助信息" + echo "" + echo "无参数运行脚本将显示交互式菜单" +} + +# 菜单函数 +show_menu() { + clear + echo "==================================================" + echo -e "${CYAN}ddns-go 管理脚本 v${SCRIPT_VERSION}${NC}" + echo "==================================================" + echo -e "1) ${GREEN}安装 ddns-go${NC}" + echo -e "2) ${RED}卸载 ddns-go${NC}" + echo -e "3) ${YELLOW}更新 ddns-go${NC}" + echo -e "4) ${BLUE}查看 ddns-go 状态${NC}" + echo -e "5) ${GREEN}重启 ddns-go 服务${NC}" + echo -e "0) ${RED}退出${NC}" + echo "==================================================" + echo "" + read -rp "请输入选项 [0-5]: " choice + + case $choice in + 1) install_ddns_go ;; + 2) uninstall_ddns_go ;; + 3) update_ddns_go ;; + 4) check_status ;; + 5) restart_service ;; + 0) exit 0 ;; + *) log_error "无效选项" && sleep 2 && show_menu ;; + esac +} + +# 主函数 +main() { + # 处理命令行参数 + if [[ $# -gt 0 ]]; then + case "$1" in + -h|--help|help) + show_help + exit 0 + ;; + install) + install_ddns_go + exit 0 + ;; + uninstall) + uninstall_ddns_go + exit 0 + ;; + restart) + restart_service + exit 0 + ;; + status) + check_status + exit 0 + ;; + update) + update_ddns_go + exit 0 + ;; + *) + log_error "未知参数: $1" + show_help + exit 1 + ;; + esac + fi + + # 无参数则显示菜单 + show_menu +} + +# 执行主函数 +main "$@" diff --git a/init/vps_init.sh b/init/vps_init.sh new file mode 100644 index 0000000..e1c852c --- /dev/null +++ b/init/vps_init.sh @@ -0,0 +1,675 @@ +#!/bin/bash +# +# VPS初始化一键脚本 +# 整合了系统更新、登录安全设置、系统清理、Docker安装、防火墙设置、时区设置、 +# 内存优化、Fail2ban安装和BBR加速 +# 使用方法: chmod +x vps_init.sh && ./vps_init.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/vps_init.sh && chmod +x vps_init.sh && ./vps_init.sh + +# =========================================== +# 用户设置区域 - 根据需要修改 +# =========================================== +NEW_PASSWORD="d!Fssw97SoALHa" # root用户新密码 +NEW_SSH_PORT="4399" # SSH新端口号 +TIMEZONE="Asia/Shanghai" # 时区设置 +SWAP_SIZE=1024 # 交换分区大小(MB) +# =========================================== + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +NC='\033[0m' # 恢复默认颜色 + +# 确保脚本以root权限运行 +if [ "$(id -u)" -ne 0 ]; then + echo -e "${RED}错误: 必须以root用户运行此脚本!${NC}" + exit 1 +fi + +# 显示欢迎信息 +echo -e "${GREEN}=============================================${NC}" +echo -e "${BLUE} VPS初始化一键脚本开始执行 ${NC}" +echo -e "${GREEN}=============================================${NC}" +echo "" + +# =========================================== +# 交互式设置选项 +# =========================================== +echo -e "${BLUE}进行交互式设置...${NC}" + +# 询问是否修改SSH端口 +echo -e "${YELLOW}1. 是否修改SSH端口? 当前设置为: ${NEW_SSH_PORT}${NC}" +while true; do + read -p "修改SSH端口? (y/n, 默认n): " CHANGE_SSH_PORT + # 设置默认值为否,用户按Enter就不修改 + CHANGE_SSH_PORT=${CHANGE_SSH_PORT:-n} + if [[ "$CHANGE_SSH_PORT" =~ ^[Yy]$ ]] || [[ "$CHANGE_SSH_PORT" =~ ^[Nn]$ ]]; then + break + else + echo -e "${RED}无效的输入,请输入 y 或 n${NC}" + fi +done + +if [[ "$CHANGE_SSH_PORT" =~ ^[Yy]$ ]]; then + echo -e "${GREEN}SSH端口将被修改为: ${NEW_SSH_PORT}${NC}" +else + echo -e "${GREEN}保持SSH端口不变: $NEW_SSH_PORT${NC}" +fi + +# 询问是否修改密码 +echo -e "${YELLOW}2. 是否修改root密码?${NC}" +while true; do + read -p "修改root密码? (y/n, 默认n): " CHANGE_PASSWORD + # 设置默认值为否,用户按Enter就不修改 + CHANGE_PASSWORD=${CHANGE_PASSWORD:-n} + if [[ "$CHANGE_PASSWORD" =~ ^[Yy]$ ]] || [[ "$CHANGE_PASSWORD" =~ ^[Nn]$ ]]; then + break + else + echo -e "${RED}无效的输入,请输入 y 或 n${NC}" + fi +done + +if [[ "$CHANGE_PASSWORD" =~ ^[Yy]$ ]]; then + echo -e "${GREEN}root密码将被修改为系统预设值${NC}" +else + echo -e "${GREEN}保持root密码不变${NC}" +fi + +# 询问是否修改主机名 +echo -e "${YELLOW}3. 是否修改主机名?${NC}" +while true; do + read -p "修改主机名? (y/n, 默认n): " CHANGE_HOSTNAME + # 设置默认值为否,用户按Enter就不修改 + CHANGE_HOSTNAME=${CHANGE_HOSTNAME:-n} + if [[ "$CHANGE_HOSTNAME" =~ ^[Yy]$ ]] || [[ "$CHANGE_HOSTNAME" =~ ^[Nn]$ ]]; then + break + else + echo -e "${RED}无效的输入,请输入 y 或 n${NC}" + fi +done + +if [[ "$CHANGE_HOSTNAME" =~ ^[Yy]$ ]]; then + # 显示当前主机名 + CURRENT_HOSTNAME=$(hostname) + echo -e "${YELLOW}当前主机名: ${CURRENT_HOSTNAME}${NC}" + + # 让用户输入新主机名 + read -p "请输入新的主机名: " NEW_HOSTNAME + if [ -n "$NEW_HOSTNAME" ]; then + CHANGE_HOSTNAME_FLAG=true + echo -e "${GREEN}主机名将被修改为: ${NEW_HOSTNAME}${NC}" + else + CHANGE_HOSTNAME_FLAG=false + echo -e "${RED}主机名不能为空,将保持不变${NC}" + fi +else + CHANGE_HOSTNAME_FLAG=false + echo -e "${GREEN}保持主机名不变${NC}" +fi + +echo -e "${BLUE}交互式设置完成${NC}" +echo "" + +# 记录开始时间 +START_TIME=$(date +%s) + +# 检查系统类型 +if [ -f /etc/debian_version ]; then + OS_TYPE="debian" + echo -e "${GREEN}检测到Debian/Ubuntu系统${NC}" +else + echo -e "${YELLOW}警告: 此脚本主要为Debian/Ubuntu系统设计${NC}" + echo -e "${YELLOW}部分功能可能在其他系统上不正常工作${NC}" + OS_TYPE="other" +fi + +# 创建日志文件 +LOG_FILE="/var/log/vps_init_$(date +%Y%m%d_%H%M%S).log" +touch $LOG_FILE +echo "VPS初始化脚本开始执行: $(date)" > $LOG_FILE + +# 定义日志函数 +log() { + echo -e "$1" | tee -a $LOG_FILE +} + +# 定义错误处理函数 +handle_error() { + local exit_code=$? + local line_no=$1 + if [ $exit_code -ne 0 ]; then + log "${RED}错误: 在第 $line_no 行发生错误,退出代码: $exit_code${NC}" + log "${RED}请检查日志文件: $LOG_FILE${NC}" + fi +} + +# 设置错误跟踪 +trap 'handle_error $LINENO' ERR + +# =========================================== +# 1. 系统更新 +# =========================================== +log "${BLUE}[1/10] 系统更新开始...${NC}" + +# 保存当前的sources.list作为备份 +if [ -f "/etc/apt/sources.list" ]; then + cp /etc/apt/sources.list /etc/apt/sources.list.bak + log "${GREEN}备份了软件源配置文件${NC}" +fi + +# 更新系统包 +if [ "$OS_TYPE" = "debian" ]; then + apt update -y || log "${RED}更新软件源失败${NC}" + DEBIAN_FRONTEND=noninteractive apt full-upgrade -y || log "${RED}系统升级失败${NC}" + apt install -y wget curl sudo vim git ufw net-tools htop iftop || log "${RED}安装基础软件包失败${NC}" + log "${GREEN}系统更新完成,安装了常用工具${NC}" +else + log "${YELLOW}非Debian系统,跳过标准更新流程${NC}" +fi + +# =========================================== +# 2. 主机名设置(如果用户选择了修改) +# =========================================== +if [ "$CHANGE_HOSTNAME_FLAG" = true ]; then + log "${BLUE}[2/10] 设置主机名...${NC}" + + # 备份当前主机名配置 + cp /etc/hostname /etc/hostname.bak + cp /etc/hosts /etc/hosts.bak + + # 修改主机名 + echo "$NEW_HOSTNAME" > /etc/hostname + hostname "$NEW_HOSTNAME" + + # 更新hosts文件 + sed -i "s/127.0.1.1.*/127.0.1.1\t$NEW_HOSTNAME/g" /etc/hosts + + # 检查是否修改成功 + CURRENT_HOSTNAME=$(hostname) + if [ "$CURRENT_HOSTNAME" = "$NEW_HOSTNAME" ]; then + log "${GREEN}主机名已成功修改为: $NEW_HOSTNAME${NC}" + else + log "${RED}主机名修改失败,当前名称: $CURRENT_HOSTNAME${NC}" + fi + + log "${GREEN}主机名设置完成${NC}" +else + log "${YELLOW}[2/10] 跳过主机名设置...${NC}" +fi + +# =========================================== +# 3. 登录安全设置 +# =========================================== +log "${BLUE}[3/10] 设置登录安全...${NC}" + +# 根据用户选择修改root密码 +if [[ "$CHANGE_PASSWORD" =~ ^[Yy]$ ]]; then + echo "root:$NEW_PASSWORD" | chpasswd + if [ $? -eq 0 ]; then + log "${GREEN}Root密码修改成功${NC}" + else + log "${RED}Root密码修改失败${NC}" + fi +else + log "${YELLOW}根据用户选择,保持root密码不变${NC}" +fi + +# 根据用户选择修改SSH端口 +if [[ "$CHANGE_SSH_PORT" =~ ^[Yy]$ ]]; then + # 备份SSH配置文件 + cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak + log "${GREEN}SSH配置已备份${NC}" + + # 修改SSH配置 + sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config + sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config + sed -i 's/#Port/Port/' /etc/ssh/sshd_config + sed -i "s/Port [0-9]\+/Port $NEW_SSH_PORT/g" /etc/ssh/sshd_config + + # 读取修改后的SSH端口以确认更改 + NEW_PORT_CONFIGURED=$(grep -P "^Port\s+\d+" /etc/ssh/sshd_config | awk '{print $2}') + if [ "$NEW_PORT_CONFIGURED" = "$NEW_SSH_PORT" ]; then + log "${GREEN}SSH端口已修改为: $NEW_SSH_PORT${NC}" + else + log "${RED}SSH端口修改失败,当前设置: $NEW_PORT_CONFIGURED${NC}" + # 尝试使用另一种方法修改 + echo "Port $NEW_SSH_PORT" >> /etc/ssh/sshd_config + log "${YELLOW}尝试使用备选方法添加端口设置${NC}" + fi + + # 重启SSH服务 + systemctl restart sshd + if [ $? -eq 0 ]; then + log "${GREEN}SSH服务重启成功${NC}" + else + log "${RED}SSH服务重启失败${NC}" + # 尝试使用service命令 + service sshd restart || service ssh restart + fi + + # 检查SSH服务状态 + systemctl status sshd --no-pager || service sshd status || service ssh status + log "${GREEN}SSH配置更改完成${NC}" + log "${YELLOW}注意:新的SSH连接端口为 $NEW_SSH_PORT${NC}" +else + log "${YELLOW}根据用户选择,保持SSH端口不变${NC}" + + # 即使不修改端口,仍然应该确保其他SSH安全设置 + sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config + sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config + + log "${GREEN}SSH基本安全设置完成${NC}" +fi + +# =========================================== +# 4. 系统清理 +# =========================================== +log "${BLUE}[4/10] 系统清理开始...${NC}" + +# 清理不需要的软件包 +if [ "$OS_TYPE" = "debian" ]; then + apt autoremove --purge -y + apt clean -y + apt autoclean -y + apt remove --purge $(dpkg -l | awk '/^rc/ {print $2}') -y 2>/dev/null || log "${YELLOW}没有需要清理的软件包配置${NC}" + + # 清理日志 + journalctl --rotate + journalctl --vacuum-time=1d + journalctl --vacuum-size=50M + log "${GREEN}系统日志已清理${NC}" + + # 清理旧内核(保留当前运行的内核) + apt remove --purge $(dpkg -l | awk '/^ii linux-(image|headers)-[^ ]+/{print $2}' | grep -v $(uname -r | sed 's/-.*//') | xargs) -y 2>/dev/null || log "${YELLOW}没有可清理的旧内核${NC}" + + log "${GREEN}系统清理完成${NC}" +else + log "${YELLOW}非Debian系统,跳过系统清理流程${NC}" +fi + +# =========================================== +# 5. Docker安装 +# =========================================== +log "${BLUE}[5/10] Docker安装开始...${NC}" + +# 检查Docker是否已安装 +if command -v docker &> /dev/null; then + log "${GREEN}Docker已经安装,版本信息:${NC}" + docker --version +else + # 安装Docker + if [ "$OS_TYPE" = "debian" ]; then + # 使用官方安装脚本 + curl -fsSL https://get.docker.com -o get-docker.sh + sh get-docker.sh + rm get-docker.sh + systemctl enable docker + + # 安装Docker Compose + if ! command -v docker-compose &> /dev/null; then + curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + chmod +x /usr/local/bin/docker-compose + log "${GREEN}Docker Compose 安装完成${NC}" + fi + + log "${GREEN}Docker安装完成,版本信息:${NC}" + docker --version + docker-compose --version + else + log "${YELLOW}非Debian系统,请手动安装Docker${NC}" + fi +fi + +# =========================================== +# 6. 防火墙设置 +# =========================================== +log "${BLUE}[6/10] 防火墙设置开始...${NC}" + +# 安装UFW +if [ "$OS_TYPE" = "debian" ]; then + apt update -y && apt install -y ufw net-tools lsof + + # 确保防火墙默认策略 + ufw default deny incoming + ufw default allow outgoing + + # 获取当前SSH端口(如果有多个SSH端口,获取所有) + CURRENT_SSH_PORT=$(grep -P "^Port\s+\d+" /etc/ssh/sshd_config | awk '{print $2}') + if [ -z "$CURRENT_SSH_PORT" ]; then + # 如果没找到,使用默认端口22 + CURRENT_SSH_PORT="22" + fi + + # 总是添加新配置的SSH端口(防止被锁在系统之外) + log "${GREEN}允许SSH端口 $NEW_SSH_PORT${NC}" + ufw allow $NEW_SSH_PORT/tcp comment 'New SSH Port' + + # 如果当前SSH端口与新端口不同,添加当前SSH端口作为备份 + if [ "$CURRENT_SSH_PORT" != "$NEW_SSH_PORT" ]; then + log "${GREEN}允许当前SSH端口 $CURRENT_SSH_PORT (备份)${NC}" + ufw allow $CURRENT_SSH_PORT/tcp comment 'Current SSH Port (Backup)' + fi + + # 添加基本Web服务端口 + log "${GREEN}允许HTTP/HTTPS端口${NC}" + ufw allow 80/tcp comment 'HTTP' + ufw allow 443/tcp comment 'HTTPS' + + # 检测活跃的网络连接和正在监听的端口 + log "${YELLOW}检测当前活跃的服务端口...${NC}" + + # 使用netstat查找监听的TCP端口 + LISTENING_PORTS=$(netstat -tlnp 2>/dev/null | grep "LISTEN" | awk '{print $4}' | awk -F: '{print $NF}' | sort -n | uniq) + + # 使用lsof作为备选方法 + if [ -z "$LISTENING_PORTS" ]; then + LISTENING_PORTS=$(lsof -i -P -n | grep LISTEN | awk '{print $9}' | awk -F: '{print $NF}' | sort -n | uniq) + fi + + # 如果仍然为空,提示手动检查 + if [ -z "$LISTENING_PORTS" ]; then + log "${YELLOW}未检测到活跃端口,只开放SSH、HTTP和HTTPS端口${NC}" + else + log "${GREEN}检测到以下活跃端口:${NC}" + for PORT in $LISTENING_PORTS; do + # 跳过SSH端口(已经添加过),以及常见的本地服务端口 + if [[ "$PORT" != "$NEW_SSH_PORT" && "$PORT" != "$CURRENT_SSH_PORT" && + "$PORT" != "80" && "$PORT" != "443" && + "$PORT" -lt "65535" && "$PORT" -gt "1024" ]]; then + + # 尝试找出服务名称 + SERVICE=$(lsof -i:$PORT -sTCP:LISTEN | grep -v "COMMAND" | awk '{print $1}' | head -1) + if [ -z "$SERVICE" ]; then + SERVICE=$(netstat -tlnp 2>/dev/null | grep ":$PORT" | awk '{print $7}' | cut -d"/" -f2 | head -1) + fi + + if [ -n "$SERVICE" ]; then + COMMENT="Service: $SERVICE" + else + COMMENT="Unknown Service" + fi + + log "${GREEN}允许端口 $PORT/tcp ($COMMENT)${NC}" + ufw allow $PORT/tcp comment "$COMMENT" + fi + done + fi + + # 删除询问用户是否手动开放端口的部分 + log "${GREEN}已自动开放SSH、HTTP、HTTPS端口和检测到的活跃服务端口${NC}" + + # 启用防火墙 + if ! ufw status | grep -q "Status: active"; then + log "${YELLOW}启用UFW防火墙...${NC}" + echo "y" | ufw enable || log "${RED}UFW启用失败${NC}" + else + log "${GREEN}UFW防火墙已启用${NC}" + fi + + # 显示防火墙状态 + ufw status numbered | tee -a $LOG_FILE + log "${GREEN}防火墙设置完成,已使用最小化原则开放端口${NC}" +else + log "${YELLOW}非Debian系统,请手动配置防火墙${NC}" +fi + +# =========================================== +# 7. 时区设置 +# =========================================== +log "${BLUE}[7/10] 时区设置开始...${NC}" + +# 设置时区 +timedatectl set-timezone $TIMEZONE +if [ $? -eq 0 ]; then + CURRENT_TZ=$(timedatectl show --property=Timezone --value) + log "${GREEN}时区设置为: $CURRENT_TZ${NC}" +else + log "${RED}时区设置失败${NC}" +fi + +# =========================================== +# 8. 内存优化 - 添加交换空间 +# =========================================== +log "${BLUE}[8/10] 内存优化开始...${NC}" + +# 获取当前所有交换空间信息 +CURRENT_SWAP_TOTAL=$(free -m | grep "Swap:" | awk '{print $2}') +log "${YELLOW}当前系统交换空间总大小: ${CURRENT_SWAP_TOTAL}MB${NC}" + +# 检查是否存在交换空间且大小与设定值相同 +if [ "$CURRENT_SWAP_TOTAL" -eq "$SWAP_SIZE" ]; then + log "${GREEN}当前交换空间大小(${CURRENT_SWAP_TOTAL}MB)与设定值一致,无需修改${NC}" + # 显示交换空间信息 + free -h | tee -a $LOG_FILE +else + # 如果不存在交换空间或大小不同,则进行处理 + if [ "$CURRENT_SWAP_TOTAL" -gt "0" ]; then + log "${YELLOW}系统已有交换空间但大小不符(${CURRENT_SWAP_TOTAL}MB),准备清理现有交换空间...${NC}" + + # 获取所有交换设备 + SWAP_DEVICES=$(swapon --show=NAME --noheadings) + + # 清理所有活跃的交换空间 + for DEVICE in $SWAP_DEVICES; do + log "${YELLOW}关闭交换空间: $DEVICE${NC}" + swapoff "$DEVICE" + done + + # 从fstab中移除所有交换空间条目(保留备份) + cp /etc/fstab /etc/fstab.bak + log "${GREEN}备份了/etc/fstab文件${NC}" + sed -i '/swap/d' /etc/fstab + + # 删除交换文件 + if [ -f /swapfile ]; then + log "${YELLOW}删除现有交换文件...${NC}" + rm -f /swapfile + fi + + log "${GREEN}所有现有交换空间已清理${NC}" + else + log "${YELLOW}系统未配置交换空间,准备创建...${NC}" + fi + + # 创建新的交换文件 + log "${GREEN}创建${SWAP_SIZE}MB大小的交换文件...${NC}" + dd if=/dev/zero of=/swapfile bs=1M count=$SWAP_SIZE status=progress + chmod 600 /swapfile + mkswap /swapfile + swapon /swapfile + + # 设置开机自动挂载 + if ! grep -q "/swapfile" /etc/fstab; then + echo "/swapfile swap swap defaults 0 0" >> /etc/fstab + log "${GREEN}已添加到fstab,开机将自动挂载${NC}" + fi + + # 调整swappiness参数(控制系统对交换空间的使用倾向) + echo "vm.swappiness=10" > /etc/sysctl.d/99-swappiness.conf + sysctl -p /etc/sysctl.d/99-swappiness.conf + + # 显示交换空间信息 + log "${GREEN}交换分区配置完成,当前内存和交换空间状态:${NC}" + free -h | tee -a $LOG_FILE +fi + +# =========================================== +# 9. Fail2ban安装和配置 +# =========================================== +log "${BLUE}[9/10] Fail2ban安装开始...${NC}" + +if [ "$OS_TYPE" = "debian" ]; then + # 安装Fail2ban + apt update -y && apt install -y fail2ban + systemctl start fail2ban + systemctl enable fail2ban + + # 配置Fail2ban + cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local + + # 清理任何现有配置 + rm -rf /etc/fail2ban/jail.d/* 2>/dev/null || true + + # 创建SSH防护配置 + cat < /etc/fail2ban/jail.d/sshd.local +[sshd] +enabled = true +mode = normal +port = $NEW_SSH_PORT +logpath = %(sshd_log)s +backend = systemd +maxretry = 5 +bantime = 1h +findtime = 10m +EOF + + # 重启Fail2ban + log "${YELLOW}重启Fail2ban服务...${NC}" + systemctl restart fail2ban + + # 等待服务启动完成 + log "${YELLOW}等待Fail2ban服务完全启动...${NC}" + sleep 5 + + # 检查服务状态 + if systemctl is-active --quiet fail2ban; then + log "${GREEN}Fail2ban服务已成功启动${NC}" + + # 显示Fail2ban状态(使用错误处理避免脚本终止) + log "${YELLOW}获取Fail2ban状态信息...${NC}" + + # 尝试获取fail2ban状态,忽略可能的错误 + fail2ban-client status >/dev/null 2>&1 || log "${YELLOW}无法获取fail2ban综合状态,但这不影响功能${NC}" + + # 尝试获取sshd监狱状态 + if fail2ban-client status sshd >/dev/null 2>&1; then + log "${GREEN}SSH防护已成功配置${NC}" + # 只有在前面成功的情况下才显示详细信息 + fail2ban-client status sshd + else + log "${YELLOW}无法获取SSH监狱状态,这可能是因为服务刚刚启动或配置需要更多时间生效${NC}" + log "${YELLOW}如果在重启后仍有问题,请检查 /var/log/fail2ban.log${NC}" + fi + + # 显示服务状态 + systemctl status fail2ban --no-pager || true + else + log "${RED}Fail2ban服务启动失败,请检查错误日志${NC}" + log "${YELLOW}尝试查看Fail2ban日志获取错误详情:${NC}" + tail -n 20 /var/log/fail2ban.log 2>/dev/null || log "${RED}无法读取Fail2ban日志${NC}" + fi + + log "${GREEN}Fail2ban安装和配置完成${NC}" + log "${YELLOW}如果出现临时错误,服务器重启后通常会正常工作${NC}" +else + log "${YELLOW}非Debian系统,请手动安装Fail2ban${NC}" +fi + +# =========================================== +# 10. BBR加速配置 +# =========================================== +log "${BLUE}[10/10] BBR配置开始...${NC}" + +# 检查BBR是否已启用 +if sysctl net.ipv4.tcp_congestion_control | grep -q "bbr"; then + log "${GREEN}BBR已经启用${NC}" +else + log "${YELLOW}配置BBR...${NC}" + # 添加BBR配置 + echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf + echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf + + # 应用设置 + sysctl -p + + # 验证设置 + if sysctl net.ipv4.tcp_congestion_control | grep -q "bbr"; then + log "${GREEN}BBR启用成功${NC}" + else + log "${RED}BBR启用失败${NC}" + fi +fi + +# 显示可用的拥塞控制算法 +log "${GREEN}当前系统支持的TCP拥塞控制算法:${NC}" +sysctl net.ipv4.tcp_available_congestion_control + +# 验证模块是否加载 +lsmod | grep bbr + +# =========================================== +# 完成处理 +# =========================================== +END_TIME=$(date +%s) +DURATION=$((END_TIME - START_TIME)) +MINUTES=$((DURATION / 60)) +SECONDS=$((DURATION % 60)) + +log "${GREEN}=======================================================${NC}" +log "${GREEN}VPS初始化完成!用时: ${MINUTES}分${SECONDS}秒${NC}" +log "${GREEN}=======================================================${NC}" +log "${YELLOW}重要提示:${NC}" + +# 根据用户选择显示相应的提示信息 +TIP_COUNT=1 + +# 如果用户选择了修改SSH端口,显示端口信息 +if [[ "$CHANGE_SSH_PORT" =~ ^[Yy]$ ]]; then + log "${YELLOW}$TIP_COUNT. SSH端口已更改为: ${NEW_SSH_PORT}${NC}" + TIP_COUNT=$((TIP_COUNT + 1)) +fi + +# 如果用户选择了修改root密码,显示密码信息 +if [[ "$CHANGE_PASSWORD" =~ ^[Yy]$ ]]; then + log "${YELLOW}$TIP_COUNT. root密码已更改为: ${NEW_PASSWORD}${NC}" + TIP_COUNT=$((TIP_COUNT + 1)) +fi + +# 如果用户选择了修改主机名,显示主机名信息 +if [ "$CHANGE_HOSTNAME_FLAG" = true ]; then + log "${YELLOW}$TIP_COUNT. 主机名已更改为: ${NEW_HOSTNAME}${NC}" + TIP_COUNT=$((TIP_COUNT + 1)) +fi + +# 始终显示防火墙和日志文件信息 +log "${YELLOW}$TIP_COUNT. 防火墙已启用,只开放了必要端口${NC}" +TIP_COUNT=$((TIP_COUNT + 1)) +log "${YELLOW}$TIP_COUNT. 日志文件保存在: ${LOG_FILE}${NC}" + +# 如果已启用BBR,显示BBR信息 +if sysctl net.ipv4.tcp_congestion_control 2>/dev/null | grep -q "bbr"; then + TIP_COUNT=$((TIP_COUNT + 1)) + log "${YELLOW}$TIP_COUNT. BBR加速已成功启用${NC}" +fi + +# 如果配置了交换空间,显示交换空间信息 +if [ "$CURRENT_SWAP_TOTAL" -gt "0" ]; then + TIP_COUNT=$((TIP_COUNT + 1)) + log "${YELLOW}$TIP_COUNT. 交换空间大小: $(free -m | grep "Swap:" | awk '{print $2}')MB${NC}" +fi + +log "${GREEN}=======================================================${NC}" +log "${BLUE}建议您现在重启服务器以应用所有更改${NC}" +log "${GREEN}=======================================================${NC}" + +# 提示用户是否立即重启 +while true; do + read -p "是否立即重启服务器?(y/n, 默认n): " REBOOT_NOW + # 设置默认值为否 + REBOOT_NOW=${REBOOT_NOW:-n} + if [[ "$REBOOT_NOW" =~ ^[Yy]$ ]] || [[ "$REBOOT_NOW" =~ ^[Nn]$ ]]; then + break + else + echo -e "${RED}无效的输入,请输入 y 或 n${NC}" + fi +done + +if [[ "$REBOOT_NOW" =~ ^[Yy]$ ]]; then + log "${GREEN}服务器将在5秒后重启...${NC}" + sleep 5 + reboot +else + log "${YELLOW}请稍后手动重启服务器以应用所有更改${NC}" +fi \ No newline at end of file diff --git a/init/xray-manager.sh b/init/xray-manager.sh new file mode 100644 index 0000000..7364536 --- /dev/null +++ b/init/xray-manager.sh @@ -0,0 +1,1935 @@ + +# Xray 管理脚本 - 集成安装、卸载和管理功能 +# 专门支持 VLESS+REALITY 协议 +# 使用方法: chmod +x xray-manager.sh && ./xray-manager.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/init/xray-manager.sh && chmod +x xray-manager.sh && ./xray-manager.sh + +# 全局变量 +XRAY_PATH="/usr/local/bin" +CONFIG_PATH="/usr/local/etc/xray" +REALITY_PORT="" # VLESS+REALITY 端口 +LOG_PATH="/var/log/xray" +LOG_FILE="/var/log/xray-manager.log" +SCRIPT_VERSION="1.0.0" +XRAY_VERSION="v25.3.6" # 当前固定的Xray版本 +UUID="" +PRIVATE_KEY="" +PUBLIC_KEY="" +CONFIG_BACKUP="" +SERVER_IP="" + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# 进度条函数 +show_progress() { + local pid=$1 + local delay=0.1 + local spinstr='|/-\' + local temp + local count=0 + local start_time=$(date +%s) + echo -n " " + + while ps -p $pid > /dev/null; do + temp=${spinstr#?} + printf "\r[%c] %s 已进行 %ds" "$spinstr" "$2" "$(($(date +%s) - start_time))" + spinstr=$temp${spinstr%"$temp"} + sleep $delay + count=$((count + 1)) + done + printf "\r\033[K" +} + +# 进度条显示函数 - 适用于apt操作 +apt_progress() { + local cmd="$1" + local msg="$2" + local logfile="$LOG_FILE.tmp" + + echo -e "${CYAN}开始 $msg...${NC}" + touch "$logfile" + ($cmd 2>&1 | tee -a "$LOG_FILE" > "$logfile") & + local pid=$! + + # 显示进度条 + local start_time=$(date +%s) + local dots="" + local status="" + local progress=0 + local last_line="" + local delay=0.2 + + while ps -p $pid > /dev/null; do + # 读取最后一行日志 + if [[ -f "$logfile" ]]; then + last_line=$(tail -n 1 "$logfile") + + # 尝试从输出中提取进度信息 + if [[ $last_line == *%* ]]; then + status="${last_line%%(*}" + progress="${last_line#*(}" + progress="${progress%%)*}" + printf "\r\033[K${CYAN}[$msg]${NC} %s %s " "$status" "$progress" + else + dots="${dots}." + if [[ ${#dots} -gt 5 ]]; then dots="."; fi + elapsed=$(($(date +%s) - start_time)) + printf "\r\033[K${CYAN}[$msg]${NC} 进行中%s (%ds)" "$dots" "$elapsed" + fi + fi + sleep $delay + done + + if wait $pid; then + printf "\r\033[K${GREEN}[$msg]${NC} 完成! 用时: %ds\n" "$(($(date +%s) - start_time))" + rm -f "$logfile" + return 0 + else + printf "\r\033[K${RED}[$msg]${NC} 失败! 查看日志: $LOG_FILE\n" + rm -f "$logfile" + return 1 + fi +} + +# 日志函数 +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" | tee -a "$LOG_FILE" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" | tee -a "$LOG_FILE" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" >&2 | tee -a "$LOG_FILE" +} + +log_debug() { + echo -e "${BLUE}[DEBUG]${NC} $1" | tee -a "$LOG_FILE" +} + +# 检查是否有 root 权限 +check_root() { + if [[ $EUID -ne 0 ]]; then + log_error "此脚本需要 root 权限运行" + exit 1 + fi +} + +# 检查系统环境 +check_system() { + # 显示系统信息 + echo "系统信息:" + echo "------------------------" + if [ -f /etc/os-release ]; then + cat /etc/os-release | grep "PRETTY_NAME" | cut -d= -f2- | tr -d '"' + fi + echo "内核版本: $(uname -r)" + echo "架构: $(uname -m)" + echo "------------------------" + + # 检查是否为 Debian/Ubuntu 系统 + if [[ ! -f /etc/debian_version && ! -f /etc/lsb-release ]]; then + log_warn "未检测到 Debian/Ubuntu 系统,脚本可能无法正常工作" + read -rp "是否继续? [y/N] " response + if [[ ! "$response" =~ ^[yY]$ ]]; then + exit 1 + fi + fi + + # 检查网络连接 + echo -n "检查网络连接... " + if ping -c 1 -W 2 github.com &>/dev/null; then + echo -e "${GREEN}连接正常${NC}" + else + echo -e "${YELLOW}无法连接到 GitHub${NC}" + log_warn "无法连接到 GitHub,请检查网络连接" + read -rp "是否继续? [y/N] " response + if [[ ! "$response" =~ ^[yY]$ ]]; then + exit 1 + fi + fi +} + +# 获取最新版本号 +get_latest_version() { + # 利用GitHub重定向特性获取最新版本 + local redirect_url=$(curl -s -L -o /dev/null -w '%{url_effective}' https://github.com/XTLS/Xray-core/releases/latest 2>/dev/null) + local version=$(echo "$redirect_url" | grep -o 'tag/v[0-9.]*' | cut -d/ -f2 2>/dev/null) + + # 如果获取失败,尝试备用方法 + if [[ -z "$version" ]]; then + # 方法2: 通过API获取 + version=$(curl -s https://api.github.com/repos/XTLS/Xray-core/releases/latest | grep -o '"tag_name": "v[0-9.]*"' | cut -d'"' -f4 2>/dev/null) + fi + + # 如果还是失败,返回当前全局版本 + if [[ -z "$version" ]]; then + version="$XRAY_VERSION" + else + # 更新全局变量 + XRAY_VERSION="$version" + fi + + echo "$version" +} + +# 备份函数 +backup_config() { + if [[ -d "$CONFIG_PATH" ]]; then + CONFIG_BACKUP="${CONFIG_PATH}_backup_$(date +%Y%m%d%H%M%S)" + log_info "备份现有配置到 $CONFIG_BACKUP" + cp -r "$CONFIG_PATH" "$CONFIG_BACKUP" || log_warn "配置备份失败" + + # 备份 Xray 信息文件 + if [[ -f "/root/xray_info.txt" ]]; then + cp "/root/xray_info.txt" "${CONFIG_BACKUP}/xray_info.txt.bak" || log_warn "Xray 信息文件备份失败" + fi + else + log_warn "找不到配置目录,跳过备份" + fi +} + +# 显示帮助信息 +show_help() { + echo "Xray 管理脚本 v${SCRIPT_VERSION}" + echo "用法: $0 [选项]" + echo "" + echo "选项:" + echo " -h, --help 显示此帮助信息" + echo " -i, --install 直接运行安装" + echo " -u, --uninstall 直接运行卸载" + echo " -s, --status 查看 Xray 状态" + echo " -up, --update 更新 Xray" + echo "" + echo "无参数运行脚本将显示交互式菜单" +} + +# 菜单函数 +show_menu() { + clear + echo "==================================================" + echo -e "${CYAN}Xray REALITY管理脚本 v${SCRIPT_VERSION}${NC}" + echo -e "${CYAN}(VLESS+REALITY 协议)${NC}" + echo "==================================================" + echo -e "1) ${GREEN}安装 Xray${NC}" + echo -e "2) ${RED}卸载 Xray${NC}" + echo -e "3) ${YELLOW}更新 Xray${NC}" + echo -e "4) ${BLUE}查看 Xray 状态${NC}" + echo -e "5) ${CYAN}查看 Xray 配置信息${NC}" + echo -e "6) ${GREEN}重启 Xray 服务${NC}" + echo -e "7) ${YELLOW}手动设置 Xray 版本号${NC}" + echo -e "0) ${RED}退出${NC}" + echo "==================================================" + echo "" + read -rp "请输入选项 [0-7]: " choice + + case $choice in + 1) install_xray ;; + 2) uninstall_xray ;; + 3) update_xray ;; + 4) check_status ;; + 5) show_config ;; + 6) restart_service ;; + 7) set_xray_version ;; + 0) exit 0 ;; + *) log_error "无效选项" && sleep 2 && show_menu ;; + esac +} + +# 设置Xray版本号 +set_xray_version() { + clear + echo "==================================================" + echo -e "${YELLOW}手动设置 Xray 版本号${NC}" + echo "==================================================" + + echo "当前Xray版本号: $XRAY_VERSION" + echo "" + echo "1) 自动获取最新版本" + echo "2) 手动输入版本号" + echo "0) 返回主菜单" + echo "" + + read -rp "请选择操作 [0-2]: " version_choice + + case $version_choice in + 1) + echo -n "正在获取最新版本... " + local latest_version=$(get_latest_version) + + if [[ "$latest_version" == "$XRAY_VERSION" && ! -z "$latest_version" ]]; then + echo -e "${GREEN}成功${NC}" + log_info "当前已是最新版本: $XRAY_VERSION" + elif [[ -z "$latest_version" || "$latest_version" == "v1.8.4" ]]; then + echo -e "${RED}失败${NC}" + log_error "无法自动获取最新版本" + else + echo -e "${GREEN}成功${NC}" + XRAY_VERSION="$latest_version" + log_info "Xray版本已自动更新为: $XRAY_VERSION" + fi + ;; + 2) + echo "请访问 https://github.com/XTLS/Xray-core/releases 查看可用版本" + read -rp "请输入新的版本号(例如 v25.3.6): " new_version + + if [[ -z "$new_version" ]]; then + log_error "版本号不能为空" + elif [[ ! "$new_version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + log_error "版本号格式不正确,请使用类似 v25.3.6 的格式" + else + XRAY_VERSION="$new_version" + log_info "Xray版本已更新为: $XRAY_VERSION" + fi + ;; + 0) + # 直接返回 + ;; + *) + log_error "无效选项" + ;; + esac + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 安装依赖 +install_dependencies() { + log_info "安装必要依赖" + + # 更新软件包列表 + apt_progress "apt-get update" "更新软件包列表" || { + log_error "更新软件包列表失败" + return 1 + } + + # 安装必要工具 + local deps=(curl wget jq unzip) + for dep in "${deps[@]}"; do + if ! command -v "$dep" &>/dev/null; then + apt_progress "apt-get install -y $dep" "安装 $dep" || { + log_error "安装 $dep 失败" + return 1 + } + else + log_info "$dep 已安装,跳过" + fi + done + + # 检查安装结果 + local all_installed=true + for dep in "${deps[@]}"; do + if ! command -v "$dep" &>/dev/null; then + log_error "$dep 安装失败" + all_installed=false + fi + done + + if [ "$all_installed" = true ]; then + log_info "所有依赖安装完成" + return 0 + else + log_error "部分依赖安装失败" + return 1 + fi +} + +# 下载 Xray +download_xray() { + log_info "开始下载 Xray" + + # 检查Xray服务是否正在运行,如果是则停止 + if systemctl is-active xray &>/dev/null; then + log_info "检测到Xray服务正在运行,先停止服务" + echo -n "停止 Xray 服务... " + if systemctl stop xray &>/dev/null; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_warn "无法停止 Xray 服务,可能会影响安装" + fi + + # 等待进程完全停止 + echo -n "等待进程释放资源... " + sleep 2 + if pgrep -x "xray" > /dev/null; then + # 如果进程仍在运行,尝试强制终止 + pkill -9 -x "xray" &>/dev/null + sleep 1 + fi + echo -e "${GREEN}完成${NC}" + fi + + # 创建临时目录 + local tmp_dir="/tmp/xray_install" + mkdir -p "$tmp_dir" + + # 获取最新版本 + echo -n "获取 Xray 最新版本... " + local latest_version=$(get_latest_version) + echo -e "${GREEN}$latest_version${NC}" + + # 确定系统架构 + local arch + case $(uname -m) in + x86_64|amd64) arch="64" ;; + armv7l|armv8l) arch="arm32-v7a" ;; + aarch64) arch="arm64-v8a" ;; + *) arch="64" ;; # 默认使用64位版本 + esac + + # 构建下载URL + local download_url="https://github.com/XTLS/Xray-core/releases/download/$latest_version/Xray-linux-$arch.zip" + log_info "下载链接: $download_url" + + # 下载Xray + echo -n "下载 Xray... " + if wget -q --show-progress -O "$tmp_dir/xray.zip" "$download_url"; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_error "下载 Xray 失败" + return 1 + fi + + # 解压文件 + echo -n "解压 Xray... " + if unzip -q -o "$tmp_dir/xray.zip" -d "$tmp_dir"; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_error "解压 Xray 失败" + return 1 + fi + + # 创建目录 + mkdir -p "$XRAY_PATH" "$CONFIG_PATH" "$LOG_PATH" + + # 复制文件前确保目标文件不被占用 + if [[ -f "$XRAY_PATH/xray" ]]; then + # 如果文件存在,先尝试重命名它 + mv "$XRAY_PATH/xray" "$XRAY_PATH/xray.old" 2>/dev/null + fi + + # 复制文件 + echo -n "安装 Xray 核心文件... " + if cp "$tmp_dir/xray" "$XRAY_PATH/xray" && chmod +x "$XRAY_PATH/xray"; then + echo -e "${GREEN}成功${NC}" + # 删除旧文件 + rm -f "$XRAY_PATH/xray.old" 2>/dev/null + else + echo -e "${RED}失败${NC}" + log_error "安装 Xray 核心文件失败" + # 恢复旧文件 + if [[ -f "$XRAY_PATH/xray.old" ]]; then + mv "$XRAY_PATH/xray.old" "$XRAY_PATH/xray" 2>/dev/null + fi + return 1 + fi + + # 复制 geoip.dat 和 geosite.dat + echo -n "安装 GeoIP 和 GeoSite 数据... " + if cp "$tmp_dir/geoip.dat" "$XRAY_PATH/geoip.dat" && \ + cp "$tmp_dir/geosite.dat" "$XRAY_PATH/geosite.dat"; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_warn "安装 GeoIP 和 GeoSite 数据失败,将在配置时下载" + fi + + # 清理临时文件 + rm -rf "$tmp_dir" + + log_info "Xray $latest_version 安装完成" + return 0 +} + +# 生成随机 PORT 和 UUID +generate_random_values() { + log_info "生成随机配置值" + + # 询问用户是否指定端口 + if [[ -z "$REALITY_PORT" ]]; then + read -rp "是否指定端口? [y/N] " specify_port + if [[ "$specify_port" =~ ^[yY]$ ]]; then + # 用户选择指定端口 + while true; do + read -rp "请输入端口号 (1-65535): " REALITY_PORT + # 验证端口是否为有效数字 + if ! [[ "$REALITY_PORT" =~ ^[0-9]+$ ]] || [ "$REALITY_PORT" -lt 1 ] || [ "$REALITY_PORT" -gt 65535 ]; then + log_error "无效的端口号,请输入1-65535之间的数字" + continue + fi + + # 检查端口是否被占用 + if ss -tuln | grep -q ":$REALITY_PORT "; then + log_warn "端口 $REALITY_PORT 已被占用,请选择其他端口" + continue + fi + + log_info "将使用指定端口: $REALITY_PORT" + break + done + else + # 用户选择随机端口,继续原来的逻辑 + # 尝试找一个未被占用的端口 + local attempts=0 + while [[ "$attempts" -lt 10 ]]; do + REALITY_PORT=$(shuf -i 10000-60000 -n 1) + # 检查端口是否被占用 + if ! ss -tuln | grep -q ":$REALITY_PORT "; then + log_info "生成随机端口: $REALITY_PORT" + break + fi + attempts=$((attempts + 1)) + done + if [[ "$attempts" -eq 10 ]]; then + log_warn "无法找到未占用的端口,使用随机端口: $REALITY_PORT" + fi + fi + else + # 验证端口是否为有效数字 + if ! [[ "$REALITY_PORT" =~ ^[0-9]+$ ]]; then + log_warn "无效的端口: $REALITY_PORT,生成新的随机端口" + REALITY_PORT=$(shuf -i 10000-60000 -n 1) + fi + fi + + # 生成 UUID + if [[ -z "$UUID" ]]; then + # 检查xray命令是否可用 + if [[ -f "$XRAY_PATH/xray" && -x "$XRAY_PATH/xray" ]]; then + UUID=$($XRAY_PATH/xray uuid) + log_info "生成 UUID: $UUID" + else + # 如果xray不可用,使用uuidgen或者随机生成 + if command -v uuidgen &>/dev/null; then + UUID=$(uuidgen) + else + # 简单的UUID生成方法(不完全符合标准但足够使用) + UUID=$(cat /proc/sys/kernel/random/uuid 2>/dev/null || + (date +%s%N | sha256sum | head -c 32 | + sed 's/\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)/\1\2\3\4-\5\6-\7\8-/')) + fi + log_info "生成 UUID: $UUID" + fi + else + # 验证UUID格式 + if ! [[ "$UUID" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]]; then + log_warn "无效的 UUID 格式: $UUID,生成新的 UUID" + if [[ -f "$XRAY_PATH/xray" && -x "$XRAY_PATH/xray" ]]; then + UUID=$($XRAY_PATH/xray uuid) + else + UUID=$(cat /proc/sys/kernel/random/uuid 2>/dev/null || + (date +%s%N | sha256sum | head -c 32 | + sed 's/\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)/\1\2\3\4-\5\6-\7\8-/')) + fi + log_info "生成新的 UUID: $UUID" + fi + fi + + # 生成 REALITY 密钥对 + log_info "生成 REALITY 密钥对" + if [[ -z "$PRIVATE_KEY" || -z "$PUBLIC_KEY" ]]; then + local key_pair + if [[ -f "$XRAY_PATH/xray" && -x "$XRAY_PATH/xray" ]]; then + key_pair=$($XRAY_PATH/xray x25519) + PRIVATE_KEY=$(echo "$key_pair" | grep "Private" | awk '{print $3}') + PUBLIC_KEY=$(echo "$key_pair" | grep "Public" | awk '{print $3}') + else + log_warn "无法使用 xray 生成密钥对,将跳过密钥生成" + log_info "安装完成后,将自动生成密钥对" + fi + fi + + # 获取服务器IP + get_server_ip + + log_debug "私钥: $PRIVATE_KEY" + log_debug "公钥: $PUBLIC_KEY" +} + +# 获取服务器IP +get_server_ip() { + log_info "获取服务器IP地址" + + if [[ -n "$SERVER_IP" ]]; then + log_info "使用已设置的IP: $SERVER_IP" + return 0 + fi + + # 尝试首选方法获取公网IP + SERVER_IP=$(curl -s -m 5 https://api.ipify.org 2>/dev/null) + + # 验证获取到的IP是否为有效IPv4地址 + if [[ -n "$SERVER_IP" && "$SERVER_IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then + log_info "成功获取公网IP: $SERVER_IP" + return 0 + fi + + # 如果第一个方法失败,尝试备用方法 + local backup_services=("https://ifconfig.me" "https://ip.sb" "https://ipinfo.io/ip") + + for service in "${backup_services[@]}"; do + SERVER_IP=$(curl -s -m 3 "$service" 2>/dev/null) + if [[ -n "$SERVER_IP" && "$SERVER_IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then + log_info "成功从 $service 获取公网IP: $SERVER_IP" + return 0 + fi + done + + # 如果所有公网IP获取方式都失败,则使用本地IP + if command -v hostname &>/dev/null; then + SERVER_IP=$(hostname -I 2>/dev/null | awk '{print $1}') + fi + + # 如果hostname命令失败,尝试使用ip命令 + if [[ -z "$SERVER_IP" && -x "$(command -v ip)" ]]; then + SERVER_IP=$(ip -4 addr show scope global | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n 1) + fi + + # 如果还是失败,尝试使用ifconfig命令 + if [[ -z "$SERVER_IP" && -x "$(command -v ifconfig)" ]]; then + SERVER_IP=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | head -n 1) + fi + + if [[ -n "$SERVER_IP" ]]; then + log_warn "无法获取公网IP,使用本地IP: $SERVER_IP" + return 0 + else + log_error "无法获取任何有效IP地址,将使用127.0.0.1作为占位符" + SERVER_IP="127.0.0.1" + return 1 + fi +} + +# 配置 Xray - 修改为 VLESS+REALITY 并支持 TUN 模式 +configure_xray() { + log_info "配置 Xray" + + # 生成随机值 + generate_random_values + + # 创建配置目录 + mkdir -p "$CONFIG_PATH" + + # 创建示例目录 + mkdir -p "$CONFIG_PATH/examples" + + log_info "创建 VLESS+REALITY 配置文件(支持TUN模式)" + + # VLESS + REALITY 配置 (添加支持TUN模式的DNS和路由配置) + cat > "$CONFIG_PATH/config.json" << EOF +{ + "log": { + "loglevel": "warning", + "access": "$LOG_PATH/access.log", + "error": "$LOG_PATH/error.log" + }, + "inbounds": [ + { + "port": $REALITY_PORT, + "protocol": "vless", + "settings": { + "clients": [ + { + "id": "$UUID", + "flow": "xtls-rprx-vision" + } + ], + "decryption": "none" + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "show": false, + "dest": "www.shopify.com:443", + "xver": 0, + "serverNames": [ + "shopify.com", + "www.shopify.com" + ], + "privateKey": "$PRIVATE_KEY", + "shortIds": [ + "", + "6ba85179e30d" + ] + } + }, + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls", + "quic" + ], + "routeOnly": false + } + } + ], + "outbounds": [ + { + "protocol": "freedom", + "tag": "direct" + }, + { + "protocol": "blackhole", + "tag": "block" + } + ], + "dns": { + "hosts": { + "dns.google": "8.8.8.8", + "proxy.example.com": "127.0.0.1" + }, + "servers": [ + { + "address": "1.1.1.1", + "domains": [ + "geosite:geolocation-!cn" + ], + "expectIPs": [ + "geoip:!cn" + ] + }, + { + "address": "223.5.5.5", + "domains": [ + "geosite:cn" + ], + "expectIPs": [ + "geoip:cn" + ] + }, + "8.8.8.8", + "https://dns.google/dns-query" + ] + }, + "routing": { + "domainStrategy": "AsIs", + "rules": [ + { + "type": "field", + "outboundTag": "block", + "domain": [ + "geosite:category-ads-all" + ] + }, + { + "type": "field", + "outboundTag": "direct", + "ip": [ + "geoip:private" + ] + }, + { + "type": "field", + "outboundTag": "direct", + "domain": [ + "geosite:private" + ] + }, + { + "type": "field", + "port": "443", + "network": "udp", + "outboundTag": "block" + }, + { + "type": "field", + "outboundTag": "direct", + "ip": [ + "geoip:cn" + ] + }, + { + "type": "field", + "outboundTag": "direct", + "domain": [ + "geosite:cn" + ] + } + ] + } +} +EOF + + if [[ -f "$CONFIG_PATH/config.json" ]]; then + log_info "配置文件创建成功" + else + log_error "配置文件创建失败" + return 1 + fi + + return 0 +} + +# 配置防火墙 - 简化只处理 REALITY 端口 +configure_firewall() { + log_info "配置防火墙" + + # 检测和关闭旧端口 + local old_ports=() + + # 从备份中查找旧端口 + if [[ -n "$CONFIG_BACKUP" && -f "$CONFIG_BACKUP/config.json" ]]; then + log_info "检测旧配置中的端口" + if command -v jq &>/dev/null; then + # 使用jq查找所有inbounds的端口 + local detected_ports=$(jq '.inbounds[].port' "$CONFIG_BACKUP/config.json" 2>/dev/null) + for port in $detected_ports; do + if [[ "$port" != "null" && -n "$port" ]]; then + old_ports+=("$port") + log_info "检测到旧端口: $port" + fi + done + else + # 使用grep查找端口 + local detected_ports=$(grep -o '"port": [0-9]*' "$CONFIG_BACKUP/config.json" | awk '{print $2}') + for port in $detected_ports; do + if [[ -n "$port" ]]; then + old_ports+=("$port") + log_info "检测到旧端口: $port" + fi + done + fi + fi + + # 如果找不到旧端口,也查找默认位置 + if [[ ${#old_ports[@]} -eq 0 && -f "$CONFIG_PATH/config.json" && "$CONFIG_PATH/config.json" != "$(readlink -f "$CONFIG_BACKUP/config.json")" ]]; then + if command -v jq &>/dev/null; then + # 使用jq查找所有inbounds的端口 + local detected_ports=$(jq '.inbounds[].port' "$CONFIG_PATH/config.json" 2>/dev/null) + for port in $detected_ports; do + if [[ "$port" != "null" && -n "$port" ]]; then + old_ports+=("$port") + log_info "检测到当前配置的端口: $port" + fi + done + else + # 使用grep查找端口 + local detected_ports=$(grep -o '"port": [0-9]*' "$CONFIG_PATH/config.json" | awk '{print $2}') + for port in $detected_ports; do + if [[ -n "$port" ]]; then + old_ports+=("$port") + log_info "检测到当前配置的端口: $port" + fi + done + fi + fi + + # 从旧端口列表中过滤掉当前端口 + local filtered_ports=() + for port in "${old_ports[@]}"; do + # 检查端口是否为有效数字 + if ! [[ "$port" =~ ^[0-9]+$ ]]; then + log_warn "无效的端口号: $port,已跳过" + continue + fi + + # 检查是否与当前端口相同 + if [[ "$port" -eq "$REALITY_PORT" ]]; then + log_info "端口 $port 与当前端口相同,已跳过" + continue + fi + + filtered_ports+=("$port") + done + old_ports=("${filtered_ports[@]}") + + # 检查是否安装了 ufw + if command -v ufw &>/dev/null; then + # 检查ufw是否启用 + local ufw_status=$(ufw status | grep -o "Status: active" 2>/dev/null) + + if [[ -z "$ufw_status" ]]; then + log_warn "UFW 防火墙未启用,可能需要手动配置防火墙规则" + log_info "您可以运行 'sudo ufw enable' 启用 UFW 防火墙" + return 0 + fi + + # 关闭旧端口 + if [[ ${#old_ports[@]} -gt 0 ]]; then + log_info "开始关闭旧端口" + local closed_ports=() + + for port in "${old_ports[@]}"; do + # 检查端口是否已开放在UFW中 + if ! ufw status | grep -q "$port/tcp"; then + log_info "端口 $port 未在 UFW 中开放,跳过" + continue + fi + + echo -n "关闭 UFW 防火墙端口 $port... " + if ufw delete allow "$port/tcp" &>/dev/null; then + echo -e "${GREEN}完成${NC}" + closed_ports+=("$port") + else + echo -e "${RED}失败${NC}" + log_warn "无法关闭端口 $port" + fi + done + + # 打印关闭的端口 + if [[ ${#closed_ports[@]} -gt 0 ]]; then + local closed_list=$(printf ", %s" "${closed_ports[@]}") + closed_list=${closed_list:2} # 移除开头的逗号和空格 + log_info "已关闭 UFW 防火墙中的旧端口: $closed_list" + else + log_info "没有需要关闭的旧端口" + fi + else + log_info "未检测到旧端口,跳过关闭端口步骤" + fi + + # 确定需要开放的端口 + local ports=("$REALITY_PORT") + + echo -n "配置 UFW 防火墙... " + local opened_ports=() + for port in "${ports[@]}"; do + # 检查端口是否为有效数字 + if ! [[ "$port" =~ ^[0-9]+$ ]]; then + log_warn "端口 '$port' 不是有效数字,已跳过" + continue + fi + + # 检查端口是否已经开放 + if ufw status | grep -q "$port/tcp"; then + log_info "端口 $port 已经开放,跳过" + opened_ports+=("$port") + continue + fi + + # 开放端口 + if ufw allow "$port/tcp" &>/dev/null; then + opened_ports+=("$port") + else + log_warn "无法开放端口 $port" + fi + done + echo -e "${GREEN}完成${NC}" + + # 打印开放的端口 + if [[ ${#opened_ports[@]} -gt 0 ]]; then + local port_list=$(printf ", %s" "${opened_ports[@]}") + port_list=${port_list:2} # 移除开头的逗号和空格 + log_info "已在 UFW 防火墙开放端口: $port_list" + else + log_warn "没有成功开放任何端口" + fi + else + log_warn "未检测到 UFW 防火墙,跳过防火墙配置" + log_info "如需管理防火墙规则,请安装 UFW: sudo apt install ufw" + fi + + return 0 +} + +# 生成客户端配置 - 更新为只提供 VLESS+REALITY +generate_client_info() { + log_info "生成客户端信息" + + # 确保IP地址已获取 + if [[ -z "$SERVER_IP" ]]; then + get_server_ip + fi + + # 生成 VLESS + REALITY 分享链接 + local share_link="vless://${UUID}@${SERVER_IP}:${REALITY_PORT}?security=reality&encryption=none&pbk=${PUBLIC_KEY}&fp=chrome&type=tcp&flow=xtls-rprx-vision&sni=www.shopify.com&sid=6ba85179e30d#Xray-Reality" + + # 保存客户端信息 + cat > /root/xray_info.txt << EOF +========================= Xray Reality 配置信息 ========================= +服务器地址: ${SERVER_IP} +端口: ${REALITY_PORT} +UUID: ${UUID} +协议: vless +传输协议: tcp +加密方式: none +流控: xtls-rprx-vision +安全: reality +公钥: ${PUBLIC_KEY} +私钥: ${PRIVATE_KEY} +SNI: www.shopify.com +指纹: chrome +短 ID: 6ba85179e30d +================================================================== + +分享链接: +${share_link} + +二维码链接: +https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=${share_link} +================================================================== + +TUN模式支持: +REALITY 协议已配置支持 TUN 模式,客户端配置示例文件已生成: +1. REALITY-TUN配置: ${CONFIG_PATH}/examples/reality_tun_example.json + +将配置文件导入到支持TUN模式的客户端后: +1. 切换到"TUN模式"选项卡 +2. 点击"启用TUN模式" +3. 选择"系统代理"或"全局代理" +4. 重启客户端并允许管理员权限 + +================================================================== + +配置文件路径: ${CONFIG_PATH}/config.json +服务控制: +启动: systemctl start xray +停止: systemctl stop xray +重启: systemctl restart xray +状态: systemctl status xray +================================================================== +EOF + + # 生成 REALITY TUN 模式配置示例 + generate_reality_tun_config + + log_info "客户端信息已保存到 /root/xray_info.txt" + + # 打印信息 + cat /root/xray_info.txt + + log_info "安装完成!Xray REALITY 已成功部署" + return 0 +} + +# 新增:生成 REALITY TUN 模式配置 +generate_reality_tun_config() { + log_info "生成 REALITY TUN 模式配置示例" + + # 确保IP地址已设置 + if [[ -z "$SERVER_IP" ]]; then + get_server_ip + fi + + # 创建 TUN 配置示例目录 + local example_dir="$CONFIG_PATH/examples" + mkdir -p "$example_dir" + + # 生成客户端配置示例,用于TUN模式 + cat > "$example_dir/reality_tun_example.json" << EOF +{ + "log": { + "loglevel": "warning" + }, + "inbounds": [ + { + "tag": "socks", + "port": 10808, + "listen": "127.0.0.1", + "protocol": "socks", + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls" + ], + "routeOnly": false + }, + "settings": { + "auth": "noauth", + "udp": true, + "allowTransparent": false + } + }, + { + "tag": "tun", + "protocol": "tun", + "settings": { + "network": "all" + }, + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls" + ], + "routeOnly": false + } + } + ], + "tun": { + "enable": true, + "stack": "gvisor", + "mtu": 9000, + "strict_route": true + }, + "outbounds": [ + { + "tag": "proxy", + "protocol": "vless", + "settings": { + "vnext": [ + { + "address": "${SERVER_IP}", + "port": ${REALITY_PORT}, + "users": [ + { + "id": "${UUID}", + "flow": "xtls-rprx-vision", + "encryption": "none" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "show": false, + "fingerprint": "chrome", + "serverName": "www.shopify.com", + "publicKey": "${PUBLIC_KEY}", + "shortId": "6ba85179e30d" + } + } + }, + { + "tag": "direct", + "protocol": "freedom" + }, + { + "tag": "block", + "protocol": "blackhole" + } + ], + "dns": { + "hosts": { + "dns.google": "8.8.8.8", + "proxy.example.com": "127.0.0.1" + }, + "servers": [ + { + "address": "1.1.1.1", + "domains": [ + "geosite:geolocation-!cn" + ], + "expectIPs": [ + "geoip:!cn" + ] + }, + { + "address": "223.5.5.5", + "domains": [ + "geosite:cn" + ], + "expectIPs": [ + "geoip:cn" + ] + }, + "8.8.8.8", + "https://dns.google/dns-query" + ] + }, + "routing": { + "domainStrategy": "IPIfNonMatch", + "rules": [ + { + "type": "field", + "outboundTag": "proxy", + "domain": [ + "domain:google.com", + "domain:googleapis.cn", + "domain:gstatic.com" + ] + }, + { + "type": "field", + "outboundTag": "direct", + "domain": [ + "geosite:cn" + ] + }, + { + "type": "field", + "outboundTag": "direct", + "ip": [ + "geoip:private", + "geoip:cn" + ] + } + ] + } +} +EOF + + log_info "REALITY TUN 模式配置示例已保存到 $example_dir/reality_tun_example.json" + log_info "使用方法: 将配置导入到支持TUN模式的客户端,然后开启TUN模式" + + return 0 +} + +# 创建系统服务 +create_service() { + log_info "创建 Xray 系统服务" + + # 创建服务文件 + cat > /etc/systemd/system/xray.service << EOF +[Unit] +Description=Xray Service +Documentation=https://github.com/XTLS/Xray-core +After=network.target nss-lookup.target + +[Service] +User=root +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE +NoNewPrivileges=true +ExecStart=$XRAY_PATH/xray run -config $CONFIG_PATH/config.json +Restart=on-failure +RestartPreventExitStatus=23 +LimitNPROC=10000 +LimitNOFILE=1000000 + +[Install] +WantedBy=multi-user.target +EOF + + # 重新加载 systemd 配置并启用服务 + systemctl daemon-reload + + echo -n "启用 Xray 服务... " + if systemctl enable xray &>/dev/null; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_error "无法启用 Xray 服务" + return 1 + fi + + echo -n "启动 Xray 服务... " + if systemctl start xray; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_error "无法启动 Xray 服务" + return 1 + fi + + return 0 +} + +# 安装完整流程 - 更新为直接安装 VLESS+REALITY +install_xray() { + clear + echo "==================================================" + echo -e "${GREEN}开始安装 Xray REALITY 协议${NC}" + echo "==================================================" + + # 检查是否为 root + check_root + + # 检查系统环境 + check_system + + # 备份现有配置 + backup_config + + # 安装依赖 + install_dependencies || { + log_error "安装依赖失败,退出安装" + return 1 + } + + # 下载和安装 Xray + download_xray || { + log_error "下载 Xray 失败,退出安装" + return 1 + } + + # 配置 Xray + configure_xray || { + log_error "配置 Xray 失败,退出安装" + return 1 + } + + # 创建系统服务 + create_service || { + log_error "创建系统服务失败,但会继续安装过程" + } + + # 配置防火墙 + configure_firewall + + # 生成客户端信息 + generate_client_info + + echo "" + log_info "Xray REALITY 协议安装成功!" + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 停止 Xray 服务 +stop_xray_service() { + log_info "停止 Xray 服务" + + if systemctl is-active xray &>/dev/null; then + echo -n "正在停止 Xray 服务... " + if systemctl stop xray &>/dev/null; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_warn "无法停止 Xray 服务,将尝试继续卸载" + fi + else + log_info "Xray 服务未运行" + fi + + echo -n "禁用 Xray 服务自启动... " + if systemctl disable xray &>/dev/null; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${YELLOW}失败${NC}" + log_warn "无法禁用 Xray 服务自启动,服务可能不存在" + fi +} + +# 读取并关闭防火墙端口 +close_firewall_port() { + log_info "尝试关闭之前开放的防火墙端口" + + # 检查是否安装了 ufw + if ! command -v ufw &>/dev/null; then + log_warn "未检测到 UFW 防火墙,跳过防火墙配置关闭" + return 0 + fi + + # 检查ufw是否启用 + local ufw_status=$(ufw status | grep -o "Status: active" 2>/dev/null) + if [[ -z "$ufw_status" ]]; then + log_warn "UFW 防火墙未启用,跳过防火墙规则关闭" + return 0 + fi + + # 尝试从配置或备份文件中读取端口 + local ports=() + + # 从当前配置中查找端口 + if [[ -f "$CONFIG_PATH/config.json" ]]; then + if command -v jq &>/dev/null; then + # 使用jq查找所有inbounds的端口 + local all_ports=$(jq '.inbounds[].port' "$CONFIG_PATH/config.json" 2>/dev/null) + for port in $all_ports; do + if [[ "$port" != "null" && -n "$port" ]]; then + ports+=("$port") + fi + done + else + # 使用grep查找端口 + local all_ports=$(grep -o '"port": [0-9]*' "$CONFIG_PATH/config.json" | awk '{print $2}') + for port in $all_ports; do + if [[ -n "$port" ]]; then + ports+=("$port") + fi + done + fi + fi + + # 如果找不到端口,从备份中查找 + if [[ ${#ports[@]} -eq 0 && -n "$CONFIG_BACKUP" && -f "$CONFIG_BACKUP/config.json" ]]; then + if command -v jq &>/dev/null; then + local all_ports=$(jq '.inbounds[].port' "$CONFIG_BACKUP/config.json" 2>/dev/null) + for port in $all_ports; do + if [[ "$port" != "null" && -n "$port" ]]; then + ports+=("$port") + fi + done + else + local all_ports=$(grep -o '"port": [0-9]*' "$CONFIG_BACKUP/config.json" | awk '{print $2}') + for port in $all_ports; do + if [[ -n "$port" ]]; then + ports+=("$port") + fi + done + fi + fi + + # 如果还是找不到端口,尝试使用全局变量 + if [[ ${#ports[@]} -eq 0 ]]; then + if [[ -n "$REALITY_PORT" && "$REALITY_PORT" =~ ^[0-9]+$ ]]; then + ports+=("$REALITY_PORT") + fi + fi + + # 去除重复的端口 + if [[ ${#ports[@]} -gt 0 ]]; then + local unique_ports=() + local port_list="" + for port in "${ports[@]}"; do + # 检查端口是否为有效数字 + if ! [[ "$port" =~ ^[0-9]+$ ]]; then + log_warn "端口 '$port' 不是有效数字,已跳过" + continue + fi + + # 检查端口是否已在列表中 + if [[ "$port_list" != *",$port,"* ]]; then + unique_ports+=("$port") + port_list="$port_list,$port," + fi + done + ports=("${unique_ports[@]}") + fi + + # 如果找到了端口,关闭防火墙规则 + if [[ ${#ports[@]} -gt 0 ]]; then + local port_list=$(printf ", %s" "${ports[@]}") + port_list=${port_list:2} # 移除开头的逗号和空格 + log_info "找到端口: $port_list,尝试关闭 UFW 防火墙规则" + + local closed_ports=() + for port in "${ports[@]}"; do + # 检查端口是否已开放在UFW中 + if ! ufw status | grep -q "$port/tcp"; then + log_info "端口 $port 未在 UFW 中开放,跳过" + continue + fi + + echo -n "关闭 UFW 防火墙端口 $port... " + if ufw delete allow "$port/tcp" &>/dev/null; then + echo -e "${GREEN}完成${NC}" + closed_ports+=("$port") + else + echo -e "${RED}失败${NC}" + log_warn "无法关闭端口 $port" + fi + done + + # 打印关闭的端口 + if [[ ${#closed_ports[@]} -gt 0 ]]; then + local closed_list=$(printf ", %s" "${closed_ports[@]}") + closed_list=${closed_list:2} # 移除开头的逗号和空格 + log_info "已关闭 UFW 防火墙中的端口: $closed_list" + else + log_warn "没有关闭任何端口" + fi + else + log_warn "无法确定之前使用的端口,跳过防火墙规则关闭" + fi +} + +# 删除 Xray 文件 +remove_xray_files() { + log_info "删除 Xray 文件" + + # 删除二进制文件 + echo -n "删除 Xray 核心文件... " + if rm -f "$XRAY_PATH/xray" "$XRAY_PATH/geoip.dat" "$XRAY_PATH/geosite.dat"; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${YELLOW}部分文件未能删除${NC}" + log_warn "部分 Xray 核心文件可能未能完全删除" + fi + + # 删除配置目录(不删除备份) + echo -n "删除 Xray 配置目录... " + if [[ -d "$CONFIG_PATH" ]]; then + if rm -rf "$CONFIG_PATH"; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_warn "无法删除配置目录 $CONFIG_PATH" + fi + else + echo -e "${YELLOW}配置目录不存在${NC}" + fi + + # 删除日志目录 + echo -n "删除 Xray 日志目录... " + if [[ -d "$LOG_PATH" ]]; then + if rm -rf "$LOG_PATH"; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_warn "无法删除日志目录 $LOG_PATH" + fi + else + echo -e "${YELLOW}日志目录不存在${NC}" + fi + + # 删除服务文件 + echo -n "删除 Xray 服务文件... " + if rm -f /etc/systemd/system/xray.service; then + echo -e "${GREEN}成功${NC}" + systemctl daemon-reload + else + echo -e "${YELLOW}服务文件不存在或无法删除${NC}" + fi + + return 0 +} + +# 完整卸载流程 +uninstall_xray() { + clear + echo "==================================================" + echo -e "${RED}开始卸载 Xray${NC}" + echo "==================================================" + + # 确认卸载 + echo -e "${YELLOW}警告: 这将卸载 Xray 并删除相关文件${NC}" + read -rp "是否继续? [y/N] " confirm + if [[ ! "$confirm" =~ ^[yY]$ ]]; then + log_info "卸载已取消" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + + # 检查 root 权限 + check_root + + # 备份配置 + backup_config + + # 停止服务 + stop_xray_service + + # 关闭防火墙端口 + close_firewall_port + + # 删除文件 + remove_xray_files + + echo "" + log_info "Xray 卸载完成" + + # 直接删除备份文件,不询问用户 + if [[ -n "$CONFIG_BACKUP" && -d "$CONFIG_BACKUP" ]]; then + rm -rf "$CONFIG_BACKUP" + log_info "备份文件已删除" + fi + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 检查 Xray 状态 +check_status() { + clear + echo "==================================================" + echo -e "${BLUE}Xray 状态检查${NC}" + echo "==================================================" + + # 检查是否安装 + if [[ ! -f "$XRAY_PATH/xray" ]]; then + echo -e "${RED}Xray 未安装${NC}" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + + # 检查版本 + echo -n "Xray 版本: " + $XRAY_PATH/xray version | head -n 1 + + # 检查服务状态 + echo -n "服务状态: " + if systemctl is-active xray &>/dev/null; then + echo -e "${GREEN}运行中${NC}" + else + echo -e "${RED}未运行${NC}" + fi + + echo -n "自启动状态: " + if systemctl is-enabled xray &>/dev/null; then + echo -e "${GREEN}已启用${NC}" + else + echo -e "${RED}未启用${NC}" + fi + + # 获取内存和 CPU 使用情况 + echo "资源使用情况:" + ps -aux | grep xray | grep -v grep | awk '{print "内存使用: " $4 "%, CPU使用: " $3 "%"}' + + # 检查端口 + if [[ -f "$CONFIG_PATH/config.json" ]]; then + local current_port="" + if command -v jq &>/dev/null; then + current_port=$(jq '.inbounds[0].port' "$CONFIG_PATH/config.json" 2>/dev/null) + else + current_port=$(grep -o '"port": [0-9]*' "$CONFIG_PATH/config.json" | head -1 | awk '{print $2}') + fi + + if [[ -n "$current_port" && "$current_port" != "null" ]]; then + echo -n "端口 $current_port 状态: " + if command -v ss &>/dev/null; then + if ss -tuln | grep -q ":$current_port "; then + echo -e "${GREEN}已开放${NC}" + else + echo -e "${RED}未开放${NC}" + fi + elif command -v netstat &>/dev/null; then + if netstat -tuln | grep -q ":$current_port "; then + echo -e "${GREEN}已开放${NC}" + else + echo -e "${RED}未开放${NC}" + fi + else + echo -e "${YELLOW}无法检查${NC}" + fi + + # 显示链接数 + echo "当前连接:" + if command -v ss &>/dev/null; then + ss -tn | grep ":$current_port" | wc -l | awk '{print "活跃连接数: " $1}' + elif command -v netstat &>/dev/null; then + netstat -tn | grep ":$current_port" | wc -l | awk '{print "活跃连接数: " $1}' + else + echo "无法获取连接信息" + fi + fi + fi + + echo -e "\n最近的日志:" + if [[ -f "$LOG_PATH/error.log" ]]; then + tail -n 10 "$LOG_PATH/error.log" + else + echo "找不到错误日志文件" + fi + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 显示配置信息 +show_config() { + clear + echo "==================================================" + echo -e "${CYAN}Xray 配置信息${NC}" + echo "==================================================" + + # 检查是否已安装 + if [[ ! -f "$XRAY_PATH/xray" ]]; then + echo -e "${RED}Xray 未安装${NC}" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + + # 显示配置文件内容 + if [[ -f "$CONFIG_PATH/config.json" ]]; then + if command -v jq &>/dev/null; then + echo "配置信息 (美化格式):" + jq . "$CONFIG_PATH/config.json" + else + echo "配置文件内容:" + cat "$CONFIG_PATH/config.json" + fi + else + echo -e "${RED}找不到配置文件${NC}" + fi + + # 显示客户端信息 + if [[ -f "/root/xray_info.txt" ]]; then + echo -e "\n客户端信息:" + cat /root/xray_info.txt + else + echo -e "\n${RED}找不到客户端信息文件${NC}" + fi + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 重启 Xray 服务 +restart_service() { + clear + echo "==================================================" + echo -e "${GREEN}重启 Xray 服务${NC}" + echo "==================================================" + + # 检查是否已安装 + if [[ ! -f "$XRAY_PATH/xray" ]]; then + echo -e "${RED}Xray 未安装${NC}" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + + echo -n "重启 Xray 服务... " + if systemctl restart xray; then + echo -e "${GREEN}成功${NC}" + log_info "Xray 服务已重启" + else + echo -e "${RED}失败${NC}" + log_error "无法重启 Xray 服务" + fi + + # 检查服务状态 + echo -n "Xray 服务状态: " + if systemctl is-active xray &>/dev/null; then + echo -e "${GREEN}运行中${NC}" + else + echo -e "${RED}未运行${NC}" + fi + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 更新 Xray +update_xray() { + clear + echo "==================================================" + echo -e "${YELLOW}更新 Xray${NC}" + echo "==================================================" + + # 检查是否已安装 + if [[ ! -f "$XRAY_PATH/xray" ]]; then + echo -e "${RED}Xray 未安装,请先安装${NC}" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + + # 获取当前版本 + local current_version + current_version=$($XRAY_PATH/xray version | head -n 1 | cut -d ' ' -f 2) + echo "当前版本: $current_version" + + # 获取最新版本 + echo -n "获取最新版本... " + local latest_version=$(get_latest_version) + echo -e "${GREEN}$latest_version${NC}" + + # 比较版本 + if [[ "$current_version" == "$latest_version" ]]; then + echo -e "${GREEN}已经是最新版本${NC}" + read -rp "是否强制更新? [y/N] " confirm + if [[ ! "$confirm" =~ ^[yY]$ ]]; then + log_info "更新已取消" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + fi + + # 备份配置 + backup_config + + # 停止服务 + echo -n "停止 Xray 服务... " + if systemctl stop xray &>/dev/null; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_warn "无法停止 Xray 服务,将尝试继续更新" + fi + + # 下载新版本 + log_info "开始下载新版本" + + # 创建临时目录 + local tmp_dir="/tmp/xray_update" + mkdir -p "$tmp_dir" + + # 确定系统架构 + local arch + case $(uname -m) in + x86_64|amd64) arch="64" ;; + armv7l|armv8l) arch="arm32-v7a" ;; + aarch64) arch="arm64-v8a" ;; + *) arch="64" ;; # 默认使用64位版本 + esac + + # 构建下载URL + local download_url="https://github.com/XTLS/Xray-core/releases/download/$latest_version/Xray-linux-$arch.zip" + log_info "下载链接: $download_url" + + # 下载Xray + echo -n "下载 Xray... " + if wget -q --show-progress -O "$tmp_dir/xray.zip" "$download_url"; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_error "下载 Xray 失败" + read -rp "按回车键返回主菜单..." temp + show_menu + return 1 + fi + + # 解压文件 + echo -n "解压 Xray... " + if unzip -q -o "$tmp_dir/xray.zip" -d "$tmp_dir"; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_error "解压 Xray 失败" + read -rp "按回车键返回主菜单..." temp + show_menu + return 1 + fi + + # 备份旧的二进制文件 + mv "$XRAY_PATH/xray" "$XRAY_PATH/xray.old" 2>/dev/null + + # 复制新文件 + echo -n "更新 Xray 核心文件... " + if cp "$tmp_dir/xray" "$XRAY_PATH/xray" && chmod +x "$XRAY_PATH/xray"; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_error "更新 Xray 核心文件失败" + + # 恢复旧文件 + if [[ -f "$XRAY_PATH/xray.old" ]]; then + mv "$XRAY_PATH/xray.old" "$XRAY_PATH/xray" + log_warn "已恢复为旧版本" + fi + + read -rp "按回车键返回主菜单..." temp + show_menu + return 1 + fi + + # 更新 geoip.dat 和 geosite.dat + echo -n "更新 GeoIP 和 GeoSite 数据... " + if cp "$tmp_dir/geoip.dat" "$XRAY_PATH/geoip.dat" && \ + cp "$tmp_dir/geosite.dat" "$XRAY_PATH/geosite.dat"; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${YELLOW}失败${NC}" + log_warn "更新 GeoIP 和 GeoSite 数据失败,但不影响核心功能" + fi + + # 删除旧备份和临时文件 + rm -f "$XRAY_PATH/xray.old" + rm -rf "$tmp_dir" + + # 启动服务 + echo -n "启动 Xray 服务... " + if systemctl start xray; then + echo -e "${GREEN}成功${NC}" + else + echo -e "${RED}失败${NC}" + log_error "启动 Xray 服务失败,请检查配置" + systemctl status xray + read -rp "按回车键返回主菜单..." temp + show_menu + return 1 + fi + + # 检查更新后的版本 + local new_version + new_version=$($XRAY_PATH/xray version | head -n 1 | cut -d ' ' -f 2) + + log_info "Xray 更新完成,版本: $new_version" + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 更新脚本版本信息 +update_script_version() { + clear + echo "==================================================" + echo -e "${GREEN}更新脚本版本信息${NC}" + echo "==================================================" + + # 显示当前脚本版本 + echo "当前脚本版本: $SCRIPT_VERSION" + + # 获取最新脚本版本 + echo -n "获取最新脚本版本... " + local latest_version + latest_version=$(curl -s https://raw.githubusercontent.com/XTLS/Xray-core/main/xray-manager.sh | grep -o 'SCRIPT_VERSION="[^"]*"' | cut -d'"' -f2) + + if [[ -z "$latest_version" ]]; then + echo -e "${RED}失败${NC}" + log_error "无法获取最新脚本版本信息" + read -rp "是否继续更新? [y/N] " confirm + if [[ ! "$confirm" =~ ^[yY]$ ]]; then + log_info "更新已取消" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + latest_version="1.0.0" # 设置一个固定版本作为备用 + log_info "将使用固定版本: $latest_version" + else + echo -e "${GREEN}$latest_version${NC}" + + # 比较版本 + if [[ "$SCRIPT_VERSION" == "$latest_version" ]]; then + echo -e "${GREEN}已经是最新版本${NC}" + read -rp "是否强制更新? [y/N] " confirm + if [[ ! "$confirm" =~ ^[yY]$ ]]; then + log_info "更新已取消" + read -rp "按回车键返回主菜单..." temp + show_menu + return 0 + fi + fi + fi + + # 更新脚本版本 + echo -n "更新脚本版本... " + sed -i "s/SCRIPT_VERSION=\"[^\"]*\"/SCRIPT_VERSION=\"$latest_version\"/" "$0" + echo -e "${GREEN}成功${NC}" + + log_info "脚本版本已更新为 $latest_version" + + read -rp "按回车键返回主菜单..." temp + show_menu +} + +# 主函数 +main() { + # 处理命令行参数 + if [[ $# -gt 0 ]]; then + case "$1" in + -h|--help) + show_help + exit 0 + ;; + -i|--install) + check_root + install_xray + exit 0 + ;; + -u|--uninstall) + check_root + uninstall_xray + exit 0 + ;; + -s|--status) + check_root + check_status + exit 0 + ;; + -up|--update) + check_root + update_xray + exit 0 + ;; + *) + log_error "未知参数: $1" + show_help + exit 1 + ;; + esac + fi + + # 无参数则显示菜单 + check_root + show_menu +} + +# 执行主函数 +main "$@" \ No newline at end of file diff --git a/install/01-Nginx.sh b/install/01-Nginx.sh new file mode 100644 index 0000000..8729910 --- /dev/null +++ b/install/01-Nginx.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# chmod +x 01-Nginx.sh && ./01-Nginx.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/01-Nginx.sh && chmod +x 01-Nginx.sh && ./01-Nginx.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=80 +port443=443 + + +# 1、更新包 +apt update -y && apt upgrade -y # 更新一下包 + + +# 2、创建 Nginx 安装目录 +mkdir -p /root/data/docker_data/Nginx +cd /root/data/docker_data/Nginx + +# 3、配置X-UI的docker-compose +cat < docker-compose.yml +version: '3.8' +services: + nginx: + image: nginx + container_name: nginx + restart: always + ports: + - $port80:80 + - $port443:443 + volumes: + - ./conf.d:/etc/nginx/conf.d + - ./certs:/etc/nginx/certs + - ./html:/var/www/html + - ./log/nginx:/var/log/nginx +EOF + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow $port80 +ufw allow $port443 +ufw status + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "http://$ipv4_address:$port443" +echo "------------------------" + diff --git a/install/02-NginxProxy.sh b/install/02-NginxProxy.sh new file mode 100644 index 0000000..e51f6e9 --- /dev/null +++ b/install/02-NginxProxy.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# chmod +x 02-NginxProxy.sh && ./02-NginxProxy.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/02-NginxProxy.sh && chmod +x 02-NginxProxy.sh && ./02-NginxProxy.sh + + +ipv4_address=$(curl -s ipv4.ip.sb) +port=8020 + + +# 1、更新包 +apt update -y && apt upgrade -y # 更新一下包 + + +# 2、创建 Nginx Proxy 安装目录 +mkdir -p /root/data/docker_data/NginxProxy +cd /root/data/docker_data/NginxProxy + + +# 3、配置Nginx Proxy的docker-compose +cat < docker-compose.yml +version: '3.8' +services: + app: + image: 'jc21/nginx-proxy-manager:latest' + container_name: nginxproxy + restart: unless-stopped + ports: + - '80:80' + - '443:443' + - '$port:81' + volumes: + - ./data:/data + - ./letsencrypt:/etc/letsencrypt +EOF + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow 80 +ufw allow 443 +ufw allow $port +ufw status + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port" +echo "Email: admin@example.com" +echo "Password: changeme" +echo "------------------------" diff --git a/install/03-X-UI.sh b/install/03-X-UI.sh new file mode 100644 index 0000000..df44771 --- /dev/null +++ b/install/03-X-UI.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# chmod +x 03-X-UI.sh && ./03-X-UI.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/03-X-UI.sh && chmod +x 03-X-UI.sh && ./03-X-UI.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=54321 +port443=8030 + + +# 1、更新包 +apt update -y && apt upgrade -y # 更新一下包 + + +# 2、创建X-UI安装目录 +mkdir -p /root/data/docker_data/X-UI +cd /root/data/docker_data/X-UI + +# 3、配置X-UI的docker-compose +cat < docker-compose.yml +version: "3" +services: + x-ui: + image: enwaiax/x-ui:alpha-zh + container_name: x-ui + restart: unless-stopped + volumes: + - ./db/:/etc/x-ui/ + - ./cert/:/root/cert/ + network_mode: host + stdin_open: true + tty: true +EOF + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow $port80 +ufw allow $port443 +ufw status + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "Email: admin" +echo "Password: admin" +echo "注意面板URL根路径: /nSAsXv/" +echo "------------------------" + diff --git a/install/04-FRP.sh b/install/04-FRP.sh new file mode 100644 index 0000000..c233208 --- /dev/null +++ b/install/04-FRP.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# chmod +x 04-FRP.sh && ./04-FRP.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/04-FRP.sh && chmod +x 04-FRP.sh && ./04-FRP.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8040 +port443=8041 + + +# 1、更新包 +apt update -y && apt upgrade -y # 更新一下包 + + +# 2、创建Frps安装目录 +mkdir -p /root/data/docker_data/Frps +cd /root/data/docker_data/Frps + + +# 3、配置Frps的docker-compose +cat < docker-compose.yml +version: '3.3' +services: + frps: + image: snowdreamtech/frps + container_name: frps + restart: always + network_mode: host + volumes: + - './frps.toml:/etc/frp/frps.toml' +EOF + + +# 4、创建frps.toml文件并设置配置 +cd /root/data/docker_data/Frps +touch frps.toml + + +# 5、配置 frps.toml +cat < frps.toml +[common] + +# frp 监听端口,与客户端绑定端口 +bind_port=$port443 +kcp_bind_port=$port443 + +# dashboard用户名 +dashboard_user=admin@gmail.com + +# dashboard密码 +dashboard_pwd=gmail.com + +# dashboard端口,启动成功后可通过浏览器访问如http://ip:9527 +dashboard_port=$port80 + +# 设置客户端token,对应客户端有页需要配置一定要记住,如果客户端不填写你连不上服务端 +token=PAioH8syP!82T% +EOF + + +# 6、安装 +docker-compose up -d + +# 7、打开防火墙的端口 +ufw allow $port80 +ufw allow $port443 +ufw status + + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "Email: admin@gmail.com" +echo "Password: gmail.com" +echo "------------------------" \ No newline at end of file diff --git a/install/05-ZeroTier.sh b/install/05-ZeroTier.sh new file mode 100644 index 0000000..4167ccf --- /dev/null +++ b/install/05-ZeroTier.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# chmod +x 05-Zerotier.sh && ./05-Zerotier.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/05-Zerotier.sh && chmod +x 05-Zerotier.sh && ./05-Zerotier.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8050 +port443=8051 + + +# 1、更新包 +apt update -y && apt upgrade -y # 更新一下包 + + +# 2、创建Zerotier安装目录 +mkdir -p /root/data/docker_data/Zerotier +cd /root/data/docker_data/Zerotier + + +# 3、配置Zerotier的docker-compose +cat < docker-compose.yml +version: '3.3' +services: + ztncui: + image: keynetworks/ztncui + container_name: ztncui + restart: always + ports: + - $port80:4000 + environment: + - HTTP_PORT=4000 + - HTTP_ALL_INTERFACES=yes + - ZTNCUI_PASSWD=mrdoc.fun + + zerotier-moon: + image: jonnyan404/zerotier-moon + container_name: zerotier-moon + restart: always + ports: + - $port443:9993 + - $port443:9993/udp + command: -4 192.168.1.1 # 改成服务器的IP + volumes: + - ./etc/ztconf/:/var/lib/zerotier-one +EOF + + +# 6、安装 +docker-compose up -d + +# 7、打开防火墙的端口 +ufw allow $port80 +ufw allow $port443 +ufw status + + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "user: admin" +echo "Password: mrdoc.fun" +echo "------------------------" +echo "查看moon ID:" +echo "docker logs zerotier-moon" +echo "------------------------" +echo "Windows 客户端加入moon服务器:" +echo "cd C:\ProgramData\ZeroTier\One:" +echo "zerotier-cli orbit [moon_id] [moon_id]:" +echo "------------------------" \ No newline at end of file diff --git a/install/06-Rustdesk.sh b/install/06-Rustdesk.sh new file mode 100644 index 0000000..670ad1e --- /dev/null +++ b/install/06-Rustdesk.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# chmod +x 06-Rustdesk.sh && ./06-Rustdesk.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/06-Rustdesk.sh && chmod +x 06-Rustdesk.sh && ./06-Rustdesk.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8061 + + +# 1、更新包 +apt update -y && apt upgrade -y # 更新一下包 + + +# 2、创建 `Rustdesk` 安装目录 +mkdir -p /root/data/docker_data/Rustdesk +cd /root/data/docker_data/Rustdesk + + +# 3、配置Duplicati的docker-compose +cat < docker-compose.yml +version: '3' + +networks: + rustdesk-net: + external: false + +services: + hbbs: + container_name: hbbs + ports: + - 8060:21115 + - $port80:21116 + - $port80:21116/udp + - 8063:21118 + image: rustdesk/rustdesk-server:latest + command: hbbs -r rustdesk2.ghuang.top:8062 # hbbs.example.com改成 + volumes: + - ./hbbs:/root + networks: + - rustdesk-net + depends_on: + - hbbr + restart: unless-stopped + + hbbr: + container_name: hbbr + ports: + - 8062:21117 + - 8064:21119 + image: rustdesk/rustdesk-server:latest + command: hbbr + volumes: + - ./hbbr:/root + networks: + - rustdesk-net + restart: unless-stopped +EOF + + +# 6、安装 +docker-compose up -d + +# 7、打开防火墙的端口 +ufw allow 8060 +ufw allow 8061 +ufw allow 8062 +ufw allow 8063 +ufw allow 8064 +ufw allow 8061/udp +ufw status + + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "------------------------" \ No newline at end of file diff --git a/install/07-Alist.sh b/install/07-Alist.sh new file mode 100644 index 0000000..2e11a84 --- /dev/null +++ b/install/07-Alist.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# chmod +x 07-Alist.sh && ./07-Alist.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/07-Alist.sh && chmod +x 07-Alist.sh && ./07-Alist.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8070 +port443=8071 + + +# 1、更新包 +apt update -y && apt upgrade -y # 更新一下包 + + +# 2、创建Zerotier安装目录 +mkdir -p /root/data/docker_data/AList +cd /root/data/docker_data/AList + + +# 3、配置Duplicati的docker-compose +cat < docker-compose.yml +version: '3.3' +services: + alist: + restart: always + volumes: + - ./data:/opt/alist/data + ports: + - $port80:5244 + environment: + - PUID=0 + - PGID=0 + - UMASK=022 + container_name: alist + image: xhofe/alist:latest +EOF + + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow $port80 +ufw allow $port443 +ufw status + + +# 6、打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "------------------------" \ No newline at end of file diff --git a/install/08-Duplicati.sh b/install/08-Duplicati.sh new file mode 100644 index 0000000..e1cdc31 --- /dev/null +++ b/install/08-Duplicati.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# chmod +x 08-Duplicati.sh && ./08-Duplicati.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/08-Duplicati.sh && chmod +x 08-Duplicati.sh && ./08-Duplicati.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8080 +port443=8081 + + +# 1、更新包 +apt update -y && apt upgrade -y # 更新一下包 + + +# 2、创建Zerotier安装目录 +mkdir -p /root/data/docker_data/Duplicati +cd /root/data/docker_data/Duplicati + + +# 3、配置Duplicati的docker-compose +cat < docker-compose.yml +version: "2.1" +services: + duplicati: + image: lscr.io/linuxserver/duplicati + container_name: duplicati + environment: + - PUID=0 + - PGID=0 + - TZ=Asia/Shanghai + volumes: + - /root/data/docker_data/Duplicati/config:/config + - /root/data/docker_data/Duplicati/backups:/backups + - /root/data:/source + ports: + - $port80:8200 + restart: unless-stopped +EOF + + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow $port80 +ufw allow $port443 +ufw status + + +# 6、打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "------------------------" \ No newline at end of file diff --git a/install/09-Syncthing.sh b/install/09-Syncthing.sh new file mode 100644 index 0000000..bfcfb48 --- /dev/null +++ b/install/09-Syncthing.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# chmod +x 09-Syncthing.sh && ./09-Syncthing.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/09-Syncthing.sh && chmod +x 09-Syncthing.sh && ./09-Syncthing.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8090 + +# 1、更新包 +apt update -y && apt upgrade -y # 更新一下包 + + +# 2、创建Zerotier安装目录 +mkdir -p /root/data/docker_data/Syncthing +cd /root/data/docker_data/Syncthing + + +# 3、配置Duplicati的docker-compose +cat < docker-compose.yml +version: "3.5" +services: + syncthing: + image: lscr.io/linuxserver/syncthing + container_name: syncthing + hostname: syncthing #optional + environment: + - PUID=1000 + - PGID=1000 + - TZ=Asia/Shanghai + volumes: + - ./config:/config + - ./Documents:/Documents + - ./Media:/Media + - ./Nextcloud:/Nextcloud + ports: + - 8090:8384 + - 8091:22000/tcp + - 8091:22000/udp + - 8092:21027/udp + restart: unless-stopped +EOF + + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow 8090 +ufw allow 8091 +ufw allow 8092 +ufw status + + +# 6、打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "------------------------" \ No newline at end of file diff --git a/install/10-Vaultwarden.sh b/install/10-Vaultwarden.sh new file mode 100644 index 0000000..d0b0c35 --- /dev/null +++ b/install/10-Vaultwarden.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# chmod +x 10-Vaultwarden.sh && ./10-Vaultwarden.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/10-Vaultwarden.sh && chmod +x 10-Vaultwarden.sh && ./10-Vaultwarden.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8100 +port443=8101 + + +# 1、更新包 +apt update -y && apt upgrade -y + +# 2、创建Vaultwarden安装目录 +mkdir -p /root/data/docker_data/Vaultwarden +cd /root/data/docker_data/Vaultwarden + +# 3、配置Vaultwarden的docker-compose +cat < docker-compose.yml +version: '3' +services: + vaultwarden: + image: vaultwarden/server:latest + container_name: vaultwarden + restart: unless-stopped + volumes: + - ./data/:/data/ + ports: + - $port80:80 + environment: + - DOMAIN=https://vaultwarden.ghuang.top # 这是您希望与您的Vaultwarden实例关联的域名。 + - LOGIN_RATELIMIT_MAX_BURST=10 # 允许在一阵登录/两步验证尝试中的最大请求次数。 + - LOGIN_RATELIMIT_SECONDS=60 # 这是来自同一IP的登录请求之间的平均秒数,在Vaultwarden限制登录次数之前。 + - ADMIN_RATELIMIT_MAX_BURST=10 # 这与LOGIN_RATELIMIT_MAX_BURST相同,只争对admin面板。 + - ADMIN_RATELIMIT_SECONDS=60 # 这与LOGIN_RATELIMIT_SECONDS相同 + - ADMIN_SESSION_LIFETIME=20 # 会话持续时间 + - ADMIN_TOKEN=FX6wU1n3i1huwVE9zo9zb6hGiX5fS5URTPhSWGK0pBu1weww0Kr0qcv6GbULX7az # 此值是Vaultwarden管理员面板的令牌(一种密码)。为了安全起见,这应该是一个长的随机字符串。如果未设置此值,则管理员面板将被禁用。建议openssl rand -base64 48 生成ADMIN_TOKEN确保安全 + - SENDS_ALLOWED=true # 此设置决定是否允许用户创建Bitwarden发送 - 一种凭证共享形式。 + - EMERGENCY_ACCESS_ALLOWED=true # 此设置控制用户是否可以启用紧急访问其账户的权限。例如,这样做可以在用户去世后,配偶可以访问密码库以获取账户凭证。可能的值:true / false。 + - WEB_VAULT_ENABLED=true # 此设置决定了网络保险库是否可访问。一旦您配置了您的账户和客户端,停止您的容器,然后将此值切换为false并重启Vaultwarden,可以用来防止未授权访问。可能的值:true/false。 + - SIGNUPS_ALLOWED=true # 此设置控制新用户是否可以在没有邀请的情况下注册账户。可能的值:true / false。 +EOF + + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow $port80 +ufw allow $port443 +ufw status + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "注意事项:" +echo "1、需要先创建账号才能使用" +echo "2、需要将 IP:prot 反向代理成域名才能创建账户" +echo "------------------------" \ No newline at end of file diff --git a/install/11-EasyImage.sh b/install/11-EasyImage.sh new file mode 100644 index 0000000..7dcad27 --- /dev/null +++ b/install/11-EasyImage.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# chmod +x 11-EasyImage.sh && ./11-EasyImage.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/11-EasyImage.sh && chmod +x 11-EasyImage.sh && ./11-EasyImage.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8110 +port443=8111 + + +# 1、更新包 +apt update -y && apt upgrade -y + +# 2、创建EasyImage安装目录 +mkdir -p /root/data/docker_data/EasyImage +cd /root/data/docker_data/EasyImage + + +# 3、配置EasyImage的docker-compose +cat < docker-compose.yml +version: '3.3' +services: + easyimage: + image: ddsderek/easyimage:latest + container_name: easyimage + restart: unless-stopped + ports: + - $port80:80 + environment: + - TZ=Asia/Shanghai + - PUID=1000 + - PGID=1000 + volumes: + - './config:/app/web/config' + - './i:/app/web/i' +EOF + + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow $port80 +ufw allow $port433 +ufw status + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "账号: admin" +echo "密码: admin@123" +echo "------------------------" diff --git a/install/12-Wordpress.sh b/install/12-Wordpress.sh new file mode 100644 index 0000000..71838de --- /dev/null +++ b/install/12-Wordpress.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# chmod +x 12-Wordpress.sh && ./12-Wordpress.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/12-Wordpress.sh && chmod +x 12-Wordpress.sh && ./12-Wordpress.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8120 +port443=8121 + + +# 1、更新包 +apt update -y && apt upgrade -y #更新一下包 + +# 2、创建Wordpress安装目录 +mkdir -p /root/data/docker_data/Wordpress +cd /root/data/docker_data/Wordpress + +# 3、配置Wordpress的docker-compose +cat < docker-compose.yml +version: '3.0' +services: + db: + image: mysql:5.7 # arm架构的机器请将mysql:5.7改为mysql:oracle + container_name: wordpress-db + restart: unless-stopped + # command: --max-binlog-size=200M --expire-logs-days=2 # 使用mysql 8.0的小伙伴建议使用 + environment: + MYSQL_ROOT_PASSWORD: password # 按需修改 + MYSQL_DATABASE: wordpress + MYSQL_USER: wordpress + MYSQL_PASSWORD: password # 按需修改 + volumes: + - './db:/var/lib/mysql' + networks: + - default + + app: + image: wordpress:latest + container_name: wordpress-app + restart: unless-stopped + ports: + - $port80:80 # 按需修改。与防火墙开放端口一致。 + environment: + WORDPRESS_DB_HOST: db + WORDPRESS_DB_NAME: wordpress + WORDPRESS_DB_USER: wordpress + WORDPRESS_DB_PASSWORD: password # 按需修改 + WORDPRESS_LANG: zh_CN # 指定中文语言 + volumes: + - './app:/var/www/html' + links: + - db:db + depends_on: + - redis + - db + networks: + - default + + redis: + image: redis:alpine + container_name: wordpress-redis + restart: unless-stopped + volumes: + - ./redis-data:/data + networks: + - default + +#networks: +# default: +# name: wordpress +EOF + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow $port80 +ufw allow $port433 +ufw status + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "Email: admin@gmail.com" +echo "------------------------" \ No newline at end of file diff --git a/install/13-Nextcloud.sh b/install/13-Nextcloud.sh new file mode 100644 index 0000000..da9835e --- /dev/null +++ b/install/13-Nextcloud.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# chmod +x 13-Nextcloud.sh && ./13-Nextcloud.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/13-Nextcloud.sh && chmod +x 13-Nextcloud.sh && ./13-Nextcloud.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8130 +port443=8131 + + +# 1、更新包 +apt update -y && apt upgrade -y #更新一下包 + +# 创建安装目录 +mkdir -p /root/data/docker_data/Nextcloud +cd /root/data/docker_data/Nextcloud + +# 3、填写docker-compose配置 +cat < docker-compose.yml +version: "3" + +services: + nextcloud: + container_name: nextcloud-app + image: nextcloud:latest + restart: unless-stopped + ports: + - $port80:80 + environment: + - MYSQL_HOST=mysql + - MYSQL_DATABASE=nextcloud + - MYSQL_USER=nextcloud + - MYSQL_PASSWORD=nextcloud + volumes: + - ./data:/var/www/html + + mysql: + image: mysql:8.0 + container_name: nextcloud-db + restart: unless-stopped + environment: + - MYSQL_DATABASE=nextcloud + - MYSQL_USER=nextcloud + - MYSQL_PASSWORD=nextcloud + - MYSQL_ROOT_PASSWORD=nextcloud + volumes: + - ./db:/var/lib/mysql + +#volumes: +# mysql: +# nextcloud: + +EOF + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow $port80 +ufw allow $port433 +ufw status + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "http://$ipv4_address:$port80" +echo "Email: admin@gmail.com" +echo "Password: gmail.com" +echo "------------------------" \ No newline at end of file diff --git a/install/14-Joplin.sh b/install/14-Joplin.sh new file mode 100644 index 0000000..0afcf14 --- /dev/null +++ b/install/14-Joplin.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# chmod +x 14-Joplin.sh && ./14-Joplin.sh +# curl -sS -O https://raw.githubusercontent.com/ghuang-top/vps/main/install/14-Joplin.sh && chmod +x 14-Joplin.sh && ./14-Joplin.sh + +ipv4_address=$(curl -s ipv4.ip.sb) +port80=8140 +port443=8141 + + +# 1、更新包 +apt update -y && apt upgrade -y #更新一下包 + +# 2、创建安装目录 +mkdir -p /root/data/docker_data/Joplin +cd /root/data/docker_data/Joplin + +# 3、填写docker-compose配置 +cat < docker-compose.yml +version: '3' +services: + db: + image: postgres:13 + container_name: joplin-db + restart: unless-stopped + ports: + - "$port433:5432" # 左边的端口可以更换,右边不要动! + volumes: + - ./data/postgres:/var/lib/postgresql/data + environment: + - POSTGRES_PASSWORD=changeme # 改成你自己的密码 + - POSTGRES_USER=username # 改成你自己的用户名 + - POSTGRES_DB=joplin + + app: + image: joplin/server:latest + container_name: joplin-app + restart: unless-stopped + ports: + - "$port80:22300" # 左边的端口可以更换,右边不要动! + depends_on: + - db + environment: + - APP_PORT=22300 + - APP_BASE_URL=https://joplin.ghuang.top # 改成反代的域名 + - DB_CLIENT=pg + - POSTGRES_PASSWORD=changeme # 与上面的密码对应! + - POSTGRES_USER=username # 与上面的用户名对应! + - POSTGRES_DATABASE=joplin + - POSTGRES_PORT=5432 # 与上面右边的对应! + - POSTGRES_HOST=db +EOF + +# 4、安装 +docker-compose up -d + +# 5、打开防火墙的端口 +ufw allow $port80 +ufw allow $port433 +ufw status + +# 打印访问链接 +echo "------------------------" +echo "访问链接:" +echo "https://joplin.ghuang.top" +echo "User: admin@localhost" +echo "Password: admin" +echo "------------------------"