Nginx não redireciona não-www para www

Nginx não redireciona não-www para www

Preciso que minha configuração do Nginx redirecione os usuários para www.example.com se eles digitarem example.com no navegador. A razão é que nosso consultor de SEO disse que deveria haver apenas um domínio preferencial, caso contrário, o Google verá isso como duplicação de conteúdo. De qualquer forma . . .

A questão é que também tenho SSL do Letsencrypt configurado no servidor, mas não consigo redirecionar de example.com para www.example.com (o servidor aceita ambas as versões). Aqui está a configuração que estou usando:

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;
    }
}

==== Atualização ====

Agora mudei minha configuração conforme recomendado por Tim (e sempre mudei nginx -t) restartem uma das respostas para o seguinte:

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;
    }
}

Aqui está a saída curl -ke os logs de acesso para todas as variações (não criei o Nginx a partir do código-fonte porque espero uma solução mais simples e não quero bagunçar o servidor):

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"

Observe a última seção, onde a saída CURL está em branco e os logs de acesso ainda fornecem um redirecionamento permanente.

Curiosamente, se eu comentar o segundo serverbloco e reiniciar o Nginx, acabo tendo o efeito oposto ao que queria: www redireciona para não www! Estou surpreso que isso esteja acontecendo, porque a versão HTTPS de www.example.com não é mencionada em nenhum lugar desta (terceira) versão da configuração.

Responder1

Provavelmente é porque você está redirecionando apenas em HTTP, mas não em HTTPS. Você deve adicionar um HTTPS ao seu vhost de redirecionamento e deixar apenas example.como nome.

Além disso, o que você está fazendo é o oposto do que as pessoas realmente fazem hoje em dia - a abordagem comum é enterrar o legadowwwprefixos da era antiga e usam apenas nomes de domínio simples, sem owww.

Responder2

A chave aqui é que você precisa lidar com quatro URLS - versões http e https dos domínios www e não www. Seu problema é que você está encaminhando a versão http do domínio www e não www para ohttps://wwwdomínio, mas seu bloco de servidor principal está escutando amboshttps://example.comehttps://www.exemplo.com

Tudo que você precisa fazer é criar um bloco de servidor separado para encaminhar ohttps://example.compara ohttps://www.exemplo.comservidor. Você precisa incluir a configuração https nisso.

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
}

Exemplo padrão

Eu tenhoum tutorialcom arquivos de configuração para download. Um exemplo padrão está abaixo.

Se isso não funcionar, você enrola cada variação (http e https, www e não www) com a opção -k para mostrar cabeçalhos e editar sua pergunta para incluí-los.

# 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;
}

Solução de problemas A melhor maneira de diagnosticar problemas é:

  • use "curl -k" (mostrar cabeçalhos) em cada uma das variantes de domínio, em conjunto com o log de acesso. Os códigos de status http retornados informam o que está acontecendo. 200 é a página, 301 é o redirecionamento permanente, 302 é o redirecionamento temporário
  • Certifique-se de que o Nginx tenha o módulo headers_more, o que você pode fazerconstruindo Nginx a partir da fonte, o que é bastante fácil. Isso permite adicionar cabeçalhos https à resposta. Esta é uma ótima ferramenta de diagnóstico. Você pode usar instruções como esta para descobrir quais blocos estão sendo executados

add_header Z_DEBUG "nome_local_ou_mensagem";

Responder3

Finalmente consegui convencer nosso especialista em SEO a considerar o domínio não www como principal. A configuração que funcionou para redirecionar www para não www foi a seguinte. Embora minha tentativa de conseguir o inverso tivesse uma configuração semelhante, não tenho certeza do que o impedia.

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;
    }
}

informação relacionada