
帮朋友看他那台刚买的 Linux 服务器时被问得最多的一个问题就是域名已经解析到服务器了服务跑在 8080 端口怎么才能让访客只输域名就能打开而不必在后面手打一个:8080问这个问题的人里有刚接触运维的学生也有写了好几年业务代码但没碰过服务器的开发。大家的直觉都是一样的——去域名解析的地方加个端口不就完了结果打开控制台发现压根没有填端口的地方。这里先把结论摆在最前面域名解析DNS从头到尾就管不到端口端口不是 DNS 的职责范围。所以把域名解析到指定的端口这句话严格来说是说不通的它其实是一个被口语化了的复合需求翻译成准确的说法应该是让某个域名在标准端口80 或 443上对外提供服务用户在浏览器里只输入域名流量自动落到 Linux 服务器上那个跑在 8080、3000、5000 之类的非标准端口上的应用。把需求翻译对之后方案就清楚了。这篇文章会把整条链路拆开讲从 DNS 记录怎么填、Linux 服务怎么配、防火墙和云安全组怎么开一直到访问不通时该怎么一层层排查。中间会给出可以直接复制修改的配置也会讲清楚每一种做法背后的取舍避免你照着抄完之后不知道自己抄的是什么。适合有一定 Linux 基础、想认真搞明白这件事的人看完全零基础也能跟下来遇到命令行的地方我都会说清楚每一条在干什么。1. 先把最大的误会拆开DNS 记录里没有端口这一栏1.1 域名解析只干了一件很窄的事打开任何一家域名服务商的控制台点进解析设置你能选的记录类型基本就那么几种A、AAAA、CNAME、MX、TXT、NS、SRV。记录值要填的地方要么是 IP 地址要么是另一个域名从来没有一个叫端口的输入框。这不是产品经理偷懒而是 DNS 这套体系在设计之初就划定好了边界。DNS 的定位可以类比成一本电话簿它只负责把老王家这个名字翻译成138xxxx这串号码。至于你打过去之后是老王本人接、还是他儿子接、还是转接到隔壁房间那是接通之后的事电话簿管不着。端口就属于接通之后由谁接的范畴它活在 TCP/UDP 协议里是传输层和应用层的地盘。1.2 端口到底归谁管TCP/UDP 四元组一次网络连接内核是靠四个要素来唯一识别的源 IP、源端口、目的 IP、目的端口。DNS 只负责把目的 IP这一项算出来剩下三项跟它无关。当你在浏览器里敲下http://demo.example.com:8080/浏览器做的是先查 DNS 拿到demo.example.com对应的 IP然后把你自己指定的8080当作目的端口拼出一个完整的目标地址再去发起连接。如果你不写端口呢浏览器会按协议给你补一个默认值。HTTP 补 80HTTPS 补 443FTP 补 21SSH 补 22。这个默认值写死在协议规范里域名服务商也改不了。协议默认端口说明HTTP80明文 Web写域名即可访问HTTPS443加密 Web写域名即可访问SSH22远程登录客户端默认连 22MySQL3306数据库客户端工具默认值Redis6379缓存服务默认只监听本机自建应用8080 / 3000 / 5000需要额外手段才能隐藏掉看这张表就明白了所谓不用带端口访问本质是让用户的请求乖乖落到 80 或 443 上再由服务器自己把流量转到真正的业务端口。DNS 在这件事里只负责把人带到这台机器门口。1.3 需求翻译对了路就只剩三条把白话需求翻译准确之后可选的实现路径其实只有三条而且它们的原理完全不同反向转发让 80/443 上跑一个转发服务最典型的是 Nginx收到请求后按域名或路径把流量交给后端的 8080。用户全程只看到域名。端口转发用内核层面的规则把进来的 80 端口数据包直接改写成发往 8080应用自己完全不知情。SRV 记录真正意义上能带端口的 DNS 记录类型但只有特定协议的客户端会去读它浏览器不认。绝大多数人需要的是第一条。但为什么是第一条、其他两条什么时候才用得上下面的章节会一条条说清楚。2. 一次访问的完整链路从敲下回车到页面出来2.1 请求走过的六个阶段想排查问题得先知道一次访问中间都发生了哪些事不然出问题就是瞎猜。以http://demo.example.com为例从敲回车到页面渲染大致经过这么几步浏览器解析地址识别出协议是 HTTP主机是demo.example.com没写端口于是补上默认的 80。DNS 查询先查浏览器缓存再查本机 hosts 和系统 DNS 缓存都没有就向配置的 DNS 服务器发起递归查询。递归服务器会依次问根域名服务器、顶级域服务器、权威域名服务器最终拿到 A 记录里的 IP。这一整圈通常几十毫秒就完成了。建立 TCP 连接和拿到的那个 IP 的 80 端口做三次握手。发送 HTTP 请求请求行里写的是相对路径同时在请求头里带一个Host: demo.example.com。服务端处理80 端口上的程序Nginx 或别的根据 Host 头和路径决定把请求转给谁。返回响应数据沿原路回去浏览器渲染。关键在第 5 步。如果你的业务服务自己监听 80那它就得自己处理所有逻辑如果 80 上站的是 Nginx那 Nginx 就是那个门卫负责把不同域名的请求分发给内网里不同的应用。2.2 Host 头为什么比你想的重要一台服务器只有一个 IP但可以绑很多域名。区分这些域名靠的就是 HTTP 请求头里的Host字段。Nginx 的server_name指令匹配的就是这个字段。这带来一个很常见的坑用 curl 直接测 IP 通了不代表用域名测也通。因为用 IP 访问时 Host 头是一个裸 IPNginx 匹配不到任何server_name会落到默认的第一个 server 块上返回的可能完全是另一个站点甚至是一个空页面。2.3 三条路线的适用边界方案用户要不要带端口是否改动应用最适合的场景主要代价反向转发不用不用Web 服务、多站点共存多一层转发配置稍多端口转发不用不用任意 TCP/UDP 服务难以区分多个站点HTTPS 证书不好处理SRV 记录取决于客户端取决于客户端特定协议的服务发现浏览器完全不支持看完这张表你应该能判断自己该走哪条了。如果对外提供的是网页服务直接看第 5 节如果是数据库、游戏服、邮件这类非 HTTP 服务且客户端不支持指定端口那第 6 节更适合你。3. 动手前的四道检查别急着改配置3.1 确认后端服务真的在跑且在听对地址上服务器第一件事是确认你要暴露的那个服务确实活着。两条命令就够ss -lntp | grep 8080 # 或者老系统上用 netstat -lntp | grep 8080输出里重点看两样东西监听地址和进程名。如果显示的是127.0.0.1:8080说明它只监听本机回环地址外部流量进不来Nginx 转发时写127.0.0.1:8080是可以的但你想让外部直接访问 8080 就没戏。如果要让外部直连得改成0.0.0.0:8080。lsof -i:8080这条也能看端口占用同时能看到是哪个进程持有的排查端口被占的时候特别顺手。3.2 确认域名已经在你手里并且你能改解析这一步听起来废话但真有人拿着别人家的域名在研究半天。判断方法很简单在域名服务商控制台能看到这个域名的解析记录且能新增、修改就说明控制权在你这边。3.3 云服务器的安全组要提前放行如果你用的是云服务器除了机器自身的防火墙外面还套了一层安全组有的厂商叫防火墙、有的叫网络 ACL。这层是独立于操作系统的在系统里用firewall-cmd怎么开都没用必须去云控制台放行。这一条是新手最容易卡住的地方我后面在排查章节会再展开。3.4 记下服务器的公网 IPcurl -s ifconfig.me或者直接在云控制台看实例详情。这个 IP 后面填 A 记录要用务必确认取的是公网 IP不是内网那一串172.16.x.x、10.x.x.x。注意如果服务器处在 NAT 环境里ip addr看到的多半是内网地址别拿它去配解析记录。4. 解析记录怎么填A 记录、CNAME 和 TTL4.1 A 记录还是 CNAME按这个标准选这两种记录是最常用的选择标准其实很明确A 记录直接指向一个 IPv4 地址。你自己的服务器有固定公网 IP就用它。AAAA 记录指向 IPv6 地址用不到 IPv6 就别加加了反而可能出问题。CNAME 记录指向另一个域名相当于起别名。典型场景是你把服务托管在某个平台上对方给了你一个域名你就用 CNAME 指过去。这样对方换了 IP 你也不用管。有个硬性限制要记住CNAME 不能和同名的其他记录共存。也就是说www这条主机记录一旦设成 CNAME就不能再给它加一条同名的 A 记录否则解析行为会变得不可预测。4.2 主机记录、记录值、TTL 分别填什么以域名example.com为例想实现访问demo.example.com能打开服务配置大致是这样字段填写内容说明记录类型A指向固定 IPv4 地址主机记录demo只填前缀不用写完整域名解析线路默认单线路场景保持默认记录值你的公网 IP比如 203.0.113.25TTL600单位秒越小改起来生效越快主机记录这一栏是新手最容易写错的地方。填demo就代表demo.example.com填代表主域名本身example.com填www就是www.example.com填*是泛解析所有没单独配置的子域名都落到这里。千万不要把完整的demo.example.com填进去那会变成demo.example.com.example.com。至于 TTL它的含义是这条记录允许被各级 DNS 缓存多久。设得大比如 3600 秒解析查询更快、压力更小设得小比如 60 秒改记录后生效更快但查询更频繁。我的习惯是正式环境先设 600如果近期打算换 IP提前一天改成 60等切换完再改回来。4.3 怎么确认解析真的生效了改完记录别急着开浏览器先用命令行验证能排除掉一大半干扰dig demo.example.com short # 或者 nslookup demo.example.com 8.8.8.8dig的输出里如果 ANSWER SECTION 返回的就是你填的那个 IP说明解析这条链路已经通了。这种方式绕过本地缓存结论最准。4.4 改完不生效的几个常见原因解析这件事有时候会看起来没生效实际原因往往不在记录本身TTL 还没过期旧的缓存还挂在各级 DNS 上只能等。本机缓存作祟Windows 上可以ipconfig /flushdnsLinux 上如果跑了systemd-resolved用resolvectl flush-caches。改了但没保存有些控制台的编辑需要点两次确认容易漏。线路解析干扰如果之前配过按运营商分线路的解析不同网络环境查到的结果可能不一样排查时容易看花眼。提示排查阶段建议直接指定一个公共 DNS 去查例如dig 8.8.8.8能把本地缓存和线路解析两个变量同时排除掉。5. 主力方案用 Nginx 把 80 的流量交给 80805.1 为什么首选 Nginx 而不是别的能承担接收 80 端口流量再转发这个角色的软件不少Nginx、Apache、Caddy、HAProxy 都能干。日常场景我更倾向 Nginx理由有三个一是资源占用低一台 1 核 2G 的小服务器跑它毫无压力二是配置语法直观一个 server 块就是一份独立的站点配置改起来不会牵一发动全身三是生态成熟以后要加 HTTPS、加缓存、加限流都是加几行配置的事。如果你的服务本身已经自带 HTTP 能力比如大多数 Web 框架那就更没必要让业务代码去监听 80。业务进程监听 80 通常需要额外权限将来做端口切换、做多站点也会很别扭。5.2 安装与目录约定主流发行版装起来都是两条命令的事# Debian / Ubuntu 系 sudo apt update sudo apt install -y nginx sudo systemctl enable --now nginx# CentOS / Rocky / 部分国产发行版 sudo yum install -y nginx sudo systemctl enable --now nginx装完之后配置目录大致是这样分工的/etc/nginx/nginx.conf是总入口里面通过include引入/etc/nginx/conf.d/*.conf和/etc/nginx/sites-enabled/*。我个人的习惯是在conf.d下新建一个以域名命名的文件比如demo.example.com.conf一个站点一个文件迁移和备份都方便。5.3 一份可以直接抄的配置server { listen 80; listen [::]:80; server_name demo.example.com; access_log /var/log/nginx/demo.access.log; error_log /var/log/nginx/demo.error.log warn; 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_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_connect_timeout 10s; proxy_read_timeout 300s; proxy_send_timeout 300s; client_max_body_size 100m; } }保存之后先做语法检查再重载sudo nginx -t sudo systemctl reload nginx5.4 那几行 set_header 到底在解决什么问题配置能跑不代表配置是对的上面那几行头部设置每一行都在填一个坑。proxy_set_header Host $host;的作用是保留下游应用看到的域名。如果不加这一行Nginx 默认会把 Host 改写成proxy_pass里写的地址也就是127.0.0.1:8080。后果是什么后端应用如果按域名做路由、做跳转、生成绝对链接全都得错。很多框架生成的登录回调地址、静态资源地址会直接变成http://127.0.0.1:8080/...用户一打开就是本地地址页面直接崩。X-Real-IP和X-Forwarded-For解决的是源 IP 丢失问题。加了转发层之后后端应用看到的来访 IP 永远是127.0.0.1日志里全是本机做风控、做统计全废。这两行把真实 IP 透传下去后端再从这两个头里取。X-Forwarded-Proto则是告诉后端用户当时用的是 http 还是 https将来升级 HTTPS 时这一行必不可少。Upgrade和Connection两行是为了 WebSocket。如果你的应用有长连接、实时推送、在线协作这类功能不加这两行握手阶段就会被断开表现是连上一秒就掉线而且日志里往往看不出明确报错非常难查。5.5 三个容易被忽略的超时与体积参数proxy_read_timeout默认只有 60 秒。如果你的接口里有导出报表、批量数据处理这类慢操作超过 60 秒就会被 Nginx 掐断用户看到 504。设成 300 秒是比较稳妥的折中。client_max_body_size默认只有 1M。上传图片、附件、视频稍微大一点就是 413 报错而且这个报错发生在 Nginx 层后端日志里什么都看不到很多人会一直去翻应用代码。按业务需要设成 50m 或 100m。proxy_connect_timeout设 10 秒足够。这个参数管的是 Nginx 连后端的那一步如果后端已经挂了早点失败早点暴露问题比让用户干等要好。5.6 让它开机自启并长期可用sudo systemctl enable nginx sudo systemctl is-enabled nginx第二行会输出enabled确认自启已经配上。服务器重启后服务自动恢复这件事一定要在交付前确认一次否则一次计划外重启就可能让站点长时间不可用。6. 备选路线用端口转发绕过应用层6.1 什么时候这条路线更划算不是所有服务都是 HTTP。数据库、游戏服务端、邮件服务、自定义的二进制协议这些场景下 Nginx 就帮不上忙了因为它只懂 HTTP 语义。这时候就要用内核层面的端口转发进来的包改个目的端口就完事应用完全无感知。它还有一个好处是零配置改动后端应用不用动一行代码也不关心外面套了什么。代价是分辨率低同一条 80 端口进来的流量没法按域名分给不同后端只能全部导到一个地方。6.2 firewalld 的做法在 CentOS、Rocky 以及不少国产发行版上默认的防火墙管理工具是 firewalldsudo firewall-cmd --permanent --add-port8080/tcp sudo firewall-cmd --permanent --add-forward-portport80:prototcp:toport8080 sudo firewall-cmd --permanent --add-masquerade sudo firewall-cmd --reload解释一下这三条第一条放行 8080让转发目标本身是可抵达的第二条声明80 端口上的 TCP 流量转到 8080第三条开启地址转换这一步是很多人漏掉的关键不开启的话转发规则不成立。改完用sudo firewall-cmd --list-all复查一遍能看到forward-ports那一行才算成功。6.3 iptables 的做法与持久化如果系统里没有 firewalld或者你更习惯直接用 iptables# 本机端口重定向流量不出本机 sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080 # 如果要转到另一台机器用 DNAT并确保内核允许转发 sudo sysctl -w net.ipv4.ip_forward1 sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.50:8080REDIRECT和DNAT的区别要分清楚目标在本机就用前者目标在另一台机器就用后者。选错了不会报错但流量会静默丢弃排查起来很费时间。iptables 的规则默认重启就没了必须持久化sudo iptables-save | sudo tee /etc/iptables/rules.v4或者用iptables-persistent这类工具把规则固化下来。做过这一步之后记得重启验证一次规则还在不在别等真出事了才发现规则丢了。6.4 端口转发解决不了 HTTPS这一点必须提前说清楚端口转发搬的是字节它不理解 TLS 握手的内容。你把 443 直接转到 8080后端拿到的就是加密数据除非后端自己持有证书并且配好了 TLS否则整个链路是断的。真要做 HTTPS还是得回到反向转发这条路Nginx 在 443 上终结 TLS解密后再把明文请求转给 8080。这也是我在实际项目里几乎总是选 Nginx 的原因——HTTPS、多域名、限流、缓存这些需求迟早会来不如一开始就架构对。7. 访问不通按这个顺序一层层剥配置全写完了浏览器一开还是打不开。这时候最忌讳东改一下西改一下按下面这个顺序查每一步只排除一个变量。7.1 第一层解析对不对dig demo.example.com short curl -I http://demo.example.com第一条看返回的 IP 是不是你的服务器。如果空着或者返回的不是你的 IP问题就在 DNS 这一层后面所有排查都是浪费时间。第二条看响应头能拿到HTTP/1.1 200或者任何状态码都说明链路至少是通的。7.2 第二层端口有没有在听ss -lntp | grep -E :(80|8080)这一条应该同时看到 80 和 8080。80 是 Nginx 在用8080 是你的业务进程。如果 8080 不在列表里说明后端根本没起来或者监听的地址不对。7.3 第三层本机自己能不能通curl -v http://127.0.0.1:8080/ curl -v -H Host: demo.example.com http://127.0.0.1/这两条是分水岭。第一条不通问题在后端应用第一条通、第二条不通问题在 Nginx 配置。第二条我特意加了-H Host: ...因为不带 Host 头访问本机 80Nginx 匹配不到对应站点会落到默认 server 上测出来的结果没有意义。7.4 第四层防火墙和云安全组sudo firewall-cmd --list-all # 或 sudo iptables -L -n --line-numbers系统防火墙确认 80 已放行之后再去云控制台看安全组。判断是不是安全组的问题有个很干脆的办法本机 curl 通、从外网 curl 不通八成就是安全组没放行。这层和系统防火墙是两套独立机制必须两边都开。注意有些云厂商的默认安全组只放行了 2280 和 443 都需要手动加规则。加规则时入方向、协议类型 TCP、源地址填 0.0.0.0/0如果要对所有访客开放。7.5 第五层应用层的 Host 校验和代理配置Nginx 这层通了页面还是不对通常有两个方向。一是后端应用做了 Host 白名单校验请求头里的域名不在允许列表里就直接拒绝这时候要么把域名加进白名单要么确认proxy_set_header Host有没有生效。二是配置文件虽然改了但没重载nginx -t加systemctl reload nginx再来一遍。7.6 第六层HTTPS 相关的坑升级到 HTTPS 之后比较隐蔽的问题是混合内容。页面本身是 https 加载的但页面里引用了 http 的图片或脚本浏览器会直接拦截。排查方法是打开开发者工具看 Console如果有 Mixed Content 提示就得把应用生成的资源地址统一改成 https或者用X-Forwarded-Proto让后端知道当前协议。另一个常见问题是证书链不全浏览器报证书无效但用命令行测又正常。有些客户端对证书链完整性要求更严补齐中间证书就能解决。8. SRV 记录唯一一种能带端口的 DNS 记录8.1 它长什么样前面说过 DNS 没有端口字段严格讲这句话有个例外——SRV 记录。它的格式是这样_service._proto.name. TTL IN SRV priority weight port target.举个具体例子某个游戏客户端支持通过 SRV 发现服务器_minecraft._tcp.example.com. 3600 IN SRV 10 60 25565 play.example.com.这条记录的含义是协议是 TCP、服务名是 minecraft、优先级 10、权重 60、端口 25565、目标是play.example.com。客户端读到之后就知道该去哪个主机、哪个端口。8.2 为什么浏览器不读它因为 HTTP 协议规范里没有约定浏览器要去查 SRV 记录。浏览器拿到域名后的处理方式是固定的补默认端口发起连接。这是浏览器的实现约定跟 DNS 支不支持没关系。所以你会看到一种现象给 Web 服务配了 SRV 记录浏览器访问依然打不开但某个支持 SRV 的客户端却能连上。这不是配置错了而是客户端能力不同。8.3 什么时候它真能派上用场适合用 SRV 的典型场景有这么几类一是自研客户端与服务端的服务发现你可以在客户端里实现 SRV 查询逻辑这样以后换服务器 IP 和端口只改 DNS 就够了不用重新发版二是邮件、语音、即时通信这类协议它们的规范里本来就定义了 SRV 的使用方式三是一些开源游戏服务端客户端原生支持 SRV 查找。但要清楚一点SRV 记录解决的是特定客户端如何找到服务它替代不了反向转发解决浏览器如何访问网站的问题两者是并行关系不是替代关系。9. 我的实际做法和一些长期维护的体会如果让我给一个标准答案对绝大多数 Web 场景我的配置组合是DNS 上一条 A 记录指向服务器公网 IP服务器上 Nginx 监听 80 和 443业务进程监听127.0.0.1:8080只对本机开放云安全组只放行 22、80、443 三个端口。把业务端口锁在回环地址上是一个我认为价值很高的习惯。这意味着外部永远无法直连 8080所有流量必须经过 Nginx。将来要做限流、要封某个 IP、要临时维护都在一层统一处理不用去动业务进程。反过来如果业务端口直接暴露在公网上会有一堆自动化扫描程序天天来试探日志里乌泱泱全是异常请求。再说两个日常维护里的小事。证书这块用自动化工具申请和续期比手动上传省心太多续期失败往往是因为验证方式选错了验证时要保证 80 端口能被外部访问到。日志这块建议在 Nginx 配置里给每个站点单独指定access_log和error_log多站点共用一个日志文件出问题的时候翻起来非常痛苦。最后还是回到开头那个问题。有人问域名怎么解析到端口其实真正想问的是怎么让用户不用记住端口号。把这句话翻译对路径自然就清楚了DNS 负责把人带到机器门口Nginx 负责把人领到正确的房间防火墙负责确认门是开着的。三件事各司其职一件都不能省也一件都不该多做。