Files
nginxserver/docs/nginxLinux服务器迁移手册.md
2026-07-16 13:03:11 +08:00

537 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NginxLinux 服务器迁移手册
> **服务器**: 10.1.1.160 (linuxNginx)
> **系统**: Rocky Linux 8.10
> **更新日期**: 2026-06-12
> **用途**: Nginx 域名转发管理平台 — Python API + Nginx 反向代理
---
## 一、迁移概览
需要迁移以下内容到新服务器:
| 类别 | 内容 | 位置 |
|------|------|------|
| 目录 | Python API 项目 | `/opt/nginx-api/` |
| 目录 | SSL 证书 + 内部 CA | `/etc/nginx/ssl/` |
| 目录 | Nginx 转发配置 | `/etc/nginx/conf.d/` |
| 目录 | acme.sh | `/root/.acme.sh/` |
| 文件 | Nginx 主配置 | `/etc/nginx/nginx.conf` |
| 文件 | systemd 服务 | `/etc/systemd/system/nginx-api.service` |
| 文件 | 环境变量 | `/root/.bashrc` (Ali_Key / Ali_Secret) |
| 文件 | Gunicorn 配置 | `/opt/nginx-api/gunicorn_config.py` |
| 定时任务 | acme.sh 自动续期 cron | `crontab -l` |
---
## 二、新服务器环境要求
### 2.1 操作系统
- Rocky Linux 8.x / CentOS 8.x / RHEL 8.x或其他 systemd Linux 发行版)
- 最小磁盘: 20G当前使用 3.6G
- 内存: 2G+(当前 1.7G,用 ~350M
### 2.2 安装软件清单
```bash
# 1. Nginx (dnf 安装)
dnf install -y nginx
# 2. Python 3 (系统自带 ≥ 3.6)
# Rocky 8 自带 Python 3.6.8,无需额外安装
# 3. pip 包
pip3 install flask==2.0.3 gunicorn==21.2.0
# 注: Python 3.6 不支持 Flask 3.x实际安装 2.0.x
# 4. acme.sh (从 GitHub cloneget.acme.sh 可能被墙)
git clone https://github.com/acmesh-official/acme.sh.git /root/.acme.sh
cd /root/.acme.sh && ./acme.sh --install --home /root/.acme.sh
# 5. 设置默认 CA
/root/.acme.sh/acme.sh --set-default-ca --server letsencrypt
```
### 2.3 需要开放的网络
| 方向 | 端口/地址 | 用途 |
|------|-----------|------|
| 入站 | 22/tcp | SSH 管理 |
| 入站 | 80/tcp | HTTP 转发 |
| 入站 | 443/tcp | HTTPS 转发 |
| 入站 | 5000/tcp | Python API仅 Java 后端访问) |
| 出站 | alidns.aliyuncs.com:443 | 阿里云 DNS APIacme.sh + DNS 管理) |
| 出站 | letsencrypt.org:443 | Let's Encrypt 证书签发/续期 |
---
## 三、迁移步骤
### Step 0: 准备工作
在新服务器上执行:
```bash
# 创建目录结构
mkdir -p /etc/nginx/ssl/ca
mkdir -p /etc/nginx/conf.d
mkdir -p /opt/nginx-api/services
# 创建 nginx-api 用户(可选,当前用 root
useradd -r -s /sbin/nologin nginx-api || true
```
### Step 1: 安装软件
```bash
# Nginx
dnf install -y nginx
systemctl enable nginx
systemctl start nginx
# Python pip 包
pip3 install flask==2.0.3 gunicorn==21.2.0
# acme.sh
git clone https://github.com/acmesh-official/acme.sh.git /root/.acme.sh
/root/.acme.sh/acme.sh --install --home /root/.acme.sh
/root/.acme.sh/acme.sh --set-default-ca --server letsencrypt
```
### Step 2: 配置防火墙
```bash
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-port=5000/tcp
firewall-cmd --reload
# SELinux
setsebool -P httpd_can_network_connect 1
```
### Step 3: 迁移 Python API 代码
```bash
# 从旧服务器拷贝整个目录
rsync -avz root@10.1.1.160:/opt/nginx-api/ /opt/nginx-api/
# 或手动拷贝文件:
# /opt/nginx-api/
# app.py — Flask 主入口
# gunicorn_config.py — Gunicorn 配置
# deploy.sh — 部署脚本
# requirements.txt — Python 依赖
# services/
# __init__.py
# nginx_service.py — Nginx 配置读写
# ssl_service.py — 证书签发管理
# dns_service.py — DNS 解析管理
# cert_notifier.py — 邮件通知脚本
```
### Step 4: 迁移 SSL 证书目录
```bash
# ⚠️ 关键:内部 CA 私钥必须保留
rsync -avz root@10.1.1.160:/etc/nginx/ssl/ /etc/nginx/ssl/
# 确保证书权限正确
chmod 700 /etc/nginx/ssl/ca
chmod 600 /etc/nginx/ssl/ca/ca.key
chmod 644 /etc/nginx/ssl/ca/ca.crt
chmod 600 /etc/nginx/ssl/*.key
chmod 644 /etc/nginx/ssl/*.pem
```
### Step 5: 迁移 Nginx 配置
```bash
# 主配置
rsync -avz root@10.1.1.160:/etc/nginx/nginx.conf /etc/nginx/nginx.conf
# 所有域名转发配置
rsync -avz root@10.1.1.160:/etc/nginx/conf.d/ /etc/nginx/conf.d/
# 验证配置
nginx -t
# 重载
systemctl reload nginx
```
### Step 6: 迁移 acme.sh
```bash
rsync -avz root@10.1.1.160:/root/.acme.sh/ /root/.acme.sh/
```
### Step 7: 迁移环境变量
将以下内容追加到 `/root/.bashrc`
```bash
export Ali_Key="LTAI5t98jUxLUadZM1LkaSa8"
export Ali_Secret="K2HyLLXizAgvOMOa0Mzc7ebs4gbAZs"
```
然后执行:
```bash
source /root/.bashrc
```
### Step 8: 安装 systemd 服务
创建 `/etc/systemd/system/nginx-api.service`
```ini
[Unit]
Description=Nginx Manager Python API
After=network.target nginx.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/nginx-api
Environment=Ali_Key=LTAI5t98jUxLUadZM1LkaSa8
Environment=Ali_Secret=K2HyLLXizAgvOMOa0Mzc7ebs4gbAZs
ExecStart=/usr/bin/python3 -m gunicorn -c gunicorn_config.py app:app
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
```bash
systemctl daemon-reload
systemctl enable nginx-api
systemctl start nginx-api
```
### Step 9: 迁移 crontab
```bash
# 查看旧服务器 crontab
crontab -l
# 添加 acme.sh 自动续期(每天 19:01
echo '1 19 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null' | crontab -
```
### Step 10: 验证
```bash
# 1. 服务状态
systemctl status nginx nginx-api
# 2. 端口监听
ss -tlnp | grep -E ":(80|443|5000)"
# 3. Nginx 配置语法
nginx -t
# 4. Python API 健康检查
curl http://localhost:5000/api/nginx/health
# 5. 证书列表
curl http://localhost:5000/api/nginx/certs
# 6. acme.sh 版本
/root/.acme.sh/acme.sh --version
```
---
## 四、完整配置文件参考
### 4.1 Nginx 主配置 `/etc/nginx/nginx.conf`
```nginx
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
# 全局 gzip 压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_types text/plain text/css text/xml application/json
application/javascript text/javascript application/xml+rss
application/x-font-ttf image/svg+xml;
# 包含所有域名转发配置
include /etc/nginx/conf.d/*.conf;
}
```
### 4.2 Gunicorn 配置 `/opt/nginx-api/gunicorn_config.py`
```python
import os
bind = "0.0.0.0:5000"
pidfile = "gunicorn.pid"
workers = int(os.environ.get('GUNICORN_WORKERS', 2))
worker_class = "sync"
timeout = 300
graceful_timeout = 10
accesslog = "-"
errorlog = "-"
loglevel = "info"
proc_name = "nginx-manager-api"
daemon = False
```
### 4.3 域名转发配置模板
**HTTP** (`/etc/nginx/conf.d/<domain>.conf`):
```nginx
server {
listen 80;
server_name <domain>;
# 静态资源缓存
location ~* \.(js|css|svg|woff2|png|jpg|ico)$ {
proxy_pass <target>;
expires 30d;
add_header Cache-Control "public, immutable";
}
location / {
proxy_pass <target>;
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;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
```
**HTTPS** (`/etc/nginx/conf.d/<domain>.conf`):
```nginx
# HTTP → HTTPS 重定向
server {
listen 80;
server_name <domain>;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name <domain>;
ssl_certificate /etc/nginx/ssl/<domain>.pem;
ssl_certificate_key /etc/nginx/ssl/<domain>.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 静态资源缓存
location ~* \.(js|css|svg|woff2|png|jpg|ico)$ {
proxy_pass <target>;
expires 30d;
add_header Cache-Control "public, immutable";
}
location / {
proxy_pass <target>;
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;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
```
---
## 五、证书体系
### 5.1 双层证书架构
| 类型 | 适用域名 | 签发方式 | 有效期 | 续期方式 |
|------|----------|----------|--------|----------|
| 内部 CA | 非 zgitm 域名 | OpenSSL 自签 | 365天 | 重新签发 |
| Let's Encrypt | `*.zgitm.com` | acme.sh DNS-01 | 90天 | 自动续期(每天cron) |
### 5.2 内部 CA
```
/etc/nginx/ssl/ca/
ca.key (600) — 根CA私钥 (RSA 2048)
ca.crt (644) — 根CA证书 (有效期10年, 至约2036年)
ca.srl — 序列号文件
```
首次启动时由 `ssl_service.py``init_ca()` 方法自动生成。**迁移时必须保留此目录**,否则所有内部 CA 签发的域名的 SSL 证书将不被信任。
### 5.3 Let's Encrypt (acme.sh)
- 安装目录: `/root/.acme.sh/`
- 证书存放: `/etc/nginx/ssl/<domain>.pem` + `.key`
- 自动续期 cron: `1 19 * * *` (每天)
- DNS 验证: 阿里云 DNS API (`dns_ali`)
- 阿里云 AccessKey 环境变量: `Ali_Key` / `Ali_Secret`
- 当前已签发: `zgitm.com`, `www.zgitm.com` (到期 2026-09-09)
### 5.4 系统保护域名
`zgitm.com``www.zgitm.com` 为系统内置域名,不允许在转发规则页面创建/修改/删除。三层拦截:
1. 前端: 操作按钮置灰
2. Java: `ForwardingRuleService.SYSTEM_DOMAINS`
3. Python: `ssl_service.is_system_domain()`
---
## 六、Python API 端点参考
基地址: `http://10.1.1.160:5000`
### 转发规则
```
GET /api/nginx/health → 健康检查
GET /api/nginx/rules → 规则列表
GET /api/nginx/rules/<domain> → 规则详情
POST /api/nginx/rules → 新增规则 {domain, protocol, target}
PUT /api/nginx/rules/<domain> → 修改规则 {domain, protocol, target}
DELETE /api/nginx/rules/<domain> → 删除规则
POST /api/nginx/reload → 重载 Nginx
```
### 证书管理
```
GET /api/nginx/certs → 证书列表(扫描所有 .pem排除 ca.*
GET /api/nginx/certs/<domain> → 证书详情
POST /api/nginx/certs/<domain>/issue → 签发 LE 证书
POST /api/nginx/certs/<domain>/renew → 续期 LE 证书
```
### DNS 管理
```
GET /api/nginx/dns/records?zone= → DNS 记录列表
POST /api/nginx/dns/records → 添加 DNS 记录
PUT /api/nginx/dns/records/<id> → 修改 DNS 记录
DELETE /api/nginx/dns/records/<id> → 删除 DNS 记录
```
---
## 七、外部依赖关系
迁移后需要确保以下连通性:
| 从 → 到 | 地址 | 端口 | 用途 |
|---------|------|------|------|
| 新服务器 | MySQL | 10.1.1.122 | 3306 | 数据库Java 用Python 不直连) |
| 新服务器 → | Java 后端 | 10.10.1.170 | 4002 | Java 调用 Python API 的反向 |
| Java 后端 → | 新服务器 | 新IP | 5000 | **需要更新 Java 配置中的 python-api.base-url** |
| 新服务器 → | 阿里云 DNS | alidns.aliyuncs.com | 443 | DNS 管理 + LE 验证 |
| 新服务器 → | Let's Encrypt | acme-v02.api.letsencrypt.org | 443 | 证书签发/续期 |
### ⚠️ 迁移后必须更新的配置
1. **Java `application-qa.yml` / `application-prod.yml`**: 修改 `python-api.base-url` 为新服务器 IP
2. **前端 `.env.production`**: 如果 Nginx 入口域名换了需更新 `VITE_API_BASE_URL`
3. **DNS 解析**: 如果 `nginx.server.zgitm.com` 指向旧服务器 IP需更新 DNS 记录
---
## 八、服务清单
| 服务 | systemd unit | 开机自启 | 端口 |
|------|-------------|----------|------|
| Nginx | nginx.service | ✅ | 80, 443 |
| Python API | nginx-api.service | ✅ | 5000 |
| SSH | sshd.service | ✅ | 22 |
| Firewalld | firewalld.service | ✅ | — |
### 常用命令
```bash
# 查看所有服务状态
systemctl status nginx nginx-api
# 重载 Nginx不中断连接
systemctl reload nginx
# 重启 Python API
systemctl restart nginx-api
# 查看日志
journalctl -u nginx-api -f
journalctl -u nginx -f
# 测试 Nginx 配置
nginx -t
# 手动签发证书LE 测试)
/root/.acme.sh/acme.sh --issue --dns dns_ali -d test.zgitm.com --staging
# 手动续期
/root/.acme.sh/acme.sh --renew -d zgitm.com --force
```
---
## 九、当前服务器资源使用
| 指标 | 值 |
|------|-----|
| 磁盘 | 17G 总量, 3.6G 已用 (22%) |
| 内存 | 1.7G 总量, ~350M 已用 |
| Python API 大小 | 152K |
| acme.sh 大小 | 3.5M |
| Nginx 配置+证书 | 376K |
| 证书文件数 | 20+ .pem |
| 转发规则数 | 17 .conf |
---
## 十、已知注意事项
1. **Python 3.6 兼容性**: Rocky 8 自带 Python 3.6Flask 最高只支持到 2.0.x。`requirements.txt` 写的 flask==3.1.0 实际上被降级安装为 2.0.3。**如果新服务器用 Python 3.9+,可以安装 Flask 3.x**。
2. **acme.sh 安装方式**: `curl https://get.acme.sh | sh` 可能被墙,建议用 `git clone` 方式安装。
3. **内部 CA 私钥**: `/etc/nginx/ssl/ca/ca.key` 是安全敏感文件迁移时不要通过不安全渠道传输。RSYNC/SCP 直接传输是安全的。
4. **阿里云 AccessKey**: 存储在 `/root/.bashrc` 环境变量中systemd service 文件中也硬编码了一份(`Environment=`),两处都需要更新。
5. **Java 后端 MyBatis-Plus**: 已从 JPA 迁移到 MyBatis-Plus2026-06-12新服务器上 Python API 代码已包含 `list_certs()` 修复(扫描全部 .pem
6. **Nginx gzip**: 主配置中包含全局 gzip 压缩(`/etc/nginx/nginx.conf``http {}` 块)。迁移时注意 `include /etc/nginx/conf.d/*.conf;` 不要丢失。