域名解析到端口为何无效:Nginx反向代理与四层转发配置指南
2026/9/17 1:38:17 网站建设 项目流程

上周有位做后端的读者私信我,说他把域名解析到了一个 Linux 服务器上,但访问时地址栏里那个:8080怎么都去不掉,问我"域名解析能不能直接指到端口上"。说实话,这个问题我这些年被问过不下二十次,而且问的人里既有刚买云服务器的新手,也有写了几年代码、只是没碰过运维的同事。答案有点反直觉:域名解析这一步,压根就不管端口。DNS 这套体系从设计之初只负责一件事——把人类看得懂的域名翻译成 IP 地址,仅此而已。

那为什么我们日常见到的https://xxx.com又确实没有端口尾巴?因为那是 443 端口做了隐藏,前面还站着一个反向代理在替我们转流量。所以"把域名解析到指定端口"这个需求是真实存在的,只是实现它的正确姿势不是改 DNS,而是在服务器上做一层转发。这篇就按我自己的实操习惯,从原理讲到配置,把 Nginx 反向代理、四层转发、SRV 记录、端口占用排查这几条路全部走一遍,配置可以直接抄,坑我也一并标出来。适合刚上手 Linux 服务器、想让自己项目看起来"正规一点"的朋友,也适合运维顺手补漏。

1. 先接受一个反常识的结论:DNS 从来不认端口

1.1 DNS 查询链路里到底发生了什么

很多人对域名解析的印象停留在"在控制台填个 IP,回车,生效"。这个印象不能说错,但它跳过了中间最关键的几层。完整的解析过程大致是这样:你在浏览器里敲下域名并回车,浏览器先查自己的缓存,再查操作系统的 DNS 缓存,再看/etc/hosts有没有手工写死的记录。这几步都没命中,请求才会发给操作系统配置的递归解析服务器——也就是resolv.conf里那个 nameserver 地址,通常是运营商给的,或者你自己指定的公共 DNS。

递归服务器拿到查询后,如果它也没有缓存,就会代替你去"逐级问路":先找根域名服务器,根服务器告诉它去问对应的顶级域服务器;顶级域服务器再告诉它去问这个域名的权威域名服务器;最后权威服务器返回真正的记录值。整条链路走完,递归服务器把结果缓存下来,TTL 到期之前,同一个域名再来问就直接返回缓存。你可以用dig +trace example.com亲眼把这条路走一遍,输出会一级一级列出来。

重点来了:这条链路上无论哪一级,返回的记录类型只有 A、AAAA、CNAME、MX、TXT、NS、SRV 这几种。A 记录返回 IPv4 地址,AAAA 返回 IPv6 地址,CNAME 返回另一个域名,MX 管邮件投递,TXT 挂各种校验文本,NS 指明权威服务器。没有任何一种记录类型里的字段是留给"端口"的。换句话说,DNS 协议本身就没有设计"域名指向 8080 端口"这种表达能力。

1.2 那句"解析到端口"实际想表达什么

把用户的话翻译成技术语言,他们的真实诉求通常是这两类:一类是"我不想在地址栏里看到端口号",希望访问app.example.com时能直接打开我跑在 8080 上的服务;另一类是"我有好几个服务跑在同一台机器上不同端口,想用不同子域名分别指过去"。这两种需求的共同点是:DNS 已经完成了它的工作——域名成功指向了服务器 IP,问题出在流量到达服务器之后,没有被送到正确的端口上。

这里打个生活化的比方。DNS 干的事相当于告诉快递员"这个包裹送到某某路 5 号楼",至于包裹进了楼以后该放 3 楼还是 8 楼,那是楼里电梯和门牌号的事,跟快递系统无关。端口就是"楼层号",它属于传输层的信息,由 TCP/UDP 协议头携带,DNS 报文里根本没有这个字段。所以我们要做的,是在"楼里"安排一个引导员,把所有进楼的包裹按规则送上对应楼层。这个引导员,就是反向代理或者端口转发规则。

1.3 四条落地路线先摆在一起对比

既然改 DNS 无效,我们把可行的方案横向摆一下,心里先有个谱再动手。下面这张表是我这几年反复用的选型依据,注意第三条限制比较多,别一上来就往那儿撞。

方案适用场景需要条件客户端是否还要带端口复杂度
Nginx 反向代理(七层)网站、API、前后端分离项目装 Nginx,有 80/443不需要
Nginx stream / firewalld 端口转发(四层)SSH、数据库、游戏服、私有协议内核转发开启不需要
DNS SRV 记录SIP、XMPP、部分游戏客户端客户端协议必须支持 SRV看客户端实现
URL 直接带端口访问快速验证、内网环境无需额外配置需要极低

看清楚这张表,后面的内容就顺了。七层反向代理是绝大多数 Web 场景的最优解,因为它不只是转发,还能顺手处理 HTTPS 证书、静态资源、请求头、压缩,等于花一份力气办好几件事。四层转发解决的是"非 HTTP 协议怎么办",比如你想让ssh.example.com直接连到服务器,这就得靠 stream 模块或者防火墙的 DNAT 规则。SRV 记录是特例中的特例,浏览器完全不认它,所以做网站的朋友可以直接跳过第三条。至于 URL 带端口,那是调试期的临时手段,不是最终方案。

2. 动手前先摸清地基:域名、服务器、端口三件事

2.1 A 记录、CNAME 和 TTL 的三分钟速通

不管走哪条路,第一步永远是让域名正确指向服务器。进入域名注册商的控制台,找到 DNS 解析设置,新增一条记录:记录类型选 A,主机记录填app(代表app.example.com)或者填@(代表裸域名example.com),记录值填服务器的公网 IP。保存之后,通常几十秒到几分钟就能生效。这里有个容易被忽略的细节:如果你希望www.example.com也能访问,需要单独再加一条 A 记录或者加一条 CNAME 指向主域名,很多人只加了@就开始调服务,结果发现 www 打不开,白白排查半小时。

CNAME 和 A 记录的取舍也值得说一句。A 记录直接指向 IP,速度快、层级少;CNAME 指向另一个域名,好处是主域名换了 IP 时,所有 CNAME 记录自动跟着变,不用挨个改。我的习惯是:裸域名用 A 记录,各种业务子域名用 CNAME 指向一个统一的主机名,这样以后迁服务器只改一处。TTL 字段控制缓存时长,默认六百秒左右,调试阶段可以调小到六十秒,方便快速验证,等服务稳定了再调回大值减少查询压力。

顺带提醒一个常见误区:改了 DNS 解析,本地机器不一定马上生效,因为上游递归服务器的缓存还没过期。这时候别急着怀疑配置有问题,先用dig @223.5.5.5 你的域名指定一个公共 DNS 查询,看返回的 IP 对不对。如果指定的公共 DNS 已经返回新 IP,而你自己电脑还是旧 IP,那纯粹是本机或运营商缓存的问题,等 TTL 到期自然就好。

2.2 服务器侧必须先确认的三件事

域名这一头搞定,转头看服务器。我见过太多人卡在"域名能 ping 通但服务访问不了",八成是下面三件事没确认。第一件是服务监听地址。用ss -tlnp看一眼你的服务监听在哪个地址上。如果是127.0.0.1:8080,那它只接受本机连接,外网流量根本进不来——这是新手最常踩的坑,尤其是本地开发时图省事写死 localhost 的项目,部署上去忘了改。正确的做法是让服务监听0.0.0.0:8080或者直接监听所有网卡。

第二件是云服务商的安全组。安全组是云平台层面的第一道墙,优先级比系统防火墙还高。默认情况下,只有 22 端口(SSH)是放行的,80、443、8080、3000 这些统统要手动加规则。加规则时注意方向选"入方向",协议选 TCP,端口范围可以写单个端口也可以写区间如8000-8100,来源建议不要图省事写0.0.0.0/0全开,尤其是数据库端口,能限制来源 IP 就限制。

第三件是系统防火墙。CentOS 系跑 firewalld,Ubuntu 系一般是 ufw,老点的机器可能还在用 iptables。热词里老有人搜"centos 防火墙开放 tcp 端口配置文件",其实就是想知道 firewalld 怎么加端口。命令不复杂:

# firewalld 放行 80 和 443 firewall-cmd --permanent --add-port=80/tcp firewall-cmd --permanent --add-port=443/tcp firewall-cmd --reload # 查看已放行的规则 firewall-cmd --list-all

如果是 ufw,对应的命令是ufw allow 80/tcp然后ufw reload。别小看这两行,它就是很多人"安全组开了、服务也起了、就是连不上"的最后一道坎。

2.3 端口怎么挑才不给自己挖坑

选端口这件事看着随意,其实有讲究。1024 以下的端口属于特权端口,非 root 身份的程序绑不上,所以你的服务如果不用 root 启动,就只能选 1024 以上。80 和 443 虽然常用,但它们是留给 HTTP/HTTPS 标准服务的,也就是说如果你打算用 Nginx 做入口,那两个端口自然就被 Nginx 占了,你的业务服务放到 8080、3000、5000 这类高位端口更合适。注意 macOS 上的 AirPlay 会占用 5000 端口,如果你后续用 Mac 做本地调试可能撞车,我一般偏向 8080 或者 3000。

另外有几个端口是绝对不能随便对外暴露的。MySQL 的 3306、Redis 的 6379、MongoDB 的 27017,这些数据库端口一旦暴露到公网,快则几小时就会被扫到并尝试爆破。热词里搜索"端口被占"的人很多,搜索"nmap 扫描端口命令"的也不少,我的建议是把 nmap 用在自己的服务器上做个体检:nmap -Pn -p 1-10000 你的公网IP,看看哪些端口意外地开着。扫描结果里出现数据库端口而你又没主动开放,那就要去安全组和防火墙里找原因了。

再补一个运维小知识:服务器时间不准会引发一堆莫名其妙的故障,比如 HTTPS 证书被判定无效、日志时间线错乱、集群节点认证失败。所以新机器上手先配好时间同步,指向国内的时间服务器地址同步一下,chronyc sources看一眼同步源是否正常。这事跟域名解析没直接关系,但属于同一批"基础设施体检项",顺手做了不亏。

3. 方案一:Nginx 反向代理,Web 场景的最优解

3.1 装好 Nginx 并写一份最小可用配置

Nginx 在不同发行版的安装方式不太一样。Ubuntu/Debian 系直接apt install nginx,CentOS/RHEL 系需要先加 EPEL 源再yum install nginx。国产 Linux 发行版(比如麒麟)基本也走 yum/dnf 这一套,包名一致,装完用systemctl enable --now nginx启动并设置开机自启。装完访问一下公网 IP,看到 Nginx 的默认欢迎页,说明 80 端口这条链路已经通了,接下来就是改配置。

配置文件的位置各发行版略有差异,主配置在/etc/nginx/nginx.conf,站点配置通常放在/etc/nginx/conf.d/或者/etc/nginx/sites-available/。我习惯在conf.d/下新建一个以域名命名的文件,比如app.example.com.conf,写进去:

server { listen 80; server_name app.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_read_timeout 300s; } }

写完务必执行nginx -t检查语法,看到syntax is oktest is successfulsystemctl reload nginx。这一步养成习惯,能省掉大量"改完没生效还以为是自己写错了"的时间。重启和 reload 的区别也顺带说一下:reload 是平滑重载,不断开已有连接;restart 是直接重启,会短暂中断服务。生产环境优先用 reload。

3.2 逐行拆解:那些 proxy_set_header 到底在干嘛

配置能跑不等于配置正确。上面那几行proxy_set_header看着像模板套话,实际每一行都在解决一个具体问题,缺了就出 bug,我把它们挨个说清楚。

proxy_pass http://127.0.0.1:8080是核心指令,意思是把所有匹配到location /的请求转发给本机的 8080 端口。注意这里写的是127.0.0.1,因为后端服务和 Nginx 在同一台机器上,走回环网卡最快也最安全,不用绕公网。

proxy_set_header Host $host解决的是"后端收到的主机名是错的"这个问题。如果不加这行,后端程序看到的 Host 头会是127.0.0.1:8080,而不是用户实际访问的域名。很多框架会拿 Host 来生成跳转链接或者做域名校验,Host 一错,就会出现登录后跳回 127.0.0.1、跨域校验失败这类诡异现象。这行基本属于必加项。

X-Real-IPX-Forwarded-For是为了让后端拿到用户真实 IP。经过代理之后,后端看到的来源 IP 都是 Nginx 本机地址,如果程序里有按 IP 限流、记录访问日志的需求,就必须靠这两个头把原始 IP 透传下去。X-Forwarded-Proto则告诉后端用户走的是 http 还是 https,避免后端生成混合内容链接被浏览器拦截。

proxy_http_version 1.1加上UpgradeConnection两个头,是为了让 WebSocket 能正常工作。默认情况下 Nginx 用 HTTP/1.0 转发,不支持长连接升级,如果你的项目里有实时推送、聊天、进度条这类功能,不加这三行会一直连不上。这套组合拳我一般是作为默认模板直接带上,不等到出问题再回头补。

3.3 让 443 接管一切,顺手上 HTTPS

80 端口跑通之后,强烈建议把 HTTPS 也配上。原因不只是安全,还有一个很实际的体验问题:现在浏览器对 http 站点会在地址栏打上"不安全"标记,而且很多前端能力(比如定位、摄像头、剪贴板)在非安全上下文里直接被禁用。上 HTTPS 之后,用户访问https://app.example.com,端口更是天然隐形。

证书获取有两条路。一条是用 Let's Encrypt 的自动签发工具,另一条是用云服务商提供的免费证书,下载下来手工配置。我一般推荐前者,因为续期全自动,省心。签发工具装好之后,它会自动读取你 Nginx 配置里的server_name,自动申请证书并回写配置,全程不用手写。生成的配置大致是这样:

server { listen 443 ssl; server_name app.example.com; ssl_certificate /etc/nginx/ssl/app.example.com.pem; ssl_certificate_key /etc/nginx/ssl/app.example.com.key; location / { proxy_pass http://127.0.0.1:8080; 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; } } server { listen 80; server_name app.example.com; return 301 https://$host$request_uri; }

第二个 server 块的作用是把所有 http 请求永久重定向到 https,这样用户不管怎么输都能落到安全连接上。注意重定向用的是 301,浏览器会记住这个规则,后续直接走 https,减少一次往返。

注意:证书文件路径要对,权限也要对。私钥文件建议设成 600 权限且属主为 root,Nginx 用 root 启动 worker 进程时才能读到。如果nginx -t报权限错误,八成是私钥权限放太开了或者属主不对。

3.4 安全组和防火墙:域名通了但服务不通的第一元凶

Nginx 配好了,证书也装了,结果浏览器转圈圈——这时候按顺序掐三处。第一处是安全组,去云控制台确认 80 和 443 的入方向规则存在且生效。第二处是系统防火墙,用firewall-cmd --list-portsufw status看端口是否放行。第三处是服务本身是否在监听,ss -tlnp | grep -E ':(80|443)'能看到 Nginx 的 master 进程就说明它起来了。

有个细节值得单独提:如果你用的是云厂商的负载均衡或者 CDN 在前、源站在后,安全组的来源可能被限制成只允许负载均衡的地址段访问。这种情况下你用自己电脑 curl 直连源站 IP 会失败,但通过域名访问又是正常的,别被这个现象误导。判断方法是curl -I http://你的公网IP,如果直连失败、走域名成功,基本可以确定是这个原因。

再补充一个 SELinux 相关的坑,CentOS 系机器上特别常见。SELinux 默认策略不允许 Nginx 主动向外发起网络连接,于是反向代理到本地 8080 时会被拦下来,日志里报 permission denied,错误码一般是 502。解决办法是放行这个布尔值:

getsebool -a | grep httpd_can_network setsebool -P httpd_can_network_connect on

-P参数表示持久化,重启后依然生效。不加-P只是临时打开,重启就白干了,这个细节很多人会漏。

4. 方案二:四层转发,让 SSH、数据库也能"隐藏端口"

4.1 用 Nginx stream 模块转发 TCP 流量

HTTP 场景用七层代理就够了,但如果你想让ssh.example.com直接连着登录服务器,或者想把数据库端口包装成一个域名,那就得用四层转发。Nginx 从 1.9 版本开始内置了 stream 模块,能转发 TCP 和 UDP。关键点在于:stream 块必须和 http 块平级,写在 nginx.conf 的顶层,不能塞进 http 里面。这一点和 server 块的写法完全不同,新手经常写错位置导致语法检查直接失败。

一个典型配置如下:

stream { upstream sshd_backend { server 127.0.0.1:22; } server { listen 2222; proxy_pass sshd_backend; proxy_timeout 600s; proxy_connect_timeout 10s; } }

这份配置的意思是:Nginx 监听 2222 端口,把所有 TCP 连接转发到本机的 22 端口。用户执行ssh -p 2222 user@example.com就能登录。有人会问,那能不能直接让 22 端口对外?可以是可以,但公网 22 端口每天会被扫描器敲几千次,日志里全是爆破记录。换个高位端口,再配上限流和密钥登录,骚扰量能下降九成以上。

proxy_timeout这个参数要留意,默认值只有十分钟,SSH 挂久了会被切断。如果你要长时间开着终端跑任务,调大一些更稳妥。proxy_connect_timeout控制连接后端的超时,设短点能让故障暴露更快。

4.2 firewalld 和 iptables 的端口转发写法

不想装额外模块的话,直接用系统自带的防火墙做转发也行。原理是网络地址转换——在数据包进入本机时把目标端口改写成另一个端口。用 firewalld 的写法:

# 开启转发功能 firewall-cmd --permanent --add-masquerade firewall-cmd --permanent --add-rich-rule='rule family=ipv4 forward-port port=80 protocol=tcp to-port=8080' firewall-cmd --reload

老一点的机器上还在用 iptables,对应的规则是:

# 先确保内核开启转发 sysctl -w net.ipv4.ip_forward=1 # 把进入 80 端口的流量重定向到 8080 iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080

这里有个非常容易忽略的点:iptables 的规则是临时的,重启就没了。要持久化得用iptables-save把规则写进配置文件,或者装iptables-services用服务方式管理。很多人调通了很开心,第二天重启服务器发现又不行了,就是栽在这里。

另外注意REDIRECTDNAT的区别。REDIRECT是把流量转到本机的另一个端口,适合本机转发;DNAT-j DNAT --to-destination 目标IP:端口)能把流量转到另一台机器,适合做内网跳板。用错指令会出现"规则加了但不生效"的情况,特别是目标地址写成本机公网 IP 时,由于回环路径问题,效果和预期完全不同。

4.3 四层和七层到底该选哪个

这两种方式不是替代关系,而是分工。七层代理看得懂 HTTP 协议,所以能做基于域名的路由、能改请求头、能缓存、能自动配 HTTPS,代价是它只能处理 HTTP/HTTPS。四层转发只管搬运字节,不关心内容,所以任何基于 TCP/UDP 的协议它都能转,包括 SSH、MySQL、Redis、自研的二进制协议、游戏服务端等等。

我的实际判断标准很简单:如果这个服务是给浏览器访问的,一律走 Nginx 七层反向代理;如果是给专门的客户端连的(比如数据库工具、SSH 客户端、游戏客户端),走四层转发。同一个域名下既有网页又有 WebSocket,七层也能一并处理,因为 WebSocket 本质上还是 HTTP 升级来的。只有当你需要同时转发的端口数量很多、协议很杂的时候,才考虑上专业的四层负载组件。

提示:不要用四层转发把数据库端口暴露给公网。即使换了域名、换了端口,扫描器照样能发现。数据库远程访问更稳妥的做法是走 SSH 隧道,或者限定来源 IP 白名单。

5. 方案三:SRV 记录和"URL 直带端口"的真相

5.1 SRV 记录能做什么,不能做什么

SRV 记录是 DNS 里唯一一个能携带端口信息的记录类型,格式大致是_service._proto.name TTL IN SRV 优先级 权重 端口 目标主机。看到那个"端口"字段,很多人眼睛一亮——这不就是我想要的吗?先别高兴太早。SRV 记录能不能用,完全取决于客户端实现认不认它。浏览器不认,curl 不认,绝大多数的 HTTP 客户端都不认。真正支持 SRV 的,是那些在协议规范里明确写了要走 SRV 查询的服务,比如部分即时通讯协议、目录服务、Minecraft 客户端等。

所以如果你的目标是让域名访问网站不带端口,SRV 记录这条路可以直接放弃,别浪费时间。它的存在价值是在那些"协议层面约定好了"的场景里,让服务发现更灵活,比如同一个域名下多个服务实例按权重分配流量。这属于进阶话题,日常做 Web 项目基本用不上。

写 SRV 记录时还有两个坑:一是主机记录里必须带上服务名前缀和下划线,比如_sip._tcp,写成别的形式解析不出来;二是目标主机最好写完整域名并且以点结尾,否则有些解析器会自动追加当前域名后缀,导致指向错误的地址。这两点在控制台里没有校验,写错了不会报错,只会静默失效。

5.2 URL 里带端口的正确姿势和它带来的麻烦

回到最原始的方式:直接访问http://example.com:8080。这种方式确实不需要任何服务器配置,域名解析生效 + 端口放行就能用,适合调试期快速验证。但它有几个实实在在的麻烦,迟早会逼着你上反向代理。

第一个麻烦是端口冲突和记忆负担。项目一多,你得记住哪个服务在哪个端口,团队协作时天天要复述端口号。第二个麻烦是前端跨域。如果你的页面在 80 端口,接口在 8080 端口,浏览器会判定为跨域请求,需要后端配合配置跨域头,多一层不必要的复杂度。第三个麻烦最隐蔽:有些第三方服务在回调地址里不接受带端口的 URL,比如支付回调、登录回调,填了端口直接被拒。这意味着你迟早得挪到标准端口上。

还有一个细节值得说清楚:HTTP 和 HTTPS 的默认端口不一样,浏览器对它们的处理也不同。访问https://example.com:443时浏览器会自动隐藏 443,同理http://example.com:80会隐藏 80。有人因此误以为自己"解析到端口成功了",其实是恰好用了默认端口。换成:8080试试,端口号立刻显形。理解这一点,你就明白为什么上 Nginx 加 HTTPS 之后,端口尾巴自然而然就没了。

6. 全链路验证:从 dig 到浏览器逐层排查

6.1 分层验证法,别一出问题就盲改配置

我排查这类问题有一套固定顺序,从不跳步。整套链路可以拆成六层:DNS 解析层、网络可达层、端口监听层、防火墙层、代理配置层、应用层。每一层都有对应的验证命令,从下往上依次确认,问题出在哪一层立刻就能定位,比漫无目的地改配置高效得多。

# 第一层:解析是否生效 dig +short app.example.com dig @223.5.5.5 app.example.com # 第二层:网络是否可达 ping -c 3 app.example.com traceroute app.example.com # 第三层:端口是否监听 ss -tlnp | grep :8080 ss -tlnp | grep -E ':(80|443)' # 第四层:端口是否放行 firewall-cmd --list-ports nmap -Pn -p 80,443,8080 你的公网IP # 第五层:代理是否正常响应 curl -I http://app.example.com curl -v --resolve app.example.com:80:你的公网IP http://app.example.com # 第六层:应用是否健康 curl -I http://127.0.0.1:8080

这里重点说curl --resolve这个参数,它是我最爱用的调试利器。它的作用是强制让 curl 把某个域名解析到指定 IP,绕过系统 DNS 缓存。这样你可以立刻验证"是不是解析还没生效"——如果加了这个参数能访问、不加就不行,那百分之百是 DNS 缓存问题,跟服务器配置无关。这招能帮你省下无数个怀疑人生的夜晚。

6.2 常见故障速查表

前面讲了原理,这里把高频问题和排查动作整理成表,遇到问题直接对号入座,按顺序试。

现象最可能的原因排查动作
域名 ping 不通解析未生效或缓存未过期dig @公共DNS 域名对比结果,等 TTL
ping 通但网页打不开端口未放行或服务未启动ss -tlnp查监听,firewall-cmd --list-ports查放行
报 502 Bad Gateway后端服务挂了或端口写错curl -I http://127.0.0.1:端口直连验证
报 504 Gateway Timeout后端处理超时或死锁调大proxy_read_timeout,查后端日志
报 403 Forbidden目录权限或 SELinux 拦截查 Nginx 错误日志,检查httpd_can_network_connect
静态资源 404路径前缀没对上检查location匹配规则和 root 路径
走 IP 能访问、走域名不行安全组来源限制或 Host 校验去掉proxy_set_header Host试试
WebSocket 连不上缺 Upgrade 相关头proxy_http_version 1.1和升级头
换行符问题导致脚本报错文件是 Windows 换行sed -i 's/\r$//' 文件名

表格里最后一行值得展开说一句。热词里老有人搜"linux 解压文件乱码",这通常也是换行符或者编码的问题:Windows 上传的 shell 脚本带\r换行,放到 Linux 上执行会报"命令未找到"或各种莫名其妙的语法错误。用file命令看一眼文件类型,如果是 CRLF 就用sed或者dos2unix转一下,问题立刻消失。这类"看起来像业务 bug、实际是环境问题"的坑,在服务器上非常普遍。

6.3 我踩过的几个真实坑

第一个坑是改完配置忘了 reload。有次我调 Nginx 的转发规则,改了三遍都不生效,最后发现是只保存了文件没执行重载,改的全是"磁盘上的配置",运行中的进程还在用旧规则。现在我养成习惯,任何配置改完先nginx -treload,两步连着做。

第二个坑是Host 头丢失导致重定向跑偏。项目里用了 OAuth 登录,走代理之后回调地址总是跳到127.0.0.1,查了半天才发现是没设proxy_set_header Host $host,后端拿到的 Host 是内网地址,于是按内网地址生成了跳转链接。加上那一行之后立刻正常。这个坑很典型,凡是涉及"根据域名生成链接"的功能,都要检查 Host 头。

第三个坑是端口占用。有次部署新服务,启动就报地址已被使用,ss -tlnp一查发现是之前一个没清理干净的进程还占着端口。用kill干掉之后又发现它被 systemd 自动拉起来了,最后是systemctl stop加禁用才彻底解决。所以遇到端口冲突,别只在应用层找,从进程和服务两个维度一起查。

第四个坑是云服务器重启后转发规则失效。前面提过,iptables 规则不持久化,用firewall-cmd加的规则如果不带--permanent也一样。我现在加规则一律先用--permanent加,最后统一--reload,避免重启后一脸茫然。

7. 上线之后还要盯住的两件事:安全和维护

配置跑通只是开始,真正让服务稳定的是后续的维护习惯。安全方面有几条底线:能不开到公网的端口坚决不开,数据库、缓存、消息队列这些组件,一律只监听回环地址或者内网网段;SSH 尽量改成密钥登录并换个高位端口,顺便装个失败登录封禁工具,能挡掉绝大部分自动化扫描;定期用 nmap 扫一遍自己服务器的公网端口,看看有没有意外暴露的服务,这个自查动作每个月花五分钟,收益极高。

代理层面要注意超时参数和连接数限制。默认的proxy_read_timeout是 60 秒,遇到耗时较长的接口很容易 504,我一般调到 300 秒并配合后端做异步处理。client_max_body_size默认只有 1M,上传大文件会直接被拒并返回 413,这个参数必须根据业务实际调,很多人第一次做文件上传功能都会栽在这里。连接数方面,如果并发量上来了,还得调整 worker 连接数配置。

日志是排障的第一手资料,务必要会用。Nginx 的访问日志和错误日志默认在/var/log/nginx/下,访问日志能看到每一个请求的来源 IP、状态码和转发目标,错误日志能直接指出配置问题。养成习惯,出问题的第一时间不是猜,而是tail -f跟一下这两份日志,答案通常就在里面。应用侧的日志同样重要,后端服务日志加上请求 ID 透传,能把整条链路的调用串起来。

证书续期也是容易被忘掉的一环。自动签发的证书有效期通常是九十天,自动续期任务如果因为某种原因失败,到期后网站会直接打不开。我的做法是在日历里设个提醒,或者写个简单的检测脚本定期检查证书剩余天数,少于十五天就告警。这件事平时看不见,一旦出事就是全站级别的故障。

我个人在实际操作中的体会是,所谓"把域名解析到端口"这件事,本质上是个认知问题而不是技术问题。想通了 DNS 只管名字到 IP 的映射,剩下的就是选一个合适的引导员——Web 服务交给 Nginx 七层代理,其他协议交给四层转发或系统防火墙。配置本身十几行就够,真正花时间的是把每一层验证清楚、把每个参数调到位。下次再有人问你这个问题,你可以直接把digss -tlnp这两条命令甩过去,让他自己看链路断在哪一环。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询