├── LICENSE
├── README.md
├── help.md
├── install.sh
└── vpsai.sh
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Protomyst
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VPSAI - 开源AI服务快速部署工具
2 |
3 |
4 | 轻松部署和管理各类AI服务的自动化脚本工具
5 |
6 |
7 |
8 |
9 | 
10 | 
11 | 
12 |
13 |
14 |
15 | ## ✨ 特性
16 |
17 | - 🚀 一键部署多种流行AI服务
18 | - 🔧 自动配置运行环境(Docker/Nginx)
19 | - 🔐 支持HTTPS和证书自动配置
20 | - 💾 数据持久化和备份方案
21 | - 🔄 支持服务状态监控和自动更新
22 |
23 | ## 📦 支持的服务
24 |
25 | ### API网关
26 | | 服务名 | 默认端口 | 说明 |
27 | |--------|----------|------|
28 | | OneAPI | 3000 | 新一代API管理平台 |
29 | | NewAPI | 4000 | OneAPI二开 |
30 | | VoAPI | 5000 | NewAPI二开(仅x86,闭源) |
31 |
32 | ### Chat前端
33 | | 服务名 | 默认端口 | 说明 |
34 | |--------|----------|------|
35 | | Open-WebUI | 6001 | 功能强大的Chat客户端 |
36 | | NextChat | 7000 | 轻量级聊天前端 |
37 | | LibreChat | 8000 | 界面美观的聊天系统 |
38 | | LobeChat | 9000 | 界面美观的聊天系统 |
39 |
40 | ## 🚀 快速开始
41 |
42 | ### 一键安装
43 | ```bash
44 | curl -fsSL https://raw.githubusercontent.com/Protomyst/vpsai/main/install.sh | sudo bash
45 | ```
46 |
47 | ### 使用教程
48 |
49 | 1. **选择服务类型**
50 | ```bash
51 | 1. API服务
52 | 2. Chat服务
53 | ```
54 |
55 | 2. **配置参数**
56 | - 端口号(可自定义)
57 | - API Key(部分服务需要)
58 | - 访问密码(可选)
59 |
60 | 3. **域名配置**
61 | ```bash
62 | # 使用自定义证书
63 | vpsai > 5 > 1
64 |
65 | # 自动申请Let's Encrypt
66 | vpsai > 5 > 2
67 | ```
68 |
69 | ## 💻 环境要求
70 |
71 | - Linux系统(Debian/Ubuntu/CentOS)
72 | - Root权限
73 | - Docker环境
74 | - 最低配置:
75 | - CPU: 1核
76 | - 内存: 2G
77 | - 硬盘: 20G
78 |
79 | ## 📝 配置说明
80 |
81 | ### 数据目录结构
82 | ```
83 | /root/ai/
84 | ├── data/ # 服务数据
85 | │ ├── one-api/
86 | │ ├── new-api/
87 | │ └── ...
88 | ├── logs/ # 运行日志
89 | └── backup/ # 备份文件
90 | ```
91 |
92 | ### 端口使用
93 | - API服务: 3000-5000
94 | - Chat服务: 6001-9000
95 | - 可自定义修改
96 |
97 | ## 🔒 安全建议
98 |
99 | 1. 修改默认密码
100 | 2. 配置域名和HTTPS
101 | 3. 定期备份数据
102 | 4. 及时更新版本
103 |
104 | ## 🆘 常见问题
105 |
106 |
107 | 1. 端口冲突解决
108 | 检查占用端口进程:
109 | ```bash
110 | netstat -tunlp | grep 端口号
111 | ```
112 |
113 |
114 |
115 | 2. 服务无法访问
116 | - 检查防火墙配置
117 | - 确认端口是否开放
118 | - 查看服务日志
119 |
120 |
121 | ## 📞 获取帮助
122 |
123 | - Issues: https://github.com/Protomyst/vpsai/issues
124 | - 邮箱: protomyst@outlook.com
125 |
126 | ## 📄 开源协议
127 |
128 | 本项目采用 [MIT](LICENSE) 协议开源。
129 |
--------------------------------------------------------------------------------
/help.md:
--------------------------------------------------------------------------------
1 | # VPSAI 帮助文档
2 |
3 | ## 基本信息
4 |
5 | - 版本:v0.0.1
6 | - 作者:Protomyst
7 | - 仓库:https://github.com/Protomyst/vpsai
8 |
9 | ## 功能说明
10 |
11 | ### 1. API服务
12 |
13 | - OneAPI (端口: 3000)
14 | - NewAPI (端口: 4000)
15 | - VoAPI (端口: 5000, 仅支持AMD64架构)
16 |
17 | ### 2. Chat服务
18 |
19 | - Open-WebUI (端口: 6001)
20 | - NextChat (端口: 7000)
21 | - LibreChat (端口: 8000)
22 | - LobeChat (端口: 9000)
23 |
24 | ### 3. 域名配置
25 |
26 | 支持:
27 | - 自定义SSL证书
28 | - 自动申请Let's Encrypt证书
29 |
30 | ### 4. 自动更新
31 |
32 | - 支持每日自动检查更新
33 | - 可手动检查更新
34 |
35 | ## 数据目录
36 |
37 | 所有服务数据存储在:/root/ai/data/{服务名称}
38 |
39 | ## 注意事项
40 |
41 | 1. 必须使用root用户运行
42 | 2. Open-WebUI建议配置不低于1核1G内存
43 | 3. 请定期备份数据目录
44 |
45 | ## 常见问题
46 |
47 | 1. 端口被占用:
48 | 检查并关闭占用端口的程序,或更换端口
49 |
50 | 2. 服务无法访问:
51 | 检查防火墙设置是否放行对应端口
52 |
53 | 3. 证书配置失败:
54 | 确保域名已正确解析到服务器IP
55 |
56 | ## 获取帮助
57 |
58 | 如遇问题请访问项目仓库提交Issue
59 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # 颜色定义
4 | RED='\033[0;31m'
5 | GREEN='\033[0;32m'
6 | YELLOW='\033[1;33m'
7 | NC='\033[0m'
8 |
9 | # 检查root权限
10 | check_root() {
11 | if [ "$(id -u)" != "0" ]; then
12 | echo -e "${RED}错误: 必须使用root权限运行此脚本${NC}"
13 | exit 1
14 | fi
15 | }
16 |
17 | # 检查系统要求
18 | check_system() {
19 | echo -e "${YELLOW}正在检查系统环境...${NC}"
20 |
21 | # 检查Linux发行版
22 | if [ -f /etc/os-release ]; then
23 | . /etc/os-release
24 | case $ID in
25 | debian|ubuntu|centos|rocky|rhel)
26 | echo -e "${GREEN}系统检查通过: $PRETTY_NAME${NC}"
27 | ;;
28 | *)
29 | echo -e "${RED}不支持的系统: $PRETTY_NAME${NC}"
30 | exit 1
31 | ;;
32 | esac
33 | else
34 | echo -e "${RED}无法确定系统类型${NC}"
35 | exit 1
36 | fi
37 |
38 | # 检查内存
39 | total_mem=$(free -m | awk '/^Mem:/{print $2}')
40 | if [ $total_mem -lt 2048 ]; then
41 | echo -e "${YELLOW}警告: 内存小于2GB,部分服务可能无法正常运行${NC}"
42 | fi
43 | }
44 |
45 | # 安装基础依赖
46 | install_base() {
47 | echo -e "${YELLOW}安装基础依赖...${NC}"
48 |
49 | # 检测包管理器
50 | if command -v apt &> /dev/null; then
51 | PKG_MANAGER="apt"
52 | PKG_UPDATE="apt update"
53 | PKG_INSTALL="apt install -y"
54 | elif command -v yum &> /dev/null; then
55 | PKG_MANAGER="yum"
56 | PKG_UPDATE="yum update"
57 | PKG_INSTALL="yum install -y"
58 | else
59 | echo -e "${RED}不支持的包管理器${NC}"
60 | exit 1
61 | fi
62 |
63 | # 更新包列表
64 | $PKG_UPDATE
65 |
66 | # 安装必要工具
67 | for pkg in curl wget git sudo; do
68 | if ! command -v $pkg &> /dev/null; then
69 | echo "安装 $pkg..."
70 | $PKG_INSTALL $pkg
71 | fi
72 | done
73 | }
74 |
75 | # 安装Docker
76 | install_docker() {
77 | echo -e "${YELLOW}安装Docker环境...${NC}"
78 |
79 | if ! command -v docker &> /dev/null; then
80 | curl -fsSL https://get.docker.com | sh
81 | systemctl start docker
82 | systemctl enable docker
83 | fi
84 |
85 | if ! command -v docker-compose &> /dev/null; then
86 | $PKG_INSTALL docker-compose
87 | fi
88 | }
89 |
90 | # 下载VPSAI
91 | install_vpsai() {
92 | echo -e "${YELLOW}安装VPSAI...${NC}"
93 |
94 | # 创建安装目录
95 | install_dir="/root/vpsai"
96 | mkdir -p "$install_dir"
97 |
98 | # 下载代码
99 | git clone https://github.com/Protomyst/vpsai.git "$install_dir"
100 |
101 | # 设置权限
102 | chmod +x "$install_dir/vpsai.sh"
103 |
104 | # 创建快捷方式
105 | ln -sf "$install_dir/vpsai.sh" /usr/local/bin/vpsai
106 |
107 | echo -e "${GREEN}VPSAI安装完成!${NC}"
108 | echo -e "使用方法:"
109 | echo -e " 1. 输入 ${YELLOW}vpsai${NC} 启动管理面板"
110 | echo -e " 2. 或进入 ${YELLOW}$install_dir${NC} 目录"
111 | echo -e " 执行 ${YELLOW}./vpsai.sh${NC}"
112 | }
113 |
114 | # 主函数
115 | main() {
116 | clear
117 | echo "================================================"
118 | echo " VPSAI 一键安装脚本 "
119 | echo "================================================"
120 | echo
121 |
122 | check_root
123 | check_system
124 | install_base
125 | install_docker
126 | install_vpsai
127 |
128 | echo
129 | echo "================================================"
130 | echo -e "${GREEN}安装已完成!${NC}"
131 | echo "现在可以使用 'vpsai' 命令启动管理面板"
132 | echo "================================================"
133 | }
134 |
135 | main
136 |
--------------------------------------------------------------------------------
/vpsai.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | VERSION="v0.0.1"
4 | AUTHOR="Protomyst"
5 | ROOT_DIR="/root/ai"
6 | DATA_DIR="${ROOT_DIR}/data"
7 |
8 | # 显示logo
9 | show_logo() {
10 | echo ' __ ______ ____ _ ___ '
11 | echo ' \ \ / / _ \/ ___| / \ |_ _|'
12 | echo ' \ \ / /| |_) \___ \ / _ \ | | '
13 | echo ' \ V / | __/ ___) / ___ \ | | '
14 | echo ' \_/ |_| |____/_/ \_\___|'
15 | echo
16 | echo " Version: ${VERSION} Author: ${AUTHOR}"
17 | echo
18 | }
19 |
20 | # 检查root权限
21 | check_root() {
22 | if [ "$(id -u)" != "0" ]; then
23 | echo "错误:必须以root用户运行此脚本"
24 | exit 1
25 | fi
26 | }
27 |
28 | # 检查系统架构
29 | check_arch() {
30 | arch=$(uname -m)
31 | is_arm=0
32 | if [ "$arch" = "aarch64" ] || [ "$arch" = "arm64" ]; then
33 | is_arm=1
34 | fi
35 | }
36 |
37 | # 检查并安装依赖
38 | install_dependencies() {
39 | echo "正在检查依赖..."
40 |
41 | # 检测包管理器
42 | if command -v apt &> /dev/null; then
43 | PKG_MANAGER="apt"
44 | PKG_UPDATE="apt update"
45 | PKG_INSTALL="apt install -y"
46 | elif command -v yum &> /dev/null; then
47 | PKG_MANAGER="yum"
48 | PKG_UPDATE="yum update"
49 | PKG_INSTALL="yum install -y"
50 | else
51 | echo "不支持的包管理器"
52 | exit 1
53 | fi
54 |
55 | # 更新包列表
56 | $PKG_UPDATE
57 |
58 | # 安装基础依赖
59 | for pkg in git docker.io docker-compose nginx; do
60 | if ! command -v $pkg &> /dev/null; then
61 | echo "正在安装 $pkg..."
62 | $PKG_INSTALL $pkg
63 | fi
64 | done
65 | }
66 |
67 | # 启动必要服务
68 | start_services() {
69 | systemctl start docker
70 | systemctl enable docker
71 | systemctl start nginx
72 | systemctl enable nginx
73 | }
74 |
75 | # 检查端口是否被占用
76 | check_port() {
77 | local port=$1
78 | if lsof -Pi :$port -sTCP:LISTEN -t >/dev/null ; then
79 | return 1
80 | fi
81 | return 0
82 | }
83 |
84 | # 开放防火墙端口
85 | open_firewall_port() {
86 | local port=$1
87 | if command -v ufw &> /dev/null; then
88 | ufw allow $port
89 | elif command -v firewall-cmd &> /dev/null; then
90 | firewall-cmd --permanent --add-port=$port/tcp
91 | firewall-cmd --reload
92 | fi
93 | }
94 |
95 | # 创建数据目录
96 | create_data_dir() {
97 | local service=$1
98 | local dir="${DATA_DIR}/${service}"
99 | mkdir -p "$dir"
100 | echo "$dir"
101 | }
102 |
103 | # 显示帮助信息
104 | show_help() {
105 | if [ -f "${ROOT_DIR}/help.md" ]; then
106 | less "${ROOT_DIR}/help.md"
107 | else
108 | echo "帮助文件不存在"
109 | fi
110 | }
111 |
112 | # 错误处理
113 | handle_error() {
114 | local error_msg="$1"
115 | echo "错误: ${error_msg}" >&2
116 | logger -t vpsai "错误: ${error_msg}"
117 | }
118 |
119 | # 显示进度
120 | show_progress() {
121 | local current="$1"
122 | local total="$2"
123 | local msg="$3"
124 | printf "\r[%-50s] %d%% %s" \
125 | "$(printf '#%.0s' $(seq 1 $(($current*50/$total))))" \
126 | $(($current*100/$total)) \
127 | "${msg}"
128 | }
129 |
130 | # 主菜单
131 | show_menu() {
132 | clear
133 | show_logo
134 | echo "请选择操作:"
135 | echo "1. 安装API服务 (OneAPI / NewAPI / VoAPI)"
136 | echo "2. 安装Chat服务 (Open-WebUI / NextChat / LibreChat (暂时失效) / LobeChat)"
137 | echo "3. 检查服务状态"
138 | echo "4. 配置自动更新或手动更新"
139 | echo "5. 配置自定义域名"
140 | echo "6. 删除Chat / API服务"
141 | echo "7. 查看帮助"
142 | echo "8. 退出脚本"
143 | echo
144 | read -p "请输入选项 [1-8]: " choice
145 |
146 | case $choice in
147 | 1) install_api_service && read -p "按回车键继续..." ;;
148 | 2) install_chat_service && read -p "按回车键继续..." ;;
149 | 3) check_service_status ;;
150 | 4) configure_updates && read -p "按回车键继续..." ;;
151 | 5) configure_domain && read -p "按回车键继续..." ;;
152 | 6) remove_service && read -p "按回车键继续..." ;;
153 | 7) show_help ;;
154 | 8) exit 0 ;;
155 | *) echo "无效选项" && read -p "按回车键继续..." ;;
156 | esac
157 | }
158 |
159 | ##################
160 | # 服务安装相关函数 #
161 | ##################
162 |
163 | install_api_service() {
164 | echo "请选择要安装的API服务:"
165 | echo "1. OneAPI (默认端口: 3000)"
166 | echo "2. NewAPI (默认端口: 4000)"
167 | if [ $is_arm -eq 0 ]; then
168 | echo "3. VoAPI (默认端口: 5000)"
169 | fi
170 | echo "0. 返回"
171 |
172 | read -p "请选择: " api_choice
173 |
174 | case $api_choice in
175 | 1) install_one_api ;;
176 | 2) install_new_api ;;
177 | 3)
178 | if [ $is_arm -eq 0 ]; then
179 | install_vo_api
180 | else
181 | echo "VoAPI 不支持 ARM 架构"
182 | fi
183 | ;;
184 | 0) return ;;
185 | *) echo "无效选项" ;;
186 | esac
187 | }
188 |
189 | # Chat服务安装
190 | install_chat_service() {
191 | echo "请选择要安装的Chat服务:"
192 | echo "1. Open-WebUI (默认端口: 6001)"
193 | echo "2. NextChat (默认端口: 7000)"
194 | echo "3. LibreChat (默认端口: 8000)"
195 | echo "4. LobeChat (默认端口: 9000)"
196 | echo "0. 返回"
197 |
198 | read -p "请选择: " chat_choice
199 |
200 | # 获取系统内存
201 | total_mem=$(free -m | awk '/^Mem:/{print $2}')
202 |
203 | case $chat_choice in
204 | 1)
205 | if [ $total_mem -lt 1024 ]; then
206 | echo "警告: 系统内存小于1GB,Open-WebUI可能无法正常运行"
207 | read -p "是否继续安装?(y/n): " confirm
208 | if [ "$confirm" != "y" ];then
209 | return
210 | fi
211 | fi
212 | install_open_webui
213 | ;;
214 | 2) install_nextchat ;;
215 | 3) install_librechat ;;
216 | 4) install_lobechat ;;
217 | 0) return ;;
218 | *) echo "无效选项" ;;
219 | esac
220 | }
221 |
222 | # 获取服务器IP
223 | get_server_ip() {
224 | # 优先获取公网IPv4地址
225 | public_ip=$(curl -s -4 ip.sb || curl -s -4 ifconfig.me || curl -s -4 icanhazip.com)
226 | if [ -n "$public_ip" ]; then
227 | echo "$public_ip"
228 | return
229 | fi
230 |
231 | # 如果获取公网IP失败,使用本地IP
232 | local_ip=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v "127.0.0.1" | head -n 1)
233 | if [ -n "$local_ip" ]; then
234 | echo "$local_ip"
235 | return
236 | fi
237 |
238 | echo "无法获取服务器IP"
239 | }
240 |
241 | # 显示访问地址
242 | show_access_info() {
243 | local service_name="$1"
244 | local port="$2"
245 | local extra_info="$3"
246 |
247 | echo "----------------------------------------"
248 | echo "🎉 $service_name 安装完成!"
249 | echo
250 | local ip=$(get_server_ip)
251 | echo "访问地址: http://$ip:$port"
252 | if [ -n "$extra_info" ]; then
253 | echo "$extra_info"
254 | fi
255 | echo "----------------------------------------"
256 | echo -e "\n按回车键返回主菜单..."
257 | read
258 | }
259 |
260 | # OneAPI安装
261 | install_one_api() {
262 | local default_port=3000
263 | read -p "请输入端口号 (默认: $default_port): " port
264 | port=${port:-$default_port}
265 |
266 | if ! check_port $port; then
267 | echo "端口 $port 已被占用"
268 | return
269 | fi
270 |
271 | local data_dir=$(create_data_dir "one-api")
272 |
273 | docker run --name one-api -d \
274 | --restart always \
275 | -p ${port}:3000 \
276 | -e TZ=Asia/Shanghai \
277 | -v ${data_dir}:/data \
278 | justsong/one-api
279 |
280 | open_firewall_port $port
281 | show_access_info "OneAPI" "$port" "初始用户名: root\n初始密码: 123456"
282 | }
283 |
284 | # NewAPI安装
285 | install_new_api() {
286 | local default_port=4000
287 | read -p "请输入端口号 (默认: $default_port): " port
288 | port=${port:-$default_port}
289 |
290 | if ! check_port $port; then
291 | echo "端口 $port 已被占用"
292 | return
293 | fi
294 |
295 | local data_dir=$(create_data_dir "new-api")
296 |
297 | docker run --name new-api -d \
298 | --restart always \
299 | -p ${port}:3000 \
300 | -e TZ=Asia/Shanghai \
301 | -v ${data_dir}:/data \
302 | calciumion/new-api:latest
303 |
304 | open_firewall_port $port
305 | show_access_info "NewAPI" "$port"
306 | }
307 |
308 | # VoAPI安装
309 | install_vo_api() {
310 | local default_port=5000
311 | read -p "请输入端口号 (默认: $default_port): " port
312 | port=${port:-$default_port}
313 |
314 | if ! check_port $port; then
315 | echo "端口 $port 已被占用"
316 | return
317 | fi
318 |
319 | local data_dir=$(create_data_dir "voapi")
320 | local compose_file="${data_dir}/docker-compose.yml"
321 |
322 | # 生成docker-compose配置
323 | cat > "$compose_file" </dev/null 2>&1; then
522 | local status="运行中"
523 | local ports=$(docker port $service 2>/dev/null | awk '{print $3}' | cut -d':' -f2 | tr '\n' ',')
524 | local mem=$(docker stats $service --no-stream --format "{{.MemUsage}}" 2>/dev/null)
525 | printf "%-15s %-10s %-20s %-10s\n" "$service" "$status" "${ports%,}" "$mem"
526 | else
527 | if docker ps -aq -f name=$service >/dev/null 2>&1; then
528 | printf "%-15s %-10s %-20s %-10s\n" "$service" "已停止" "-" "-"
529 | else
530 | printf "%-15s %-10s %-20s %-10s\n" "$service" "未安装" "-" "-"
531 | fi
532 | fi
533 | done
534 |
535 | echo -e "\n输入服务名可以管理该服务,直接回车返回主菜单"
536 | read -p "请输入: " service_name
537 |
538 | if [ -n "$service_name" ]; then
539 | if [[ " ${services[@]} " =~ " ${service_name} " ]]; then
540 | manage_service "$service_name"
541 | else
542 | echo "无效的服务名"
543 | fi
544 | fi
545 | }
546 |
547 | ##################
548 | # 自定义域名配置 #
549 | ##################
550 | # 配置域名
551 | configure_domain() {
552 | echo "域名配置:"
553 | echo "1. 使用自定义证书"
554 | echo "2. 自动申请Let's Encrypt证书"
555 | echo "0. 返回"
556 |
557 | read -p "请选择: " choice
558 |
559 | case $choice in
560 | 1) configure_custom_cert ;;
561 | 2) configure_letsencrypt ;;
562 | 0) return ;;
563 | *) echo "无效选项" ;;
564 | esac
565 | }
566 |
567 | # 配置自定义证书
568 | configure_custom_cert() {
569 | read -p "请输入域名: " domain
570 | read -p "请输入证书路径: " cert_path
571 | read -p "请输入私钥路径: " key_path
572 |
573 | if [ ! -f "$cert_path" ] || [ ! -f "$key_path" ]; then
574 | echo "证书文件不存在"
575 | return
576 | fi
577 |
578 | # 选择要配置的服务
579 | echo "请选择要配置的服务:"
580 | echo "1. OneAPI (端口: 3000)"
581 | echo "2. NewAPI (端口: 4000)"
582 | echo "3. VoAPI (端口: 5000)"
583 | echo "4. Open-WebUI (端口: 6001)"
584 | echo "5. NextChat (端口: 7000)"
585 | echo "6. LibreChat (端口: 8000)"
586 | echo "7. LobeChat (端口: 9000)"
587 |
588 | read -p "请选择 [1-7]: " service_choice
589 |
590 | local port
591 | case $service_choice in
592 | 1) port=3000 ;;
593 | 2) port=4000 ;;
594 | 3) port=5000 ;;
595 | 4) port=6001 ;;
596 | 5) port=7000 ;;
597 | 6) port=8000 ;;
598 | 7) port=9000 ;;
599 | *)
600 | echo "无效选项"
601 | return
602 | ;;
603 | esac
604 |
605 | create_nginx_config "$domain" "$cert_path" "$key_path" "$port"
606 | }
607 |
608 | # 配置Let's Encrypt证书
609 | configure_letsencrypt() {
610 | # 清理可能存在的旧临时配置
611 | rm -f /etc/nginx/sites-enabled/*.temp
612 | rm -f /etc/nginx/sites-available/*.temp
613 |
614 | read -p "请输入域名: " domain
615 | read -p "请输入邮箱(用于证书通知): " email
616 |
617 | # 创建验证目录
618 | local acme_dir="/var/www/letsencrypt/.well-known/acme-challenge"
619 | mkdir -p "$acme_dir"
620 |
621 | # 创建初始Nginx配置用于验证
622 | local nginx_temp="/etc/nginx/sites-available/${domain}.temp"
623 | cat > "$nginx_temp" < /dev/null; then
657 | echo "正在安装certbot..."
658 | snap install --classic certbot
659 | # 等待安装完成
660 | sleep 2
661 | fi
662 |
663 | # 申请证书
664 | certbot certonly \
665 | --webroot \
666 | --agree-tos \
667 | --email "$email" \
668 | --webroot-path /var/www/letsencrypt \
669 | --domains "$domain" \
670 | --non-interactive
671 |
672 | local cert_result=$?
673 |
674 | # 清理临时配置
675 | rm -f "$nginx_temp"
676 | rm -f "/etc/nginx/sites-enabled/${domain}.temp"
677 | systemctl reload nginx
678 |
679 | if [ $cert_result -ne 0 ]; then
680 | echo "证书申请失败"
681 | return 1
682 | fi
683 |
684 | # 获取证书路径
685 | local cert_path="/etc/letsencrypt/live/$domain/fullchain.pem"
686 | local key_path="/etc/letsencrypt/live/$domain/privkey.pem"
687 |
688 | if [ ! -f "$cert_path" ] || [ ! -f "$key_path" ]; then
689 | echo "证书文件不存在"
690 | return 1
691 | fi
692 |
693 | # 配置服务
694 | echo "请选择要配置的服务:"
695 | echo "1. OneAPI (端口: 3000)"
696 | echo "2. NewAPI (端口: 4000)"
697 | echo "3. VoAPI (端口: 5000)"
698 | echo "4. Open-WebUI (端口: 6001)"
699 | echo "5. NextChat (端口: 7000)"
700 | echo "6. LibreChat (端口: 8000)"
701 | echo "7. LobeChat (端口: 9000)"
702 |
703 | read -p "请选择 [1-7]: " service_choice
704 |
705 | local port
706 | case $service_choice in
707 | 1) port=3000 ;;
708 | 2) port=4000 ;;
709 | 3) port=5000 ;;
710 | 4) port=6001 ;;
711 | 5) port=7000 ;;
712 | 6) port=8000 ;;
713 | 7) port=9000 ;;
714 | *)
715 | echo "无效选项"
716 | return 1
717 | ;;
718 | esac
719 |
720 | create_nginx_config "$domain" "$cert_path" "$key_path" "$port"
721 |
722 | # 配置自动续期
723 | echo "配置证书自动续期..."
724 | (crontab -l 2>/dev/null | grep -v "certbot renew"; echo "0 0 1 * * certbot renew --quiet") | crontab -
725 |
726 | echo "证书配置完成!"
727 | echo "域名访问地址: https://$domain"
728 | }
729 |
730 | # 创建Nginx配置
731 | create_nginx_config() {
732 | domain=$1
733 | cert_path=$2
734 | key_path=$3
735 | port=$4
736 |
737 | nginx_config="/etc/nginx/sites-available/$domain"
738 |
739 | # 创建最终的Nginx配置
740 | cat > "$nginx_config" </dev/null 2>&1; then
827 | cd vpsai
828 | remote_version=$(grep "VERSION=" vpsai.sh | cut -d'"' -f2)
829 | if [ "$remote_version" != "$VERSION" ]; then
830 | echo "发现新版本: $remote_version"
831 | read -p "是否更新?(y/n): " update_choice
832 | if [ "$update_choice" = "y" ]; then
833 | cp -r * /root/vpsai/
834 | echo "更新完成"
835 | fi
836 | else
837 | echo "已是最新版本"
838 | fi
839 | cd ..
840 | rm -rf vpsai
841 | else
842 | echo "检查更新失败"
843 | fi
844 | }
845 |
846 | # 配置自动更新
847 | configure_updates() {
848 | echo "更新配置:"
849 | echo "1. 立即检查更新"
850 | echo "2. 配置自动更新"
851 | echo "3. 取消自动更新"
852 | echo "0. 返回"
853 |
854 | read -p "请选择: " choice
855 |
856 | case $choice in
857 | 1) check_script_update ;;
858 | 2) setup_auto_update ;;
859 | 3) remove_auto_update ;;
860 | 0) return ;;
861 | *) echo "无效选项" ;;
862 | esac
863 | }
864 |
865 | # 检查单个服务更新
866 | check_service_update() {
867 | local service="$1"
868 | local image="$2"
869 |
870 | echo "检查 $service 更新..."
871 | if docker pull "$image" | grep -q "Image is up to date"; then
872 | echo "$service 已是最新版本"
873 | return 0
874 | else
875 | echo "发现 $service 新版本"
876 | read -p "是否更新?(y/n): " update_choice
877 | if [ "$update_choice" = "y" ]; then
878 | docker stop "$service"
879 | docker rm "$service"
880 | return 1
881 | fi
882 | fi
883 | return 0
884 | }
885 |
886 | # 优化自动更新设置
887 | setup_auto_update() {
888 | # 创建更新脚本
889 | cat > /etc/cron.daily/vpsai-update < >(tee -a "${ROOT_DIR}/logs/vpsai.log")
934 | exec 2> >(tee -a "${ROOT_DIR}/logs/vpsai.error.log")
935 |
936 | install_dependencies
937 | start_services
938 |
939 | while true; do
940 | show_menu
941 | # 这里不需要额外的暂停,因为在show_menu中已经处理了
942 | done
943 | }
944 |
945 | main
946 |
--------------------------------------------------------------------------------