删除“www”并使用 nginx 重定向到“https”

Dev*_*vin 70 rewrite ssl nginx https

我想在 nginx 中创建一个规则来做两件事:

  1. 删除“www”。从请求 URI
  2. 如果请求 URI 是“http”,则重定向到“https”

有很多关于如何单独执行这些操作的示例,但我无法找到一个正确执行这两项操作的解决方案(即不创建重定向循环并正确处理所有情况)。

它需要处理所有这些情况:

1. http://www.example.com/path
2. https://www.example.com/path
3. http://example.com/path
4. https://example.com/path
Run Code Online (Sandbox Code Playgroud)

这些都应该在https://example.com/path (#4) 结束而不循环。有任何想法吗?

kol*_*ack 114

实现此目的的最佳方法是使用三个服务器块:一个将 http 重定向到 https,一个将 https www-name 重定向到 no-www,一个实际处理请求。使用额外的服务器块而不是 ifs 的原因是服务器选择是使用哈希表执行的,而且速度非常快。使用服务器级别的 if 意味着对每个请求都运行 if,这很浪费。此外,在重写中捕获请求的 uri 是一种浪费,因为 nginx 已经在 $uri 和 $request_uri 变量(分别没有和有查询字符串)中包含了这些信息。

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

server {
    listen 443 ssl;
    ssl_certificate /path/to/server.cert;
    ssl_certificate_key /path/to/server.key;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

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

    <locations for processing requests>
}
Run Code Online (Sandbox Code Playgroud)

  • 第二个块也需要证书信息。 (10认同)
  • 第一个块只处理 http。中间块是将 https 请求从 https://www.example.com/ 重定向到 https://example.com/ 所必需的。(对不起,多余的空格,否则我无法让它显示 https) (5认同)
  • 尝试这个答案,我遇到了另一个问题。以为我可以 301 从 `www.sub.example.com` 重定向到 `sub.example.com` 然后只获取 `sub.example.com` 的 SSL 证书现在我知道 ssl 证书检查发生在 301 重定向之前,所以它不能工作。更多解释在这里:http://serverfault.com/a/358625/144811 (3认同)
  • 中间块是必要的吗?第一个块不是已经从 www 重写为非 www 了吗? (2认同)
  • 只是一个次要的格式说明 - 如果您想避免创建链接,您可以将评论文本放在反引号 \` 中,即波浪号下的那个。它会显示为:`https://example.com/` (2认同)

e18*_*18r 12

这对我有用:

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

server {
    listen              443 ssl;
    server_name         www.yourdomain.com;
    ssl_certificate     /path/to/certificate.crt;
    ssl_certificate_key /path/to/private/key.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    return              301 https://yourdomain.com$request_uri;
}

server {
    listen              443 ssl;
    server_name         yourdomain.com;
    ssl_certificate     /path/to/certificate.crt;
    ssl_certificate_key /path/to/private/key.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;

    # do the proper handling of the request
}
Run Code Online (Sandbox Code Playgroud)

请记住,这两个 yourdomain.com www.yourdomain.com 必须在你的SSL证书。这是可能的通配符证书或与服务器备用名称作为解释在这里。检查https://www.startssl.com以获得执行此操作的漂亮且免费的证书。(伊迪丝:从 Chrome 版本 56 开始,startssl 证书将不再受信任。请尝试使用https://letsencrypt.org/。)


小智 9

在花了这么多时间处理数百个类似案例之后,我想出了以下代码片段。它很短,可以很容易地调整以适应任何东西。

server {
    listen 80;
    listen 443 ssl;
    server_name example.com www.example.com;
    ssl_certificate /path/to/my/certs/example.com/fullchain.pem;
    ssl_certificate_key /path/to/my/certs/example.com/privkey.pem;

    # Redirect to the correct place, if needed
    set $https_redirect 0;
    if ($server_port = 80) { set $https_redirect 1; }
    if ($host ~ '^www\.') { set $https_redirect 1; }
    if ($https_redirect = 1) {
        return 301 https://example.com$request_uri;
    }

    location / {
    # ...
}
Run Code Online (Sandbox Code Playgroud)

哦可是if邪恶的

是的,可以。但它存在是有原因的,应该不会伤害那些知道如何正确使用它的人。;)