Soru SSL'ye nginx'te nasıl zorlanır veya yönlendirilir?


Bir alt alandaki gibi bir kayıt sayfam var: https://signup.example.com

Sadece HTTPS üzerinden erişilebilir olmalı, ancak endişe duyan insanlar bir şekilde HTTP üzerinden tökezleyebilir ve bir 404 elde edebilir.

Nginx'teki html / server bloğum şu şekilde görünüyor:

html {
  server {
    listen 443;
    server_name signup.example.com;

    ssl                        on;
    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;

    ssl_session_timeout 30m;

    location / {
      root /path/to/my/rails/app/public;
      index index.html;
        passenger_enabled on;
    }
  }
}

Gidecek kişilere ne ekleyebilirim? http://signup.example.com yönlendirilmek https://signup.example.com ? (FYI biliyorum zorlayabilir Rails eklentileri vardır SSL ama bundan kaçınmayı umuyordu)


210
2018-03-22 18:45


Menşei


Olası kopya Nginx'te, alt alan adı korurken tüm http isteklerini https’e nasıl yazabilirim? - Nasreddine


Cevaplar:


Göre nginx tuzaklarıgereksiz yakalamayı çıkarmak için biraz daha iyi. $request_uri yerine. Bu durumda, nginx'in sorgu sorgularını iki katına çıkarmasını önlemek için bir soru işareti ekleyin.

server {
    listen      80;
    server_name signup.mysite.com;
    rewrite     ^   https://$server_name$request_uri? permanent;
}

137
2018-03-22 19:22



Veya, bağlandığınız siteye göre, "DAHA İYİ": return 301 http://domain.com$request_uri; - nh2
Bir yorum. $ server_name $, ilk server_name değişkenini seçer. Konfigürasyonunuzda FQN isminiz yoksa, bunun farkında olun. - engineerDave
@ nh2 Bu, kullanımından beri yanlış belgelerin başka bir durumudur return 301... Yeniden yazma yöntemi gerçekten çalışırken "çok fazla yönlendirme" hatasına neden olur. - Mike Bethany
Şimdi "KÖTÜ" olarak da belgelendi. @MikeBethany return 301 işe yaramazsa (sanırım) bunu tetikliyorsanız Ayrıca Doğru URL'ler için, her iki bağlantı noktasını dinleyerek (örneğin, sorunu tetikleyen bir yapılandırma örneği) serverfault.com/a/474345/29689's ilk cevap ve ihmal et). - Blaisorblade
Yıllar boyunca neler değiştiğini ve bu diğer cevabın daha iyi olup olmadığını merak ediyorum: serverfault.com/a/337893/119666 - Ryan


Açıklandığı şekilde en iyi yol resmi nasıl yapılır kullanarak return direktif:

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

236
2017-09-03 23:50



En kısa cevap ve benim durumumda mükemmel çalıştı - mateusz.fiolka
Bu genellikle önerilir çünkü bir 301 Moved Permanently (bağlantılarınız kalıcı olarak taşındı) ve yeniden yazıyor - sgb
Bu, ayarlamış olsanız bile "çok fazla yönlendirme" hatasına neden olduğu için çalışmaz proxy_set_header X-Forwarded-Proto https; - Mike Bethany
@MikeBethany tanımlıyor musunuz listen 443; aynı blokta? - Joe B
Bu kabul edilen cevap olmalı. - sjas


Hepsini bir sunucu bloğunda tutmak istiyorsanız, bu doğru ve en etkili yoldur:

server {
    listen   80;
    listen   [::]:80;
    listen   443 default_server ssl;

    server_name www.example.com;

    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;

    if ($scheme = http) {
        return 301 https://$server_name$request_uri;
    }
}

Yukarıdaki her şey, "yeniden yazmak" veya "ssl_protocol" vb. Kullanmak daha yavaş ve daha kötüdür.

Burada aynı, ama daha verimli, sadece http protokolü üzerinde yeniden yazma işlemini çalıştırarak, her istekte $ şema değişkenini kontrol etmekten kaçınıyor. Ama cidden, onları ayırmak zorunda kalmayacak kadar küçük bir şey.

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

    server_name www.example.com;

    return 301 https://$server_name$request_uri;
}
server {
    listen   443 default_server ssl;

    server_name www.example.com;

    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;
}

108
2018-01-31 20:43



Harika, bazı korkak bu cevabı doğru olmasına rağmen neden bu cevabı reddetti. Belki bir diğeri "eğer kötüyse" külterler. If ile ilgili Nginx belgelerini okumaktan rahatsızlık duyarsanız, IfIsNOTEvil, sadece CERTAIN'in bir yerde {} içerikte kullandığını, bunların hiçbirinin burada yapmadığımızı bileceksiniz. Cevabım kesinlikle bir şeyler yapmanın doğru yolu! - DELETEDACC
Bunu oylamadım, ancak en son sürümlerde varsayılanın 'default_server' olarak değiştirildiğini belirtmek isterim. - spuder
İkincisi daha verimli ise, ilk çözüm en verimli olamaz. Ve hatta, neden orada kullanmamanız gerektiğini anlatıyorsunuz: "her istekte $ şema değişkenini kontrol etmekten kaçınıyor". İfs kullanmama noktası sadece performansla ilgili değil, aynı zamanda deklaratif olmak ve zorunlu değil. - pepkin88
İf +1 ($ scheme = http) - Fernando Kosh
Diğer cevaplarda belirtildiği gibi, burada $ host kullanmalısınız. - Artem Russakovskii


Yeni ikili HTTP ve HTTPS sunucu tanımını kullanıyorsanız, aşağıdakileri kullanabilirsiniz:

server {
    listen   80;
    listen   [::]:80;
    listen   443 default ssl;

    server_name www.example.com;

    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;

    if ($ssl_protocol = "") {
       rewrite ^   https://$server_name$request_uri? permanent;
    }
}

Bu benim için çalışıyor ve yönlendirme döngülerine neden olmaz.

Düzenle:

Değiştirilen:

rewrite ^/(.*) https://$server_name/$1 permanent;

Pratik'in yeniden yazma satırı ile.


56
2017-08-08 11:12



@DavidPashley çözümünüz benim için bir çekicilik gibi çalıştı. Teşekkürler - Jayesh Gopalan
If you are using the new dual HTTP and HTTPS server definition o zaman ayırmalısınız. - VBart
zarif ve mükemmel çalışıyor! - jipipayo
Bu benim Laravel / Homestead Nginx konfigürasyonumda benim için çalışan tek çözüm oldu. - Jared Eitnier
Ayrıca, yeniden yazma satırı da return 301 https://$server_name$request_uri; tercih edilen yöntem budur. - Jared Eitnier


Yine de Host: istek üstbilgisini koruyan ve "İYİ" örneğini izleyen başka bir değişken nginx tuzakları:

server {
    listen   10.0.0.134:80 default_server;

    server_name  site1;
    server_name  site2;
    server_name  10.0.0.134;

    return 301 https://$host$request_uri;
}

Sonuçlar burada. Kullanarak olduğunu unutmayın $server_name yerine $host her zaman yönlendirir https://site1.

# curl -Is http://site1/ | grep Location
Location: https://site1/

# curl -Is http://site2/ | grep Location
Location: https://site2/


# curl -Is http://site1/foo/bar | grep Location
Location: https://site1/foo/bar

# curl -Is http://site1/foo/bar?baz=qux | grep Location
Location: https://site1/foo/bar?baz=qux

27
2018-04-11 12:20



Note that using $server_name instead of $host would always redirect to https://site1 öyle değil mi $request_uri için? - Jürgen Paul
$request_uri bir ana makine veya alan adı içermiyor. Başka bir deyişle, her zaman bir "/" karakteri ile başlar. - Peter
Uzakta en iyi cevap. - Ashesh
Bu cevabın neden oy çok düşük olduğundan emin değilim. Kullanmaya değer tek kişi. - zopieux
Çok fazla insanın $ server_name kullandığını düşünürsek, bunu yapmanın doğru yolu budur. - Greg Ennis


Herhangi bir çerezde 'güvenli' ayarlandığınızdan emin olun, aksi takdirde HTTP isteği üzerine gönderilir ve Firesheep gibi bir araç tarafından yakalanabilir.


3
2018-03-23 00:40





server {
    listen x.x.x.x:80;

    server_name domain.tld;
    server_name www.domian.tld;
    server_name ipv4.domain.tld;

    rewrite     ^   https://$server_name$request_uri? permanent;
}

Bu bence daha iyi çalışır. x.x.x.x sunucunuzun IP adresini belirtir. Plesk 12 ile çalışıyorsanız, bunu yapmak istediğiniz alan için "/var/www/vhosts/system/domain.tld/conf" dizinindeki "nginx.conf" dosyasını değiştirerek bunu yapabilirsiniz. Yapılandırmayı kaydettikten sonra nginx hizmetini yeniden başlatmayı unutmayın.


1
2017-08-23 19:40



rewrite ^ https://$host$request_uri? permanent;  Bir vhost üzerinde birkaç sunucu ismi olabileceğinden daha iyi bir çözüm olurdu


Bunun en basit çözüm olduğunu düşünüyorum. Hem HTTPS olmayan hem de WWW olmayan trafiği HTTPS'ye ve yalnızca www'ye zorlar.

server {
    listen 80;
    listen 443 ssl;

    server_name domain.tld www.domain.tld;

    # global HTTP handler
    if ($scheme = http) {
        return 301 https://www.domain.tld$request_uri;
    }

    # global non-WWW HTTPS handler
    if ($http_host = domain.tld) {
        return 303 https://www.domain.tld$request_uri;
    }
}

DÜZENLEME - Nisan 2018: Çözümü w / o IF'ler buradaki mesajımda bulunabilir: https://stackoverflow.com/a/36777526/6076984


0
2018-04-21 18:30



Koşullar nginx dünyasında kötülük ve verimsiz kabul edilmiyor mu? - PKHunter
Evet, genel olarak. Fakat bu basit kontroller için tahmin etmem. Yine de daha fazla kod yazmayı içeren uygun bir yapılandırma dosyasına sahibim, ancak IF'nin tamamen ortadan kaldırılmasını sağlar. - stamster
Google, 303 yerine 301 kullanılmasını tavsiye ediyor. Kaynak: support.google.com/webmasters/answer/6073543?hl=en - dylanh724
@DylanHunt - Test için sadece 303'ü bıraktım, 1. Handler'ın 301'e ayarlandığını not al, sadece 2'si değiştirmeyi unuttum :) Ayrıca, IF'nin çözümü ile de: stackoverflow.com/a/36777526/6076984 - stamster