Nginx no-www a www e www a no-www


497

Sto usando nginx su Rackspace cloud seguendo un tutorial e dopo aver cercato in rete e finora non riesco a risolvere questo problema.

Voglio che www.mysite.com vada normalmente su mysite.com in .htaccess per SEO e altri motivi.

La mia configurazione /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;
       }

Ho anche provato

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

Ho anche provato. Entrambi i secondi tentativi danno errori di reindirizzamento.

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

Il mio DNS è configurato come standard:

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

(esempio IP e cartelle sono stati usati per esempi e per aiutare le persone in futuro). Uso Ubuntu 11.


1
Mi sento obbligato a commentare che se stai lavorando con un sito Web WordPress, controlla Dashboard > Settings > General Settingse assicurati che non ci siano wwwURL di indirizzo / indirizzo sito di WordPress. Indipendentemente da come configuri il tuo nginx, se hai un www in questi URL verrebbe reindirizzato a quello con www in esso.
Abhinav Sood,

Risposte:


792

Soluzione HTTP

Dalla documentazione , "il modo giusto è definire un server separato per esempio.org":

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

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

Soluzione HTTPS

Per chi desidera una soluzione tra cui 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: non ho originariamente incluso https://nella mia soluzione poiché utilizziamo i servizi di bilanciamento del carico e il nostro server https: // è un server di pagamento SSL ad alto traffico: non mescoliamo https: // e http: //.


Per verificare la versione di nginx, utilizzare nginx -v.

Rimuovi www dall'URL con il reindirizzamento di 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#
}

Quindi è necessario disporre di DUE codici server.

Aggiungi il www all'URL con il reindirizzamento di nginx

Se ciò di cui hai bisogno è l'opposto, per reindirizzare da domain.com a www.domain.com, puoi utilizzare questo:

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

Come puoi immaginare, questo è esattamente l'opposto e funziona nello stesso modo del primo esempio. In questo modo, non si riducono i contrassegni SEO, poiché è completo per il reindirizzamento e lo spostamento. Il WWW no viene forzato e viene visualizzata la directory!

Alcuni dei miei codici mostrati di seguito per una visione migliore:

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

3
@puk lo apprezzo. Nginx è sorprendente, ma una buona documentazione che rimane aggiornata con la versione del server e le modifiche all'hardware del sistema operativo e del server è piuttosto noiosa. La migliore risorsa che mi serve è howtoforge.com in quanto supporta le versioni cloud di RackSpace. Alcuni dei comandi sopra non funzioneranno nelle versioni successive. Ma questo nginx / 0.8.54 - credo, il miglior server nginx) non è necessario aggiornare o aggiornare. Funziona bene. 100.000 hit unici al giorno con 4200 transazioni in media al giorno. Nginx è RAPID. come usare un sito senza traffico.
TheBlackBenzKid

17
Le riscritture dovrebbero diventare resi, come in return 301 $scheme://domain.com$request_uri;. Non è necessario catturare alcun motivo, vedi le insidie ​​di Nginx
Roberto,

4
@TheBlackBenzKid Siamo spiacenti, forse mi sono perso qualcosa, ma la soluzione aggiornata non funziona. È perché ascolta 80 - con questo, stai dicendo che solo HTTP corrisponde a questo. Dovrebbero esserci più porte da ascoltare se si utilizza la stessa configurazione per HTTP e HTTPS ... O? Ma sicuramente mi ha aiutato, +1. Grazie per la risposta. Saluti.
tomis

3
@TheBlackBenzKid Era solo una nota. Ho scoperto una soluzione funzionante. Nel tuo esempio, solo Listen 443 deve essere aggiunto e completo funzionante.
tomis,

2
la risposta è sbagliata. reindirizza tutti i sottodomini su www.
r3wt

399

In realtà non hai nemmeno bisogno di una riscrittura.

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

Poiché la mia risposta è ottenere sempre più voti, ma anche quanto sopra. Non dovresti mai usare a rewritein questo contesto. Perché? Perché nginx deve elaborare e avviare una ricerca. Se usi return(che dovrebbe essere disponibile in qualsiasi versione di nginx), interrompe direttamente l'esecuzione. Questo è preferito in qualsiasi contesto.

Reindirizzare entrambi, non SSL e SSL alla loro controparte non 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 $schemevariabile conterrà solo httpse il server è in ascolto solo sulla porta 80 (impostazione predefinita) e l'opzione di ascolto non contiene la sslparola chiave. Non usare la variabile non ti farà ottenere alcuna prestazione.

Si noti che sono necessari ancora più blocchi server se si utilizza HSTS, poiché le intestazioni HSTS non devono essere inviate tramite connessioni non crittografate. Pertanto, sono necessari blocchi server non crittografati con reindirizzamenti e blocchi server crittografati con reindirizzamenti e intestazioni HSTS.

Reindirizza tutto su SSL (configurazione personale su 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...
}

Immagino che tu possa immaginare altri composti con questo schema ora da solo.

Altre mie configurazioni? Vai qui e qui .


3
Chrome non dovrebbe essere in grado di accedere al tuo dominio www se utilizzi HSTS. Apri una nuova domanda con il maggior numero possibile di dettagli e ti aiuterò (puoi pubblicare l'URL alla domanda come commento qui).
Fleshgrinder,

1
@Fleshgrinder Sto cercando di implementare la tua configurazione ma ricevo il seguente problema su stackoverflow.com/questions/29451409/… Qualche idea su come farlo funzionare?
YPCrumble

4
Nel secondo blocco "Reindirizza entrambi, non SSL e SSL alla loro controparte non www:", entrambi i blocchi server dovrebbero avere le direttive SSL, poiché il browser deve verificare il certificato per www.example.com prima di reindirizzare all'esempio .com.
Jeff Tsay,

1
Naturalmente, ho aggiunto anche questo e una breve informazione su HSTS.
Fleshgrinder,

1
@YPCrumble sì, è MOLTO più veloce in questo modo perché non eseguiamo la corrispondenza delle espressioni regolari su ogni richiesta. Reindirizziamo solo se sappiamo che dobbiamo reindirizzare. Nessun controllo, nessuna convalida, niente: solo reindirizzamento. =)
Fleshgrinder

37

Potresti scoprire di voler utilizzare la stessa configurazione per più domini.

Lo snippet seguente rimuove www prima di qualsiasi dominio:

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

7
Mi piace così meglio dei blocchi server dedicati. Passare httpa$scheme
ck_

2
Molto meglio, non riesco a credere che così tanti codificherebbero i domini in configurazioni per questa attività.
MrYellow,

1
@Oli Quel link non menziona (ad oggi) le prestazioni ma piuttosto non sono sicure al 100%. Dice "Le uniche cose sicure al 100% che possono essere fatte all'interno se in un contesto di posizione sono: return ...e rewrite ... last". Eventuali collegamenti aggiornati a problemi di prestazioni?
Adam,

1
Questo non ha funzionato per me. Continuo a ricevere un errore sul browser dicendo risposta non valida.
Nico Brenner,

1
Sfortunatamente, non ho trovato un modo senza "se". Uso la stessa configurazione per molti domini, la codifica dei nomi di dominio non è un'opzione. Qualsiasi suggerimento / commento è apprezzato!
Martin Höger,

27

Sono necessari due blocchi server.

Inseriscili nel tuo file di configurazione, ad es /etc/nginx/sites-available/sitename

Supponiamo che tu decida di avere http://example.com come indirizzo principale da utilizzare.

Il tuo file di configurazione dovrebbe apparire così:

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
}

Il primo blocco server conterrà le istruzioni per reindirizzare eventuali richieste con il prefisso "www". Ascolta le richieste per l'URL con prefisso "www" e reindirizza.

Non fa nient'altro.

Il secondo blocco server conterrà il tuo indirizzo principale: l'URL che desideri utilizzare. Tutte le altre impostazioni vanno qui come root, index, location, ecc Controllare il file di default per queste altre impostazioni è possibile includere nel blocco del server.

Il server necessita di due record DNS A.

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

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

Per ipv6 crea la coppia di record AAAA usando il tuo indirizzo ipv6.


23

Ecco come farlo per più nomi di server da www a no-www (l'ho usato per sottodomini):

server {
        server_name 
             "~^www\.(sub1.example.com)$"
             "~^www\.(sub2.example.com)$"
             "~^www\.(sub3.example.com)$";
         return 301 $scheme://$1$request_uri ;
}

20
  1. Best Practice: separato servercon hardcodedserver_name

La migliore pratica con nginx è quella di utilizzare un metodo separato serverper un reindirizzamento come questo (non condiviso con la serverconfigurazione principale), per codificare tutto e non usare affatto espressioni regolari.

Potrebbe essere necessario codificare i domini se si utilizza HTTPS, poiché è necessario conoscere anticipatamente i certificati che verranno forniti.

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. Utilizzo delle espressioni regolari all'interno server_name

Se disponi di un numero di siti e non ti preoccupi delle massime prestazioni, ma desideri che ognuno di essi abbia la stessa politica rispetto al www.prefisso, puoi utilizzare le espressioni regolari. La migliore pratica di utilizzare un separato serversarebbe ancora valida.

Nota che questa soluzione diventa complicata se usi https, dato che devi avere un unico certificato per coprire tutti i tuoi nomi di dominio se vuoi che funzioni correttamente.


non www- wwww / regex in un singolo dedicato serverper tutti i siti:

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

wwwa non www-regex in un singolo dedicato serverper tutti i siti:

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

wwwa non www-regex in un dedicato solo serverper alcuni siti:

Potrebbe essere necessario limitare l'espressione regolare per coprire solo un paio di domini, quindi si può usare qualcosa di simile per abbinare solo 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;
}

Test delle espressioni regolari w / nginx

Puoi provare che regex funziona come previsto pcretestsul tuo sistema, che è esattamente la stessa pcrelibreria che il tuo nginx utilizzerà per le espressioni regolari:

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

Nota che non devi preoccuparti dei punti finali o del caso, poiché nginx se ne occupa già, come per regex nome server nginx quando l'intestazione "Host" ha un punto finale .


  1. Cospargere ifall'interno di server/ HTTPS esistente :

Questa soluzione finale non è generalmente considerata la migliore pratica, tuttavia funziona ancora e fa il suo lavoro.

In effetti, se stai usando HTTPS, questa soluzione finale potrebbe essere più facile da mantenere, poiché non dovresti copiare e incollare un intero gruppo di direttive ssl tra le diverse serverdefinizioni e potresti invece posizionare gli snippet solo in i server necessari, semplificando il debug e la manutenzione dei siti.


non wwwa www:

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

wwwa non- www:

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

hardcoding di un singolo dominio preferito

Se vuoi un po 'più di prestazioni, oltre alla coerenza tra più domini che un singolo serverpuò usare, potrebbe comunque avere senso codificare esplicitamente un singolo dominio preferito:

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

Riferimenti:


16

Questa soluzione nasce dalla mia esperienza personale. Abbiamo utilizzato diversi bucket Amazon S3 e un server per il reindirizzamento non-wwwai wwwnomi di dominio in modo che corrispondano ai criteri dell'intestazione "Host" S3 .

Ho usato la seguente configurazione per il server nginx :

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

Questo corrisponde a tutti i nomi di dominio puntati al server a partire da qualunque cosa ma www.e reindirizza a www.<domain>. Allo stesso modo puoi fare il reindirizzamento opposto da wwwa non-www.


che dire di https? nota: https
HA

Qui non c'è assolutamente alcun problema con HTTPS. Dopo listen 80è necessario aggiungere listen 443 ssle quindi ssl_certificatee le ssl_certificate_keydirettive.
VisioN

nessuno usa http al giorno d'oggi. Stavo leggendo una guida in cima a Google che mostrava il tuo esempio solo con la riga aggiunta listen 443 ssl con certificato mancante. Che wont lavoro e sta causando alcuni gravi mal di testa.
Toskan

Non so di quale guida stai parlando. Ho questa configurazione funzionante con successo per quasi tre anni. L'anno scorso ho aggiunto il supporto per SSL e funziona come previsto. E ovviamente devi avere un certificato con una chiave privata in mano.
VisioN

quindi questo bloccherà tutti i sottodomini tranne www, giusto?
Metagrafo

15

Ho combinato la migliore di tutte le risposte semplici, senza domini codificati.

301 reindirizzamento permanente da non www a www (HTTP o HTTPS):

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

    # Regular location configs...
}

Se preferisci non HTTPS, non www a HTTPS, www reindirizza allo stesso tempo:

server {
    listen 80;

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

    rewrite ^ https://$host$request_uri permanent;
}

11

Reindirizzare non www a www

Per dominio singolo:

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

Per tutti i domini:

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

Reindirizzare www a non www per dominio singolo:

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

Per tutti i domini:

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

Potresti fornire una differenziazione tra 80e 443?
Hassan Baig,

1
Sembra funzionare senza listendirettive per me (nginx 1.4.6).
Ibrahim,

11

prova questo

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

Altro modo: 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;
}

e da www a no-www

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

Perché gli autori hanno fornito un'istruzione if in nginx e poi hanno detto alle persone di evitarlo? Mi sembra irriverente.
Greg Smethells,

4
Si afferma "IF in location is evil". Puoi tranquillamente inserirlo se nel tuo blocco server
Kukunin

Preventivo diretto dal link sopra ... Le uniche cose sicure al 100% che possono essere fatte all'interno se nel contesto della posizione sono: return ...; riscrivi ... ultimo;
Giustino E

8

Formato unico:

server {
  listen 80;
  server_name "~^www\.(.*)$" ;
  return 301 https://$1$request_uri ;
}

1
Puoi renderlo generico scrivendolo in questo modo: 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; 
    } 
}

1
$scheme://www.domain.com$1per evitare la doppia barra
karimhossenbux,

3

non sono sicuro se qualcuno nota che potrebbe essere corretto restituire un 301 ma i browser lo fanno soffocare

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

è più veloce di:

return 301 $scheme://yoursite.com$request_uri;


1
il mio commento è stato diretto al browser, non all'efficienza dal lato nginx! con un reindirizzamento il browser invia 2 richieste contro 1 richiesta quando si esegue il nuovo test
steven

2

Blog fantasma

per fare in modo che il metodo nginx raccomandato return 301 $scheme://example.com$request_uri;funzioni con Ghost, dovrai aggiungere il tuo blocco server principale:

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;  

2

Se non si desidera codificare il nome dominio, è possibile utilizzare questo blocco di reindirizzamento. Il dominio senza il www principale viene salvato come variabile $domainche può essere riutilizzato nell'istruzione di reindirizzamento.

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

RIF: reindirizzare un sottodominio con un'espressione regolare in nginx


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

-6

Se hai problemi a farlo funzionare, potresti dover aggiungere l'indirizzo IP del tuo server. Per esempio:

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

dove XXX.XXX.XXX.XXX è l'indirizzo IP (ovviamente).

Nota: ssl crt e posizione della chiave devono essere definiti per reindirizzare correttamente le richieste https

Non dimenticare di riavviare nginx dopo aver apportato le modifiche:

service nginx restart

3
/etc/init.d/nginx reloadpuoi anche reloadil server che non causa alcun tempo morto.
TheBlackBenzKid
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.