v0.5.5: 应急页 v0.5.4 + 移除IT设备升级 + admin登录修复 + 内容审核架构 + 知识库

This commit is contained in:
Simon
2026-06-16 10:07:42 +08:00
parent 10b37a6acc
commit 60e67b0681
59 changed files with 4195 additions and 110 deletions
+362
View File
@@ -0,0 +1,362 @@
# nginx 真实 IP 还原 — 生产部署(小白友好版)
> 术语速查:**nginx** = 你这台服务器的"门卫",负责把用户请求分发给后端 / 把静态文件返回给浏览器
> **配置** = nginx 的工作规则,改配置 = 改门卫的工作方式
---
## 我们要做啥(整体目标)
**一句话目标**:`https://itsupport.servyou.com.cn/itadmin/` 之前返回 403(被门卫拦了),原因是门卫把"代理服务器 IP"当成了"用户 IP",而代理 IP 不在白名单里。这次我们改门卫的规则,让它从请求头里读"真实用户 IP"。
**一共 7 个动作**:
| # | 动作 | 大概多久 | 风险 |
|---|---|---|---|
| 1 | PuTTY 连上服务器 | 1 分钟 | ⚪ 无风险 |
| 2 | 备份当前配置 | 几秒 | 🟢 备份原文件,可还原 |
| 3 | 写入 13 行新规则 | 几秒 | 🟡 改配置,但有备份 |
| 4 | 确认写入正确 | 几秒 | ⚪ 只读不写 |
| 5 | 检查配置语法 | 几秒 | ⚪ 只读不写 |
| 6 | 让 nginx 重新读规则 | 1 秒 | 🟡 短暂重载,服务不中断 |
| 7 | 浏览器看效果 | 几秒 | ⚪ 只读 |
**总耗时**:第一次大概 5-10 分钟;熟练了 2 分钟
**整体风险**:🟢 **低** — 每一步都给了"回滚"按钮,改坏了随时能恢复
---
## PuTTY 是啥?在哪儿打开?
**PuTTY** = 一个 SSH 客户端软件,作用是让你从你的 Windows 电脑远程连到公司的 Linux 服务器
**打开方式**:
-`Win 键` → 输入 `putty` → 回车
- 或者开始菜单 → 找到 PuTTY 图标
打开后会看到一个灰底配置界面,我们要填 4 项:
```
┌──────────────────────────────────────┐
│ Host Name (or IP address) │ ← 填: 10.212.189.210
│ Port │ ← 填: 2222
│ Connection type │ ← 选: SSH(默认就是)
│ Saved Sessions │ ← 填: wecom-bastion(起个名)
└──────────────────────────────────────┘
点 Save 保存 → 点 Open 开始连接
```
连接后会黑底白字,提示 `login as:` → 输入 `sxn` 回车 → 提示 `password:` → 输入你的堡垒机密码(输入时屏幕不显示,正常,输完回车就行)
**注意**:输错密码不会锁账号,直接重新输
---
## 动作 1:PuTTY 连服务器(⚪ 无风险)
> **为啥要连服务器?**:改配置必须在服务器上操作,你 Windows 这边只是"遥控器"
连上堡垒机后,黑底白字会显示一个类似 `sxn@jump-host:~$` 的提示符,说明你已经到堡垒机了。
**决策树**:
```
你现在看到了堡垒机提示符(类似 sxn@jump-host:~$)
├─ 是 → 在 PuTTY 里继续输入下面命令
└─ 否 → 截图发给我,卡哪儿了
```
贴下面的命令(右键 = 粘贴,Enter = 执行):
```bash
# 从堡垒机跳到真正的生产服务器
ssh sxn@10.90.5.110
```
回车后可能要输密码(堡垒机和目标机密码可能不同,试一下你之前用过的那个)
**✅ 成功长这样**:
```text
sxn@prod-server:~$
```
**❌ 失败常见**:
- `Permission denied` → 密码错了,重输
- `Connection timed out` → 网络问题,可能 VPN 没连
- 卡住不动 → 可能需要输 `yes` 确认服务器指纹,看到 `(yes/no/[fingerprint])?` 就输 `yes` 回车
---
## 动作 2:备份当前配置(🟢 低风险,改坏了能还原)
> **为啥要备份?**:运维铁律 — **改任何东西之前先备份**,这样改坏了能用备份还原,不会把生产搞挂
```bash
# 进入 nginx 配置所在目录
cd /opt/wecom-it-desk/nginx
# 复制一份当前配置,文件名带当前时间(分),方便区分
sudo cp nginx.conf nginx.conf.bak-$(date +%H%M)
# 列出所有备份文件,确认刚才那行成功
ls -la nginx.conf.bak-*
```
**为啥用 `$(date +%H%M)`?**:这个写法会自动拼上当前时间(比如 1430 表示 14:30),每次备份文件名都不一样,不会覆盖之前的备份
**✅ 成功长这样**:
```text
-rw-r--r-- 1 root root 4821 Jun 15 14:30 nginx.conf.bak-1430
```
**❌ 失败常见**:
- `cp: cannot stat 'nginx.conf'` → 当前不在 nginx 目录,先 `cd /opt/wecom-it-desk/nginx` 进去
- `Permission denied` → 缺 `sudo`,命令前面加 `sudo` 重试
---
## 动作 3:写入 13 行新规则(🟡 中风险,但有备份兜底)
> **写入啥?**:13 行 nginx 配置,告诉 nginx"从请求头 X-Forwarded-For 里读真实用户 IP"
>
> **为啥要这样做?**:用户通过公司 WAF/堡垒机访问,WAF 会把真实 IP 放在 `X-Forwarded-For` 请求头里,但 nginx 默认只看直连 IP,所以才误判 403
**重要**:把下面**从 `cat > /tmp/patch.py``PYEOF`** 的**整段**一次性粘贴进 PuTTY(右键 = 粘贴)。整段会作为一条命令执行。
```bash
# 创建一个 python 脚本到 /tmp/patch.py
cat > /tmp/patch.py << 'PYEOF'
fp = '/opt/wecom-it-desk/nginx/nginx.conf'
with open(fp) as f:
c = f.read()
patch = '''
# ------------------------------------------------------------------
# 真实 IP 还原(2026-06-15 v0.5.1 修复)
# ------------------------------------------------------------------
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from 10.212.0.0/16;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
'''
old = 'error_log /var/log/nginx/error.log warn;'
new = old + patch
new_c = c.replace(old, new, 1)
with open(fp, 'w') as f:
f.write(new_c)
print('patched, +{} bytes'.format(len(new_c) - len(c)))
PYEOF
# 运行这个 python 脚本,它会自动把上面那 13 行插入到 nginx.conf
sudo python3 /tmp/patch.py
```
**术语解释**:
- `cat > /tmp/patch.py` → 创建一个文件,内容是后面所有内容
- `<< 'PYEOF' ... PYEOF` → 这种写法叫 **heredoc**(直译"这里是文档"),作用是把多行文字原样写入文件
- `sudo` → 以管理员身份运行(改系统文件需要权限)
**✅ 成功长这样**:
```text
patched, +492 bytes
```
**❌ 失败常见**:
- `Permission denied` → 缺 `sudo`,或者 nginx.conf 不存在
- `NameError: name 'fp' is not defined` → heredoc 没贴完整,最末尾的 `PYEOF` 没贴上
- 没任何输出 → python 没运行,看光标有没有新行,可能没回车
---
## 动作 4:确认写入正确(⚪ 无风险,只读)
> **为啥要确认?**:虽然脚本说写入了,但**人眼看到才真的算**。这步只读不写,放心跑
```bash
# 在 nginx.conf 里搜索"真实 IP 还原"关键字,并显示后面 13 行
sudo grep -A 13 "真实 IP 还原" /opt/wecom-it-desk/nginx/nginx.conf
```
**✅ 成功长这样**(应该看到完整 13 行):
```nginx
# 真实 IP 还原(2026-06-15 v0.5.1 修复)
# ------------------------------------------------------------------
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from 10.212.0.0/16;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
```
**❌ 失败**:
- 啥也没输出 → 写入失败,回到动作 3 重做
- 只输出一两行 → heredoc 没贴全,需要回滚后重来
---
## 动作 5:检查配置语法(⚪ 无风险,只读不执行)
> **为啥要检查?**:这个命令 nginx 会"假装"按新配置启动,只检查语法,不会真的重启。**通过 = 配置写得对,放心用;不通过 = 写得有问题,继续走会出问题**
```bash
# 在 nginx 容器(就是跑 nginx 服务的那个小 Linux)内,做配置语法检查
docker compose exec nginx nginx -t
```
**术语解释**:
- `docker compose` → 管理这台服务器上所有"容器"的命令
- `exec` → "钻进"某个容器里执行命令
- `nginx -t` → nginx 自带的"语法检查"工具(全称 `--test`)
**✅ 成功长这样**:
```text
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```
**❌ 失败**(`test is successful` 没出现):
- `unexpected "}"` / `unknown directive` → 写错字了,回去动作 4 看看哪里对不上
- **直接停下,不要继续** → 复制错误信息贴回给我
---
## 动作 6:让 nginx 重新读规则(🟡 中风险,但服务不中断)
> **"重新读"是啥意思?**:nginx 现在用的还是旧配置,我们让 nginx 不用重启(不会断服务)就把新配置加载进来。这个动作叫"热加载"或 "reload"
>
> **会断网吗?**:不会,reload 是无缝的,用户那边无感知
```bash
# 通知 nginx 容器内的 master 进程重新读配置
docker compose exec nginx nginx -s reload
```
**术语解释**:`-s reload` = 发信号(英文 signal)给 nginx,告诉它"重读配置"
**✅ 成功长这样**(没报错即成功):
```text
2026/06/15 14:35:12 [notice] 1#1: signal process started
```
**❌ 失败**:
- `nginx: [error]` 开头 → 配置没通过,回去动作 5 看哪里没对
- 啥也没输出 → 命令没执行,看光标位置
---
## 动作 7:浏览器看效果(⚪ 无风险)
**为啥这步是浏览器而不是 curl?**:curl 看响应头,浏览器看真实页面。**人眼看到才作数**
**操作步骤**:
1. 打开浏览器
2. **开隐身模式**(`Ctrl + Shift + N`,Chrome / Edge 都是这个快捷键)
- **为啥要隐身?**:隐身模式不读本地缓存,看到的就是 nginx **当下**返回的
3. 地址栏输入 `https://itsupport.servyou.com.cn/itadmin/`
4. 按回车
**✅ 成功长这样**:
- 页面正常显示
-`F12` 打开开发者工具 → `Network` 选项卡 → 顶部那一行状态码是 **200**(不是 403)
**❌ 失败**:
- 仍然是 403 → 见下面"如果还是 403"段
- 502 / 504 → nginx 后面那个服务挂了,贴错误给我
- 页面打不开(连接被拒) → DNS 没配,联系 IT 运维
---
## 如果还是 403 — 看 WAF 出口 IP(诊断)
> **啥是 WAF?**:公司部署在 nginx 前面的"统一入口",所有用户请求先经过 WAF 再到 nginx。WAF 自己的 IP 不一定在你写的 4 段内网里,所以还得加
```bash
# 看 nginx 最后 20 条访问日志,找 $remote_addr 是不是 WAF 的 IP
docker compose exec nginx tail -20 /var/log/nginx/access.log
```
**日志长这样**:
```text
10.80.5.123 - - [15/Jun/2026:14:35:45 +0800] "GET /itadmin/ HTTP/1.1" 403 ...
^^^^^^^
这就是 $remote_addr
```
把那个 IP 数字(比如 `10.80.5.123`)贴回给我,我会:
1. 给你追加一行 `set_real_ip_from 10.80.5.123;`
2. 让你重跑动作 5 + 动作 6
---
## 如果改坏了 — 回滚(啥时候都能用)
> **啥时候用?**:任何一个动作出问题,你都可以直接回滚到动作 2 备份的版本
```bash
# 列出所有备份,挑最近的一个
ls -la /opt/wecom-it-desk/nginx/nginx.conf.bak-*
```
```bash
# 用最近那个备份覆盖当前配置(把 1430 换成上面列出的真实时间)
sudo cp /opt/wecom-it-desk/nginx/nginx.conf.bak-1430 /opt/wecom-it-desk/nginx/nginx.conf
```
```bash
# 重新加载回滚后的配置
docker compose exec nginx nginx -s reload
```
回滚后页面应该回到改之前的状态(403 回来),说明回滚成功
---
## 一张图看懂流程
```
PuTTY 连服务器
备份原配置
写入 13 行新规则
确认写入正确 ──→ ❌ 不对 ──→ 重做写入 / 回滚
│ ✅
检查配置语法 ──→ ❌ 语法错 ──→ 复制错误贴回给我,不要继续
│ ✅
重载 nginx ─────→ ❌ 报错 ──→ 检查容器状态 / 找 Claude
│ ✅
浏览器看效果 ──→ ❌ 还是 403 ──→ 看 WAF 出口 IP,贴给 Claude
│ ✅
🎉 完成
```
---
## 我建议你第一次做
**第一次建议**:动作 1 → 动作 2 → **停一下,截图发给我** → 我确认备份成功 → 你再继续动作 3 之后
**熟练了以后**:一口气跑完动作 1-7,中间不打断
---
## 关联
- 评审报告:`review-p0-security-2026-06-14.md` P0-3
- 待办:`ip-whitelist-trust-proxies-todo.md` — v1.0 前必须收窄 4 段 → 4 个 IP
- 本地配置:`deploy-server/nginx/nginx.conf`(已包含 patch,下次重打包自动带)
- 服务器 IP 变更:`project-production-server-ip-2026-06-15.md` — 10.80.0.136 已下线,用 10.90.5.110
- 客户端约束:`feedback-putty-not-openssh.md` — 用 PuTTY,不用 `ssh -J`
- 命令行规范:`feedback-cmd-step-by-step.md` — 每行一条 + 中文注释
- 小白引导规范:`feedback-beginner-friendly-guide.md` — 讲清目标+风险、术语解释、出错兜底