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


222

Aşağıdaki gibi bir alt alan adında bir kayıt sayfam var: https://signup.example.com

Yalnızca HTTPS üzerinden erişilebilir olmalıdır, ancak insanların bir şekilde HTTP üzerinden tökezleyip 404 elde etmeleri konusunda endişeliyim.

Nginx içindeki html / server bloğum şöyle 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;
    }
  }
}

http://signup.example.comYeniden yönlendirilecek kişilerin yönlendirilmesi için ne ekleyebilirim https://signup.example.com? (Bilginize, zorlayabilen SSLancak bundan kaçınmayı umduğu Rails eklentileri olduğunu biliyorum )


Yanıtlar:


145

Nginx tuzaklar göre , $request_uriyerine kullanarak gereksiz yakalamayı atlamak için biraz daha iyidir . Bu durumda, nginx'in herhangi bir sorgu alanı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;
}

68
Veya, bağlı sitesine göre "İYİ" :return 301 http://domain.com$request_uri;
— NH2

13
Bir yorum. $ server_name $ ilk server_name değişkenini seçer. Konfigürasyonunuzda FQN olmayan isimleriniz varsa bunun farkında olun
— MühendisDave

2
@ nh2 Bu, belgelerin yanlış olmasının bir başka nedenidir, çünkü return 301...yeniden yazma yöntemi gerçekte çalışırken, "çok fazla yönlendirici" hataya neden olur.
— Mike Bethany,

1
Bu şimdi de "KÖTÜ" olarak belgelenmiştir. @MikeBethany return 301(sanırım) sürece bunu tetikleyen ediyoruz, çalışır da (her iki bağlantı noktalarında yapılandırma örneğini dinleyerek, doğru URL'ler için sorunu tetikleyen:. Almak serverfault.com/a/474345/29689's ilk cevap ve eğer ihmal ).
— Blaisorblade,

1
Yıllar içinde nelerin değiştiğini ve diğer cevapların daha iyi olup olmadığını merak ediyorum: serverfault.com/a/337893/119666
— Ryan

256

O açıklandığı gibi iyi yolu resmi Nasıl Yapılır kullanmaktır returndirektifini:

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

5
en kısa cevap ve benim durumumda mükemmel çalıştı
— mateusz.fiolka

1
Bu genellikle tavsiye edilir, çünkü 301 Moved Permanentlytekrar
— bağlanır

1
Bu ayarlanmış olsa bile "çok fazla yönlendirici" hataya neden olduğu için çalışmıyorproxy_set_header X-Forwarded-Proto https;
— Mike Bethany

1
@MikeBethany listen 443;aynı blokta tanımlıyor musunuz?
— Joe B,

2
Bu kabul edilen cevap olmalı.
— sjas

119

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

Her şey yukarıda "yeniden yazma" veya "eğer ssl_protocol" vb. Kullanarak daha yavaş ve daha kötüdür.

İşte aynıdır, ancak daha verimlidir, yalnızca http protokolünde yeniden yazmayı çalıştırarak her istek için $ scheme değişkenini kontrol etmek zorunda kalmaz. Fakat cidden, onları ayırmanıza gerek 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;
}

8
Harika, bazı korkaklar, bu cevabı doğru olsa bile, nedenini söylemeden bu cevabı oyladı. Belki de bunlardan bir diğeri de "kötüyse" kültürcülerdir. If hakkında Nginx belgelerini okumak için uğraşırsanız, IfIsNOTEvil'in sadece CERTAIN'in {} bağlamında, hiçbirini burada yapmadığımız bir konumda kullandığını bileceksiniz. Cevabım kesinlikle bir şeyler yapmanın doğru yoludur!
— DELETEDACC

2
Buna oy vermedim, 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, eğer orada bir if kullanmamalısınız: IFS kullanmama konusu sadece performans ile ilgili değil aynı zamanda bildirimsel ve zorunlu olmakla da ilgilidir.
— pepkin88

İf için +1 ($ şema = http)
— Fernando Kosh 21

Diğer cevaplarda da belirtildiği gibi burada $ host kullanmalı.
— Artem Russakovskii

56

Yeni çift 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 gibi görünüyor ve yönlendirme döngülerine neden olmuyor.

Düzenle:

Değiştirilen:

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

Pratik'in yeniden yazma çizgisiyle.


2
@DavidPashley Çözümün benim için bir cazibe gibi çalıştı. Teşekkürler
— Jayesh Gopalan 17:12

1
If you are using the new dual HTTP and HTTPS server definitiono zaman ayırmalısın.
— VBart

2
zarif ve mükemmel çalışıyor!
— jacktrade

2
Laravel / Homestead Nginx yapılandırmamda benim için çalışan tek çözüm buydu.
— Jared Eitnier,

1
Ayrıca, yeniden yazma çizgisinin return 301 https://$server_name$request_uri;tercih edilen yöntem olduğu gibi olması gerekir .
— Jared Eitnier

27

Host'u koruyan bir başka değişken daha: istek başlığı ve nginx tuzaklar üzerinde "İYİ" örneğini izler :

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. $server_nameBunun yerine kullanmanın $hosther zaman yönlendireceğinize dikkat edin 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

Note that using $server_name instead of $host would always redirect to https://site1bunun için değil $request_urimi?
— Jürgen Paul

2
$request_uribir ana bilgisayar veya etki alanı adı içermiyor. Başka bir deyişle, her zaman bir "/" karakteriyle başlar.
— Peter,

2
Şimdiye kadar en iyi cevap.
— Ashesh,

3
Bu cevabın oylarda neden bu kadar düşük olduğundan emin değilim. Kullanmaya değer tek kişi.
— zopieux

2
Pek çok insanın $ server_name kullandığına inanmıyorum, bunu yapmanın doğru yolu budur
— Greg Ennis

3

Çerezleri 'güvenli' olarak ayarladığınızdan emin olun, aksi takdirde HTTP isteğinde gönderilirler ve Firesheep gibi bir araç tarafından ele geçirilebilirler.


1
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 daha iyi çalışıyor sanırım. xxxx, sunucunuzun IP'sini belirtir. Eğer Plesk 12 ile çalışıyorsanız, istediğiniz etki alanı için "/var/www/vhosts/system/domain.tld/conf" dizinindeki "nginx.conf" dosyasını değiştirerek yapabilirsiniz. Yapılandırmayı kaydettikten sonra nginx servisini yeniden başlatmayı unutmayın.


rewrite ^ https://$host$request_uri? permanent; bir

0

Bunun en basit çözüm olduğunu düşünüyorum. Hem HTTPS olmayan hem de WWW dışı trafiği yalnızca HTTPS ve 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;
    }
}

EDIT - Nisan 2018: Bu yazışmada IF'ler olmadan Çözümü bulunur: https://stackoverflow.com/a/36777526/6076984


1
IF koşulları nginx dünyasında kötü ve verimsiz sayılmaz mı?
— PKHunter

Evet, genel olarak onlar. Ancak bu basit çekler için sanmıyorum. Yine de daha fazla kod yazmayı içeren uygun bir konfigürasyon dosyam var ancak IF'leri tamamen önlüyor.
— stamster

Google, 303 yerine 301 kullanmanızı önerir. Kaynak: support.google.com/webmasters/answer/6073543?hl=tr
— dylanh724

@DylanHunt - Sadece test için 303'ü bıraktım, 1. işleyicinin 301'e ayarlandığını not ettim, sadece
— 2.ini
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.