# 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 clone,get.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 API(acme.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/.conf`): ```nginx server { listen 80; server_name ; # 静态资源缓存 location ~* \.(js|css|svg|woff2|png|jpg|ico)$ { proxy_pass ; expires 30d; add_header Cache-Control "public, immutable"; } location / { proxy_pass ; 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/.conf`): ```nginx # HTTP → HTTPS 重定向 server { listen 80; server_name ; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name ; ssl_certificate /etc/nginx/ssl/.pem; ssl_certificate_key /etc/nginx/ssl/.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # 静态资源缓存 location ~* \.(js|css|svg|woff2|png|jpg|ico)$ { proxy_pass ; expires 30d; add_header Cache-Control "public, immutable"; } location / { proxy_pass ; 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/.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/ → 规则详情 POST /api/nginx/rules → 新增规则 {domain, protocol, target} PUT /api/nginx/rules/ → 修改规则 {domain, protocol, target} DELETE /api/nginx/rules/ → 删除规则 POST /api/nginx/reload → 重载 Nginx ``` ### 证书管理 ``` GET /api/nginx/certs → 证书列表(扫描所有 .pem,排除 ca.*) GET /api/nginx/certs/ → 证书详情 POST /api/nginx/certs//issue → 签发 LE 证书 POST /api/nginx/certs//renew → 续期 LE 证书 ``` ### DNS 管理 ``` GET /api/nginx/dns/records?zone= → DNS 记录列表 POST /api/nginx/dns/records → 添加 DNS 记录 PUT /api/nginx/dns/records/ → 修改 DNS 记录 DELETE /api/nginx/dns/records/ → 删除 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.6,Flask 最高只支持到 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-Plus(2026-06-12),新服务器上 Python API 代码已包含 `list_certs()` 修复(扫描全部 .pem)。 6. **Nginx gzip**: 主配置中包含全局 gzip 压缩(`/etc/nginx/nginx.conf` 中 `http {}` 块)。迁移时注意 `include /etc/nginx/conf.d/*.conf;` 不要丢失。