Nginx 在不应该的时候转发到另一个服务器块

Nginx forwarding to another server block when it shouldn't

我的 nginx 服务器上有 3 个不同的站点,每个站点都有自己的服务器块。为了安全起见,我将只使用 domain1.com、domain2.com 和 domain3.com 而不是实际域。 Domain3 仍在等待转让给我的所有权,因此它根本无法运行。

问题是无论何时你去domain1.com,它都会把我转到domain2.com。据我所知,没有人说 domain1.com 应该转发给 domain2.com。我清除了我的 DNS 缓存以及所有浏览器缓存和 cookie。

这里是domain1.com

的server_block配置
#This is for redirecting everyone from www.domain.com to domain.com
server {
    listen   80; ## listen for ipv4; this line is default and implied
    #listen   [::]:80 default_server ipv6only=on; ## listen for ipv6

    server_name www.domain1.com;

    return 301 https://domain1.com$request_uri;
}

server {
    #listen 80 default_server;
    #listen [::]:80 default_server ipv6only=on;

    listen 443;

    server_name domain1.com;

    #keepalive_timeout 70;

    root /var/www/domain1.com/html;
    index index.php index.html index.htm;

    ssl on;
        ssl_certificate /etc/nginx/ssl/domain1.com/ssl.crt;
        ssl_certificate_key /etc/nginx/ssl/domain1.com/ssl.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
        # Uncomment to enable naxsi on this location
        # include /etc/nginx/naxsi.rules
    }

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /var/www/domain1.com/html;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    # Only for nginx-naxsi used with nginx-naxsi-ui : process denied requests
    #location /RequestDenied {
    #   proxy_pass http://127.0.0.1:8080;    
    #}

    #error_page 404 /404.html;

    # redirect server error pages to the static page /50x.html
    #
    #error_page 500 502 503 504 /50x.html;
    #location = /50x.html {
    #   root /usr/share/nginx/html;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
    #   # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
    #
    #   # With php5-cgi alone:
    #   fastcgi_pass 127.0.0.1:9000;
    #   # With php5-fpm:
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #   deny all;
    #}
}

domain2.com配置如下:

#This is for redirecting everyone from www.domain.com to domain.com
server {
    listen   80; ## listen for ipv4; this line is default and implied
    #listen   [::]:80  ipv6only=on; ## listen for ipv6

    server_name www.domain2.com;

    return 301 https://domain2.com$request_uri;
}
server {
    #listen 80;
    #listen [::]:80  ipv6only=on;

    listen 443;
    server_name domain2.com;

    ssl on;
    ssl_certificate /etc/nginx/ssl/domain2.com/ssl.crt;
    ssl_certificate_key /etc/nginx/ssl/domain2.com/ssl.key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    ssl_ciphers HIGH:!aNULL:!MD5;

    ssl_prefer_server_ciphers on;

    root /var/www/domain2.com/html;
    index index.php index.html index.htm;

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
        # Uncomment to enable naxsi on this location
        # include /etc/nginx/naxsi.rules
    }

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /var/www/domain2.com/html;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    # Only for nginx-naxsi used with nginx-naxsi-ui : process denied requests
    #location /RequestDenied {
    #   proxy_pass http://127.0.0.1:8080;    
    #}

    #error_page 404 /404.html;

    # redirect server error pages to the static page /50x.html
    #
    #error_page 500 502 503 504 /50x.html;
    #location = /50x.html {
    #   root /usr/share/nginx/html;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
    #   # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
    #
    #   # With php5-cgi alone:
    #   fastcgi_pass 127.0.0.1:9000;
    #   # With php5-fpm:
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #   deny all;
    #}
}

根据 nginx -t 没有配置问题。任何帮助将不胜感激!

access.log

警告:

您可能知道的一个问题是使用 TLS 为多个网站提供服务。 TLS 握手实际上是在 发送 HTTP 请求之前 完成的,并且 HTTP 请求是包含主机名的部分。这意味着 nginx 必须选择一个 TLS 证书用于握手,如果它不知道选择哪个证书,它就不会总是使用正确的证书。 This is documented here. This is usually solved with using different IPs for each website, or using SNI (more on SNI in nginx here)。我一直在与 nginx 上的 SNI 作斗争,但也许你可以让它工作。如果 SNI 已经为您工作,请忽略此答案的这一部分。


问题:

问题似乎是您只在端口 80 (HTTP) 上侦听 www.* 主机名。如果客户端尝试连接到 domain1.com:80 (HTTP)(请注意缺少 www.),则您没有服务器在端口 80 (HTTP) 上侦听 domain1.comnginx will use the first server in its configuration to handle unknown/unmatched hostnames.

在您的终端中尝试以下操作:

curl -v http://www.domain1.com
curl -v https://domain1.com
curl -v http://domain1.com
curl -v https://www.domain1.com

这将显示 HTTP 请求和响应 headers。您将看到前两个 http://www.domain1.com(端口 80)和 https://domain1.com(端口 443)按预期工作。但是,最后两个 http://domain1.com(端口 80)和 https://www.domain1.com(端口 443)没有按预期工作,因为它们不匹配任何服务器块(错误的 port/hostname)。


要更详细地研究问题,以下命令应输出以下内容:


$ curl -v http://www.domain1.com
[...]
< HTTP/1.1 301 Moved Permanently
[...]
< Location: https://domain1.com/
[...]

这个不错。您有一个服务器在端口 80 (HTTP) 上侦听 www.domain1.com。这与您的重定向服务器配置相匹配。如您所见,服务器的 HTTP 响应 headers return HTTP 301 并指向新位置 https://domain1.com/。这是正确的,并且符合您要求重定向服务器执行的操作。


$ curl -v https://domain1.com
[...]
< HTTP/1.1 200 OK
[...]

这个不错。您有一个服务器在端口 443 (HTTPS) 上侦听 domain1.com。这与 domain1.com 的主服务器配置相匹配。如您所见,服务器的 HTTP 响应 headers return HTTP 200,并且服务器 return 请求了 HTML 页面。这是正确的,并且与您要求主服务器配置为 domain1.com.

执行的操作相匹配
$ curl -v http://domain1.com
[...]
< HTTP/1.1 301 Moved Permanently
[...]
< Location: https://domain2.com/
[...]

这很糟糕。您没有在端口 80 (HTTP) 上侦听 domain1.com 的服务器。这与您的任何服务器配置都不匹配。由于此请求与您的任何服务器都不匹配,因此 nginx 不会执行您想要的操作。 nginx 只是默认使用它看到的第一个服务器配置,不幸的是这不是你想要的。它似乎使用 domain2.com 的重定向服务器,因为它 return 是到 domain2.com.

的 301 重定向

这可以通过让 domain1.com 的重定向服务器同时侦听与 domain1.com 的端口 80 (HTTP) 连接来解决(不仅仅是 www.domain1.com,因为它目前是这样做的)。如果你不这样做,nginx 不知道该请求使用哪个服务器,它最终会 returning 错误。


$ curl -v https://www.domain1.com

这很糟糕。您没有在端口 443 (HTTPS) 上侦听 www.domain1.com 的服务器(您目前只有一个在端口 80 (HTTP) 上)。这与您的任何服务器配置都不匹配。由于此请求与您的任何服务器都不匹配,因此 nginx 不会执行您想要的操作。 nginx 只是默认使用它看到的第一个服务器配置,不幸的是这不是你想要的。

这可以通过让 domain1.com 的重定向服务器同时侦听到 www.domain1.com 的端口 443 (HTTPS) 连接(而不仅仅是端口 80 (HTTP) www.domain1.com 连接)来解决,就像现在一样)。如果你不这样做,nginx 不知道该请求使用哪个服务器,它最终会 returning 错误。

解决方案:

您需要将 domain1.com 配置更改为:

# For forwarding HTTP (port 80) connections to your website:
server {
    listen 80;
    server_name domain1.com www.domain1.com;
    return 301 https://domain1.com$request_uri;
}

# For forwarding HTTPS (port 443) connections to www.domain1.com:
server {
    listen 443 ssl;
    ... add the other SSL configuration options ...
    server_name www.domain1.com;
    return 301 https://domain1.com$request_uri;
}

# Your main server configuration:
server {
    ... keep it as you currently have it for your domain1.com server ...
}

你的 domain2.com 配置为:

# For forwarding HTTP (port 80) connections to your website:
server {
    listen 80;
    server_name domain2.com www.domain2.com;
    return 301 https://domain2.com$request_uri;
}

# For forwarding HTTPS (port 443) connections to www.domain2.com:
server {
    listen 443 ssl;
    ... add the other SSL configuration options ...
    server_name www.domain2.com;
    return 301 https://domain2.com$request_uri;
}

# Your main server configuration:
server {
    ... keep it as you currently have it for your domain2.com server ...
}

我居然找到了...

server {
    server_name domain2.com  www.domain2.com;
    rewrite ^(.*) https://domain2.com permanent;
}

.

server {
    server_name domain1.com www.domain1.com;
    rewrite ^(.*) https://domain1.com permanent;
}

本质上需要发生的是,对于传入的 www 或无 www 请求,它需要 重写 它而不是转发。在此之后,我只需指定 listen 443 ssl; 和标准域名即可!