查询 25 次,耗时 0.2151 秒

从域名解析到源站上线:一套可回滚、可验证的 HTTPS 服务器部署与安全加固流程

132222222222222qaz

New member

132222222222222qaz Rep
0
0
0
Rep
0
132222222222222qaz Vouches
Vouches
0
1 MONTH
1 1 MONTH OF SERVICE
132222222222222qaz 获得
0
0
0
获得
0
132222222222222qaz 凭证
0
0
0
凭证
0
主题
2
点赞
0
HakB
1 月
在社区成长 1 月
LEVEL 1 1 XP
 
一、背景与目标

域名上线并不只是“添加一条 A 记录”。一次完整且可靠的部署至少涉及权威 DNS、递归缓存、IPv4/IPv6、TLS 证书、Web 服务、系统防火墙、反向代理、监控和回滚策略。实践中常见的事故包括:修改解析后无法快速回退、AAAA 记录指向未配置的 IPv6 服务、证书续期被防火墙阻断、开启 DNSSEC 时 DS 配置错误导致整个域名无法解析,以及源站仅依赖 CDN 隐藏却没有真正限制直连访问。

本文以 example.com 和一台 Debian/Ubuntu 系服务器为示例,目标是部署 www.example.com 的 HTTPS 服务。所有地址和域名均为文档占位符,操作时应替换为自己有权限管理的资源。涉及端口探测和验证的命令仅应针对自有服务器、本地实验环境或明确授权的测试目标。

二、工作原理与风险边界

用户访问 https://www.example.com 时,通常经历以下链路:

1. 递归 DNS 服务器查询域名的 A 或 AAAA 记录;
2. 客户端连接解析得到的 IPv4 或 IPv6 地址;
3. TLS 握手期间,服务器根据 SNI 返回对应证书;
4. Nginx 等反向代理接收请求,再转发到本机应用端口;
5. 应用响应经反向代理返回客户端。

因此,“DNS 已生效”不等于“网站可用”。必须分别验证权威解析、公共递归解析、TCP 端口、TLS 证书、虚拟主机和后端应用。

TTL 也不是严格的全球倒计时。递归服务器会在缓存剩余时间结束后重新查询,但客户端、操作系统或应用可能存在额外缓存。降低 TTL 只影响降低之后新获取的记录,无法提前清除已经缓存的旧记录。

三、前置条件

1. 已注册并可管理 example.com;
2. 拥有 DNS 服务商控制台或权威 DNS 配置权限;
3. 一台具有固定公网地址的 Linux 服务器;
4. 可通过密钥登录的普通管理用户,并具备 sudo 权限;
5. 安全组或上游防火墙允许必要的 22、80、443 端口;
6. 本地安装 dig、curl 和 openssl;
7. 应用先监听在本机地址,例如 127.0.0.1:3000,而不是直接暴露到公网。

不要在确认 IPv6 路由、防火墙和 Web 服务均正常之前添加 AAAA 记录。部分客户端会优先尝试 IPv6,错误的 AAAA 记录可能造成“部分用户打不开”的间歇性故障。

四、第一阶段:建立基线并设计回滚

上线前记录旧值:

dig +noall +answer example.com A
dig +noall +answer www.example.com A
dig +noall +answer www.example.com AAAA
dig +noall +answer example.com CAA

在 DNS 控制台导出现有区域记录,至少保存记录名、类型、值、TTL 和代理状态。若计划次日迁移,可提前 24 小时将目标记录 TTL 从较大值降到 300 秒。迁移完成并稳定运行后,再恢复到 1800 或 3600 秒,避免权威 DNS 承担不必要的查询压力。

回滚条件应事先明确,例如:持续五分钟 HTTP 5xx 超过 2%、证书验证失败、关键接口不可用,或新服务器负载明显异常。回滚动作通常是把 A/AAAA 记录恢复到旧地址,并确保旧服务器在至少一个最长缓存周期内保持可用。不要在切换解析后立即销毁旧实例。

五、第二阶段:初始化服务器与 SSH 加固

更新系统并安装基础组件:

sudo apt update
sudo apt full-upgrade -y
sudo apt install -y nginx ufw fail2ban curl dnsutils unattended-upgrades

创建独立管理账户并配置公钥后,再调整 /etc/ssh/sshd_config。建议确认以下配置:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3

修改后先检查语法:

sudo sshd -t
sudo systemctl reload ssh

风险提示:不要在唯一 SSH 会话中直接关闭密码登录。应先打开第二个终端,确认密钥账户能够成功登录,再保留现有会话执行 reload。若云平台提供串口控制台或救援模式,也应提前确认可用。

配置主机防火墙:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

云安全组与 UFW 是两层控制,任意一层拒绝都会导致连接失败。应用端口 3000 不应对公网放行,只需监听 127.0.0.1。

六、第三阶段:部署应用和 Nginx 反向代理

假设应用健康检查位于 http://127.0.0.1:3000/health,先在服务器本机验证:

curl -fsS http://127.0.0.1:3000/health
ss -lntp | grep 3000

若 ss 显示 0.0.0.0:3000,说明应用监听了所有 IPv4 网卡。优先修改应用配置为 127.0.0.1:3000,而不是仅依赖防火墙隐藏端口。

创建 /etc/nginx/sites-available/example.com:

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

location / {
proxy_pass http://127.0.0.1:3000
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_read_timeout 30s;
}
}

启用站点并检查配置:

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

在修改公网 DNS 之前,可以使用 curl 的 resolve 参数验证指定 IP 上的虚拟主机。假设新服务器地址为 203.0.113.10:

curl -v --resolve www.example.com:80:203.0.113.10 http://www.example.com/

该方法只在本次 curl 请求中覆盖解析,不会修改系统 hosts 文件,适合上线前验证 Host 匹配和 Nginx 转发逻辑。

七、第四阶段:配置 DNS 并验证传播

常见配置如下:

example.com. A 203.0.113.10
www.example.com. CNAME example.com.

若已经完整配置 IPv6,可增加:

example.com. AAAA 2001:db8::10

注意,203.0.113.0/24 和 2001:db8::/32 是文档示例网段,不能作为真实生产地址。

修改后分别查询权威服务器和公共递归服务器。先找到权威 NS:

dig +short NS example.com

然后向某台权威服务器直接查询:

dig @ns1.dns-provider.example example.com A +noall +answer

再检查递归视角:

dig @1.1.1.1 example.com A +noall +answer
dig @8.8.8.8 example.com A +noall +answer

若权威结果正确而递归结果仍旧,通常是缓存尚未到期;若权威结果本身错误,应优先检查记录名、区域、是否误填完整域名,以及 DNS 服务商是否自动追加根域名。

八、第五阶段:申请 TLS 证书

可使用发行版提供的 Certbot 和 Nginx 插件:

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

申请前应确保域名已指向当前服务器,且公网能够访问 80 端口。HTTP-01 验证通常需要验证机构访问特定 HTTP 路径。如果源站只允许 CDN 节点访问,或强制认证、错误重写验证路径,自动签发可能失败。此时可以使用 DNS-01,但应选用受支持的 DNS API,并将 API 凭据限制到所需区域和最小权限,不能把全账户主密钥长期存放在服务器上。

验证续期流程:

sudo certbot renew --dry-run

检查证书内容和有效期:

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

SNI 参数不可省略,否则多站点服务器可能返回默认证书。证书自动续期成功也不代表 Nginx 一定加载了新证书,应同时关注续期任务日志和 HTTPS 实际返回的证书日期。

九、安全响应头与 TLS 注意事项

可在 HTTPS server 块中按业务兼容性添加:

add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
add_header X-Frame-Options SAMEORIGIN always;

HSTS 应谨慎启用。只有确认域名及必要子域名长期支持 HTTPS 后,才考虑:

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

不要在测试阶段直接添加 includeSubDomains 或提交预加载列表。HSTS 会被浏览器缓存,配置失误无法通过简单回滚 DNS 立即消除,可能使尚未支持 HTTPS 的子域名不可访问。

内容安全策略 CSP 也不适合盲目复制。应先使用 Content-Security-Policy-Report-Only 收集违规情况,再根据实际脚本、样式和第三方资源制定策略,否则可能破坏前端功能。

十、DNSSEC 与 CAA

DNSSEC 用于让验证型递归服务器校验 DNS 数据的真实性和完整性,但不负责加密 DNS 查询。启用时通常需要 DNS 服务商生成区域签名,并在注册商侧发布 DS 记录。最大风险是 DS 与当前 DNSKEY 不匹配:验证型解析器会将结果视为失败,表现为 SERVFAIL。

启用后可检查:

dig example.com A +dnssec
dig example.com DS +short

不能只看到 RRSIG 就认定整条信任链有效,可使用支持验证的工具或多个验证型递归服务交叉检查。迁移 DNS 服务商时,应严格遵循双方的 DNSSEC 迁移流程;不确定时不要同时仓促更换 NS、DNSKEY 和 DS。

CAA 可限制哪些证书颁发机构被授权为域名签发证书。例如:

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

具体值应根据实际使用的证书机构填写。配置错误可能阻止后续签发或续期,因此应在增加 CAA 后执行一次测试签发或续期演练。CAA 不是替代证书透明度监控、私钥保护或 TLS 配置的万能措施。

十一、性能与可观测性

性能优化应基于测量,而不是无条件增加缓存。先观察 Nginx 请求耗时、上游响应时间、状态码和连接数。建议在日志格式中加入 $request_time 与 $upstream_response_time,并确保日志轮转生效。

静态文件可按内容版本策略设置缓存,例如带哈希文件名的资源:

location ~* \.(css|js|png|jpg|svg|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}

如果文件名不会随内容变化,不应设置过长 immutable 缓存,否则发布新版本后客户端可能长期使用旧内容。动态接口也不能仅为追求命中率而缓存包含用户数据或鉴权结果的响应。

启用 gzip 前可确认 CPU 余量和资源类型。对于已经压缩的图片、视频和归档文件,再压缩通常收益有限。HTTP/2 可提升多资源场景下的连接复用效果,但实际结果仍应通过浏览器开发者工具或压测数据验证。

基础检查命令包括:

systemctl status nginx --no-pager
journalctl -u nginx --since "10 minutes ago"
tail -f /var/log/nginx/access.log /var/log/nginx/error.log
ss -s
df -h
free -h

监控至少覆盖:DNS 解析结果、TCP 连接、TLS 到期时间、HTTP 状态码、响应时间、磁盘空间、内存、CPU 和应用进程状态。仅监控 ping 不足以判断 HTTPS 服务是否正常。

十二、上线后的验证清单

1. dig 返回预期 A/AAAA/CNAME,且不存在意外的旧记录;
2. IPv4 与 IPv6 分别测试,curl -4 和 curl -6 均符合预期;
3. HTTP 正确跳转 HTTPS,且不存在循环重定向;
4. 证书域名、签发链和有效期正确;
5. 直接访问健康检查和关键业务路径均返回预期状态;
6. 外网只能访问明确开放的端口;
7. 应用端口仅监听回环地址;
8. Certbot dry-run 成功;
9. 日志轮转、监控和告警已验证;
10. 旧服务器尚未销毁,DNS 回滚值可立即恢复。

可执行:

curl -4 -I https://www.example.com/
curl -6 -I https://www.example.com/
curl -sS -o /dev/null -w 'code=%{http_code} connect=%{time_connect} tls=%{time_appconnect} total=%{time_total}\n' https://www.example.com/

十三、常见问题

问题一:本地能访问,其他地区不能访问。

先比较不同递归 DNS 的结果,再检查是否存在错误 AAAA 记录、区域线路解析差异或仅允许了本地出口 IP。不要仅用一台电脑的浏览器缓存判断全球生效情况。

问题二:域名解析正确,但浏览器提示证书不匹配。

检查 Nginx 的 server_name、443 监听块和证书包含的 SAN。使用 openssl s_client 时必须带 -servername,以确认特定 SNI 下返回的证书。

问题三:启用 CDN 后源站仍能被直接访问。

隐藏 DNS 记录不等于隐藏源站。可以在确认 CDN 出口地址范围及其更新机制后,仅允许可信代理访问 80/443,并通过受控请求头或双向 TLS进一步验证回源身份。若直接信任客户端可伪造的 X-Forwarded-For,会导致日志、限流和访问控制失真。

问题四:DNSSEC 开启后部分网络出现 SERVFAIL。

重点检查注册商处 DS 是否与当前权威 DNS 发布的 DNSKEY 对应,以及更换 DNS 服务商后旧 DS 是否仍存在。DNSSEC 故障不应通过反复随机改记录处理,应先核对信任链和变更时间线。

问题五:证书首次申请成功,几个月后续期失败。

常见原因是 80 端口后来被关闭、验证路径被重写、DNS 已切到其他服务器、DNS API 令牌失效,或续期任务未运行。应设置证书剩余天数告警,而不是完全依赖定时任务。

十四、总结

可靠的域名与服务器上线应当具备三个特征:变更前有基线和回滚方案,变更中按 DNS、网络、TLS、反向代理和应用逐层验证,变更后有持续监控和自动续期检查。安全加固也需要明确边界:防火墙不能替代应用鉴权,CDN 不能自动保护未限制的源站,DNSSEC 不能加密查询,CAA 不能替代私钥保护,HSTS 也不应在未评估子域名兼容性时贸然开启。

最稳妥的实施顺序是:先在新服务器完成本机验证,再用 curl --resolve 测试虚拟主机,随后降低 TTL 并切换 DNS,最后验证 TLS、IPv4/IPv6、监控和回滚。每一步都保留可观测证据,而不是仅凭“浏览器能打开”判断上线成功。
 
顶部