Nginx no-www a www y www a no-www

497

Estoy usando nginx en la nube de Rackspace después de un tutorial y después de haber buscado en la red y hasta ahora no puedo solucionar esto.

Quiero que www.mysite.com vaya a mysite.com de manera normal en .htaccess por SEO y otras razones.

Mi /etc/nginx/sites-available/www.example.com.vhost config:

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

También he intentado

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

También lo intenté. Tanto los segundos intentos dan errores de bucle de redireccionamiento.

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

Mi DNS está configurado de forma estándar:

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

(las IP y carpetas de ejemplo se han utilizado como ejemplos y para ayudar a las personas en el futuro). Yo uso Ubuntu 11.

TheBlackBenzKid
fuente
1
Me siento obligado a comentar que si está trabajando con un sitio web de WordPress, verifique Dashboard > Settings > General Settingsy asegúrese de que no haya ninguna wwwen las URL de dirección de sitio / sitio de WordPress. No importa cómo configure su nginx, si tiene un www en estas URL, se redirigirá al que tiene www.
Abhinav Sood

Respuestas:

792

Solución HTTP

De la documentación , "la forma correcta es definir un 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;
    ...
}

Solución HTTPS

Para aquellos que desean una solución que incluya 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 no lo he incluido https://en mi solución ya que usamos balanceadores de carga y nuestro servidor https: // es un servidor de pago SSL de alto tráfico: no mezclamos https: // y http: //.


Para verificar la versión nginx, use nginx -v.

Eliminar www de url con redireccionamiento 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#
}

Por lo tanto, debe tener DOS códigos de servidor.

Agregue el www a la url con nginx redirect

Si lo que necesita es lo contrario, para redirigir de domain.com a www.domain.com, puede usar esto:

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 puede imaginar, esto es todo lo contrario y funciona de la misma manera que el primer ejemplo. De esta manera, no obtienes marcas de SEO, ya que es una redirección y movimiento permanente. ¡No se fuerza WWW y se muestra el directorio!

Algunos de mis códigos se muestran a continuación para una mejor vista:

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
fuente
3
@puk lo aprecio. Nginx es sorprendente, pero una buena documentación que se mantiene actualizada con la versión del servidor y los cambios en el sistema operativo y el hardware del servidor es bastante agotador. El mejor recurso que me sirve es howtoforge.com, ya que es compatible con las versiones de la nube RackSpace. Algunos de los comandos anteriores no funcionarán en versiones posteriores. Pero este nginx / 0.8.54 - créanme, el mejor servidor nginx) no es necesario actualizar ni actualizar. Funciona bien. 100,000 visitas únicas al día con 4200 transacciones promedio por día. Nginx es RAPIDO. como usar un sitio sin tráfico.
TheBlackBenzKid
17
Sus reescrituras deben convertirse en devoluciones, como en return 301 $scheme://domain.com$request_uri;. No hay necesidad de capturar ningún patrón, vea las trampas de Nginx
Roberto
44
@TheBlackBenzKid Lo siento, tal vez me haya perdido algo, pero la solución actualizada no funciona. Es porque escucha 80: con eso, estás diciendo que solo HTTP coincide con esto. Debería haber más puertos para escuchar si se usa la misma configuración para HTTP y HTTPS ... ¿O? Pero definitivamente me ayudó, +1. Gracias por responder. Salud.
tomis
3
@TheBlackBenzKid Fue solo una nota. He encontrado una solución de trabajo. En su ejemplo, solo se debe agregar Listen 443 y completar el trabajo.
tomis
2
La respuesta es incorrecta. redirige todos los subdominios a www.
r3wt
399

En realidad, ni siquiera necesitas una reescritura.

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 mi respuesta es obtener más y más votos, pero también lo anterior. Nunca debe usar a rewriteen este contexto. ¿Por qué? Porque nginx tiene que procesar e iniciar una búsqueda. Si usa return(que debería estar disponible en cualquier versión nginx), detiene directamente la ejecución. Esto se prefiere en cualquier contexto.

Redireccione ambos, no SSL y SSL a su contraparte no 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...
}

La $schemevariable solo contendrá httpsi su servidor solo está escuchando en el puerto 80 (predeterminado) y la opción de escuchar no contiene la sslpalabra clave. No usar la variable no te dará ningún rendimiento.

Tenga en cuenta que necesita incluso más bloques de servidor si usa HSTS, porque los encabezados HSTS no deben enviarse a través de conexiones no cifradas. Por lo tanto, necesita bloques de servidor sin cifrar con redireccionamientos y bloques de servidor cifrados con redireccionamientos y encabezados HSTS.

Redireccionar todo a SSL (configuración personal en UNIX con 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...
}

Supongo que puedes imaginar otros compuestos con este patrón ahora solo.

¿Más de mis configuraciones? Ve aquí y aquí .

Grillete de carne
fuente
3
Tu Chrome no debería poder ir al dominio www tuyo si estás usando HSTS. Abra una nueva pregunta con tantos detalles como sea posible y lo ayudaré (puede publicar la URL de la pregunta como comentario aquí).
Fleshgrinder
1
@Fleshgrinder Estoy tratando de implementar su configuración, pero obtengo el siguiente problema en stackoverflow.com/questions/29451409 /... ¿Alguna idea sobre cómo hacer que funcione?
YPCrumble
44
En el segundo bloque "Redirigir ambos, no SSL y SSL a su contraparte que no es www:", ambos bloques de servidores deben tener las directivas SSL, ya que el navegador debe verificar el certificado de www.example.com antes de redirigir al ejemplo .com.
Jeff Tsay
1
Por supuesto, agregué eso así como una breve información sobre HSTS.
Fleshgrinder
1
@YPCrumble sí, es MUCHO más rápido de esta manera porque no estamos realizando coincidencias de expresiones regulares en cada solicitud. Solo redirigimos si sabemos que tenemos que redirigir. Sin controles, sin validación, nada: solo redirigir. =)
Fleshgrinder
37

Puede descubrir que desea utilizar la misma configuración para más dominios.

El siguiente fragmento elimina www antes de cualquier dominio:

if ($host ~* ^www\.(.*)$) {
    rewrite / $scheme://$1 permanent;
}
Martin Höger
fuente
77
Me gusta más que los bloques de servidores dedicados. Cambiar httpa$scheme
ck_
2
Mucho mejor, no puedo creer que muchos codifiquen dominios en configuraciones para esta tarea.
MrYellow
1
@Oli Ese enlace no menciona (a partir de hoy) el rendimiento, sino que no es 100% seguro. Sí dice "Las únicas cosas 100% seguras que se pueden hacer en el interior si en un contexto de ubicación son: return ...y rewrite ... last". ¿Algún enlace actualizado a problemas de rendimiento?
Adam
1
Esto no funcionó para mí. Seguí recibiendo un error en el navegador que decía una respuesta no válida.
Nico Brenner
1
Desafortunadamente, no encontré una manera sin "si". Utilizo la misma configuración para muchos dominios, codificar los nombres de dominio no es una opción. Cualquier sugerencia / comentario es apreciada!
Martin Höger
27

Necesita dos bloques de servidor.

Póngalos en su archivo de configuración, por ejemplo /etc/nginx/sites-available/sitename

Digamos que decide tener http://example.com como la dirección principal para usar.

Su archivo de configuración debería verse así:

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
}

El primer bloque de servidor contendrá las instrucciones para redirigir cualquier solicitud con el prefijo 'www'. Escucha las solicitudes de la URL con el prefijo 'www' y redirige.

No hace nada más.

El segundo bloque de servidor contendrá su dirección principal, la URL que desea usar. Todos los demás ajustes van aquí como root, index, location, etc. Compruebe el archivo por defecto para estos otros ajustes se pueden incluir en el bloque de servidor.

El servidor necesita dos 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 ipv6, cree el par de registros AAAA usando su dirección-ipv6.

rojo
fuente
23

Aquí se explica cómo hacerlo para varios nombres de servidor de www a no-www (lo usé para subdominios):

server {
        server_name 
             "~^www\.(sub1.example.com)$"
             "~^www\.(sub2.example.com)$"
             "~^www\.(sub3.example.com)$";
         return 301 $scheme://$1$request_uri ;
}
Eric Johnson
fuente
20
  1. Mejor práctica: separado servercon código rígidoserver_name

La mejor práctica con nginx es usar un separado serverpara una redirección como esta (no compartida con la serverde su configuración principal), para codificar todo y no usar expresiones regulares en absoluto.

También puede ser necesario codificar los dominios si está usando HTTPS, ya que debe saber por adelantado qué certificados proporcionará.

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 expresiones regulares dentro server_name

Si tiene varios sitios y no le interesa el rendimiento máximo, pero desea que cada uno de ellos tenga la misma política con respecto al www.prefijo, puede usar expresiones regulares. La mejor práctica de usar un separado serveraún se mantendría.

Tenga en cuenta que esta solución se vuelve complicada si usa https, ya que debe tener un solo certificado para cubrir todos sus nombres de dominio si desea que esto funcione correctamente.


non- wwwto wwww / regex en un single dedicado serverpara todos los sitios:

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

wwwa non- wwww / regex en un single dedicado serverpara todos los sitios:

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

wwwa non- wwww / regex en un sitio dedicado solo serverpara algunos sitios:

Puede ser necesario restringir la expresión regular para cubrir sólo un par de dominios, entonces usted puede usar algo como esto para solo www.example.org, www.example.comy www.subdomain.example.net:

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

Prueba de expresiones regulares con nginx

Puede probar que la expresión regular funciona como se esperaba pcretesten su sistema, que es exactamente la misma pcrebiblioteca que su nginx usará para expresiones 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> 

Tenga en cuenta que no tiene que preocuparse por los puntos finales o el caso, ya que nginx ya se encarga de eso, según el nombre del servidor nginx regex cuando el encabezado "Host" tiene un punto final .


  1. Asperjar ifdentro de serverHTTPS existente :

Esta solución final generalmente no se considera la mejor práctica, sin embargo, todavía funciona y hace el trabajo.

De hecho, si está utilizando HTTPS, entonces esta solución final puede resultar más fácil de mantener, ya que no tendría que copiar y pegar un montón de directivas SSL entre las diferentes serverdefiniciones, y en su lugar podría colocar los fragmentos solo en los servidores necesarios, lo que facilita la depuración y el mantenimiento de sus sitios.


no wwwa www:

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

wwwa no- www:

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

codificar un solo dominio preferido

Si desea un poco más de rendimiento, así como la consistencia entre múltiples dominios que un solo serverpuede usar, aún podría tener sentido codificar explícitamente un solo dominio preferido:

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

Referencias

cnst
fuente
16

Esta solución proviene de mi experiencia personal. Utilizamos varios cubos de Amazon S3 y un servidor para redirigir non-wwwa wwwnombres de dominio para que coincidan con la política de encabezado "Host" de S3 .

Usé la siguiente configuración para el servidor nginx :

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

Esto coincide con todos los nombres de dominio apuntados al servidor comenzando con lo que sea pero www.y redirige a www.<domain>. De la misma manera, puede hacer una redirección opuesta de wwwa non-www.

Visión
fuente
¿Qué hay de https? nota: https NECESITA el certificado
Toskan
No hay absolutamente ningún problema con HTTPS aquí. Después listen 80es necesario agregar listen 443 ssly, a continuación ssl_certificatey ssl_certificate_keydirectivas.
VisioN
nadie usa http hoy en día. Estaba leyendo una de las principales guías de Google que mostraba su ejemplo solo con la línea agregada listen 443 ssl con el certificado faltante. Eso no funcionará y está causando un fuerte dolor de cabeza.
Toskan
No sé de qué guía estás hablando. Tengo esta configuración trabajando con éxito durante casi tres años. El año pasado agregué soporte para SSL y funciona como se esperaba. Y, por supuesto, debe tener un certificado con una clave privada en la mano.
VisioN
así que esto golpeará todos los subdominios excepto www, ¿correcto?
Metagrapher
15

Combiné la mejor de todas las respuestas simples, sin dominios codificados.

Redirección permanente 301 de no www a www (HTTP o HTTPS):

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

    # Regular location configs...
}

Si prefiere no HTTPS, no www a HTTPS, redireccione www al mismo tiempo:

server {
    listen 80;

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

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

Redirigir no www a www

Para dominio único:

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

Para todos los dominios:

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

Redirigir www a no www Para dominio único:

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

Para todos los dominios:

server {
         server_name "~^www\.(.*)$" ;
         return 301 $scheme://$1$request_uri ;
}
Ravindra Bhalothia
fuente
¿Podría proporcionar diferenciación entre 80y 443?
Hassan Baig
1
Parece funcionar sin listendirectivas para mí (nginx 1.4.6).
Ibrahim
11

prueba esto

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

Otra forma: Nginx no-www a www

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

y www a no-www

server {
  listen       80;
  server_name  www.yoursite.com;
  root /path/;
  index index.php;
  return       301 https://yoursite.com$request_uri;
}
Kevin Nguyen
fuente
¿Por qué los autores proporcionaron una declaración if en nginx y luego le dijeron a las personas que la evitaran? Suena frívolo para mí.
Greg Smethells
44
Se dice "SI en el lugar es malo". Puede ponerlo con seguridad en su bloque de servidor
Kukunin
Cita directa desde el enlace de arriba ... Las únicas cosas 100% seguras que se pueden hacer dentro si están en contexto de ubicación son: return ...; reescribir ... último;
Justin E
8

Formato único:

server {
  listen 80;
  server_name "~^www\.(.*)$" ;
  return 301 https://$1$request_uri ;
}
Andriyun
fuente
1
Puede hacerlo genérico escribiéndolo de esta manera: server { server_name "~^www\.(.*)$" ; return 301 $scheme://$1$request_uri ; }
Ramast
5
location / { 
    if ($http_host !~ "^www.domain.com"){ 
        rewrite ^(.*)$ $scheme://www.domain.com/$1 redirect; 
    } 
}
Maoz Zadok
fuente
1
$scheme://www.domain.com$1para evitar el doble corte
karimhossenbux
3

No estoy seguro si alguien se da cuenta de que puede ser correcto devolver un 301, pero los navegadores se ahogan al hacerlo

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

es más rápido que:

return 301 $scheme://yoursite.com$request_uri;
Steven
fuente
1
mi comentario fue dirigido al navegador, no a la eficiencia en el lado nginx! con un redireccionamiento, el navegador realiza 2 solicitudes frente a 1 solicitud cuando rewittea
steven
2

Blog fantasma

Para que el método recomendado de nginx return 301 $scheme://example.com$request_uri;funcione con Ghost, deberá agregar su bloque de servidor principal:

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
fuente
2

Si no desea codificar el nombre de dominio, puede usar este bloque de redireccionamiento. El dominio sin el www principal se guarda como variable $domainque se puede reutilizar en la instrucción de redireccionamiento.

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

REF: Redirigir un subdominio con una expresión regular en nginx

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

Si tiene problemas para que esto funcione, es posible que deba agregar la dirección IP de su servidor. Por ejemplo:

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

donde XXX.XXX.XXX.XXX es la dirección IP (obviamente).

Nota: ssl crt y la ubicación de la clave se deben definir para redirigir correctamente las solicitudes https

No olvide reiniciar nginx después de realizar los cambios:

service nginx restart
deshacerlo
fuente
3
/etc/init.d/nginx reloadtambién puede reloadusar el servidor, lo que no causa ningún tiempo de inactividad.
TheBlackBenzKid