Nginx 不会将非 www 重定向到 www

Nginx 不会将非 www 重定向到 www

我需要我的 Nginx 设置,当用户在浏览器中输入 example.com 时,将用户重定向到 www.example.com。原因是我们的 SEO 顾问说应该只有一个首选域,否则 Google 会将其视为内容重复。无论如何……

所以关键是,我在服务器上也设置了 Letsencrypt 的 SSL,但我无法实现从 example.com 到 www.example.com 的重定向(服务器接受这两个版本)。这是我使用的配置:

server {
    listen 80; 
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://www.example.com$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    server_name example.com www.example.com;
    root /home/my_site;
    index index.php index.html index.htm;

    # for letsencrypt
    location ~ /.well-known {
        allow all;
    }   

    location / { 
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }   

    error_page 404 /404.html;

    error_page 500 502 503 504 /50x.html;

    location = /50x.html {
        root /usr/share/nginx/html;
    }

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

====更新====

我现在按照 Tim 的建议(我总是这样nginx -trestart)将我的配置更改为以下答案之一:

server {
    listen 80; 
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://www.example.com$request_uri;
}    

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;
    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;
    return 301 https://www.example.com$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name www.example.com;
    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    root /home/ankush/wp_ankushthakur;
    index index.php index.html index.htm;

    # for letsencrypt
    location ~ /.well-known {
        allow all;
    }   

    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    error_page 404 /404.html;

    error_page 500 502 503 504 /50x.html;

    location = /50x.html {
        root /usr/share/nginx/html;
    }

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

以下是所有变体的输出curl -k和访问日志(我没有从源代码构建 Nginx,因为我希望有一个更简单的解决方案并且不想弄乱服务器):

curl -k http://example.com
Curl output: 301 - Moved permanently
Access logs: "GET / HTTP/1.1" 301 194 "-" "curl/7.47.0"

curl -k http://www.example.com
Curl output: 301 - Moved permanently
Access logs: "GET / HTTP/1.1" 301 194 "-" "curl/7.47.0"

curl -k https://example.com
Curl output: 301 - Moved permanently
Access logs: "GET / HTTP/1.1" 301 194 "-" "curl/7.47.0"

curl -k https://www.example.com
Curl output: <Blank>
Access logs: "GET / HTTP/1.1" 301 5 "-" "curl/7.47.0"

注意最后一部分,其中 CURL 输出是空白的,并且访问日志仍然提供永久重定向。

有趣的是,如果我注释掉第二个server块,然后重新启动 Nginx,我最终会得到与我想要的相反的效果:www 重定向到非 www!我很惊讶会发生这种情况,因为 www.example.com 的 HTTPS 版本在此(第三)版配置中没有被提及。

答案1

这可能是因为您只在 HTTP 上重定向,而不是在 HTTPS 上重定向。您应该将 HTTPS 添加到重定向虚拟主机,并只保留其example.com名称。

此外,你所做的与现在人们实际所做的正好相反——常见的做法是埋葬遗产万维网旧时代的前缀,只使用简单的域名,没有万维网

答案2

这里的关键是您需要处理四个 URL - www 和非 www 域的 http 和 https 版本。您的问题是您正在将 www 和非 www 域的 http 版本转发到https://www域,但您的主服务器块正在监听这两个https://example.comhttps://www.example.com

您需要做的就是创建一个单独的服务器块来转发https://example.comhttps://www.example.com服务器。您需要将 https 设置包含在内。

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  include snippets/ssl-example.com.conf;
  include snippets/ssl-params.conf;

  server_name example.com;
  return 301 https://www.example.com$request_uri;
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  include snippets/ssl-example.com.conf;
  include snippets/ssl-params.conf;

  server_name  www.example.com;

  # Main server block for main server continues
}

标准示例

我有教程带有可下载的配置文件。下面是一个标准示例。

如果这对您不起作用,请使用 -k 选项卷曲每个变体(http 和 https、www 和非 www)以显示标题,并编辑您的问题以包含它们。

# Main server
server {
  server_name www.example.com;
  listen 443 ssl http2;
  # etc, add all locations, call PHP or servers, etc
}


# Forward http requests to https www server
server {
  listen       80;
  server_name  example.com www.example.com;
  return       301 https://www.example.com$request_uri;
}

# Forward https non-www requests to the https www server
# Requires https setup for this server
server {
  listen 443 ssl http2;
  server_name example.com;

  ssl_certificate /var/lib/acme/certs/***CERT_DIRECTORY/fullchain;
  ssl_certificate_key /var/lib/acme/certs/***CERT_DIRECTORY/privkey;

  # Set up preferred protocols and ciphers. TLS1.2 is required for HTTP/2
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

  return 301 https://www.example.com$request_uri;
}

解决问题 诊断问题的最佳方法是:

  • 在每个域变体上使用“curl -k”(显示标头),并结合访问日志。返回的 http 状态代码会告诉您发生了什么。200 是页面,301 是永久重定向,302 是临时重定向
  • 确保 Nginx 具有 headers_more 模块,您可以通过以下方式执行此操作从源代码构建 Nginx,这很容易。这允许您将 https 标头添加到响应中。这是一个很棒的诊断工具。您可以使用这样的语句来确定正在执行哪些块

添加标题 Z_DEBUG “位置名称或消息”;

答案3

我终于说服了我们的 SEO 人员将非 www 域名视为主要域名。将 www 重定向到非 www 的配置如下。虽然我尝试实现反向操作时使用了类似的配置,但我不确定是什么阻止了它。

server {
    listen 80; 
    listen [::]:80;

    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    server_name example.com;

    root /home/mysite;
    index index.php;

    location ~ /.well-known {
        allow all;
    }

    location / {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        try_files $uri $uri/ /index.php?$query_string;
        set $path_info $fastcgi_path_info;
        fastcgi_param PATH_INFO $path_info;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }
}

相关内容