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.