Remova "www" e redirecione para "https" com nginx

46

Eu quero criar uma regra no nginx que faça duas coisas:

  1. Remove o "www". da solicitação URI
  2. Redireciona para "https" se o URI da solicitação for "http"

Existem muitos exemplos de como fazer cada uma dessas coisas individualmente, mas não consigo descobrir uma solução que faça as duas coisas corretamente (ou seja, não crie um loop de redirecionamento e lide com todos os casos corretamente).

Ele precisa lidar com todos esses casos:

1. http://www.example.com/path
2. https://www.example.com/path
3. http://example.com/path
4. https://example.com/path

Tudo isso deve terminar no link (# 4) sem loop. Alguma idéia?

    
por Devin 11.04.2011 / 18:37

7 respostas

66

A melhor maneira de conseguir isso é usar três blocos de servidor: um para redirecionar http para https, um para redirecionar o https www-name para o não-www e um para lidar com as solicitações. O motivo para usar blocos de servidores extras em vez de ifs é que a seleção do servidor é executada usando uma tabela de hash e é muito rápida. Usando um nível de servidor, se o if for executado para cada solicitação, o que é um desperdício. Além disso, capturar o uri solicitado na reescrita é um desperdício, já que o nginx já possui essas informações nas variáveis $ uri e $ request_uri (sem e com a string de consulta, respectivamente).

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>
}
    
por 11.04.2011 / 20:21
8

Isso funciona para mim:

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
}

Lembre-se de que ambos yourdomain.com e www.yourdomain.com devem estar em seu certificado SSL. Isso é possível com um certificado curinga ou com um Nome alternativo do servidor, conforme explicado aqui . Verifique o link para obter certificados agradáveis e gratuitos que fazem isso. ( Edith : a partir da versão 56 do Chrome, os certificados startssl deixarão de ser confiáveis. Tente link em seu lugar.)

    
por 09.05.2015 / 17:45
7

Depois de passar tanto tempo com centenas de casos semelhantes, eu inventei o seguinte trecho. É curto e pode ser facilmente ajustado para qualquer coisa.

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 / {
    # ...
}

Oh but if is evil!

Sim, pode ser. Mas existe por uma razão e não deve causar dano àqueles que sabe como usá-lo corretamente. ;)

    
por 24.01.2017 / 15:11
3

Eu prefiro retornar com um código de resposta para que o navegador saiba que você está redirecionando para outro URL.

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

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

então outro bloco de configurações do servidor para o https

server {
        listen   443 ssl;
        server_name  example.com;
        ...
    }
    
por 18.09.2013 / 14:16
0

que tal criar um bloco de servidores para esse propósito:

server{
    listen 80;
    server_name www.example.net example.net;
    rewrite ^(.*) https://example.net$1 permanent;
}

depois reiniciar o nginx

    
por 11.04.2011 / 18:45
0

Acho que isso deve funcionar.

Em sua definição de servidor HTTP simples, algo como anthonysomerset sugeriu, isto é:

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

Em seguida, na sua definição de servidor SSL:

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

Dessa forma, o redirecionamento só deve acontecer uma vez por solicitação, independentemente da URL para a qual o usuário acessa originalmente.

    
por 11.04.2011 / 19:56
0

Aqui está o exemplo completo que acabou funcionando para mim. O problema é que eu não tinha os detalhes do ssl ( ssl_certificate , etc.) no bloco de redirecionamento www. Lembre-se de verificar seus logs ( sudo tail -f /var/log/nginx/error.log )!

# HTTP — redirect all traffic to HTTPS
server {
    listen 80;
    listen [::]:80 default_server ipv6only=on;
    return 301 https://$host$request_uri;
}

# HTTPS — redirects www to non-www
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name www.example.com;

    # Use the Let's Encrypt certificates
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Include the SSL configuration from cipherli.st
    include snippets/ssl-params.conf;
    return 301 https://example.com$request_uri;
}

# HTTPS — proxy all requests to the app (port 3001)
server {
    # Enable HTTP/2
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com sub.example.com;

    # Use the Let's Encrypt certificates
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Include the SSL configuration from cipherli.st
    include snippets/ssl-params.conf;

    # For LetsEncrypt:
    location ~ /.well-known {
        root /var/www/html;
        allow all;
    }

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://localhost:3001;
        proxy_ssl_session_reuse off;
        proxy_set_header Host $http_host;
        proxy_cache_bypass $http_upgrade;
        proxy_redirect off;
    }
}
    
por 07.02.2017 / 04:58