轻量应用服务器部署指南(腾讯云)
把 Spring Boot 应用放到腾讯云轻量应用服务器上,核心是三件事:机器环境(Java、MySQL、Nginx)、生产配置与证书、用 systemd 把进程管住。下面按一台 OpenCloudOS 9 实例来写。
轻量应用服务器(腾讯云)
查看服务器信息
cat /etc/os-release
# NAME="OpenCloudOS"
# VERSION="9.4"
# ID="opencloudos"
# ID_LIKE="opencloudos"
# VERSION_ID="9.4"
# PLATFORM_ID="platform:oc9"
# PRETTY_NAME="OpenCloudOS 9.4"
# ANSI_COLOR="0;31"
# CPE_NAME="cpe:/o:opencloudos:opencloudos:9"
# HOME_URL="https://www.opencloudos.org/"
# BUG_REPORT_URL="https://bugs.opencloudos.tech/"
uname -a
# Linux VM-4-6-opencloudos 6.6.114-43.oc9.x86_64 #1 SMP Fri Nov 7 15:35:09 CST 2025 x86_64 x86_64 x86_64 GNU/Linux
arch
# x86_64
更新系统、安装必要工具
# 更新系统
sudo dnf update -y
# 安装编译工具和依赖
sudo dnf install -y git zsh curl wget gcc make ncurses-devel
终端美化(Zsh + Oh My Zsh)
# 验证 zsh 是否可用
which zsh
# /usr/bin/zsh
官方脚本和国内镜像二选一。官方脚本会克隆仓库并生成 ~/.zshrc;走 Gitee 时要自己拷模板。
# 方案一:官方脚本
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
# 方案二:国内镜像(访问 GitHub 困难时)
git clone https://gitee.com/mirrors/oh-my-zsh.git ~/.oh-my-zsh
cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc
# 切换当前用户的默认 shell
chsh -s $(which zsh)
# 重新登录或启动新终端,验证安装是否成功
echo $SHELL
安装 Java 环境(Java 17)
Spring Boot 3 最低 Java 17;Boot 4 同样要求 17 及以上。生产用 17 或 21(LTS)都可以。
# OpenCloudOS 9 默认使用 dnf
sudo dnf install -y java-17-openjdk-devel
# 验证安装
java -version
安装 MySQL
OpenCloudOS 9 的 AppStream 里通常是 mysql-server,服务名是 mysqld。若 dnf 提示冲突或装到的是 MariaDB,先确认服务名(mysqld 或 mariadb),或改用 MySQL 官方仓库的 mysql-community-server。
# 安装 MySQL 服务器
sudo dnf install -y mysql-server mysql
# 启动 MySQL
sudo systemctl start mysqld
sudo systemctl enable mysqld
# 查看服务状态
sudo systemctl status mysqld
# 查看 MySQL 监听的端口和地址(OpenCloudOS 9 默认没有 netstat,用 ss)
sudo ss -tlnp | grep -E 'mysql|3306'
# MySQL 安装后需要设置 root 密码
sudo mysql_secure_installation
# 按照提示:
# - 输入当前 root 密码(首次安装密码为空,直接回车;官方仓库安装则先看 /var/log/mysqld.log 里的临时密码)
# - 设置密码强度验证策略(建议选 0 或 1)
# - 设置新的 root 密码
# - 删除匿名用户(选 Y)
# - 禁止远程 root 登录(选 Y)
# - 删除测试数据库(选 Y)
# - 重新加载权限表(选 Y)
# 使用密码登录
sudo mysql -u root -p
-- 查看当前用户
SELECT USER(), CURRENT_USER();
-- 创建数据库
CREATE DATABASE IF NOT EXISTS springboot_app DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 创建用户
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';
-- 授予权限
GRANT ALL PRIVILEGES ON springboot_app.* TO 'app_user'@'localhost';
-- 刷新权限
FLUSH PRIVILEGES;
-- 查看创建结果
SELECT user, host FROM mysql.user WHERE user = 'app_user';
SHOW GRANTS FOR 'app_user'@'localhost';
MySQL 8 默认认证插件是 caching_sha2_password。Spring Boot 使用的 MySQL Connector/J 8.0.9 及以上已经支持,不必再改成已过时的 mysql_native_password(MySQL 8.4 起该插件已弃用)。只有极老的客户端连不上时才需要改插件。
-- 仅当旧客户端不支持 caching_sha2_password 时才执行
ALTER USER 'app_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'StrongPassword123!';
FLUSH PRIVILEGES;
SELECT user, host, plugin FROM mysql.user WHERE user = 'app_user';
# 新开一个终端窗口,使用新创建的用户登录
mysql -u app_user -p springboot_app
# 在轻量应用服务器,上传 myapp.sql 到 /opt/myapp/ 目录,然后导入数据
mysql -u app_user -p springboot_app < /opt/myapp/myapp.sql
安装 Nginx
# 安装 nginx
sudo dnf install -y nginx
安装后,Nginx 的配置文件位于 /etc/nginx/,主配置文件为 /etc/nginx/nginx.conf。OpenCloudOS、RHEL 系站点配置放在 /etc/nginx/conf.d/(sites-enabled 是 Debian 布局,目录不存在时不要照搬)。把下面这段存成 /etc/nginx/conf.d/app.conf 之类的文件。这是静态站点(8443),和后面 Spring Boot 监听的 443 是两套 HTTPS,不要混成同一份配置。
server {
listen 8443 ssl;
listen [::]:8443 ssl;
server_name app.izhao.com.cn; # 域名已解析再填,如 www.yourdomain.com
ssl_certificate /opt/yizhao/ssl/app.izhao.com.cn_bundle.crt;
ssl_certificate_key /opt/yizhao/ssl/app.izhao.com.cn.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
root /opt/yizhao/www;
index index.html index.htm;
location / {
try_files $uri $uri/ /index.html;
}
}
# 测试配置是否成功(改过 conf.d 后要测)
sudo nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo systemctl status nginx
sudo systemctl start nginx
sudo systemctl reload nginx
sudo systemctl restart nginx
sudo systemctl enable nginx
防火墙配置
轻量应用服务器有两层过滤:控制台「防火墙」(安全组)和机器上的 firewalld。只开其中一层,另一层仍会拦。数据库只给本机 Java 用时,不要对公网开放 3306。
# 安装 firewalld
sudo dnf install -y firewalld
# 启动并启用
sudo systemctl start firewalld
sudo systemctl enable firewalld
# 检查状态
sudo systemctl status firewalld
# 开放端口(22、80、443、8443 按实际对外服务开;8080、9443 仅在确实对公网提供时再开)
sudo firewall-cmd --permanent --add-port=22/tcp
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --permanent --add-port=8443/tcp
sudo firewall-cmd --permanent --add-port=9443/tcp
# 数据库只给本机用时不要对公网开放 3306
sudo firewall-cmd --permanent --add-port=3306/tcp
sudo firewall-cmd --reload
# 查看开放端口
sudo firewall-cmd --list-all
sudo firewall-cmd --list-ports
sudo firewall-cmd --list-services
部署前准备
生产环境配置
创建一个生产环境的配置文件:src/main/resources/application-prod.properties(不要提交到 Git),将同目录下的 application.properties 文件的内容复制过来,然后修改:server.ssl.key-store-password、spring.datasource.url、username、password 等属性。
Spring Boot 2.4 起,--spring.config.location 会替换默认搜索路径(jar 内的 application.properties 不再自动加载)。只靠这一份外置文件时,把需要的项都写进去;若要叠加,改用 --spring.config.additional-location。
Hibernate 6(Spring Boot 3+)用 MySQLDialect,不要再写已移除的 MySQL8Dialect。本机 MySQL 走 TCP 时 useSSL=false 更常见;若开启 SSL,再改回 true。
spring.application.name=uni-spring-boot
# 证书配置
server.address=0.0.0.0
server.port=443
server.ssl.enabled=true
server.ssl.key-store=/opt/myapp/keystore.p12
server.ssl.key-alias=tomcat
server.ssl.key-password=123456
server.ssl.key-store-password=123456
server.ssl.key-store-type=PKCS12
server.tomcat.connection-timeout=30s
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/[myDatabase]?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
spring.datasource.username=[username]
spring.datasource.password=[password]
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA/Hibernate 配置
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
security.public-paths=/api/login/**,/api/hello/**,/api/public/**,/api/test/**
spring.web.resources.add-mappings=false
本地打包
在项目根目录执行:
# 在 IntelliJ IDEA
# 方案一:使用 Maven 面板,双击 clean(清理)、package(打包)
# 方案二:打开底部 Terminal 标签,执行:
mvn clean package -DskipTests
# 打包成功后,在 target/ 目录下,查看生成的 JAR 包
ls -lh target/*.jar
# 本地测试(可选)
java -jar target/你的应用名.jar
java -jar target/你的应用名.jar --spring.profiles.active=prod
java -jar target/你的应用名.jar --spring.config.location=file:./application-prod.properties
运行应用
准备上传文件清单
在项目根目录创建部署文件夹:deploy/server。
deploy/
├── server/
│ ├── 你的应用名.jar
│ ├── application-prod.properties # 生产配置
│ ├── keystore.p12 或 keystore.jks # HTTPS 证书
│ ├── start.sh # 启动脚本
│ ├── stop.sh # 停止脚本
│ ├── restart.sh # 重启脚本
│ └── myapp.service # systemd 单元(必须是 .service 后缀)
start.sh
绑定 443 需要 root 或 CAP_NET_BIND_SERVICE。脚本里不要使用未定义的 $sudo_cmd。
#!/bin/bash
APP_NAME="uni-spring-boot-0.0.1-SNAPSHOT.jar"
APP_PORT="443"
JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC -Dspring.profiles.active=prod -Dserver.port=$APP_PORT"
LOG_FILE="/opt/myapp/logs/app.log"
PID_FILE="/opt/myapp/app.pid"
KEYSTORE_FILE="/opt/myapp/keystore.p12"
echo "========================================"
echo "🔐 启动 Spring Boot HTTPS 应用"
echo "应用: $APP_NAME"
echo "端口: $APP_PORT (HTTPS)"
echo "时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "========================================"
# 检查是否已运行
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if ps -p $PID > /dev/null 2>&1; then
echo "⚠️ 应用已在运行,PID: $PID"
exit 1
fi
fi
# 检查证书文件
if [ ! -f "$KEYSTORE_FILE" ]; then
echo "❌ 错误: 未找到证书文件 $KEYSTORE_FILE"
exit 1
fi
echo "✅ 证书文件存在: $(ls -lh "$KEYSTORE_FILE")"
# 创建日志目录
mkdir -p /opt/myapp/logs
# 备份旧日志
if [ -f "$LOG_FILE" ]; then
mv "$LOG_FILE" "${LOG_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
fi
echo "🚀 启动应用..."
cd /opt/myapp
# 启动命令
nohup java $JAVA_OPTS -jar $APP_NAME > "$LOG_FILE" 2>&1 &
# 等待并获取进程 ID
sleep 3
APP_PID=$(ps -ef | grep "$APP_NAME" | grep -v grep | awk '{print $2}')
if [ -n "$APP_PID" ]; then
echo $APP_PID > "$PID_FILE"
echo ""
echo "✅ 启动成功!"
echo " PID: $APP_PID"
echo " 端口: https://服务器IP:$APP_PORT"
echo " 日志: $LOG_FILE"
echo ""
echo "📋 常用命令:"
echo " 查看日志: tail -f $LOG_FILE"
echo " 实时日志: tail -100f $LOG_FILE"
echo " 停止应用: ./stop.sh"
echo " 重启应用: ./restart.sh"
echo " 检查状态: ps -ef | grep $APP_NAME"
else
echo "❌ 启动失败!"
echo "查看错误日志:"
tail -30 "$LOG_FILE"
exit 1
fi
chmod +x start.sh
./start.sh
stop.sh
#!/bin/bash
APP_NAME="uni-spring-boot-0.0.1-SNAPSHOT.jar"
PID_FILE="/opt/myapp/app.pid"
echo "停止 Spring Boot 应用..."
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
echo "找到进程 PID: $PID"
# 优雅停止
kill -15 $PID 2>/dev/null
sleep 3
# 检查是否停止
if ps -p $PID > /dev/null 2>&1; then
echo "强制停止..."
kill -9 $PID 2>/dev/null
fi
rm -f "$PID_FILE"
echo "✅ 应用已停止"
else
echo "⚠️ 未找到 PID 文件,尝试通过名称停止..."
PIDS=$(ps -ef | grep "$APP_NAME" | grep -v grep | awk '{print $2}')
if [ -z "$PIDS" ]; then
echo "应用未运行"
else
echo "停止进程: $PIDS"
kill -15 $PIDS 2>/dev/null
sleep 2
kill -9 $PIDS 2>/dev/null
echo "✅ 应用已停止"
fi
fi
chmod +x stop.sh
./stop.sh
restart.sh
#!/bin/bash
echo "重启应用..."
echo ""
./stop.sh
sleep 2
./start.sh
myapp.service
systemd 不会像 shell 那样拆开 JAVA_OPTS 里的空格,写在 ExecStart 里会变成一个参数。JVM 参数放到 JAVA_TOOL_OPTIONS,由 Java 自己读取。单元文件必须是 /etc/systemd/system/xxx.service。
若 MySQL 实际服务名是 mariadb.service,把下面的 mysqld.service 改掉。User=root 才能直接绑 443;若改成普通用户,需要保留 AmbientCapabilities=CAP_NET_BIND_SERVICE。
[Unit]
Description=Uni Spring Boot HTTPS Application
After=network.target mysqld.service
Wants=mysqld.service
Requires=mysqld.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/myapp
Environment="JAVA_TOOL_OPTIONS=-Xms512m -Xmx1024m -XX:+UseG1GC"
ExecStart=/usr/bin/java -jar /opt/myapp/uni-spring-boot-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod --spring.config.location=file:/opt/myapp/application-prod.properties
ExecStop=/bin/kill -15 $MAINPID
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SuccessExitStatus=143
# 安全配置
PrivateTmp=true
ProtectSystem=full
ReadWritePaths=/opt/myapp/logs
# 非 root 用户绑 443 时需要
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
ls -la deploy/server/
注意: 在腾讯云轻量应用服务器,通过 systemd 来管理应用,myapp.service 里已经定义了:ExecStart(启动)、ExecStop(停止)、Restart=always(崩溃后自动重启),start.sh、stop.sh、restart.sh 从功能上已经不再是必需的。这三个脚本可以用于:手动调试或在不通过 systemd 的情况下临时启动 JAR、本地测试服务器上用。
上传文件到服务器
把 myapp.service 上传到 /etc/systemd/system/myapp.service(文件名必须以 .service 结尾),其余文件放到 /opt/myapp/,并在该目录下创建 logs。
systemd 服务管理命令
sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl stop myapp
sudo systemctl restart myapp
sudo systemctl status myapp
# 查看详细日志
sudo journalctl -u myapp -f # 实时日志
sudo journalctl -u myapp --since "10 minutes ago"
sudo journalctl -u myapp -n 100 # 最近 100 行
# 启用、禁用开机启动
sudo systemctl enable myapp
sudo systemctl disable myapp
# 重新加载服务配置(修改 .service 文件后)
sudo systemctl daemon-reload
sudo systemctl restart myapp
测试 HTTPS
# 检查端口监听
sudo ss -tulpn | grep :443
# 在服务器内部测试
curl -k https://localhost:443
curl -k https://localhost:443/api/hello/welcome
# 从外部测试
# 获取服务器公网 IP
curl -s ifconfig.me
# 然后用浏览器或另一台电脑访问
# https://你的服务器公网IP:443
域名、证书
域名解析
先购买域名,然后在 DNS 服务商处配置解析,然后查看:
# 在服务器上测试
nslookup mydomain.com
ping mydomain.com
curl -I http://mydomain.com
curl -I https://mydomain.com
SSL 证书申请
在腾讯云「SSL 证书」页面申请免费证书,下载时选 Nginx(适用大部分场景)(pem 文件、crt 文件、key 文件)。
下载解压后,通常会得到以下文件:
mydomain.csrmydomain.keymydomain_bundle.crtmydomain_bundle.pem
上传证书到服务器:/etc/ssl/myapp。打 PKCS12 时用带完整链的 mydomain_bundle.crt(或 .pem),不要只用缺中间证书的单张 mydomain.crt。
# 将证书和私钥转换为 PKCS12 格式
sudo openssl pkcs12 -export \
-in mydomain_bundle.crt \
-inkey mydomain.key \
-out keystore.p12 \
-name "tomcat" \
-CAfile mydomain_bundle.crt \
-caname "root" \
-password pass:123456
# 复制证书
sudo cp keystore.p12 /opt/myapp/
# 修改 application-prod.properties
server.ssl.key-store=/opt/myapp/keystore.p12
server.ssl.key-alias=tomcat
server.ssl.key-password=123456
server.ssl.key-store-password=123456
server.ssl.key-store-type=PKCS12
# 重启应用(服务名与上面的 myapp.service 一致)
sudo systemctl restart myapp
sudo systemctl status myapp
# 验证
curl -k https://localhost:443
curl -k https://localhost:443/api/hello/welcome