查询 31 次,耗时 0.6939 秒

从 DNS 到 Nginx:面向 API 服务的域名解析、HTTPS 部署与服务器安全加固实战

黄先生嗯

New member

黄先生嗯 Rep
0
0
0
Rep
0
黄先生嗯 Vouches
Vouches
0
1 MONTH
1 1 MONTH OF SERVICE
黄先生嗯 获得
0
0
0
获得
0
黄先生嗯 凭证
0
0
0
凭证
0
主题
15
点赞
0
HakB
1 月
在社区成长 1 月
LEVEL 1 1 XP
 
一、背景

很多服务上线时只完成了“域名解析到服务器、Nginx 转发到应用”这两步,却忽略了 DNS 变更策略、源站端口暴露、TLS 配置、访问频率限制、日志留存和回滚方案。结果往往是:切换服务器时解析迟迟不生效,后端端口可以绕过 Nginx 直接访问,证书续期失败后业务中断,或者接口被异常请求拖垮。

本文以保留示例域名 api.example.com、Ubuntu/Debian 系服务器和 Nginx 为例,搭建一套适合网站及移动 APP API 的基础架构。所有命令应在自有服务器或授权测试环境执行,示例地址需要替换为自己的实际配置。

二、整体架构与原理

推荐的访问链路如下:

客户端 → 递归 DNS → 权威 DNS → 公网服务器 443 端口 → Nginx → 本机应用 127.0.0.1:8080

这里有四个主要攻击面:

1. DNS 层:账号被盗、记录误改、TTL 设置不合理、域名过期或解析被劫持。
2. 网络层:SSH、数据库、应用调试端口直接暴露在公网。
3. TLS 层:旧协议、弱密码套件、证书过期或私钥权限不当。
4. 应用入口:缺少限速、请求体限制、超时控制和日志审计。

安全加固的核心不是堆叠配置,而是缩小暴露面:公网原则上只开放必要端口,后端服务仅监听环回地址,由 Nginx 统一处理 TLS、请求限制和审计日志。

三、前置条件

1. 一个自己可管理 DNS 的域名,本文使用 api.example.com 作为示例。
2. 一台具有固定公网 IPv4 地址的 Linux 服务器;若使用 IPv6,需要同步配置 AAAA 记录和 IPv6 防火墙。
3. 具有 sudo 权限的运维账号。
4. 应用已经能够在 127.0.0.1:8080 提供 HTTP 服务。
5. 云厂商安全组允许 TCP 80 和 443;SSH 端口应仅向可信管理地址开放。
6. 修改前备份现有 Nginx 配置、DNS 记录和防火墙规则,并准备控制台登录方式,避免误封 SSH 后无法恢复。

四、第一步:规划 DNS 记录和 TTL

在 DNS 控制台添加:

api.example.com. 300 IN A 203.0.113.10

203.0.113.0/24 是文档示例网段,不能直接作为生产地址。若服务器有稳定 IPv6,可增加 AAAA 记录;若 IPv6 服务、防火墙或监听配置尚未完成,不要提前发布 AAAA,否则部分客户端会优先走 IPv6 并出现间歇性失败。

上线或迁移前,可把 TTL 临时调整为 300 秒,以便快速切换。业务稳定后建议恢复到 1800 秒或 3600 秒,减少权威 DNS 查询压力。需要注意,降低 TTL 只影响记录之后产生的缓存,不能让已经缓存的旧记录立即失效,因此应至少提前一个旧 TTL 周期修改。

使用以下命令验证解析:

dig api.example.com A +short
dig api.example.com AAAA +short
dig @1.1.1.1 api.example.com A
dig @8.8.8.8 api.example.com A

如果不同递归 DNS 返回不同结果,先检查记录是否刚变更、是否存在多条冲突记录,以及域名是否委派到了预期的权威 DNS。还可以执行:

dig example.com NS +short
dig api.example.com +trace

+trace 会显示从根区到权威服务器的查询链,适合定位委派或权威记录问题,但不应把单次结果当成全球解析状态。

建议为 DNS 服务商账号启用多因素认证、独立高强度密码和变更通知。支持 DNSSEC 时,可在充分理解 DS 记录更新流程后启用;错误或残留的 DS 记录可能导致启用校验的递归 DNS 将域名判定为不可用。还可以按证书颁发机构的实际情况配置 CAA,例如:

example.com. 3600 IN CAA 0 issue "letsencrypt.org"

CAA 只是限制允许签发证书的 CA 范围,不能替代账号安全和证书透明度监控。

五、第二步:安装 Nginx 并约束后端监听地址

安装软件:

sudo apt update
sudo apt install -y nginx curl
sudo systemctl enable --now nginx

确认应用只监听本机地址:

sudo ss -lntp | grep ':8080'

理想结果应显示 127.0.0.1:8080,而不是 0.0.0.0:8080。如果应用监听所有网卡,即使 Nginx 配置正确,攻击者仍可能通过公网 IP 加端口绕过 HTTPS、限速和访问日志。应优先修改应用启动参数,例如:

./my-api --host 127.0.0.1 --port 8080

若应用必须监听内网地址,则至少通过安全组和主机防火墙限制来源,只允许反向代理节点访问。

六、第三步:配置 Nginx 反向代理

创建配置文件 /etc/nginx/sites-available/api.example.com:

server {
listen 80;
listen [::]:80;
server_name api.example.com;

location / {
proxy_pass http://127.0.0.1:8080
proxy_http_version 1.1;
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 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
client_max_body_size 10m;
}
}

启用配置并检查语法:

sudo ln -s /etc/nginx/sites-available/api.example.com /etc/nginx/sites-enabled/api.example.com
sudo nginx -t
sudo systemctl reload nginx

不要在未执行 nginx -t 的情况下直接重启。reload 会在配置有效时平滑加载,通常比 restart 更适合线上环境。

X-Forwarded-For 只能在后端确认请求确实来自可信反向代理时使用。若应用端无条件相信客户端直接提交的同名请求头,可能造成审计 IP 被伪造。后端框架应配置可信代理列表,而不是笼统信任所有代理来源。

七、第四步:申请证书并启用 HTTPS

确认域名已经解析到本机、80 端口可从公网访问后,安装 Certbot:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d api.example.com

完成后检查自动续期:

sudo systemctl status certbot.timer
sudo certbot renew --dry-run

生产环境应监控证书剩余有效期,不能只依赖定时任务存在。可使用以下命令查看当前证书信息:

openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates

建议禁用过旧 TLS 协议,仅启用 TLS 1.2 和 TLS 1.3。具体密码套件应结合当前 Nginx、OpenSSL 版本以及客户端兼容范围设置,不要机械复制多年以前的配置。移动端如果仍需兼容老旧系统,应先统计真实客户端版本,再决定兼容边界。

在确认全站 HTTPS 长期稳定后,可以添加 HSTS:

add_header Strict-Transport-Security "max-age=31536000" always;

首次启用时建议先使用较短的 max-age 验证。不要在尚有 HTTP 子域、证书部署不稳定或无法保证长期 HTTPS 时贸然加入 includeSubDomains 或提交 HSTS preload,因为客户端记住策略后,证书或 HTTPS 故障会直接阻断访问。

八、第五步:配置防火墙和 SSH 基础加固

如果使用 UFW,可先放行当前 SSH 服务,再启用防火墙:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status verbose

远程操作时务必保持一个现有 SSH 会话,并另开窗口验证新连接,确认无误后再退出。云服务器还要同步检查云安全组,因为安全组和 UFW 任一层拒绝都会造成连接失败。

SSH 建议使用密钥登录。在确认密钥可用后,再修改 /etc/ssh/sshd_config 或独立的 sshd_config.d 文件:

PasswordAuthentication no
PermitRootLogin no

修改后先验证配置:

sudo sshd -t
sudo systemctl reload ssh

不要在没有备用登录渠道时直接关闭密码认证。数据库端口、应用端口和管理面板不得为了图方便向 0.0.0.0/0 开放。

九、第六步:增加限速、连接控制与基础防护

在 Nginx 的 http 上下文中定义共享区域:

limit_req_zone $binary_remote_addr zone=api_rate:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=api_conn:10m;

然后在 API 的 location 中使用:

limit_req zone=api_rate burst=20 nodelay;
limit_conn api_conn 20;

这些数值只是起点,必须根据接口类型、客户端并发和 NAT 用户规模调整。以单个 IP 限速时,公司网络、校园网或移动运营商出口后的大量正常用户可能共享一个公网 IP,设置过严会误伤。登录、短信、找回密码等高风险接口最好同时在应用层结合账号、设备标识和业务状态做限制,Nginx 限速不能代替应用鉴权。

还应设置合理的 client_max_body_size 和超时时间,防止超大请求体或长期占用连接。对于上传接口,可单独建立 location 并配置不同上限,不要为了一个上传功能把全站限制放大到数 GB。

十、第七步:日志、监控与故障定位

常用检查命令如下:

sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
sudo journalctl -u nginx --since '30 minutes ago'
sudo ss -s
df -h
df -i
free -h

日志本身也可能成为磁盘风险,应确认 logrotate 正常工作:

sudo logrotate -d /etc/logrotate.d/nginx

API 日志不要记录密码、验证码、完整令牌、Cookie、银行卡信息或其他敏感字段。查询参数也可能包含凭证,设计接口时应优先使用 Authorization 请求头,并在代理层和应用层做脱敏。移动 APP 出现“网络错误”时,应按 DNS 解析、TCP 连接、TLS 握手、Nginx 状态码和上游应用日志逐层定位,不要直接把所有问题归因于客户端。

可设置最小化健康检查接口,例如 /healthz,只返回必要状态。健康检查不应暴露数据库地址、版本详情、环境变量或密钥。外部监控可以检查 DNS、HTTPS 状态码和证书有效期,内部监控再检查 CPU、内存、磁盘、连接数、5xx 比例和上游响应时间。

十一、上线验证与回滚

上线前依次执行:

curl -I http://api.example.com
curl -I https://api.example.com
curl --resolve api.example.com:443:203.0.113.10 https://api.example.com/healthz
sudo nginx -t

--resolve 可以在不修改公共 DNS 的情况下,把指定域名临时解析到新服务器,同时仍携带正确的 Host 和 TLS SNI,适合迁移前验证。它只能用于自己的服务或授权环境。

迁移时建议先降低 TTL,在新旧服务器同时保持服务,验证新节点后再切换 A/AAAA 记录。旧服务器至少保留一个观察周期,不要切换后立即销毁。若新节点异常,可恢复旧记录;但由于递归 DNS 缓存存在,回滚不会对所有用户瞬间生效,因此新旧节点在过渡期都应具备处理请求的能力。

十二、风险与注意事项

1. DNS 修改具有缓存延迟,控制台显示成功不等于所有用户立即生效。
2. 发布 AAAA 前必须确认 IPv6 路径、Nginx 监听和防火墙完整可用。
3. 证书私钥应限制读取权限,不能上传到代码仓库或发送到群聊。
4. 代理后的真实 IP 处理必须建立在可信代理边界上。
5. 防火墙变更可能造成远程失联,操作前准备云控制台或带外管理。
6. HSTS、DNSSEC 和 CAA 都有明确使用条件,配置错误可能影响可用性。
7. 限速规则需要结合业务指标调优,不能把安全配置变成拒绝正常用户的原因。
8. 自动续期需要同时验证证书签发、Nginx 加载和外部访问结果。

十三、常见问题

问:DNS 已解析,为什么浏览器仍打不开?
答:依次检查本地解析结果、安全组、UFW、Nginx 是否监听 80/443、证书是否匹配域名,以及后端是否监听 127.0.0.1:8080。使用 curl -v 可以区分 DNS、连接、TLS 和 HTTP 层错误。

问:出现 502 Bad Gateway 怎么排查?
答:502 通常表示 Nginx 无法从上游获得有效响应。检查应用进程、监听地址和端口,再看 Nginx error.log。还要确认 proxy_pass 使用的协议是否正确,例如上游只提供 HTTP 时不要写成 https。

问:出现 504 Gateway Timeout 是服务器带宽问题吗?
答:不一定。504 更常见于上游处理超时、数据库查询缓慢或依赖服务无响应。盲目增大 proxy_read_timeout 只会延后报错,应结合上游耗时和日志定位根因。

问:已经有云安全组,还需要 UFW 吗?
答:两者可以形成分层防护。安全组负责云平台边界,主机防火墙负责实例自身策略。但必须维护一致的变更记录,避免排障时遗漏其中一层。

问:能否直接把应用的 8080 端口开放给客户端?
答:通常不建议。这样会绕过 Nginx 的 TLS、限速、请求大小限制和统一日志。更稳妥的方式是让应用仅监听环回地址,通过 443 对外服务。

十四、总结

一套可靠的域名与服务器部署,不只是把 A 记录指向公网 IP。完整流程应包括:合理规划 DNS 和 TTL、验证权威解析、让后端仅监听可信地址、通过 Nginx 统一承载 HTTPS、最小化开放端口、配置适度限速、保护日志与凭证,并提前准备迁移和回滚方案。

对于网站和 APP API,最重要的安全原则是减少可直接接触的入口,并让每一层都能够被验证和监控。先通过 ss、dig、curl、openssl 和日志确认现状,再逐项加固,比一次复制大量来源不明的配置更安全,也更容易在故障发生时快速定位。
 

xiaobinz08

New member

xiaobinz08 Rep
0
0
0
Rep
0
xiaobinz08 Vouches
Vouches
0
1 MONTH
1 1 MONTH OF SERVICE
xiaobinz08 获得
0
0
0
获得
0
xiaobinz08 凭证
0
0
0
凭证
0
主题
12
点赞
0
HakB
1 月
在社区成长 1 月
LEVEL 1 1 XP
 
建议补一项可验证的上线回滚流程:切换 DNS 前,先用 `curl --resolve api.example.com:443:新IP https://api.example.com/health` 绕过公共解析,核验证书、SNI、Nginx 路由及后端健康状态;再从外网确认 8080 端口不可达。Nginx 配置应纳入版本管理,发布时先执行 `nginx -t`,并保留上一版配置和旧源站至少一个 TTL 周期。限速也应按接口区分,登录、验证码等高风险端点宜使用更严格的独立规则,避免全局限速误伤正常 API。
 
顶部