Chapter 01
反向代理 — 核心概念
1.1 什么是反向代理
通过同一个端口进入服务器,由服务器内的程序根据请求中的域名(Host 头)将流量分发到不同的内部端口。
1.2 工作原理
域名 A ──┐
├──→ 服务器:80/443(反向代理)──→ 内部端口 3000
域名 B ──┘
──→ 内部端口 8080
- DNS 将不同域名解析到同一个公网 IP
- 反向代理读取
Host头判断域名 - 根据域名转发到对应的内部端口
1.3 关键机制
| 机制 | 说明 |
|---|---|
| 依据 | HTTP 请求头中的 Host 字段 |
| HTTPS 场景 | 通过 SNI(Server Name Indication)在 TLS 握手阶段确定域名 |
| 内部端口 | 只监听 127.0.0.1,对外完全不可见 |
Chapter 02
三种实现方式与安全性对比
2.1 实现方式概览
| 工具 | 语言 | 特点 |
|---|---|---|
| Nginx | C | 20+ 年历史,生态最成熟,配置灵活可控 |
| Caddy | Go | 现代设计,默认安全,自动 HTTPS |
| Node.js 自写 | JavaScript | 完全可控,但所有安全细节需自行处理 |
2.2 安全性排名
Nginx ≈ Caddy ≫ Node.js 自写
2.3 安全维度详细对比
| 安全维度 | Nginx | Caddy | Node.js 自写 |
|---|---|---|---|
| 代码成熟度 | 20+ 年,经受海量攻击考验 | 较新但设计现代,Go 天然内存安全 | 取决于个人代码质量 |
| 内存安全 | C 编写,历史有极少量缓冲区溢出漏洞 | Go 编写,天然无缓冲区溢出 | JS 本身安全,依赖库可能有问题 |
| HTTPS / TLS | 需手动配置,选项丰富 | 默认强制 HTTPS,自动签发续期证书 | 需自行实现,容易出错 |
| 默认安全程度 | 较高,需正确配置 | 最高,安全默认值最好 | 最低,全部自行负责 |
| Header 暴露 | 默认暴露 Server: nginx,需手动隐藏 |
默认不暴露多余信息 | 取决于实现 |
| 请求限制 | 完善的 limit_req、limit_conn |
内置 rate limiting | 需自行实现 |
| 维护负担 | 中等 | 最低 | 最高 |
| 社区审计 | 极广泛,安全问题发现快 | 活跃且快速增长 | 无人帮你审计 |
2.4 选型建议
追求开箱即用安全
Caddy
默认强制 HTTPS,自动管理证书,安全默认值最好
需要极致可控、有运维经验
Nginx
20+ 年生态沉淀,配置灵活,社区广泛
开发 / 内网环境
Node.js
完全可控,适合开发调试和内部系统
2.5 配置示例
Nginx
nginx
server {
listen 80;
server_name a.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name a.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://127.0.0.1:3000;
}
}
Caddy
caddyfile
a.com {
reverse_proxy localhost:3000
}
b.com {
reverse_proxy localhost:8080
}
Node.js
javascript
const http = require('http');
const httpProxy = require('http-proxy');
const proxy = httpProxy.createProxyServer();
const routes = {
'a.com': 'http://127.0.0.1:3000',
'b.com': 'http://127.0.0.1:8080',
};
http.createServer((req, res) => {
const host = req.headers.host.split(':')[0];
const target = routes[host];
if (target) {
proxy.web(req, res, { target });
} else {
res.writeHead(404);
res.end('Unknown host');
}
}).listen(80);
Chapter 03
流量入口
3.1 入口端口
所有面向公网的 HTTP/HTTPS 请求都从 80(HTTP)或 443(HTTPS)进入服务器。
| 域名写法 | 浏览器默认连接端口 | 协议 |
|---|---|---|
http://a.com | 80 | HTTP |
https://a.com | 443 | HTTPS |
3.2 这是协议标准决定的
- 用户不需要在域名后写
:80或:443 - 浏览器根据协议自动补全
- 全球统一规范
3.3 安全意义
Security Tip
内部端口(3000、8080 等)对外完全不可见。攻击面只有一个入口,守住 80/443 就守住了所有流量。防火墙只需开放 80 和 443 两个端口。
Chapter 04
流量出口
4.1 出口端口特点
| 入口 | 出口 | |
|---|---|---|
| 端口 | 固定 80/443 | 操作系统随机分配(49152–65535) |
| 谁决定 | 协议标准 | 操作系统内核 |
| 防火墙 | 需主动开放 | 通常默认允许所有出站 |
4.2 四种流量场景
1. 响应用户请求 → 出口就是 443 本身(同一个 TCP 连接)
2. 调用第三方 API → 随机端口 → 目标:443
3. 发送邮件 → 随机端口 → smtp.xxx.com:465
4. Nginx → 内部应用 → 内网通信,不走公网
4.3 出口安全防护
- 出站白名单:只允许访问已知外部 API 地址
- 出站协议限制:只允许 443、53 等必要协议
- 异常监控:监控服务器是否大量访问未知 IP(可能被入侵)
firewall
# 防火墙配置示例
入站:只开放 80, 443
出站:只允许访问 api.stripe.com:443, smtp.qq.com:465
拒绝其他所有出站流量
Chapter 05
端口 80 vs 443
5.1 核心区别
- 80 → HTTP → 明文传输,数据裸奔
- 443 → HTTPS → 加密传输,截获也看不懂
5.2 详细对比
| 端口 80 (HTTP) | 端口 443 (HTTPS) | |
|---|---|---|
| 数据加密 | 无,明文传输 | TLS/SSL 加密 |
| URL 前缀 | http:// | https:// |
| 证书 | 不需要 | 需要 TLS 证书 |
| 浏览器显示 | 标记“不安全” | 锁头图标 |
| 速度 | 略快 | 几乎无差别 |
| SEO | 搜索引擎降权 | 搜索引擎优先收录 |
| 防篡改 | 中间人可修改内容 | 无法篡改,会被检测 |
5.3 HTTPS 加密原理(简化版)
1. 客户端 → 服务器:我要建立连接
2. 服务器 → 客户端:这是我的证书(公钥)
3. 客户端验证证书是否可信
4. 客户端用公钥加密一个随机密钥,发给服务器
5. 双方都拿到了同一个对称密钥
6. 后续所有数据用这个密钥加密传输
5.4 现代互联网为什么必须用 443
Why 443?
浏览器把 HTTP 标记为“不安全”,吓跑用户;Let's Encrypt 提供免费证书,零成本;Google 搜索排名对 HTTPS 优先;HTTP/2 和 HTTP/3 主流浏览器只支持 HTTPS;许多新 API 只接受 HTTPS 请求。
Chapter 06
只用 443 不开 80 的可行性分析
6.1 三种方案对比
| 只开 443 | 80 重定向到 443 | HSTS 预加载 | |
|---|---|---|---|
| 用户体验 | 差,首次输入域名可能报错 | 好,无感跳转 | 最好,浏览器直接走 443 |
| 安全 | 最高,无任何明文 | 高,80 有一次明文请求 | 最高 |
| 配置难度 | 最简单 | 简单 | 较复杂,需申请预加载 |
| 适用场景 | 内部系统、纯 API | 绝大多数网站 | 大型公开网站 |
6.2 只开 443 的问题
用户直接输入 a.com(不写 https://)
→ 浏览器默认尝试 http://(80 端口)
→ 端口未开放,连接失败
→ 用户看到 错误页面
6.3 标准做法(推荐)
nginx
# 80 端口只做一件事:重定向到 443
server {
listen 80;
server_name a.com;
return 301 https://$host$request_uri;
}
# 443 端口提供实际服务
server {
listen 443 ssl;
server_name a.com;
# ...
}
6.4 适用只开 443 的场景
Warning
仅在以下场景考虑只开 443:所有用户都会手动输入 https://、纯 API 服务(不需要浏览器访问)、内部系统(入口已通过其他方式确保 HTTPS)。
Chapter 07
知识点关系总图
用户输入域名
│
▼
DNS 解析 → 服务器公网 IP
│
▼
流量入口:端口 80(HTTP)或 443(HTTPS)
│
├── 80 端口:明文,通常只做重定向到 443
│
▼
443 端口:TLS 加密
│
▼
反向代理(Nginx / Caddy / Node.js)
│
├── 读取 Host 头 / SNI
├── 域名 A → localhost:3000
├── 域名 B → localhost:8080
│
▼
内部应用处理请求
│
▼
流量出口:
├── 响应用户 → 同一个 TCP 连接(443)
└── 主动外联 → 随机高位端口(49152–65535)