Nginx 实现域名跳转的几种方式详解
为什么“域名跳转”不能只会一种写法
在 Nginx 里做域名跳转,看起来只是把一个域名导到另一个域名,但实际场景差别很大:
- 旧域名迁移到新域名
www和裸域统一http强制跳https- 多个历史域名统一收口
- 某些路径跳转,某些路径保留
真正容易出问题的,不是语法本身,而是跳转类型选错、规则顺序写错、Host 和 URI 丢失、重定向层级过多。这些问题一旦上线,轻则 SEO 受影响,重则直接形成重定向循环。
下面把 Nginx 中几种常见的域名跳转方式拆开讲清楚。
301 和 302 先分清楚
在写配置之前,先明确两类最常见的重定向状态码:
| 状态码 | 含义 | 适用场景 |
|---|---|---|
| 301 | 永久重定向 | 域名永久迁移、www 统一、HTTP 跳 HTTPS |
| 302 | 临时重定向 | 临时活动页、灰度切换、短期测试跳转 |
选择建议
- 长期固定规则:优先用
301 - 短期临时跳转:用
302 - 不确定是不是长期规则时,别急着上
301。因为浏览器和搜索引擎会缓存永久跳转,后面改起来会比较麻烦
很多人本地测试觉得“能跳就行”,但线上不是这样。 301 一旦被缓存,你改配置后未必马上能看到结果,这也是排查时经常让人误判的地方。
方式一:用 return 做整站域名跳转
这是最推荐的方式,也是最干净的一种。
场景:旧域名整体跳到新域名
比如把 old.example.com 全量迁移到 new.example.com:
server {
listen 80;
server_name old.example.com;
return 301 https://new.example.com$request_uri;
}
说明
301:永久跳转https://new.example.com:目标域名$request_uri:保留原始请求路径和参数
比如用户访问:
http://old.example.com/user/list?id=10
会跳转到:
https://new.example.com/user/list?id=10
为什么推荐 return
因为它有几个明显优势:
- 配置简单,意图清晰
- 性能比
rewrite更直接 - 不容易写出复杂且难维护的规则
- 做整站跳转时,几乎就是最合适的选择
如果你的需求只是“这个域名整个换掉”,优先考虑 return,不要一上来就写 rewrite。
方式二:用 rewrite 实现域名跳转
rewrite 更灵活,但也更容易写乱。
示例:将旧域名跳转到新域名
server {
listen 80;
server_name old.example.com;
rewrite ^/(.*)$ https://new.example.com/$1 permanent;
}
说明
^/(.*)$:匹配请求路径https://new.example.com/$1:拼接目标地址permanent:表示301- 如果写成
redirect,则表示302
对应关系
| 参数 | 实际含义 |
|---|---|
permanent |
301 |
redirect |
302 |
这种方式适合什么场景
rewrite 更适合做带规则匹配的路径级跳转,比如:
- 旧 URL 结构迁移到新 URL 结构
- 某类路径批量改写
- 根据正则提取参数进行重定向
例如:
server {
listen 80;
server_name old.example.com;
rewrite ^/article/(.*)$ https://new.example.com/posts/$1 permanent;
}
这表示:
http://old.example.com/article/123
跳转为:
https://new.example.com/posts/123
不建议滥用 rewrite
因为很多整站跳转场景,其实不需要正则。 你用 rewrite 也能做,但维护成本更高,而且后面别人接手时不容易一眼看懂。
方式三:基于 server_name 做多个域名统一跳转
这是线上最常见的收口方式之一。
场景:多个旧域名统一跳到一个主域名
server {
listen 80;
server_name a.example.com b.example.com c.example.com;
return 301 https://www.example.com$request_uri;
}
这表示:
a.example.comb.example.comc.example.com
都会跳到:
https://www.example.com/原始路径
适用场景
- 历史域名合并
- 品牌升级后的域名统一
- 测试域名、备用域名收口
- 多个二级域名统一导流到主站
这种方式的好处是简单直接,尤其适合整理历史遗留配置。
方式四:www 和非 www 域名互相跳转
这是非常经典的一类需求。
你必须先决定,系统最终要统一成哪一种:
www.example.comexample.com
不要两种都放着能访问。这样会带来:
- SEO 权重分散
- Cookie 域问题变复杂
- 对外链接不统一
- 排查问题时 Host 不一致
1)非 www 跳转到 www
server {
listen 80;
server_name example.com;
return 301 https://www.example.com$request_uri;
}
2)www 跳转到非 www
server {
listen 80;
server_name www.example.com;
return 301 https://example.com$request_uri;
}
一般怎么选
没有绝对标准,但实践里通常是:
- 企业官网、门户类站点:常见统一到
www - 接口服务、后台服务:很多统一到裸域或专用子域名
重点不是选哪一个,而是只保留一个对外主域名。
方式五:HTTP 强制跳转到 HTTPS
这个配置几乎已经是标配。
配置示例
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
说明
$host:保留当前访问的域名$request_uri:保留路径和参数
比如:
http://www.example.com/login?redirect=/home
会跳到:
https://www.example.com/login?redirect=/home
为什么这里常用 $host
因为当你同时接收多个域名时:
server_name example.com www.example.com;
使用 $host 可以保持当前请求的域名不变,只做协议升级。
如果你还要统一主域名
那就不要只写协议跳转,而是一步到位,直接收口。例如统一到 https://www.example.com:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://www.example.com$request_uri;
}
这样可以避免两次跳转:
- 第一次:HTTP → HTTPS
- 第二次:非
www→www
最好一跳到位。
方式六:按路径做域名跳转
有些需求不是整站迁移,而是某个模块迁走了。
示例:/blog 跳到另一个域名
server {
listen 80;
server_name example.com;
location /blog/ {
return 301 https://blog.example.com$request_uri;
}
}
访问:
http://example.com/blog/post-1
会跳到:
https://blog.example.com/blog/post-1
如果你不想保留 /blog
比如希望:
http://example.com/blog/post-1
跳到:
https://blog.example.com/post-1
可以这样写:
server {
listen 80;
server_name example.com;
location /blog/ {
rewrite ^/blog/(.*)$ https://blog.example.com/$1 permanent;
}
}
这类场景里,rewrite 就比 return 更合适,因为你确实需要改路径结构。
方式七:使用独立的默认站点兜底跳转
有时候你希望所有未明确配置的域名都跳转到某个统一站点。
示例
server {
listen 80 default_server;
server_name _;
return 301 https://www.example.com$request_uri;
}
适用场景
- 非法访问统一收口
- 测试环境中做简单兜底
- 历史 DNS 残留流量导流
但这个配置要谨慎
因为它会接住所有没有命中其他 server_name 的请求。 如果你的机器上托管多个站点,兜底跳转写得太随意,可能会把本不该跳的请求也导走。
return 和 rewrite 该怎么选
很多人纠结的其实是这个。
| 对比项 | return | rewrite |
|---|---|---|
| 配置复杂度 | 低 | 高 |
| 性能 | 更直接 | 略复杂 |
| 可读性 | 好 | 一般 |
| 是否支持正则改写 | 不擅长 | 擅长 |
| 适合整站跳转 | 非常适合 | 能做但不优先 |
| 适合路径重写 | 一般 | 更适合 |
实战建议
- 整站域名跳转:优先
return - HTTP 跳 HTTPS:优先
return www统一:优先return- 复杂路径迁移:使用
rewrite
一句话总结:
只要不是必须改路径结构,就优先用
return。
生产环境里经常踩的坑
1. 忘了带 $request_uri
错误写法:
return 301 https://www.example.com;
这样会导致用户访问任意路径,都只跳到首页。
例如:
http://old.example.com/order/detail?id=100
最终变成:
https://www.example.com
原始路径和参数全部丢失。
正确写法
return 301 https://www.example.com$request_uri;
2. 配置导致重定向循环
比如你在 HTTPS 站点里又写了一条“跳 HTTPS”的规则,或者 A 域名跳 B,B 又跳回 A。
常见现象:
- 浏览器提示
ERR_TOO_MANY_REDIRECTS - 接口请求一直 301/302
- 登录流程直接失效
排查思路
先用 curl 看响应头:
curl -I http://example.com
如果要跟踪多次跳转:
curl -IL http://example.com
看 Location 是否出现来回跳。
3. HTTP 和 HTTPS 各写一套,结果规则不一致
比如:
- 80 端口跳到
www - 443 端口却没有统一 Host
- 或者 80 上保留 URI,443 上丢 URI
结果就是不同入口行为不一致,用户看起来像“有时候能打开,有时候跳错地址”。
比较稳妥的做法是:
- 80 端口:只负责收口和协议升级
- 443 端口:只提供最终站点服务
- 所有入口都尽量一步跳到最终目标地址
4. 把跳转和反向代理混在一起
有些配置会写成这样:
location / {
proxy_pass http://backend;
rewrite ^/(.*)$ https://www.example.com/$1 permanent;
}
这种写法通常是有问题的,或者至少非常难维护。 因为请求处理阶段不同,规则优先级也不同,后面排查时很容易搞不清到底是重定向了,还是转发到上游了。
建议
- 要跳转,就明确用
return或rewrite - 要转发,就明确用
proxy_pass - 尽量不要把两种意图揉在同一个位置里
5. 多层跳转影响性能和收录
比如用户访问一次,经历了:
http://example.com- 跳到
https://example.com - 再跳到
https://www.example.com - 最后又跳到
https://www.example.com/home
虽然最终能打开,但中间多了好几次往返。
这会带来:
- 首次访问更慢
- 爬虫抓取效率降低
- 用户排查问题更困难
最理想的是:
从任意入口,一次 301 直接到最终 URL。
一组比较实用的标准写法
下面给一套比较常见、也比较顺手的配置思路: 把 http://example.com 和 http://www.example.com 全部统一到 https://www.example.com。
1)HTTP 入口统一跳转
server {
listen 80;
server_name example.com www.example.com;
return 301 https://www.example.com$request_uri;
}
2)HTTPS 下裸域继续收口
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
return 301 https://www.example.com$request_uri;
}
3)HTTPS 主站提供正式服务
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
这一套的特点
- 所有入口最终统一到一个主域名
- 规则职责明确
- 不容易产生循环
- 后续接 CDN、做 SEO、配证书都更清晰
验证跳转是否生效
修改配置后,不要直接重启,先检查语法。
1)检查配置
nginx -t
2)重新加载配置
nginx -s reload
或者:
systemctl reload nginx
3)用 curl 验证
查看响应头:
curl -I http://example.com/test?a=1
预期应看到类似:
HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/test?a=1
如果要确认多层跳转链路:
curl -IL http://example.com/test?a=1
这个命令非常实用,能快速看出有没有多跳、循环、路径丢失等问题。
总结
Nginx 实现域名跳转,常见方式主要有:
return做整站跳转rewrite做规则化路径跳转- 基于
server_name做多域名收口 www与非www统一- HTTP 强制跳 HTTPS
- 指定路径跳转到新域名
default_server做兜底跳转
真正实战里,建议记住两条:
- 整站跳转优先用
return - 目标地址尽量一次跳到最终态
语法不是最难的,最难的是把规则写得清晰、可维护、不会互相打架。 尤其当站点同时涉及多个域名、HTTPS、反向代理和历史路径兼容时,跳转配置越“聪明”,后面往往越难排查。