ChatGPT解决这个技术问题 Extra ChatGPT

Nginx no-www 到 www 和 www 到 no-www

我正在使用 nginx on Rackspace cloud following a tutorial 并且已经搜索了网络,但到目前为止无法对其进行排序。

出于 SEO 和其他原因,我希望 www.mysite.example 在 .htaccess 中正常转到 mysite.example

我的 /etc/nginx/sites-available/www.example.com.vhost 配置:

server {
       listen 80;
       server_name www.example.com example.com;
       root /var/www/www.example.com/web;

       if ($http_host != "www.example.com") {
                 rewrite ^ http://example.com$request_uri permanent;
       }

我也试过

server {
       listen 80;
       server_name example.com;
       root /var/www/www.example.com/web;

       if ($http_host != "www.example.com") {
                 rewrite ^ http://example.com$request_uri permanent;
       }

我也试过。第二次尝试都给出了重定向循环错误。

if ($host = 'www.example.com' ) {
rewrite ^ http://example.com$uri permanent;
}

我的 DNS 设置为标准:

site.example 192.192.6.8 A type at 300 seconds
www.site.example 192.192.6.8 A type at 300 seconds

(示例 IP 和文件夹已用于示例并在将来帮助人们)。我使用 Ubuntu 11。

我觉得有必要评论一下,如果您使用的是 WordPress 网站,请检查 Dashboard > Settings > General Settings 并确保 WordPress 地址/站点地址 URL 中没有 www。无论您如何配置您的 nginx,如果您在这些 URL 中有 www,它将被重定向到其中包含 www 的那个。

S
Stephen Ostermiller

HTTP 解决方案

documentation 开始,“正确的方法是为 example.org 定义一个单独的服务器”:

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

server {
    listen       80;
    server_name  www.example.com;
    ...
}

HTTPS 解决方案

对于那些想要包括 https:// 在内的解决方案的人...

server {
        listen 80;
        server_name www.domain.example;
        # $scheme will get the http protocol
        # and 301 is best practice for tablet, phone, desktop and seo
        return 301 $scheme://domain.example$request_uri;
}

server {
        listen 80;
        server_name domain.example;
        # here goes the rest of your config file
        # example
        location / {

            rewrite ^/cp/login?$ /cp/login.php last;
            # etc etc...

        }
}

注意:我最初没有在我的解决方案中包含 https://,因为我们使用负载平衡器并且我们的 https:// 服务器是高流量 SSL 支付服务器:我们不混合使用 https:// 和 http://。

要检查 Nginx 版本,请使用 nginx -v

使用 Nginx 重定向从 URL 中去除 www

server {
    server_name  www.domain.example;
    rewrite ^(.*) http://domain.example$1 permanent;
}

server {
    server_name  domain.example;
    #The rest of your configuration goes here#
}

所以你需要有两个服务器代码。

使用 Nginx 重定向将 www 添加到 URL

如果您需要的是相反的,从 domain.example 重定向到 www.domain.example,您可以使用这个:

server {
    server_name  domain.example;
    rewrite ^(.*) http://www.domain.example$1 permanent;
}

server {
    server_name  www.domain.example;
    #The rest of your configuration goes here#
}

正如你可以想象的那样,这正好相反,工作方式与第一个示例相同。这样,您就不会降低 SEO 标记,因为它是完整的烫发重定向和移动。强制 no WWW 并显示目录!

下面显示了我的一些代码以获得更好的视图:

server {
    server_name  www.google.com;
    rewrite ^(.*) http://google.com$1 permanent;
}
server {
       listen 80;
       server_name google.com;
       index index.php index.html;
       ####
       # now pull the site from one directory #
       root /var/www/www.google.com/web;
       # done #
       location = /favicon.ico {
                log_not_found off;
                access_log off;
       }
}

@puk 感激不尽。 Nginx 非常棒,但是与服务器版本、操作系统和服务器硬件变化保持同步的良好文档非常令人厌烦。为我服务的最佳资源是 howtoforge.com,因为它支持 RackSpace 云版本。上面的某些命令在以后的版本中不起作用。但是这个 nginx/0.8.54 - 相信我,最好的 nginx 服务器)不需要升级或更新。工作正常。每天有 100,000 次唯一点击,平均每天有 4200 次交易。 Nginx 是快速的。就像使用没有流量的网站一样。
您的重写应该变成返回,如 return 301 $scheme://domain.com$request_uri;。无需捕获任何模式,请参阅 Nginx pitfalls
@TheBlackBenzKid 对不起,也许我错过了一些东西,但更新的解决方案不起作用。这是因为听 80 - 你说只有 HTTP 匹配这个。如果 HTTP 和 HTTPS 使用相同的配置,应该有更多的端口来监听……或者?但绝对帮助我,+1。谢谢您的回复。干杯。
@TheBlackBenzKid 只是请注意。我找到了可行的解决方案。在您的示例中,只应添加 Listen 443 并完成工作。
答案是错误的。它将所有子域重定向到 www。
F
Fleshgrinder

其实你甚至不需要重写。

server {
    #listen 80 is default
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
}

server {
    #listen 80 is default
    server_name example.com;
    ## here goes the rest of your conf...
}

因为我的回答是得到越来越多的赞成票,但以上也是如此。在这种情况下,您永远不应使用 rewrite。为什么?因为 nginx 必须处理并开始搜索。如果您使用 return(应该在任何 nginx 版本中都可用),它会直接停止执行。这在任何情况下都是首选。

将非 SSL 和 SSL 都重定向到它们的非 www 对应物:

server {
    listen               80;
    listen               443 ssl;
    server_name          www.example.com;
    ssl_certificate      path/to/cert;
    ssl_certificate_key  path/to/key;

    return 301 $scheme://example.com$request_uri;
}

server {
    listen               80;
    listen               443 ssl;
    server_name          example.com;
    ssl_certificate      path/to/cert;
    ssl_certificate_key  path/to/key;

    # rest goes here...
}

如果您的服务器仅侦听端口 80(默认)并且侦听选项不包含 ssl 关键字,则 $scheme 变量将仅包含 http。不使用该变量不会获得任何性能。

请注意,如果您使用 HSTS,则需要更多的服务器块,因为 HSTS 标头不应通过非加密连接发送。因此,您需要带有重定向的未加密服务器块和带有重定向和 HSTS 标头的加密服务器块。

将所有内容重定向到 SSL(在 UNIX 上使用 IPv4、IPv6、SPDY 进行个人配置...):

#
# Redirect all www to non-www
#
server {
    server_name          www.example.com;
    ssl_certificate      ssl/example.com/crt;
    ssl_certificate_key  ssl/example.com/key;
    listen               *:80;
    listen               *:443 ssl spdy;
    listen               [::]:80 ipv6only=on;
    listen               [::]:443 ssl spdy ipv6only=on;

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

#
# Redirect all non-encrypted to encrypted
#
server {
    server_name          example.com;
    listen               *:80;
    listen               [::]:80;

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

#
# There we go!
#
server {
    server_name          example.com;
    ssl_certificate      ssl/example.com/crt;
    ssl_certificate_key  ssl/example.com/key;
    listen               *:443 ssl spdy;
    listen               [::]:443 ssl spdy;

    # rest goes here...
}

我想您现在可以自己想象具有这种模式的其他化合物。

更多我的配置?前往 herehere


如果您使用的是 HSTS,您的 Chrome 应该无法访问您的 www 域。请打开一个包含尽可能详细信息的新问题,我会为您提供帮助(您可以在此处将问题的 URL 作为评论发布)。
@Fleshgrinder 我正在尝试实施您的设置,但在 stackoverflow.com/questions/29451409/… 遇到以下问题关于如何使其工作的任何想法?
在第二个块“将非 SSL 和 SSL 都重定向到它们的非 www 对应物:”中,两个服务器块都应该有 SSL 指令,因为浏览器需要在重定向到示例之前验证 www.example.com 的证书.com。
当然,我添加了这一点以及有关 HSTS 的简短信息。
@YPCrumble 是的,这种方式要快得多,因为我们没有对每个请求执行正则表达式匹配。只有当我们知道必须重定向时,我们才会重定向。没有检查,没有验证,什么都没有:只是重定向。 =)
C
Community

最佳实践:带有硬编码 server_name 的单独服务器

nginx 的最佳实践是使用单独的 server 进行这样的重定向(不与主配置的 server 共享),对所有内容进行硬编码,并且根本不使用正则表达式。

如果您使用 HTTPS,可能还需要对域进行硬编码,因为您必须预先知道您将提供哪些证书。

server {
    server_name www.example.com;
    return  301 $scheme://example.com$request_uri;
}
server {
    server_name www.example.org;
    return  301 $scheme://example.org$request_uri;
}
server {
    server_name example.com example.org;
    # real configuration goes here
}

在 server_name 中使用正则表达式

如果您有多个站点,并且不关心最高性能,但希望每个站点都对 www. 前缀具有相同的策略,那么您可以使用正则表达式。使用单独的 server 的最佳做法仍然有效。

请注意,如果您使用 https,此解决方案会变得很棘手,因为如果您希望它正常工作,您必须拥有一个证书来覆盖您的所有域名。

非 www 到 www w/ 正则表达式在所有站点的专用单一服务器中:

server {
    server_name ~^(?!www\.)(?<domain>.+)$;
    return  301 $scheme://www.$domain$request_uri;
}

www 到非 www w/ 正则表达式在所有站点的专用单个服务器中:

server {
    server_name ~^www\.(?<domain>.+)$;
    return  301 $scheme://$domain$request_uri;
}

www 到非 www w/ regex 仅适用于某些站点的专用服务器:

可能需要将正则表达式限制为仅涵盖几个域,然后您可以使用类似的内容仅匹配 www.example.orgwww.example.comwww.subdomain.example.net

server {
    server_name ~^www\.(?<domain>(?:example\.org|example\.com|subdomain\.example\.net))$;
    return  301 $scheme://$domain$request_uri;
}

使用 nginx 测试正则表达式

您可以使用系统上的 pcretest 测试正则表达式是否按预期工作,这与您的 nginx 将用于正则表达式的 pcre 库完全相同:

% pcretest 
PCRE version 8.35 2014-04-04

  re> #^www\.(?<domain>(?:example\.org|example\.com|subdomain\.example\.net))$#
data> test
No match
data> www.example.org
 0: www.example.org
 1: example.org
data> www.test.example.org
No match
data> www.example.com
 0: www.example.com
 1: example.com
data> www.subdomain.example.net
 0: www.subdomain.example.net
 1: subdomain.example.net
data> subdomain.example.net
No match
data> www.subdomain.example.net.
No match
data> 

请注意,您不必担心尾随点或大小写,因为 nginx 已经按照 nginx server name regex when "Host" header has a trailing dot 处理了它。

如果在现有服务器/HTTPS 中,则撒上:

这个最终解决方案通常不被认为是最佳实践,但是,它仍然有效并且可以完成工作。

事实上,如果您使用的是 HTTPS,那么最终的解决方案可能会更容易维护,因为您不必在不同的 server 定义之间复制粘贴一大堆 ssl 指令,而是可以将仅将片段提取到所需的服务器中,从而更容易调试和维护您的站点。

非 www 到 www:

if ($host ~ ^(?!www\.)(?<domain>.+)$) {
    return  301 $scheme://www.$domain$request_uri;
}

www 到非 www:

if ($host ~ ^www\.(?<domain>.+)$) {
    return  301 $scheme://$domain$request_uri;
}

硬编码单个首选域

如果您想要更高的性能,以及单个 server 可能使用的多个域之间的一致性,显式硬编码单个首选域可能仍然有意义:

if ($host != "example.com") {
    return  301 $scheme://example.com$request_uri;
}

参考:

http://nginx.org/r/server_name

http://nginx.org/r/return

http://nginx.org/en/docs/http/server_names.html


M
Martin Höger

您可能会发现要对更多域使用相同的配置。

以下代码段在任何域之前删除 www:

if ($host ~* ^www\.(.*)$) {
    rewrite / $scheme://$1 permanent;
}

我比专用服务器块更喜欢这种方式。将 http 更改为 $scheme
好多了,不敢相信有这么多人会为这项任务将域硬编码到配置中。
@Oli 该链接没有(截至今天)提到性能,而是它们不是 100% 安全的。它确实说“如果在位置上下文中,可以在内部完成的唯一 100% 安全的事情是:return ...rewrite ... last”。性能问题的任何更新链接?
这对我不起作用。一直在浏览器上收到错误消息,说响应无效。
不幸的是,我没有找到没有“如果”的方法。我对许多域使用相同的配置,对域名进行硬编码不是一种选择。任何建议/评论表示赞赏!
S
Stephen Ostermiller

您需要两个服务器块。

将这些放入您的配置文件中,例如 /etc/nginx/sites-available/sitename

假设您决定使用 http://example.com 作为主要地址。

您的配置文件应如下所示:

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

        # this is the main server block
        # insert ALL other config or settings in this server block
}

第一个服务器块将保存重定向任何带有“www”前缀的请求的指令。它侦听带有“www”前缀的 URL 请求并进行重定向。

它什么也不做。

第二个服务器块将保存您的主地址——您要使用的 URL。所有其他设置都放在此处,例如 rootindexlocation 等。检查默认文件以获取可以包含在服务器块中的这些其他设置。

服务器需要两条 DNS A 记录。

Name: @ IPAddress: your-ip-address (for the example.com URL)

Name: www IPAddress: your-ip-address (for the www.example.com URL)

对于 ipv6,使用 your-ipv6-address 创建一对 AAAA 记录。


E
Eric Johnson

以下是如何为多个 www 到 no-www 服务器名称执行此操作(我将其用于子域):

server {
        server_name 
             "~^www\.(sub1.example.com)$"
             "~^www\.(sub2.example.com)$"
             "~^www\.(sub3.example.com)$";
         return 301 $scheme://$1$request_uri ;
}

M
Matt Janssen

我结合了所有简单答案中最好的,没有硬编码的域。

从非 www 到 www(HTTP 或 HTTPS)的 301 永久重定向:

server {
    if ($host !~ ^www\.) {
        rewrite ^ $scheme://www.$host$request_uri permanent;
    }

    # Regular location configs...
}

如果您更喜欢非 HTTPS、非 www 而不是 HTTPS,同时 www 重定向:

server {
    listen 80;

    if ($host !~ ^www\.) {
        rewrite ^ https://www.$host$request_uri permanent;
    }

    rewrite ^ https://$host$request_uri permanent;
}

V
VisioN

这个解决方案来自我的个人经验。我们使用多个 Amazon S3 存储桶和一台服务器将 non-www 重定向到 www 域名以匹配 S3 "Host" header policy

我对 nginx 服务器使用了以下配置:

server {
    listen 80;
    server_name ~^(?!www\.)(?<domain>.+)$;
    return 301 $scheme://www.$domain$request_uri;
}

这匹配指向服务器的所有域名,但以 www. 开头并重定向到 www.<domain>。以同样的方式,您可以执行从 wwwnon-www 的反向重定向。


https呢?注意:https 需要证书
这里的 HTTPS 绝对没有问题。在 listen 80 之后,您需要添加 listen 443 ssl,然后是 ssl_certificatessl_certificate_key 指令。
现在没有人使用http。我正在阅读 google 中列出的顶级指南,该指南仅显示了您的示例,其中添加了缺少证书的行 listen 443 ssl。这不会工作,并导致一些严重的头痛。
不知道你说的是什么导游。我有这个配置成功地工作了近三年。去年我添加了对 SSL 的支持,它按预期工作。当然,您需要有一个带有私钥的证书。
所以这将破坏除www之外的所有子域,对吗?
S
Stephen Ostermiller

尝试这个

if ($host !~* ^www\.){
    rewrite ^(.*)$ https://www.yoursite.example$1;
}

其他方式:Nginx no-www 到 www

server {
  listen       80;
  server_name  yoursite.example;
  root /path/;
  index index.php;
  return       301 https://www.yoursite.example$request_uri;
}

和 www 到 no-www

server {
  listen       80;
  server_name  www.yoursite.example;
  root /path/;
  index index.php;
  return       301 https://yoursite.example$request_uri;
}

为什么作者在 nginx 中提供了一个 if 语句,然后告诉人们避免使用它?对我来说听起来很轻率。
有说明“如果位置是邪恶的”。您可以安全地将 if 放入您的服务器块
从上面的链接直接引用......如果在位置上下文中,唯一可以在内部完成的 100% 安全的事情是:返回......;重写...最后;
R
Ravindra Bhalothia

将非 www 重定向到 www

对于单域:

server {
        server_name example.com;
        return 301 $scheme://www.example.com$request_uri;
}

对于所有域:

server {
        server_name "~^(?!www\.).*" ;
        return 301 $scheme://www.$host$request_uri;
}

将 www 重定向到非 www 对于单个域:

server {
        server_name www.example.com;
        return 301 $scheme://example.com$request_uri;
}

对于所有域:

server {
         server_name "~^www\.(.*)$" ;
         return 301 $scheme://$1$request_uri ;
}

您能区分 80443 吗?
对我来说,它似乎在没有 listen 指令的情况下工作(nginx 1.4.6)。
A
Andriyun

独特的格式:

server {
  listen 80;
  server_name "~^www\.(.*)$" ;
  return 301 https://$1$request_uri ;
}

您可以通过这样编写使其通用:server { server_name "~^www\.(.*)$" ; return 301 $scheme://$1$request_uri ; }
D
Drakes

如果您不想对域名进行硬编码,可以使用此重定向块。没有前导 www 的域被保存为变量 $domain,可以在重定向语句中重用。

server {
    ...
    # Redirect www to non-www
    if ( $host ~ ^www\.(?<domain>.+) ) {
       rewrite ^/(.*)$ $scheme://$domain/$1;
    }
}

参考:Redirecting a subdomain with a regular expression in nginx


可怕的解决方案!
M
Maoz Zadok
location / {
    if ($http_host !~ "^www.domain.example"){
        rewrite ^(.*)$ $scheme://www.domain.example$1 redirect;
    }
}

$scheme://www.domain.com$1 避免双斜杠
S
Stephen Ostermiller

不知道是否有人注意到返回 301 可能是正确的,但浏览器对此感到窒息

rewrite ^(.*)$ https://yoursite.example$1;

比:

return 301 $scheme://yoursite.example$request_uri;

我的评论是针对浏览器的,而不是针对 nginx 方面的效率!使用重定向时,浏览器会发出 2 个请求与 1 个请求
s
stevek-pro

鬼博客

为了使带有 return 301 $scheme://example.com$request_uri; 的 nginx 推荐方法与 Ghost 一起使用,您需要在主服务器块中添加:

proxy_set_header    X-Real-IP           $remote_addr;
proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
proxy_set_header    Host                $http_host;
proxy_set_header    X-Forwarded-Proto   $scheme;
proxy_set_header    X-NginX-Proxy       true;

proxy_pass_header   X-CSRF-TOKEN;
proxy_buffering     off;
proxy_redirect      off;  

k
karadayi
if ($host ~* ^www.example.com$) {
    return 301 $scheme://example.com$request_uri;
}

S
Stephen Ostermiller

我的配置是 - Nginx + tomcat 9 + Ubuntu 20.04 + spring boot app 以上所有答案都对我不起作用 - Nginx 文件中的上游符号也不起作用 - 所以我更改了我的设置

感谢上帝的 certbot - 这个工具非常有用,它为您的站点生成基本文件,然后我添加了我的更改 - 将 https://www.example.comhttp://www.example.com 重定向到只有一个 https://example.com

server {
if ($host = www.example.com) {
    return 301 https://example.com$request_uri;
}
    root /var/www/example.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name example.com www.example.com;

    location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_pass http://127.0.0.1:8080; # This is upstream name, note the variable $scheme in it
      proxy_redirect off;
    }
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
    if ($host = www.example.com) {
        return 301 https://example.com$request_uri;
    } # managed by Certbot
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
        listen 80;
        listen [::]:80;
        server_name example.com www.example.com;
    return 404; # managed by Certbot
}

@Stephen Ostermiller 感谢您的格式化。
u
undoIT

如果您无法使其正常工作,您可能需要添加服务器的 IP 地址。例如:

server {
listen XXX.XXX.XXX.XXX:80;
listen XXX.XXX.XXX.XXX:443 ssl;
ssl_certificate /var/www/example.com/web/ssl/example.com.crt;
ssl_certificate_key /var/www/example.com/web/ssl/example.com.key;
server_name www.example.com;
return 301 $scheme://example.com$request_uri;
}

其中 XXX.XXX.XXX.XXX 是 IP 地址(显然)。

注意:必须定义 ssl crt 和 key location 才能正确重定向 https 请求

进行更改后不要忘记重新启动 nginx:

service nginx restart

/etc/init.d/nginx reload您也可以reload服务器,这不会导致任何停机。

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅