Alihkan non-www ke www melalui SSL dengan Nginx

25

Saya mengalami kesalahan saat mencoba mengalihkan https://example.com ke https://www.example.com .

Ketika saya pergi ke https://example.com , itu tidak mengarahkan dan mengembalikan status halaman / 200.

Saya tidak ingin ini, saya ingin mengarahkan ulang ke https://www.example.com .

Ketika saya mengunjungi http://example.com , itu dialihkan ke https://www.example.com

Adakah yang bisa memberitahu saya di mana saya salah?

Ini adalah file konfigurasi default dan ssl default saya:

default.conf

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

default-ssl.conf

upstream app_server_ssl {
    server unix:/tmp/unicorn.sock fail_timeout=0;
}

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

    listen 443;
    root /home/app/myproject/current/public;
    index index.html index.htm;

    error_log /srv/www/example.com/logs/error.log info;
    access_log /srv/www/example.com/logs/access.log combined;

    ssl on;
    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_certificate /srv/www/example.com/keys/ssl.crt;
    ssl_certificate_key /srv/www/example.com/keys/www.example.com.key;
    ssl_ciphers AES128-SHA:RC4-MD5:ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:RSA+3DES:!ADH:!AECDH:!MD5:AES128-SHA;
    ssl_prefer_server_ciphers on;

    client_max_body_size 20M;


    try_files $uri/index.html $uri.html $uri @app;


    # CVE-2013-2028 http://mailman.nginx.org/pipermail/nginx-announce/2013/000112.html
    if ($http_transfer_encoding ~* chunked) {
            return 444;
        }

    location @app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://app_server_ssl;
    }

    error_page 500 502 503 504 /500.html;

    location = /500.html {
        root /home/app/example/current/public;
    }
}
Thomas V.
sumber
1
Apa gunanya membuat 2 file conf?
Sandip Subedi
Pemisahan masalah, konfigurasi non SSL sangat kecil sehingga tampaknya terbaik untuk memisahkannya dari konfigurasi SSL saja.
Thomas V.

Jawaban:

34

Anda kehilangan listenarahan dalam file default-ssl.conf. Tambahkan listen 443;direktif ini

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

Secara default, jika Anda menghilangkan direktif ini, nginx menganggap bahwa Anda ingin mendengarkan pada port 80. Berikut dokumentasi perilaku default ini.


Sunting: Terima kasih atas komentar dari @TeroKilkanen.

Di sini konfigurasi lengkap untuk default-ssl.conf Anda

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /srv/www/example.com/keys/ssl.crt;
    ssl_certificate_key /srv/www/example.com/keys/www.example.com.key;
    return 301 https://www.example.com$request_uri;
}

Sidenote : Anda dapat mengganti ssl on;direktif dengan listen 443 ssl;rekomendasi dari dokumentasi nginx .

masegaloeh
sumber
4
Anda juga perlu mengatur ssl_certificatedan ssl_certificate_keymengarahkan dalam blok ini, dan menggunakannya listen 443 ssl;agar itu adalah vhost SSL.
Tero Kilkanen
Silakan kirim konten saat ini default-ssl.conf. Mungkin beberapa kesalahan ketik atau pemesanan ulang menyebabkan hal itu.
masegaloeh
Ini memalukan: \ Pelakunya adalah konfigurasi nginx duplikat di / etc / nginx / sites-enabled, /etc/nginx/sites-enabled/default-ssl.backup mengganggu pengalihan pada default-ssl. Kesalahan konyol.
Thomas V.
jadi saya harus mengeluarkan 2 sertifikat: untuk www-domain dan untuk non-www
vladkras
Bagaimana hal ini dapat dicapai pada port katakanlah 5007: example.com:5007 ke example.com:5007
CP3O
5

Masukkan saja pernyataan if dan Anda harus segera pergi. Saya memeriksa hasilnya di curl.exe -Saya dan semua kasus selain https://www.example.com diperlakukan sebagai 301. SSL rumit karena diperiksa sebelum Anda mendapatkan 301 redirection URL. Karenanya, Anda mendapatkan kesalahan sertifikat.

Secara pribadi, saya suka menghapus www dari domain tetapi saya menulis kode saya di bawah untuk menjawab pertanyaan Anda.

server {
listen 443 ssl;
listen [::]:443 ssl; # IPV6

server_name example.com www.example.com; # List all variations here

# If the domain is https://example.com, lets fix it!

if ($host = 'example.com') {
  return 301 https://www.example.com$request_uri;
}

# If the domain is https://www.example.com, it's OK! No changes necessary!

... # SSL .pem stuff
...
}

server {
listen 80;
listen [::]:80;

# If the domain is http://example.com or https://www.example.com, let's change it to https!

server_name example.com www.example.com;
return 310 https://www.example.com$request_uri;
}
Brian Lee
sumber
3

Cara saya melakukannya adalah dengan menggunakan pernyataan if di dalam blok server ssl yang dialihkan ke https www

ssl_certificate /srv/www/example.com/keys/ssl.crt;
ssl_certificate_key /srv/www/example.com/keys/www.example.com.key;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES128-SHA:RC4-MD5:ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:RSA+3DES:!ADH:!AECDH:!MD5:AES128-SHA;
ssl_prefer_server_ciphers on;
client_max_body_size 20M;

upstream app_server_ssl {
    server unix:/tmp/unicorn.sock fail_timeout=0;
}

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

server {
    listen 443 default_server ssl;
    server_name www.example.com;

    # redirect https://example.com to https://www.example.com
    # mainly for SEO purposes etc
    #we will use a variable to do that
    set $redirect_var 0;

    if ($host = 'example.com') {
      set $redirect_var 1;
    }
    if ($host = 'www.example.com') {
      set $redirect_var 1;
    }

    if ($redirect_var = 1) {
      return 301 https://www.example.com$request_uri;
    } 

    try_files $uri/index.html $uri.html $uri @app;

    # CVE-2013-2028 http://mailman.nginx.org/pipermail/nginx-announce/2013/000112.html
    if ($http_transfer_encoding ~* chunked) {
            return 444;
        }

    location @app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://app_server_ssl;
    }

    error_page 500 502 503 504 /500.html;

    location = /500.html {
        root /home/app/example/current/public;
    }
}

Tentu saja, kapan pun Anda ingin menggunakan pernyataan if dalam file konfigurasi nginx; Anda seharusnya sudah membaca: https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/

Komu
sumber
syaratnya if ($host = 'www.example.com')tidak perlu.
Karl.S
2

Ini 2018 sekarang dan saya pikir untuk memberikan yang ini kesempatan baru jika seseorang mencari solusi sederhana.

Pandangan saya tentang ini sebagai pendatang baru adalah membuat segala sesederhana mungkin. Pada dasarnya Anda ingin mengarahkan kembali http://example.com dan https://example.com ke https : // www .example.com. Dan Anda hanya berhasil mengarahkan ulang http://example.com

Ini adalah operasi yang sangat mudah yang hanya membutuhkan dua blok server (saya akan menunjukkan ini secara singkat dalam satu file konfigurasi)

# 1. Server block to redirect all non-www and/or non-https to https://www
server {
    # listen to the standard http port 80
    listen 80; 

    # Now, since you want to route https://example.com to http://www.example.com....
    # you need to get this block to listen on https port 443 as well
    # alternative to defining 'ssl on' is to put it with listen 443
    listen 443 ssl; 

    # define server_name
    server_name example.com *.example.com; 

    # DO NOT (!) forget your ssl certificate and key
    ssl_certificate PATH_TO_YOUR_CRT_FILE;
    ssl_certificate_key PATH_TO_YOUR_KEY_FILE; 

    # permanent redirect
    return 301 https://www.example.com$request_uri;  
    # hard coded example.com for legibility 
}
# end of server block 1. nearly there....

# 2. Server block for the www (primary) domain
# note that this is the block that will ultimately deliver content
server {
    # define your server name
    server_name www.example.com; 

    # this block only cares about https port 443
    listen 443 ssl;

    # DO NOT (!) forget your ssl certificate and key
    ssl_certificate PATH_TO_YOUR_CRT_FILE;
    ssl_certificate_key PATH_TO_YOUR_KEY_FILE; 

    # define your logging .. access , error , and the usual 

    # and of course define your config that actually points to your service
    # i.e. location / { include proxy_params; proxy_pass PATH_TO_SOME_SOCKET; }
}
# End of block 2.
# voilà! 

Sekarang http://example.com dan https://example.com keduanya harus dialihkan ke https://www.example.com . Pada dasarnya pengaturan ini mengalihkan semua yang non-www dan / atau non-https ke https: // www .

aaronlhe
sumber
-1

Untuk mengalihkan semua permintaan ke https://www.example

buat blok server untuk pengalihan dan domain utama pada port SSL Anda (biasanya 443) serta port http default 80

# non-www to ssl www redirect
server {
  listen 80; 
  listen 443 ssl;
  server_name example.com;
  return 301 https://www.example.com$request_uri;
  # ... ssl certs
}

# ssl setup for www (primary) domain
server {
  listen 80;
  listen 443 ssl;
  server_name www.example.com;
  if ($scheme = http) {
    return 301 https://www.example.com$request_uri;
  }
  # ... the rest of your config + ssl certs
}

simpan dan ikuti sudo nginx -s reload

Ini akan mengarahkan ulang

http://example      301 -> https://www.example
https://example     301 -> https://www.example
http://www.example  301 -> https://www.example
https://www.example 200
lfender6445
sumber
Anda kehilangan a ;di blok server kedua di klausa if. Seharusnyareturn 301 https://www.example.com$request_uri;
Lukas Oppermann
1
Namun, apakah itu akan berhasil? Bisakah mendengarkan httppada 443?
Lukas Oppermann
Anda benar, saya hilang dengarkan 80, ive menambahkannya.
lfender6445