Nginx 301跳转配置异常排查:Magento站点状态码问题
先梳理下目前遇到的重定向问题:
- 旧站点:HTTPS的两个域名(带www/不带www)都能返回301,符合预期;但HTTP的两个域名完全没触发301,这是个问题
- 新站点:
https://www.newsite.com是正常的目标站点,没问题https://newsite.com返回的是302而非要求的301- HTTP的两个域名同样没有301重定向
接下来逐个拆解四个配置文件的问题:
1. oldsite.com.nginx.conf(旧站HTTP端口)
这个配置语法上是对的,但为啥HTTP请求没触发301?大概率是这个server块没被Nginx匹配到。常见原因要么是有其他监听同IP:80的default_server抢了请求,要么是这个配置文件根本没被加载到Nginx主配置里。
如果确认配置已经加载,建议给这个server加上default_server标记,确保所有HTTP请求都能命中它:
server { listen ipaddress:80 default_server; server_name oldsite.com www.oldsite.com; root /home/oldsite/web/oldsite.com/public_html; index index.php index.html index.htm; location / { return 301 https://www.newsite.com$request_uri; } include /home/oldsite/conf/web/nginx.oldsite.com.conf*; }
2. oldsite.com.nginx.ssl.conf(旧站HTTPS端口)
这个配置没毛病!已经完美实现了HTTPS两个域名的301重定向,符合预期,不用改。
3. newsite.com.nginx.conf(新站HTTP端口)
这里藏了个致命的顺序错误:return 301居然写在了server_name前面!
Nginx的逻辑是先根据listen和server_name匹配对应的server块,再执行块里的指令。虽然语法上允许把return放前面,但这里的问题是,return之后的server_name等指令根本不会被执行,再加上如果这个server没设为default_server,HTTP请求可能直接跑到其他默认server去,自然触发不了301。
正确的姿势是把server_name放前面,而且加上default_server确保所有HTTP请求都被捕获,同时删掉return后面的冗余指令(因为return执行后后面的代码都走不到):
server { listen ipaddress:80 default_server; server_name newsite.com www.newsite.com; return 301 https://www.newsite.com$request_uri; # 下面这些指令在return之后不会生效,直接删掉就行 # root /home/newsite/web/newsite.com/public_html/pub; # index index.php; # autoindex off; # charset UTF-8; # error_page 404 403 = /errors/404.php; # add_header "X-UA-Compatible" "IE=Edge"; }
4. newsite.com.nginx.ssl.conf(新站HTTPS端口)
当前配置同时处理带www和不带www的HTTPS域名,但没给不带www的域名做301重定向,导致访问https://newsite.com时,Magento内部返回了302(临时重定向),不符合永久重定向的要求。
推荐用拆分server块的方式(比用if指令更符合Nginx最佳实践)来修复:
# 专门处理不带www的HTTPS域名,直接返回301到www版本 server { listen ipaddress:443 http2; server_name newsite.com; ssl on; ssl_certificate /home/newsite/conf/web/ssl.newsite.com.pem; ssl_certificate_key /home/newsite/conf/web/ssl.newsite.com.key; return 301 https://www.newsite.com$request_uri; } # 主站点的HTTPS配置 server { listen ipaddress:443 http2 default_server; server_name www.newsite.com; root /home/newsite/web/newsite.com/public_html/pub; index index.php; autoindex off; charset UTF-8; error_page 404 403 = /errors/404.php; add_header "X-UA-Compatible" "IE=Edge"; ssl on; ssl_certificate /home/newsite/conf/web/ssl.newsite.com.pem; ssl_certificate_key /home/newsite/conf/web/ssl.newsite.com.key; # 记得加上Magento需要的PHP处理配置,比如: location ~ \.php$ { fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; # 换成你实际的PHP-FPM路径 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
如果不想拆分server块,也可以在原配置里加个if判断,但要注意Nginx里if的使用场景,尽量少用:
server { listen ipaddress:443 http2; server_name newsite.com www.newsite.com; root /home/newsite/web/newsite.com/public_html/pub; index index.php; autoindex off; charset UTF-8; error_page 404 403 = /errors/404.php; add_header "X-UA-Compatible" "IE=Edge"; ssl on; ssl_certificate /home/newsite/conf/web/ssl.newsite.com.pem; ssl_certificate_key /home/newsite/conf/web/ssl.newsite.com.key; # 新增:匹配不带www的域名,返回301 if ($host = 'newsite.com') { return 301 https://www.newsite.com$request_uri; } # 剩下的Magento配置保持不变 }
内容的提问来源于stack exchange,提问作者Zoya

