Nginx no-www ke www dan www ke no-www


497

Saya menggunakan nginx di cloud Rackspace mengikuti tutorial dan setelah mencari di internet dan sejauh ini tidak bisa mendapatkan ini diurutkan.

Saya ingin www.mysite.com pergi ke mysite.com seperti biasa dalam .htaccess untuk SEO dan alasan lainnya.

/Etc/nginx/sites-available/www.example.com.vhost konfigurasi saya :

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

Saya juga sudah mencoba

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

Saya juga mencoba. Kedua upaya kedua memberikan kesalahan redirect loop.

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

DNS saya diset sebagai standar:

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

(IP contoh dan folder telah digunakan untuk contoh dan untuk membantu orang di masa depan). Saya menggunakan Ubuntu 11.


1
Saya merasa terdorong untuk berkomentar bahwa jika Anda bekerja dengan situs web WordPress, periksa Dashboard > Settings > General Settingsdan pastikan tidak ada wwwdi Alamat WordPress / URL Alamat Situs. Tidak masalah bagaimana Anda mengkonfigurasi nginx Anda, jika Anda memiliki www di URL ini, itu akan diarahkan ke yang memiliki www di dalamnya.
Abhinav Sood

Jawaban:


792

Solusi HTTP

Dari dokumentasi , "cara yang benar adalah mendefinisikan server terpisah untuk 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;
    ...
}

Solusi HTTPS

Bagi mereka yang menginginkan solusi termasuk 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...

        }
}

Catatan: Awalnya saya belum termasuk https://dalam solusi saya karena kami menggunakan loadbalancers dan https kami: // server adalah server pembayaran SSL lalu lintas tinggi: kami tidak mencampur https: // dan http: //.


Untuk memeriksa versi nginx, gunakan nginx -v.

Hapus www dari url dengan redirect 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#
}

Jadi, Anda perlu memiliki dua kode server.

Tambahkan www ke url dengan redirect nginx

Jika yang Anda butuhkan adalah sebaliknya, untuk mengarahkan ulang dari domain.com ke www.domain.com, Anda dapat menggunakan ini:

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

Seperti yang dapat Anda bayangkan, ini adalah kebalikannya dan bekerja dengan cara yang sama sebagai contoh pertama. Dengan cara ini, Anda tidak mendapatkan nilai SEO turun, karena perm pengalihan lengkap dan bergerak. WWW no terpaksa dan direktori ditampilkan!

Beberapa kode saya ditampilkan di bawah untuk tampilan yang lebih baik:

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 hargai itu. Nginx luar biasa, tetapi dokumentasi bagus yang tetap up to date dengan versi server dan perubahan OS dan perangkat keras server cukup melelahkan. Sumber daya terbaik yang melayani saya adalah howtoforge.com karena mendukung versi cloud RackSpace. Beberapa perintah di atas tidak akan berfungsi di versi yang lebih baru. Tapi nginx / 0.8.54 ini - percayalah, server nginx terbaik) tidak perlu memutakhirkan atau memperbarui. Bekerja dengan baik. 100.000 hit unik sehari dengan rata-rata transaksi 4200 sehari. Nginx adalah CEPAT. seperti menggunakan situs tanpa lalu lintas.
TheBlackBenzKid

17
Penulisan ulang Anda harus menjadi pengembalian, seperti pada return 301 $scheme://domain.com$request_uri;. Tidak perlu menangkap pola apa pun, lihat perangkap Nginx
Roberto

4
@TheBlackBenzKid Maaf, mungkin saya telah melewatkan sesuatu, tetapi solusi yang diperbarui tidak berfungsi. Itu karena mendengarkan 80 - dengan itu, Anda mengatakan bahwa hanya HTTP yang cocok dengan ini. Seharusnya ada lebih banyak port untuk didengarkan jika konfigurasi yang sama digunakan untuk HTTP dan HTTPS ... Atau? Tapi definitelly membantu saya, +1. Terima kasih atas balasannya Bersulang.
tomis

3
@TheBlackBenzKid Itu hanya catatan. Saya telah menemukan solusi yang berfungsi. Dalam contoh Anda, hanya Dengarkan 443 yang harus ditambahkan dan selesai berfungsi.
tomis

2
jawabannya salah. itu mengalihkan semua subdomain ke www.
r3wt

399

Sebenarnya Anda bahkan tidak perlu menulis ulang.

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

Karena jawaban saya mendapatkan semakin banyak suara tetapi di atas juga. Anda tidak boleh menggunakan a rewritedalam konteks ini. Mengapa? Karena nginx harus memproses dan memulai pencarian. Jika Anda menggunakan return(yang seharusnya tersedia dalam versi nginx) langsung menghentikan eksekusi. Ini lebih disukai dalam konteks apa pun.

Alihkan keduanya, non-SSL dan SSL ke mitra non-www mereka:

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

The $schemevariabel hanya akan berisi httpjika server Anda hanya mendengarkan pada port 80 (default) dan mendengarkan pilihan tidak mengandung sslkata kunci. Tidak menggunakan variabel tidak akan memberi Anda kinerja apa pun.

Perhatikan bahwa Anda memerlukan lebih banyak blok server jika Anda menggunakan HSTS, karena header HSTS tidak boleh dikirim melalui koneksi yang tidak dienkripsi. Oleh karena itu, Anda memerlukan blok server tidak terenkripsi dengan pengalihan dan blok server terenkripsi dengan pengalihan dan header HSTS.

Redirect semuanya ke SSL (konfigurasi pribadi di UNIX dengan 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...
}

Saya kira Anda dapat membayangkan senyawa lain dengan pola ini sekarang sendiri.

Lebih banyak konfigurasi saya? Buka di sini dan di sini .


3
Chrome Anda seharusnya tidak dapat pergi ke domain www Anda jika Anda menggunakan HSTS. Silakan buka pertanyaan baru dengan sebanyak mungkin detail dan saya akan membantu Anda (Anda dapat memposting URL ke pertanyaan sebagai komentar di sini).
Fleshgrinder

1
@Fleshgrinder Saya mencoba menerapkan pengaturan Anda tetapi mendapatkan masalah berikut di stackoverflow.com/questions/29451409/... Adakah gagasan tentang cara membuatnya bekerja?
YPCrumble

4
Di blok 2 "Arahkan kedua, non-SSL dan SSL ke mitra non-www mereka:", kedua blok server harus memiliki arahan SSL, karena browser perlu memverifikasi sertifikat untuk www.example.com sebelum dialihkan ke contoh .com.
Jeff Tsay

1
Tentu saja, saya menambahkan itu serta info singkat tentang HSTS.
Fleshgrinder

1
@YPCrumble ya, JAUH lebih cepat dengan cara ini karena kami tidak melakukan pencocokan ekspresi reguler pada setiap permintaan. Kami hanya mengarahkan jika kami tahu bahwa kami harus mengarahkan. Tidak ada pemeriksaan, tidak ada validasi, tidak ada: hanya redirect. =)
Fleshgrinder

37

Anda mungkin mengetahui bahwa Anda ingin menggunakan konfigurasi yang sama untuk lebih banyak domain.

Cuplikan berikut menghapus www sebelum domain apa pun:

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

7
Saya suka cara ini lebih baik daripada blok server khusus. Ubah httpke$scheme
ck_

2
Jauh lebih baik, tidak dapat percaya bahwa banyak orang akan meng-hardcode domain menjadi konfigurasi untuk tugas ini.
MrYellow

1
@Oli Tautan itu tidak (pada hari ini) menyebutkan kinerja tetapi lebih tepatnya tidak 100% aman. Itu mengatakan "Hanya 100% hal aman yang dapat dilakukan di dalam jika dalam konteks lokasi adalah: return ...dan rewrite ... last". Adakah tautan yang diperbarui ke masalah kinerja?
Adam

1
Ini tidak berhasil untuk saya. Terus mendapatkan kesalahan di browser yang mengatakan respons tidak valid.
Nico Brenner

1
Sayangnya, saya tidak menemukan jalan tanpa "jika". Saya menggunakan konfigurasi yang sama untuk banyak domain, hardcoding nama-nama domain bukan pilihan. Setiap saran / komentar dihargai!
Martin Höger

27

Anda memerlukan dua blok server.

Masukkan ini ke dalam file konfigurasi Anda, mis /etc/nginx/sites-available/sitename

Katakanlah Anda memutuskan untuk menggunakan http://example.com sebagai alamat utama yang akan digunakan.

File konfigurasi Anda akan terlihat seperti ini:

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
}

Blok server pertama akan menyimpan instruksi untuk mengarahkan permintaan dengan awalan 'www'. Itu mendengarkan permintaan untuk URL dengan awalan 'www' dan pengalihan.

Tidak melakukan apa-apa lagi.

Blok server kedua akan menyimpan alamat utama Anda - URL yang ingin Anda gunakan. Semua pengaturan lainnya pergi di sini seperti root, index, location, dll Periksa file default untuk ini pengaturan lainnya yang dapat dimasukkan dalam blok server.

Server membutuhkan dua catatan DNS A.

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

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

Untuk ipv6 buat pasangan rekaman AAAA menggunakan alamat-ipv6 Anda.


23

Berikut cara melakukannya untuk beberapa www ke nama server no-www (Saya menggunakan ini untuk subdomain):

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

20
  1. Praktik Terbaik: pisahkan serverdg hardcodeserver_name

Praktik terbaik dengan nginx adalah menggunakan terpisah serveruntuk pengalihan seperti ini (tidak dibagikan dengan serverkonfigurasi utama Anda), untuk meng-hardcode semuanya, dan tidak menggunakan ekspresi reguler sama sekali.

Mungkin juga diperlukan untuk melakukan hardcode pada domain jika Anda menggunakan HTTPS, karena Anda harus tahu di muka sertifikat mana yang akan Anda berikan.

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. Menggunakan Ekspresi Reguler di dalam server_name

Jika Anda memiliki sejumlah situs, dan tidak peduli dengan kinerja terbaik, tetapi ingin setiap situs memiliki kebijakan yang sama terkait dengan www. awalan, maka Anda dapat menggunakan ekspresi reguler. Praktik terbaik untuk menggunakan yang terpisah servermasih akan berlaku.

Perhatikan bahwa solusi ini menjadi rumit jika Anda menggunakan https, karena Anda harus memiliki satu sertifikat untuk mencakup semua nama domain Anda jika Anda ingin ini berfungsi dengan baik.


non- wwwke www/ regex dalam satu khusus serveruntuk semua situs:

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

wwwke non- wwww / regex dalam satu khusus serveruntuk semua situs:

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

www untuk non-www / regex di khusus serveruntuk beberapa situs saja:

Mungkin perlu untuk membatasi regex untuk hanya mencakup beberapa domain, maka Anda dapat menggunakan sesuatu seperti ini hanya untuk mencocokkan www.example.org, www.example.comdan www.subdomain.example.net:

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

Menguji Ekspresi Reguler dengan nginx

Anda dapat menguji apakah regex berfungsi seperti yang diharapkan pcretestpada sistem Anda, yang merupakan pcrepustaka yang sama persis dengan yang akan digunakan nginx Anda untuk ekspresi reguler:

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

Perhatikan bahwa Anda tidak perlu khawatir tentang trailing dots atau case, karena nginx sudah mengatasinya, seperti nginx nama server regex ketika header "Host" memiliki trailing dot .


  1. Taburkan ifdalam yang ada server/ HTTPS:

Solusi akhir ini umumnya tidak dianggap sebagai praktik terbaik, namun tetap berfungsi dan berfungsi.

Bahkan, jika Anda menggunakan HTTPS, maka solusi akhir ini mungkin lebih mudah dikelola, karena Anda tidak perlu menyalin-menempelkan sejumlah arahan ssl di antara serverdefinisi yang berbeda , dan sebagai gantinya dapat menempatkan cuplikan hanya ke dalam server yang dibutuhkan, membuatnya lebih mudah untuk debug dan memelihara situs Anda.


tanpa wwwke www:

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

wwwuntuk non- www:

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

hardcoding domain pilihan tunggal

Jika Anda ingin sedikit lebih banyak kinerja, dan juga konsistensi antara beberapa domain yang serverdapat digunakan tunggal , mungkin masih masuk akal untuk secara eksplisit melakukan hardcode satu domain yang disukai:

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

Referensi:


16

Solusi ini berasal dari pengalaman pribadi saya. Kami menggunakan beberapa ember Amazon S3 dan satu server untuk mengarahkan ulang non-wwwke wwwnama domain agar sesuai dengan kebijakan header "Host" S3 .

Saya menggunakan konfigurasi berikut untuk server nginx :

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

Ini cocok dengan semua nama domain yang menunjuk ke server dimulai dengan apa pun kecuali www.dan dialihkan ke www.<domain>. Dengan cara yang sama Anda dapat melakukan redirect berlawanan dari wwwke non-www.


bagaimana dengan https? catatan: https MEMBUTUHKAN sertifikat
Toskan

Sama sekali tidak ada masalah dengan HTTPS di sini. Setelah listen 80Anda perlu menambahkan listen 443 ssldan kemudian ssl_certificatedan ssl_certificate_keyarahan.
VisioN

tidak ada yang menggunakan http saat ini. Saya sedang membaca panduan teratas yang terdaftar di google yang menunjukkan contoh Anda hanya dengan baris yang ditambahkan listen 443 ssl dengan sertifikat hilang. Itu tidak akan berhasil dan menyebabkan beberapa sakit kepala serius.
Toskan

Saya tidak tahu panduan apa yang Anda bicarakan. Saya memiliki konfigurasi ini berhasil berfungsi selama hampir tiga tahun. Tahun lalu saya menambahkan dukungan untuk SSL dan berfungsi seperti yang diharapkan. Dan tentu saja Anda harus memiliki sertifikat dengan kunci pribadi di tangan.
VisioN

jadi ini akan mengalahkan semua subdomain kecuali www, benar?
Metagrapher

15

Saya menggabungkan yang terbaik dari semua jawaban sederhana, tanpa domain kode keras.

301 redirect permanen dari non-www ke www (HTTP atau HTTPS):

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

    # Regular location configs...
}

Jika Anda lebih suka non-HTTPS, non-www ke HTTPS, www redirect secara bersamaan:

server {
    listen 80;

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

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

11

Alihkan non-www ke www

Untuk Domain Tunggal:

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

Untuk Semua Domain:

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

Redirect www ke non-www Untuk Domain Tunggal:

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

Untuk Semua Domain:

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

Bisakah Anda memberikan perbedaan antara 80dan 443?
Hassan Baig

1
Tampaknya bekerja tanpa listenarahan untuk saya (nginx 1.4.6).
Ibrahim

11

coba ini

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

Cara lain: Nginx no-www ke www

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

dan www ke no-www

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

Mengapa penulis memberikan pernyataan if di nginx dan kemudian memberitahu orang untuk menghindarinya? Kedengarannya kurang ajar bagiku.
Greg Smethells

4
Ada yang menyatakan "JIKA di lokasi itu jahat". Anda dapat dengan aman memasukkannya ke dalam blok server Anda
Kukunin

Kutipan langsung dari tautan di atas ... Hanya 100% hal aman yang dapat dilakukan di dalam jika dalam konteks lokasi adalah: kembali ...; tulis ulang ... terakhir;
Justin E

8

Format unik:

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

1
Anda dapat membuatnya generik dengan menuliskannya seperti ini: 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$1untuk menghindari double slash
karimhossenbux


2

Blog hantu

untuk membuat metode yang direkomendasikan nginx dengan return 301 $scheme://example.com$request_uri;bekerja dengan Ghost Anda perlu menambahkan di blok server utama Anda:

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

Jika Anda tidak ingin mengubah kode nama domain, Anda dapat menggunakan blok pengalihan ini. Domain tanpa www utama disimpan sebagai variabel $domainyang dapat digunakan kembali dalam pernyataan pengalihan.

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

REF: Mengarahkan ulang subdomain dengan ekspresi reguler di nginx


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

-6

Jika Anda mengalami masalah agar ini berfungsi, Anda mungkin perlu menambahkan alamat IP server Anda. Sebagai contoh:

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

di mana XXX.XXX.XXX.XXX adalah alamat IP (jelas).

Catatan: ssl crt dan lokasi utama harus ditentukan untuk mengarahkan ulang permintaan https dengan benar

Jangan lupa untuk me-restart nginx setelah melakukan perubahan:

service nginx restart

3
/etc/init.d/nginx reloadAnda juga dapat reloadserver yang tidak menyebabkan downtime.
TheBlackBenzKid
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.