为何Nginx会选用server_name为_的server块处理http://example.pro请求?
Nginx HTTP请求匹配异常问题解析
问题描述
访问https://example.pro时一切正常,但访问http://example.pro时,Nginx却返回了server_name _那个server块的内容。确认请求的Host头和server_name example.pro完全匹配,而且HTTPS协议下这个server块明明能正常工作。
提供的Nginx配置
http { sendfile on; tcp_nopush on; types_hash_max_size 2048; server_tokens on; include /etc/nginx/mime.types; default_type application/octet-stream; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; access_log /_nginx_logs/access.log; error_log /_nginx_logs/error.log; gzip on; server { server_name www.example.pro; listen 80; listen 443 ssl; return 301 https://example.pro$request_uri; ssl_certificate "/etc/letsencrypt/live/www.example.pro/fullchain.pem"; ssl_certificate_key "/etc/letsencrypt/live/www.example.pro/privkey.pem"; } server { server_name example.pro listen 80; listen 443 ssl; ssl_certificate "/etc/letsencrypt/live/example.pro/fullchain.pem"; ssl_certificate_key "/etc/letsencrypt/live/example.pro/privkey.pem"; location / { proxy_pass http://localhost:3000; } location /api { proxy_pass http://localhost:7500; proxy_set_header X-Forwarded-For $remote_addr; } } server { server_name _; listen 80 default_server; location / { root /projects/site-stub; } } }
问题原因
问题出在第二个server块里的server_name example.pro——这行末尾少了个分号;。
Nginx的配置语法有硬性要求:所有指令必须以分号结尾。少了分号会导致配置解析混乱:
- 这行
server_name指令无法被正确识别,Nginx根本不知道这个server块是用来处理example.pro的请求的 - 当80端口的HTTP请求进来时,Nginx找不到匹配
Host: example.pro的server块,就会自动用配置里标记为default_server的那个(也就是server_name _的块) - 至于HTTPS能正常工作,是因为加载配置时,这个server块里的HTTPS相关指令(比如
listen 443 ssl、证书配置)没被这个语法错误完全搞崩,还能被Nginx解析到,所以HTTPS请求能匹配上
解决方法
给server_name example.pro末尾加上分号,修正后的代码片段如下:
server { server_name example.pro; listen 80; listen 443 ssl; ssl_certificate "/etc/letsencrypt/live/example.pro/fullchain.pem"; ssl_certificate_key "/etc/letsencrypt/live/example.pro/privkey.pem"; location / { proxy_pass http://localhost:3000; } location /api { proxy_pass http://localhost:7500; proxy_set_header X-Forwarded-For $remote_addr; } }
改完之后执行命令重新加载Nginx配置就行:
nginx -s reload
内容的提问来源于stack exchange,提问作者Dmitriy Zhuravlev
相关产品推荐
相关产品推荐

