Nginx no-www para www e www para no-www

497

Estou usando o nginx na nuvem da Rackspace, seguindo um tutorial e tendo pesquisado na net e até agora não consigo resolver isso.

Quero que www.mysite.com acesse meu site.com normalmente no .htaccess por SEO e outros motivos.

Minha configuração do /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;
       }

Eu também tentei

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

Eu também tentei. Ambas as segundas tentativas fornecem erros de loop de redirecionamento.

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

Meu DNS está configurado como padrão:

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

(IPs e pastas de exemplo foram usados ​​para exemplos e para ajudar pessoas no futuro). Eu uso o Ubuntu 11.

TheBlackBenzKid
fonte
1
Sinto-me compelido a comentar que, se você estiver trabalhando com um site WordPress, verifique Dashboard > Settings > General Settingse verifique se não há wwwnos URLs de endereço / endereço do site do WordPress. Não importa como você configure seu nginx, se você tiver um www nesses URLs, ele será redirecionado para aquele com www.
Abhinav Sood

Respostas:

792

Solução HTTP

Na documentação , "o caminho certo é definir um servidor separado para 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;
    ...
}

Solução HTTPS

Para quem quer uma solução, incluindo https://...

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

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

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

        }
}

Nota: originalmente não incluí https://na minha solução, pois usamos balanceadores de carga e nosso servidor https: // é um servidor de pagamento SSL de alto tráfego: não combinamos https: // e http: //.


Para verificar a versão do nginx, use nginx -v.

Retire o www do URL com o redirecionamento nginx

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

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

Então você precisa ter dois códigos de servidor.

Adicione o www ao URL com redirecionamento nginx

Se o que você precisa é o contrário, para redirecionar de domain.com para www.domain.com, você pode usar o seguinte:

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

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

Como você pode imaginar, isso é exatamente o oposto e funciona da mesma maneira que o primeiro exemplo. Dessa forma, você não obtém as marcas de SEO, pois ele é completo, permite redirecionar e mover. A não WWW é forçada e o diretório é mostrado!

Alguns dos meus códigos mostrados abaixo para uma melhor visualização:

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;
       }
}
TheBlackBenzKid
fonte
3
@puk aprecio isso. O Nginx é incrível, mas uma boa documentação que se mantém atualizada com a versão do servidor e as alterações de hardware do sistema operacional e do servidor é bastante cansativa. O melhor recurso que me serve é o howtoforge.com, pois suporta as versões em nuvem do RackSpace. Alguns dos comandos acima não funcionarão em versões posteriores. Mas este nginx / 0.8.54 - é, acredite, o melhor servidor nginx), não há necessidade de atualizar ou atualizar. Funciona bem. 100.000 acessos únicos por dia, com 4200 transações em média por dia. Nginx é RAPID. como usar um site sem tráfego.
TheBlackBenzKid
17
Suas reescritas devem se tornar devoluções, como em return 301 $scheme://domain.com$request_uri;. Não há necessidade de capturar quaisquer padrões, consulte armadilhas Nginx
Roberto
4
@TheBlackBenzKid Desculpe, talvez eu tenha perdido algo, mas a solução atualizada não está funcionando. É porque escute 80 - com isso, você está dizendo que apenas HTTP está correspondendo a isso. Deve haver mais portas para escutar se a mesma configuração for usada para HTTP e HTTPS ... Ou? Mas definitivamente me ajudou, +1. Obrigado pela resposta. Felicidades.
Tomis 14/05
3
@TheBlackBenzKid Foi apenas nota. Eu descobri a solução de trabalho. No seu exemplo, apenas o Listen 443 deve ser adicionado e concluir o trabalho.
tomis 15/05
2
resposta está errada. ele redireciona todos os subdomínios para www.
R3wt
398

Na verdade, você nem precisa de uma reescrita.

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

Como minha resposta está recebendo mais e mais votos, mas o acima também. Você nunca deve usar um rewritenesse contexto. Por quê? Porque o nginx precisa processar e iniciar uma pesquisa. Se você usar return(que deve estar disponível em qualquer versão do nginx), ele interrompe diretamente a execução. Isso é preferido em qualquer contexto.

Redirecione ambos, não SSL e SSL para sua contraparte não 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...
}

A $schemevariável conterá apenas httpse o servidor estiver escutando apenas na porta 80 (padrão) e a opção de escuta não contiver a sslpalavra - chave. Não usar a variável não terá nenhum desempenho.

Observe que você precisa de ainda mais blocos de servidor se usar o HSTS, porque os cabeçalhos do HSTS não devem ser enviados por conexões não criptografadas. Portanto, você precisa de blocos de servidor não criptografados com redirecionamentos e blocos de servidor criptografados com redirecionamentos e cabeçalhos HSTS.

Redirecione tudo para SSL (configuração pessoal no UNIX com 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...
}

Eu acho que você pode imaginar outros compostos com esse padrão agora sozinho.

Mais das minhas configurações? Vá aqui e aqui .

Triturador de Carne
fonte
3
Seu Chrome não poderá acessar o seu domínio www se você estiver usando o HSTS. Abra uma nova pergunta com o maior número de detalhes possível e eu o ajudarei (você pode postar o URL da pergunta como um comentário aqui).
Fleshgrinder
1
@Fleshgrinder Estou tentando implementar sua configuração, mas obtendo o seguinte problema em stackoverflow.com/questions/29451409/… Alguma idéia de como fazê-lo funcionar?
usar o seguinte comando
4
No 2º bloco "Redirecione ambos, não SSL e SSL para sua contraparte não www:", os dois blocos de servidor devem ter as diretivas SSL, pois o navegador precisa verificar o certificado para www.example.com antes de redirecionar para o exemplo .com.
Jeff Tsay
1
É claro, eu adicionei isso, além de uma breve informação sobre o HSTS.
Fleshgrinder
1
@YPCrumble sim, é MUITO mais rápido dessa maneira, porque não estamos executando correspondência de expressão regular em cada solicitação. Somente redirecionamos se soubermos que precisamos redirecionar. Sem verificações, sem validação, nada: apenas redirecionar. =)
Fleshgrinder
37

Você pode descobrir que deseja usar a mesma configuração para mais domínios.

O fragmento a seguir remove www antes de qualquer domínio:

if ($host ~* ^www\.(.*)$) {
    rewrite / $scheme://$1 permanent;
}
Martin Höger
fonte
7
Eu gosto desta maneira melhor do que blocos de servidor dedicados. Alterar httppara$scheme
ck_
2
Muito melhor, não posso acreditar que tantos codificariam domínios em configurações para esta tarefa.
MrYellow 27/10/2015
1
@ Oli Esse link não menciona (até hoje) o desempenho, mas sim que não é 100% seguro. Diz "As únicas coisas 100% seguras que podem ser feitas dentro de um ambiente de localização são: return ...e rewrite ... last". Algum link atualizado para problemas de desempenho?
Adam
1
Isso não funcionou para mim. Continuou recebendo um erro no navegador dizendo resposta inválida.
Nico Brenner
1
Infelizmente, não encontrei um caminho sem "se". Eu uso a mesma configuração para muitos domínios, codificar os nomes de domínio não é uma opção. Qualquer sugestão / comentário é apreciado!
Martin Höger
27

Você precisa de dois blocos de servidor.

Coloque-os no seu arquivo de configuração, por exemplo /etc/nginx/sites-available/sitename

Digamos que você decida ter http://example.com como o endereço principal a ser usado.

Seu arquivo de configuração deve ficar assim:

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
}

O primeiro bloco do servidor conterá as instruções para redirecionar todas as solicitações com o prefixo 'www'. Ele escuta solicitações de URL com o prefixo 'www' e redireciona.

Não faz mais nada.

O segundo bloco do servidor conterá o seu endereço principal - o URL que você deseja usar. Todas as outras configurações aqui como root, index, location, etc. Verifique o arquivo padrão para essas outras configurações que você pode incluir no bloco de servidor.

O servidor precisa de dois registros DNS A.

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

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

Para o ipv6, crie o par de registros AAAA usando o seu endereço-ipv6.

Vermelho
fonte
23

Veja como fazer isso para vários nomes de servidores www para no-www (usei isso para subdomínios):

server {
        server_name 
             "~^www\.(sub1.example.com)$"
             "~^www\.(sub2.example.com)$"
             "~^www\.(sub3.example.com)$";
         return 301 $scheme://$1$request_uri ;
}
Eric Johnson
fonte
20
  1. Prática recomendada: separado servercom código fixoserver_name

A melhor prática com o nginx é usar um separado serverpara um redirecionamento como este (não compartilhado com o serverda sua configuração principal), codificar tudo e não usar expressões regulares.

Também pode ser necessário codificar os domínios se você estiver usando HTTPS, porque é necessário saber antecipadamente quais certificados você estará fornecendo.

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
}

  1. Usando expressões regulares em server_name

Se você possui vários sites e não se importa com o melhor desempenho, mas deseja que cada um deles tenha a mesma política em relação ao www.prefixo, poderá usar expressões regulares. A melhor prática de usar um separado serverainda permaneceria.

Observe que esta solução fica complicada se você usar https, pois você deve ter um único certificado para cobrir todos os seus nomes de domínio, se quiser que isso funcione corretamente.


non- wwwto www/ regex em um single dedicado serverpara todos os sites:

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

wwwpara non- wwww / regex em um single dedicado serverpara todos os sites:

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

wwwpara non- wwww / regex em um dedicado apenas serverpara alguns sites:

Pode ser necessário restringir a regex para cobrir apenas um par de domínios, em seguida, você pode usar algo como isto apenas corresponder www.example.org, www.example.come www.subdomain.example.net:

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

Testando expressões regulares com nginx

Você pode testar se o regex funciona conforme o esperado pcretestno seu sistema, que é exatamente a mesma pcrebiblioteca que o nginx usará para expressões regulares:

% 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> 

Observe que você não precisa se preocupar com pontos ou maiúsculas à direita, pois o nginx já cuida disso, conforme regex do nome do servidor nginx quando o cabeçalho "Host" possui um ponto à direita .


  1. Polvilhe ifdentro do server/ HTTPS existente :

Essa solução final geralmente não é considerada a melhor prática, no entanto, ainda funciona e faz o trabalho.

De fato, se você estiver usando HTTPS, essa solução final poderá ficar mais fácil de manter, pois você não precisará copiar e colar várias diretivas ssl entre as diferentes serverdefinições e, em vez disso, poderá colocar os snippets apenas em os servidores necessários, facilitando a depuração e manutenção de seus sites.


não wwwpara www:

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

wwwpara não www:

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

codificar um único domínio preferido

Se você deseja um pouco mais de desempenho, além da consistência entre vários domínios que um único serverpode usar, ainda pode fazer sentido codificar explicitamente um único domínio preferido:

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

Referências:

cnst
fonte
16

Esta solução vem da minha experiência pessoal. Usamos vários buckets do Amazon S3 e um servidor para redirecionar non-wwwpara wwwnomes de domínio para corresponder à política de cabeçalho "Host" do S3 .

Eu usei a seguinte configuração para o servidor nginx :

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

Isso corresponde a todos os nomes de domínio apontados para o servidor começando com o que quer que seja www.e redireciona para www.<domain>. Da mesma maneira, você pode fazer o redirecionamento oposto de wwwpara non-www.

Visão
fonte
e quanto a https? Nota: https precisa do certificado
Toskan
Não há absolutamente nenhum problema com HTTPS aqui. Depois listen 80você precisa adicionar listen 443 ssle então ssl_certificatee ssl_certificate_keydiretivas.
VisioN
hoje ninguém usa http. Eu estava lendo um guia listado no topo do Google que mostrava seu exemplo apenas com a linha adicionada listen 443 ssl com o certificado ausente. Isso não funciona e está causando algumas sérias dores de cabeça.
Toskan
Não sei de que guia você está falando. Eu tenho essa configuração trabalhando com sucesso por quase três anos. No ano passado, adicionei suporte para SSL e funciona como esperado. E é claro que você precisa ter um certificado com uma chave privada na mão.
VisioN
então isso derruba todos os subdomínios, exceto www, correto?
Metagrafista 23/01
15

Combinei o melhor de todas as respostas simples, sem domínios codificados.

301 redirecionamento permanente de não www para www (HTTP ou HTTPS):

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

    # Regular location configs...
}

Se você preferir não HTTPS, não www para HTTPS, www redirecione ao mesmo tempo:

server {
    listen 80;

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

    rewrite ^ https://$host$request_uri permanent;
}
Matt Janssen
fonte
11

Redirecionar não www para www

Para domínio único:

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

Para todos os domínios:

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

Redirecione www para não www para Domínio Único:

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

Para todos os domínios:

server {
         server_name "~^www\.(.*)$" ;
         return 301 $scheme://$1$request_uri ;
}
Ravindra Bhalothia
fonte
Você poderia fornecer diferenciação entre 80e 443?
Hassan Baig
1
Parece funcionar sem listendiretivas para mim (nginx 1.4.6).
Ibrahim
11

tente isso

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

Outra maneira: Nginx no-www para www

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

e www para no-www

server {
  listen       80;
  server_name  www.yoursite.com;
  root /path/;
  index index.php;
  return       301 https://yoursite.com$request_uri;
}
Kevin Nguyen
fonte
Por que os autores forneceram uma declaração if no nginx e depois disseram às pessoas para evitá-lo? Parece irreverente para mim.
Greg Smethells
4
É declarado "SE no local é mau". Você pode colocar com segurança se em seu bloco servidor
Kukunin
Citação direta no link acima ... As únicas coisas 100% seguras que podem ser feitas dentro de um ambiente de localização são: return ...; reescrever ... por último;
Justin E
8

Formato exclusivo:

server {
  listen 80;
  server_name "~^www\.(.*)$" ;
  return 301 https://$1$request_uri ;
}
Andriyun
fonte
1
Você pode torná-lo genérico, escrevendo-o desta maneira: server { server_name "~^www\.(.*)$" ; return 301 $scheme://$1$request_uri ; }
Ramast 29/07/2015
5
location / { 
    if ($http_host !~ "^www.domain.com"){ 
        rewrite ^(.*)$ $scheme://www.domain.com/$1 redirect; 
    } 
}
Maoz Zadok
fonte
1
$scheme://www.domain.com$1para evitar barra dupla
karimhossenbux 26/06
3

não tenho certeza se alguém notou que pode ser correto retornar um 301, mas os navegadores se engasgam

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

é mais rápido que:

return 301 $scheme://yoursite.com$request_uri;
steven
fonte
1
meu comentário foi direcionado para o navegador não para eficiência no lado nginx! com um redirecionamento do navegador faz 2 pedidos vs 1 pedido quando rewiting
steven
2

Blog fantasma

para que o método nginx seja recomendado return 301 $scheme://example.com$request_uri;com o Ghost, você precisará adicionar no bloco principal do servidor:

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;  
stevek
fonte
2

Se você não deseja codificar o nome de domínio, pode usar este bloco de redirecionamento. O domínio sem o www principal é salvo como variável $domainque pode ser reutilizada na instrução de redirecionamento.

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

REF: redirecionando um subdomínio com uma expressão regular em nginx

Drakes
fonte
0
if ($host ~* ^www.example.com$) {
    return 301 $scheme://example.com$request_uri;
}
karadayi
fonte
-6

Se estiver com problemas para fazer isso funcionar, pode ser necessário adicionar o endereço IP do seu servidor. Por exemplo:

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

onde XXX.XXX.XXX.XXX é o endereço IP (obviamente).

Nota: ssl crt e local da chave devem ser definidos para redirecionar corretamente solicitações https

Não se esqueça de reiniciar o nginx depois de fazer as alterações:

service nginx restart
desfazer
fonte
3
/etc/init.d/nginx reloadvocê também pode reloadusar o servidor, o que não causa nenhum tempo de inatividade.
TheBlackBenzKid