Spring Boot云原生安全部署实战指南

前言

在云原生时代,如何安全、高效地部署Spring Boot应用是每个开发者都需要掌握的核心技能。本文将详细介绍一套生产级的安全部署方案,通过服务器分离、端口隔离、反向代理、CDN加速等技术手段,构建一个既安全又高性能的部署架构。

读完本文,你将掌握:

  • 如何设计安全的服务器架构
  • 如何使用Nginx实现反向代理和端口隔离
  • 如何配置CDN实现IP隐藏和加速
  • 如何配置SSL证书实现HTTPS访问
  • 如何保障数据库和缓存的访问安全

一、整体架构设计

1.1 架构概览

在生产环境中,我们推荐采用服务分离的架构设计,将应用服务器和数据服务器分开部署,这样做有以下优势:

  • 安全性提升:数据库不对外暴露,只允许应用服务器访问
  • 性能优化:应用和数据库分别使用独立的计算资源,互不影响
  • 扩展性强:应用服务器可以水平扩展,数据服务器可以独立升级
  • 故障隔离:某个服务器出现问题不会影响整个系统

1.2 服务器规划

应用服务器(Server A):

  • 部署Spring Boot应用
  • 部署Nginx反向代理
  • 开放端口:80、443
  • 关闭端口:9001(应用端口)

数据服务器(Server B):

  • 部署MySQL数据库
  • 部署Redis缓存
  • 配置防火墙只允许Server A的IP访问
  • 不对外开放任何端口

1.3 网络拓扑图

1
2
3
4
5
6
7
8
9
10
11
用户请求
↓
CDN节点(隐藏真实IP)
↓
域名解析(CNAME指向CDN)
↓
Nginx(Server A:80/443)
↓
Spring Boot应用(Server A:9001,内网访问)
↓
MySQL/Redis(Server B,仅允许Server A访问)

二、服务器环境准备

2.1 系统要求

  • 操作系统:CentOS 7/8、Ubuntu 20.04+ 或 Debian 10+
  • JDK版本:OpenJDK 11 或 17(推荐)
  • Nginx版本:1.18+
  • MySQL版本:8.0+
  • Redis版本:6.0+

应用服务器环境安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 更新系统
sudo yum update -y # CentOS/RHEL
# 或
sudo apt update && sudo apt upgrade -y # Ubuntu/Debian

# 安装OpenJDK 17
sudo yum install java-17-openjdk java-17-openjdk-devel -y
# 或
sudo apt install openjdk-17-jdk -y

# 验证Java安装
java -version

# 安装Nginx
sudo yum install nginx -y
# 或
sudo apt install nginx -y

# 启动Nginx并设置开机自启
sudo systemctl start nginx
sudo systemctl enable nginx

# 安装其他必要工具
sudo yum install wget curl vim git -y

2.3 数据服务器环境安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 安装MySQL 8.0
# CentOS/RHEL
sudo yum install mysql-server -y
sudo systemctl start mysqld
sudo systemctl enable mysqld

# Ubuntu/Debian
sudo apt install mysql-server -y
sudo systemctl start mysql
sudo systemctl enable mysql

# 安全配置MySQL
sudo mysql_secure_installation

# 安装Redis
# CentOS/RHEL
sudo yum install redis -y

# Ubuntu/Debian
sudo apt install redis-server -y

# 启动Redis
sudo systemctl start redis
sudo systemctl enable redis

三、Spring Boot应用部署

3.1 构建应用

在本地开发环境打包Spring Boot应用:

1
2
3
4
5
# 使用Maven打包
mvn clean package -DskipTests

# 或使用Gradle打包
./gradlew build -x test

打包完成后,会在target目录下生成your-app.jar文件。

3.2 配置application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
server:
port: 9001
# 只监听本地回环地址,不对外暴露
address: 127.0.0.1

spring:
application:
name: your-app

# 数据库配置(连接到数据服务器)
datasource:
url: jdbc:mysql://<数据服务器IP>:3306/your_database?useSSL=true&serverTimezone=Asia/Shanghai
username: your_username
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000

# Redis配置(连接到数据服务器)
redis:
host: <数据服务器IP>
port: 6379
password: your_redis_password
database: 0
timeout: 3000
lettuce:
pool:
max-active: 20
max-idle: 10
min-idle: 5

# 日志配置
logging:
level:
root: INFO
com.yourpackage: DEBUG
file:
name: /var/log/your-app/application.log
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

3.3 上传并部署应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 在应用服务器上创建应用目录
sudo mkdir -p /opt/your-app
sudo mkdir -p /var/log/your-app

# 使用scp上传jar包
scp target/your-app.jar user@<应用服务器IP>:/opt/your-app/

# SSH登录到应用服务器
ssh user@<应用服务器IP>

# 创建启动脚本
cat > /opt/your-app/start.sh << 'EOF'
#!/bin/bash
APP_NAME="your-app"
APP_JAR="/opt/your-app/your-app.jar"
PID_FILE="/var/run/${APP_NAME}.pid"

# JVM参数配置
JVM_OPTS="-Xms512m -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200"

# 启动应用
nohup java $JVM_OPTS -jar $APP_JAR > /var/log/your-app/console.log 2>&1 &
echo $! > $PID_FILE
echo "应用已启动,PID: $(cat $PID_FILE)"
EOF

# 创建停止脚本
cat > /opt/your-app/stop.sh << 'EOF'
#!/bin/bash
PID_FILE="/var/run/your-app.pid"

if [ -f $PID_FILE ]; then
PID=$(cat $PID_FILE)
kill -15 $PID
echo "正在停止应用,PID: $PID"

# 等待应用优雅关闭
for i in {1..30}; do
if ! ps -p $PID > /dev/null; then
echo "应用已停止"
rm -f $PID_FILE
exit 0
fi
sleep 1
done

# 强制停止
kill -9 $PID
rm -f $PID_FILE
echo "应用已强制停止"
else
echo "PID文件不存在,应用可能未运行"
fi
EOF

# 赋予执行权限
chmod +x /opt/your-app/start.sh
chmod +x /opt/your-app/stop.sh

# 启动应用
/opt/your-app/start.sh

3.4 配置systemd服务(推荐)

为了更好地管理应用,建议配置为systemd服务:

1
2
# 创建systemd服务文件
sudo vim /etc/systemd/system/your-app.service

填入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[Unit]
Description=Your Spring Boot Application
After=syslog.target network.target

[Service]
Type=simple
User=root
WorkingDirectory=/opt/your-app
ExecStart=/usr/bin/java -Xms512m -Xmx2g -XX:+UseG1GC -jar /opt/your-app/your-app.jar
ExecStop=/bin/kill -15 $MAINPID
SuccessExitStatus=143
Restart=on-failure
RestartSec=10

StandardOutput=journal
StandardError=journal
SyslogIdentifier=your-app

[Install]
WantedBy=multi-user.target

启动服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 重新加载systemd配置
sudo systemctl daemon-reload

# 启动应用
sudo systemctl start your-app

# 设置开机自启
sudo systemctl enable your-app

# 查看状态
sudo systemctl status your-app

# 查看日志
sudo journalctl -u your-app -f

3.5 验证应用运行

在应用服务器内部测试:

1
2
3
4
5
6
7
8
9
10
11
12
# 检查端口监听(应该只监听127.0.0.1)
netstat -tlnp | grep 9001
# 输出示例:tcp 0 0 127.0.0.1:9001 0.0.0.0:* LISTEN 12345/java

# 测试API接口(内网访问)
curl http://127.0.0.1:9001/api/health
# 应该返回正常响应

# 从外网测试(应该无法访问)
# 在本地电脑执行
curl http://<应用服务器公网IP>:9001/api/health
# 应该返回连接超时或拒绝

此时,应用已经在服务器内部正常运行,但外网无法直接访问,这正是我们期望的安全状态。


四、Nginx反向代理配置

4.1 Nginx配置原理

Nginx作为反向代理服务器,可以:

  • 对外开放80和443端口
  • 接收外部请求
  • 将请求转发到内网的127.0.0.1:9001
  • 隐藏应用端口,提升安全性
  • 提供负载均衡、限流、缓存等功能

4.2 基础配置

1
2
3
4
5
# 备份原有配置
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak

# 创建站点配置文件
sudo vim /etc/nginx/conf.d/your-app.conf

填入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# 上游服务器配置
upstream backend {
server 127.0.0.1:9001 max_fails=3 fail_timeout=30s;
keepalive 32;
}

# HTTP服务器配置(用于重定向到HTTPS)
server {
listen 80;
server_name your-domain.com www.your-domain.com;

# 访问日志
access_log /var/log/nginx/your-app-access.log;
error_log /var/log/nginx/your-app-error.log;

# 重定向到HTTPS
return 301 https://$server_name$request_uri;
}

# HTTPS服务器配置(后续配置SSL证书后启用)
server {
listen 443 ssl http2;
server_name your-domain.com www.your-domain.com;

# SSL证书配置(先注释,后续配置)
# ssl_certificate /etc/nginx/ssl/your-domain.crt;
# ssl_certificate_key /etc/nginx/ssl/your-domain.key;

# SSL安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

# 日志配置
access_log /var/log/nginx/your-app-ssl-access.log;
error_log /var/log/nginx/your-app-ssl-error.log;

# 客户端请求限制
client_max_body_size 100M;
client_body_timeout 60s;
client_header_timeout 60s;

# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/rss+xml font/truetype font/opentype
application/vnd.ms-fontobject image/svg+xml;

# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
proxy_pass http://backend;
proxy_cache_valid 200 7d;
proxy_cache_valid 404 1m;
expires 7d;
add_header Cache-Control "public, immutable";
}

# API接口代理
location /api/ {
proxy_pass http://backend;

# 代理请求头
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# WebSocket支持(如需要)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# 超时配置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;

# 缓冲区配置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 8k;

# 错误处理
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
}

# 根路径代理
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

# 健康检查端点
location /nginx-health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}

4.3 防火墙配置

1
2
3
4
5
6
7
8
9
10
11
12
13
# CentOS/RHEL使用firewalld
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

# Ubuntu/Debian使用ufw
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload

# 确认9001端口未开放
sudo firewall-cmd --list-ports # CentOS
sudo ufw status # Ubuntu

4.4 启动Nginx

1
2
3
4
5
6
7
8
9
10
11
# 检查配置语法
sudo nginx -t

# 如果配置正确,重启Nginx
sudo systemctl restart nginx

# 查看Nginx状态
sudo systemctl status nginx

# 查看错误日志
sudo tail -f /var/log/nginx/error.log

4.5 验证反向代理

此时,虽然还没有配置域名和SSL,但可以通过服务器IP测试:

1
2
3
4
5
# 从外网访问HTTP(应该能访问)
curl http://<应用服务器公网IP>/api/health

# 直接访问9001端口(应该无法访问)
curl http://<应用服务器公网IP>:9001/api/health

五、域名解析配置

5.1 购买域名

在域名注册商(如阿里云、腾讯云、GoDaddy等)购买域名,例如:your-domain.com

5.2 初始DNS解析(临时)

在域名管理控制台添加A记录:

记录类型 主机记录 记录值 TTL
A @ <应用服务器公网IP> 600
A www <应用服务器公网IP> 600

说明:

  • @ 代表根域名(your-domain.com)
  • www 代表子域名(www.your-domain.com)
  • TTL设置为600秒(10分钟),方便后续修改

5.3 验证域名解析

1
2
3
4
5
6
7
8
9
10
11
# 等待DNS解析生效(通常5-10分钟)
# 使用dig或nslookup验证
dig your-domain.com +short
# 应该返回应用服务器的公网IP

nslookup your-domain.com
# 应该返回应用服务器的公网IP

# 测试HTTP访问
curl http://your-domain.com/api/health
# 应该返回正常响应

六、CDN配置与IP隐藏

6.1 CDN的作用

使用CDN可以实现:

  • 隐藏源站IP:防止DDoS攻击直接打到源站
  • 加速访问:全球节点就近访问
  • 流量清洗:过滤恶意请求
  • SSL卸载:在CDN层面处理HTTPS

6.2 阿里云CDN配置

6.2.1 开通CDN服务

  1. 登录阿里云控制台
  2. 搜索”CDN”,开通服务
  3. 点击”添加域名”

6.2.2 配置加速域名

配置项 值
加速域名 your-domain.com
业务类型 全站加速
源站类型 IP
源站地址 <应用服务器公网IP>
端口 80 和 443

6.2.3 获取CNAME地址

配置完成后,阿里云会分配一个CNAME地址,例如:

1
your-domain.com.cdn.aliyuncs.com

6.2.4 回源配置

在CDN控制台 → 域名管理 → 回源配置:

1
2
3
回源协议: 协议跟随
回源Host: your-domain.com
回源超时: 30秒

6.3 腾讯云CDN配置

6.3.1 开通CDN服务

  1. 登录腾讯云控制台
  2. 搜索”内容分发网络 CDN”
  3. 点击”添加域名”

6.3.2 配置加速域名

1
2
3
4
5
6
7
8
域名: your-domain.com
所属项目: 默认项目
加速区域: 中国境内
业务类型: CDN网页小文件
源站配置:
源站类型: 自有源
源站地址: <应用服务器公网IP>
回源协议: HTTP

6.3.3 获取CNAME地址

配置完成后,腾讯云会分配CNAME地址,例如:

1
your-domain.com.cdn.dnsv1.com

6.4 修改DNS解析为CNAME

回到域名管理控制台,修改DNS记录:

记录类型 主机记录 记录值 TTL
CNAME @ your-domain.com.cdn.aliyuncs.com 600
CNAME www your-domain.com.cdn.aliyuncs.com 600

重要:删除之前的A记录,改为CNAME记录。

6.5 CDN高级配置

6.5.1 缓存配置

在CDN控制台配置缓存规则:

1
2
3
4
5
6
7
# 静态资源缓存
文件类型: jpg,jpeg,png,gif,ico,css,js,woff,woff2,ttf,svg
缓存时间: 7天

# 动态内容不缓存
路径: /api/*
缓存时间: 不缓存

6.5.2 访问控制

1
2
3
4
5
6
7
8
# IP黑白名单
类型: 黑名单
IP列表: [恶意IP列表]

# Referer防盗链
类型: 白名单
允许域名: your-domain.com, www.your-domain.com
允许空Referer: 是

6.5.3 性能优化

1
2
3
4
5
6
7
8
9
# 开启压缩
Gzip压缩: 开启
Brotli压缩: 开启

# 开启HTTP/2
HTTP/2: 开启

# 智能压缩
智能压缩: 开启

6.6 验证IP隐藏

1
2
3
4
5
6
7
8
9
# Ping域名,应该返回CDN节点IP,而非源站IP
ping your-domain.com
# 输出示例:
# PING your-domain.com.cdn.aliyuncs.com (120.55.xxx.xxx)
# 这是CDN节点IP,不是你的应用服务器IP

# 使用在线工具验证
# 访问 https://www.ipip.net/ip.html
# 输入域名查询,应该显示CDN节点信息

七、SSL证书配置

7.1 申请免费SSL证书

7.1.1 阿里云SSL证书

  1. 登录阿里云控制台
  2. 搜索”SSL证书”
  3. 选择”免费证书” → “立即购买”
  4. 填写域名:your-domain.com 和 www.your-domain.com
  5. 验证方式选择”DNS验证”
  6. 添加DNS TXT记录完成验证
  7. 下载证书(选择Nginx格式)

7.1.2 腾讯云SSL证书

  1. 登录腾讯云控制台
  2. 搜索”SSL证书”
  3. 申请免费证书
  4. 填写域名信息
  5. DNS验证
  6. 下载证书(Nginx格式)

7.1.3 Let’s Encrypt免费证书

1
2
3
4
5
6
7
8
9
10
11
12
# 安装certbot
sudo yum install certbot python3-certbot-nginx -y
# 或
sudo apt install certbot python3-certbot-nginx -y

# 申请证书
sudo certbot --nginx -d your-domain.com -d www.your-domain.com

# 自动续期(Let's Encrypt证书有效期90天)
sudo crontab -e
# 添加以下行(每天检查并自动续期)
0 3 * * * /usr/bin/certbot renew --quiet

7.2 在CDN配置SSL证书

7.2.1 阿里云CDN SSL配置

  1. CDN控制台 → 域名管理 → HTTPS配置
  2. 点击”修改配置”
  3. 上传证书:
    • 证书名称:your-domain-2025
    • 证书内容:复制.crt或.pem文件内容
    • 私钥内容:复制.key文件内容
  4. 强制HTTPS跳转:开启
  5. HTTP/2:开启
  6. OCSP Stapling:开启

7.2.2 腾讯云CDN SSL配置

  1. CDN控制台 → 域名管理 → 高级配置 → HTTPS配置
  2. 证书来源:自有证书
  3. 上传证书和私钥
  4. 强制HTTPS:开启
  5. HTTP/2.0:开启

7.3 Nginx SSL配置(作为后备)

如果不使用CDN的SSL,也可以在Nginx层配置:

1
2
3
4
5
6
7
8
# 上传证书到服务器
sudo mkdir -p /etc/nginx/ssl
sudo scp your-domain.crt user@<应用服务器IP>:/etc/nginx/ssl/
sudo scp your-domain.key user@<应用服务器IP>:/etc/nginx/ssl/

# 修改证书权限
sudo chmod 600 /etc/nginx/ssl/your-domain.key
sudo chmod 644 /etc/nginx/ssl/your-domain.crt

修改Nginx配置,取消SSL相关注释:

1
2
3
4
5
6
7
8
9
10
server {
listen 443 ssl http2;
server_name your-domain.com www.your-domain.com;

# 启用SSL证书
ssl_certificate /etc/nginx/ssl/your-domain.crt;
ssl_certificate_key /etc/nginx/ssl/your-domain.key;

# 其他配置保持不变...
}

重启Nginx:

1
2
sudo nginx -t
sudo systemctl reload nginx

7.4 验证HTTPS访问

1
2
3
4
5
6
7
8
9
# 访问HTTPS接口
curl https://your-domain.com/api/health

# 检查SSL证书
openssl s_client -connect your-domain.com:443 -servername your-domain.com

# 使用在线工具检查SSL评级
# 访问 https://www.ssllabs.com/ssltest/
# 输入域名检查,目标评级:A或A+

八、数据库和Redis安全配置

8.1 MySQL安全配置

8.1.1 修改绑定地址

编辑MySQL配置文件:

1
2
3
4
5
# CentOS/RHEL
sudo vim /etc/my.cnf

# Ubuntu/Debian
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf

修改配置:

1
2
3
4
5
6
7
8
9
10
[mysqld]
# 绑定到内网IP或所有地址
bind-address = 0.0.0.0

# 或只绑定内网IP
# bind-address = <数据服务器内网IP>

# 其他安全配置
max_connections = 200
max_connect_errors = 10

重启MySQL:

1
2
sudo systemctl restart mysqld  # CentOS
sudo systemctl restart mysql # Ubuntu

8.1.2 创建远程访问用户

1
2
# 登录MySQL
sudo mysql -u root -p
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 创建专用用户(只允许应用服务器IP访问)
CREATE USER 'your_user'@'<应用服务器IP>' IDENTIFIED BY 'strong_password_here';

-- 授予权限
GRANT ALL PRIVILEGES ON your_database.* TO 'your_user'@'<应用服务器IP>';

-- 刷新权限
FLUSH PRIVILEGES;

-- 验证用户
SELECT User, Host FROM mysql.user WHERE User = 'your_user';

-- 退出
EXIT;

8.1.3 防火墙配置

1
2
3
4
5
6
7
8
# 只允许应用服务器IP访问MySQL
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="<应用服务器IP>" port protocol="tcp" port="3306" accept'
sudo firewall-cmd --reload

# 或使用iptables
sudo iptables -A INPUT -p tcp -s <应用服务器IP> --dport 3306 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 3306 -j DROP
sudo iptables-save > /etc/sysconfig/iptables

8.2 Redis安全配置

8.2.1 修改Redis配置

编辑Redis配置文件:

1
2
3
sudo vim /etc/redis/redis.conf
# 或
sudo vim /etc/redis.conf

修改以下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 绑定地址(允许远程访问)
bind 0.0.0.0
# 或只绑定内网IP
# bind <数据服务器内网IP>

# 保护模式(建议关闭,因为已有防火墙保护)
protected-mode no

# 设置强密码
requirepass your_strong_redis_password_here

# 禁用危险命令
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG "CONFIG_SAFE_COMMAND"
rename-command SHUTDOWN "SHUTDOWN_SAFE_COMMAND"

# 最大内存限制
maxmemory 1gb
maxmemory-policy allkeys-lru

# 持久化配置
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec

重启Redis:

1
sudo systemctl restart redis

8.2.2 防火墙配置

1
2
3
4
5
6
7
8
# 只允许应用服务器IP访问Redis
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="<应用服务器IP>" port protocol="tcp" port="6379" accept'
sudo firewall-cmd --reload

# 或使用iptables
sudo iptables -A INPUT -p tcp -s <应用服务器IP> --dport 6379 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 6379 -j DROP
sudo iptables-save > /etc/sysconfig/iptables

8.3 验证安全配置

8.3.1 从应用服务器测试连接

1
2
3
4
5
6
7
8
9
10
# SSH到应用服务器
ssh user@<应用服务器IP>

# 测试MySQL连接
mysql -h <数据服务器IP> -u your_user -p
# 应该能成功连接

# 测试Redis连接
redis-cli -h <数据服务器IP> -p 6379 -a your_redis_password
# 应该能成功连接

8.3.2 从其他IP测试(应该失败)

1
2
3
4
5
6
# 从本地电脑测试(应该拒绝连接)
mysql -h <数据服务器IP> -u your_user -p
# 应该返回:ERROR 2003 (HY000): Can't connect to MySQL server

redis-cli -h <数据服务器IP> -p 6379
# 应该返回:Could not connect to Redis

8.4 数据库备份策略

1
2
# 创建备份脚本
sudo vim /opt/backup/mysql-backup.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
BACKUP_DIR="/opt/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
MYSQL_USER="your_user"
MYSQL_PASS="your_password"
MYSQL_HOST="localhost"
DATABASE="your_database"

# 创建备份目录
mkdir -p $BACKUP_DIR

# 执行备份
mysqldump -h $MYSQL_HOST -u $MYSQL_USER -p$MYSQL_PASS \
--single-transaction --routines --triggers --events \
$DATABASE | gzip > $BACKUP_DIR/${DATABASE}_${DATE}.sql.gz

# 只保留最近7天的备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete

echo "备份完成: ${DATABASE}_${DATE}.sql.gz"
1
2
3
4
5
6
# 赋予执行权限
sudo chmod +x /opt/backup/mysql-backup.sh

# 添加定时任务(每天凌晨2点备份)
sudo crontab -e
0 2 * * * /opt/backup/mysql-backup.sh >> /var/log/mysql-backup.log 2>&1

九、监控与日志

9.1 应用日志监控

1
2
3
4
5
6
7
8
# 实时查看应用日志
sudo journalctl -u your-app -f

# 查看最近的错误日志
sudo journalctl -u your-app -p err -n 50

# 查看指定时间范围的日志
sudo journalctl -u your-app --since "2025-11-19 00:00:00" --until "2025-11-19 23:59:59"

9.2 Nginx访问日志分析

1
2
3
4
5
6
7
8
9
10
11
12
# 统计访问最多的IP
awk '{print $1}' /var/log/nginx/your-app-access.log | sort | uniq -c | sort -rn | head -20

# 统计访问最多的接口
awk '{print $7}' /var/log/nginx/your-app-access.log | sort | uniq -c | sort -rn | head -20

# 统计HTTP状态码分布
awk '{print $9}' /var/log/nginx/your-app-access.log | sort | uniq -c | sort -rn

# 统计响应时间(需配置$request_time)
awk '{print $NF}' /var/log/nginx/your-app-access.log | \
awk '{sum+=$1; count++} END {print "平均响应时间:", sum/count, "秒"}'

9.3 系统资源监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 安装监控工具
sudo yum install htop iotop nethogs -y

# 实时监控CPU和内存
htop

# 监控磁盘IO
sudo iotop

# 监控网络流量
sudo nethogs

# 查看系统负载
uptime

# 查看磁盘使用
df -h

# 查看内存使用
free -h

9.4 配置告警(可选)

使用阿里云/腾讯云的云监控服务配置告警:

  • CPU使用率 > 80%
  • 内存使用率 > 85%
  • 磁盘使用率 > 90%
  • 网络流量异常
  • 应用进程退出

十、性能优化建议

10.1 JVM性能调优

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 生产环境推荐的JVM参数
JAVA_OPTS="
-Xms2g -Xmx2g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/your-app/heapdump.hprof
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:/var/log/your-app/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=10M
"

10.2 数据库连接池优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spring:
datasource:
hikari:
# 最小空闲连接数
minimum-idle: 10
# 最大连接数
maximum-pool-size: 50
# 连接超时时间(毫秒)
connection-timeout: 30000
# 空闲连接存活最大时间(毫秒)
idle-timeout: 600000
# 连接的最长生命周期(毫秒)
max-lifetime: 1800000
# 连接测试查询
connection-test-query: SELECT 1

10.3 Redis连接池优化

1
2
3
4
5
6
7
8
9
10
11
12
13
spring:
redis:
lettuce:
pool:
# 最大活动连接数
max-active: 50
# 最大空闲连接数
max-idle: 20
# 最小空闲连接数
min-idle: 10
# 最大等待时间(毫秒)
max-wait: 3000
shutdown-timeout: 100ms

10.4 Nginx性能优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 在http块添加以下配置
http {
# 工作进程数(建议等于CPU核心数)
worker_processes auto;

# 单个工作进程最大连接数
events {
worker_connections 4096;
use epoll;
multi_accept on;
}

# 开启文件缓存
open_file_cache max=10000 inactive=60s;
open_file_cache_valid 120s;
open_file_cache_min_uses 2;
open_file_cache_errors on;

# 调整缓冲区大小
client_body_buffer_size 128k;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;

# 开启sendfile
sendfile on;
tcp_nopush on;
tcp_nodelay on;

# 调整超时时间
keepalive_timeout 65;
keepalive_requests 1000;
}

十一、安全加固清单

11.1 服务器安全

  • 禁用root远程登录
  • 配置SSH密钥认证
  • 修改SSH默认端口
  • 配置fail2ban防暴力破解
  • 定期更新系统补丁
  • 配置防火墙规则
  • 启用SELinux或AppArmor
1
2
3
4
5
6
7
8
# 禁用root远程登录
sudo vim /etc/ssh/sshd_config
# 修改:PermitRootLogin no

# 配置fail2ban
sudo yum install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

11.2 应用安全

  • 使用HTTPS加密传输
  • 实现JWT或OAuth2认证
  • 配置CORS策略
  • 实现请求限流和防重放
  • 敏感数据加密存储
  • 输入验证和SQL注入防护
  • 配置安全响应头
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Spring Security配置示例
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

// 配置安全响应头
http.headers()
.contentSecurityPolicy("default-src 'self'")
.and()
.xssProtection()
.and()
.frameOptions().deny();
}
}

11.3 数据安全

  • 定期备份数据库
  • 加密敏感字段
  • 配置数据库审计日志
  • 限制数据库访问IP
  • 使用强密码
  • 定期轮换密钥和证书

十二、故障排查指南

12.1 应用无法启动

1
2
3
4
5
6
7
8
9
10
11
# 检查日志
sudo journalctl -u your-app -n 100

# 检查端口占用
sudo netstat -tlnp | grep 9001

# 检查JVM内存
free -h

# 检查磁盘空间
df -h

12.2 数据库连接失败

1
2
3
4
5
6
7
8
9
# 测试网络连通性
ping <数据服务器IP>
telnet <数据服务器IP> 3306

# 检查防火墙规则
sudo firewall-cmd --list-all

# 检查MySQL日志
sudo tail -f /var/log/mysqld.log

12.3 Nginx 502/504错误

1
2
3
4
5
6
7
8
9
10
11
12
13
# 检查后端服务是否运行
curl http://127.0.0.1:9001/api/health

# 检查Nginx错误日志
sudo tail -f /var/log/nginx/error.log

# 检查Nginx配置
sudo nginx -t

# 增加超时时间
# 在nginx配置中添加:
proxy_read_timeout 300s;
proxy_connect_timeout 300s;

12.4 CDN缓存问题

1
2
3
4
5
6
# 刷新CDN缓存
# 在CDN控制台手动刷新或使用API

# 验证缓存命中
curl -I https://your-domain.com/api/test
# 查看响应头:X-Cache: HIT 或 MISS

十三、总结

通过本文的详细介绍,我们实现了一套完整的云原生安全部署方案:

13.1 架构优势

  1. 安全性:

    • 应用端口未对外暴露,只能通过Nginx访问
    • CDN隐藏了真实服务器IP
    • 数据库只允许应用服务器访问
    • 全链路HTTPS加密传输
  2. 性能:

    • CDN全球加速
    • Nginx反向代理和缓存
    • 数据库和应用分离,独立扩展
    • 优化的JVM和连接池配置
  3. 可维护性:

    • 清晰的架构分层
    • 完善的日志和监控
    • 自动化的备份和告警
    • 标准化的配置管理

13.2 最佳实践总结

  1. 服务分离:应用、数据库、缓存分别部署
  2. 最小暴露:只开放必要的端口(80、443)
  3. 纵深防御:防火墙 + CDN + Nginx多层防护
  4. 加密传输:全程HTTPS,保护数据安全
  5. 监控告警:实时监控系统状态,及时响应故障
  6. 定期备份:数据定期备份,防止数据丢失

13.3 扩展建议

随着业务增长,可以进一步优化:

  1. 水平扩展:增加应用服务器,通过Nginx负载均衡
  2. 高可用:部署主从数据库,实现故障自动切换
  3. 容器化:迁移到Docker/Kubernetes,实现自动伸缩
  4. 微服务化:拆分单体应用为微服务架构
  5. DevOps:引入CI/CD,实现自动化部署

附录:完整配置文件

A.1 application.yml完整配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
server:
port: 9001
address: 127.0.0.1
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,application/json,application/javascript
tomcat:
max-threads: 200
min-spare-threads: 20
max-connections: 10000
connection-timeout: 60000

spring:
application:
name: your-app

datasource:
url: jdbc:mysql://<数据服务器IP>:3306/your_database?useSSL=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8
username: your_user
password: ${DB_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
minimum-idle: 10
maximum-pool-size: 50
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
connection-test-query: SELECT 1

redis:
host: <数据服务器IP>
port: 6379
password: ${REDIS_PASSWORD}
database: 0
timeout: 3000ms
lettuce:
pool:
max-active: 50
max-idle: 20
min-idle: 10
max-wait: 3000ms

jpa:
hibernate:
ddl-auto: none
show-sql: false
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
format_sql: true

logging:
level:
root: INFO
com.yourpackage: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"
file:
name: /var/log/your-app/application.log
max-size: 100MB
max-history: 30

management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: when-authorized

A.2 Nginx完整配置

见第四章详细配置。

A.3 防火墙脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
# firewall-setup.sh

echo "配置应用服务器防火墙..."
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

echo "配置数据服务器防火墙..."
APP_SERVER_IP="<应用服务器IP>"

sudo firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='${APP_SERVER_IP}' port protocol='tcp' port='3306' accept"
sudo firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='${APP_SERVER_IP}' port protocol='tcp' port='6379' accept"
sudo firewall-cmd --reload

echo "防火墙配置完成!"

参考资源


通过以上配置,你已经拥有了一套完整的、生产级的、安全的云原生部署方案。祝你部署顺利!如有问题,欢迎交流讨论。