“Www” yi kaldırın ve nginx ile “https” ye yönlendirin


57

Nginx'te iki şeyi yapan bir kural oluşturmak istiyorum:

  1. "Www" yi kaldırır istek URI'sından
  2. İstek URI'si "http" ise "https" ye yönlendirir

Bunların her birinin ayrı ayrı nasıl yapılacağına dair pek çok örnek var, ancak her ikisini de doğru yapan bir çözüm bulamıyorum (yani, bir yönlendirme döngüsü oluşturmaz ve tüm vakaları doğru şekilde ele alır).

Bu davaların hepsini ele alması gerekiyor:

1. http://www.example.com/path
2. https://www.example.com/path
3. http://example.com/path
4. https://example.com/path

Bunların hepsi döngü olmadan https://example.com/path (# 4) ile bitmelidir . Herhangi bir fikir?


Www.mydomain.com adresini DNS düzeyinde mydomain.com sitesine yönlendirdim ve https olmayanlar için nginx'te https için bir 301 ekledim. Görünüşe göre iyi olmalı ¯ \ _ (ツ) _ / ¯
jonathanbell

Yanıtlar:


94

Bunu başarmanın en iyi yolu üç sunucu bloğu kullanmaktır: biri http'den https'ye yönlendirmek, diğeri https www-isimini www-yönlendirmek, diğeri istekleri işlemek için. Ifs yerine fazladan sunucu blokları kullanmanın nedeni, sunucu seçiminin bir karma tablo kullanılarak yapılması ve çok hızlı olmasıdır. Bir sunucu düzeyinde kullanılması, israf gerektiren her istek için if'nin çalıştırıldığı anlamına gelir. Ayrıca, istenen uri'yi yeniden yazmada yakalamak zahmetlidir, çünkü nginx zaten bu bilgiyi $ uri ve $ request_uri değişkenlerinde (sırasıyla sorgu dizgisi olan ve olmayan) içerir.

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

server {
    listen 443 ssl;
    ssl_certificate /path/to/server.cert;
    ssl_certificate_key /path/to/server.key;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    ssl_certificate /path/to/server.cert;
    ssl_certificate_key /path/to/server.key;
    server_name example.com;

    <locations for processing requests>
}

2
Orta blok gerekli mi? İlk blok zaten www'den www olmayanlara yeniden yazma değil mi?
pbreitenbach

3
İlk blok sadece http'i kullanır. Orta blok, https isteklerini https: // www.example.com/ adresinden https: // example.com/ adresine yönlendirmek için gereklidir. (Ekstra alanlar için özür dilerim, aksi takdirde https gösteremem)
kolbyjack

1
sadece küçük bir biçimlendirme notu - bir bağlantı yapmaktan kaçınmak istiyorsanız, yorum metnini tilde altındaki bir arka tırnak `ın içine koyabilirsiniz. https://example.com/
Şunun

9
İkinci bloğun ayrıca sertifika bilgisine ihtiyacı var.
ricka

3
Bu cevabı deneyerek başka bir problemle karşılaştım. 301'den yeniden yönlendirme www.sub.example.comyapabileceğimi sub.example.comve sonra yalnızca SSL sertifikası alabileceğimi düşündüm . sub.example.comŞimdi ssl sertifika kontrolünün 301 yönlendirmesinden önce olduğunu biliyorum, bu yüzden çalışamıyor. Burada daha fazla açıklama: serverfault.com/a/358625/144811
Gruzzles

11

Bu benim için çalışıyor:

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

server {
    listen              443 ssl;
    server_name         www.yourdomain.com;
    ssl_certificate     /path/to/certificate.crt;
    ssl_certificate_key /path/to/private/key.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    return              301 https://yourdomain.com$request_uri;
}

server {
    listen              443 ssl;
    server_name         yourdomain.com;
    ssl_certificate     /path/to/certificate.crt;
    ssl_certificate_key /path/to/private/key.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;

    # do the proper handling of the request
}

Unutmayın hem yourdomain.com ve www.yourdomain.com gereken SSL sertifikası olmak. Bu, bir joker karakter sertifikasıyla veya burada açıklandığı gibi bir Sunucu Alternatif Adıyla mümkündür . Bunu yapan hoş ve ücretsiz sertifikalar için https://www.startssl.com adresini kontrol edin . ( Edith : Chrome sürüm 56'dan başlayarak, şaşırtan sertifikalara artık güvenilmez. Bunun yerine https://letsencrypt.org/ adresini deneyin .)


Bu aslında işe yarıyor, ama yinelenen yapılandırma satırları olmadan daha net bir şekilde yapılabileceğini düşündüm.
zloynemec

@zloynemec SSL öğelerini ayrı bir .conf dosyasına koyabilir ve includeher iki SSL sunucu bloğuna eklemek için kuralı kullanabilirsiniz .
Igettäjä

Ayrıca cloudflare kullanıyorsanız, 2 alt etki alanını (www + bir şey) yeniden yönlendirebilmek ve proxy yapmak için $ 10 / moert ödemeniz gerekir. Bir geçici çözüm varsa bana bildirin.
Freedo

7

Yüzlerce benzer dava ile çok fazla zaman geçirdikten sonra, aşağıdaki kod parçasını buldum. Kısadır ve her şeye uyacak şekilde kolayca ayarlanabilir.

server {
    listen 80;
    listen 443 ssl;
    server_name example.com www.example.com;
    ssl_certificate /path/to/my/certs/example.com/fullchain.pem;
    ssl_certificate_key /path/to/my/certs/example.com/privkey.pem;

    # Redirect to the correct place, if needed
    set $https_redirect 0;
    if ($server_port = 80) { set $https_redirect 1; }
    if ($host ~ '^www\.') { set $https_redirect 1; }
    if ($https_redirect = 1) {
        return 301 https://example.com$request_uri;
    }

    location / {
    # ...
}

Ah, ama ifşeytan !

Evet olabilir . Ancak bir sebepten dolayı var ve onu doğru kullanmayı bilenlere zarar vermemeliydi. ;)


Bu hoşuma gitti, ama performans hit hakkında herhangi bir veri var mı? Teşekkür ederim!
Freedo

1
Dürüst olmak gerekirse, hiçbir zaman kıyaslama yapmadım, ancak etkinin hemen hemen aynı olması nedeniyle ayrı kurallara göre bir etkinin olamayacağına inanıyorum.
emyller 24:18

yönlendirme konusunda kriter? Gerçekten uygun değil hayır? (gerçek soru, trol değil ^^)
Matrix

3

Bir yanıt koduyla geri dönmeyi tercih ederim, böylece tarayıcı onu başka bir URL'ye yönlendirdiğinizi bilir.

server {
    listen   80;
    server_name  www.example.com;

    return 301 https://example.com$request_uri;
}

sonra başka bir sunucu yapılandırmaları https

server {
        listen   443 ssl;
        server_name  example.com;
        ...
    }

0

bu amaçla bir sunucu bloğu oluşturmaya ne dersiniz:

server{
    listen 80;
    server_name www.example.net example.net;
    rewrite ^(.*) https://example.net$1 permanent;
}

sonra nginx yeniden başlatılıyor


Yeniden başlatırken "çakışan bir sunucu adı" hatası alıyorum. Ayrıca, bu komut SSL için 443 numaralı bağlantı noktasında dinlemez ve yönlendirme dert etmenize gerek https://www.example.comiçin https://example.comde.
Devin

0

Bunun çalışması gerektiğini düşünüyorum.

Düz HTTP sunucusu tanımınızda, anthonysomerset'in önerdiği gibi bir şey, yani:

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

Ardından, SSL sunucu tanımınızda:

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

Bu şekilde, yönlendirme, kullanıcının orijinal olarak hangi URL'ye gittiğine bakılmaksızın, istek başına yalnızca bir kez yapılmalıdır.


İşe yaradı, teşekkürler. if ($host = 'www.example.com') {İhtiyaçlarını değiştirmek zorunda kaldım çünkü regex'in benim için işe yaramadı. Neden olduğu hakkında hiçbir fikrim yok, doğru göründüğü gibi.
Devin

Unutmayın yapın eğer kötülük ve bir bildirime yol kullanmak genellikle daha iyidir.
Blaise

0

İşte benim için çalışmaya başlayan tam örnek. Sorun, ssl_certificatewww yönlendirme bloğunda ssl ayrıntılarına ( , vb.) Sahip olmamamdı. Günlüklerinizi kontrol etmeyi unutmayın ( sudo tail -f /var/log/nginx/error.log)!

# HTTP — redirect all traffic to HTTPS
server {
    listen 80;
    listen [::]:80 default_server ipv6only=on;
    return 301 https://$host$request_uri;
}

# HTTPS — redirects www to non-www
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name www.example.com;

    # Use the Let's Encrypt certificates
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Include the SSL configuration from cipherli.st
    include snippets/ssl-params.conf;
    return 301 https://example.com$request_uri;
}

# HTTPS — proxy all requests to the app (port 3001)
server {
    # Enable HTTP/2
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com sub.example.com;

    # Use the Let's Encrypt certificates
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Include the SSL configuration from cipherli.st
    include snippets/ssl-params.conf;

    # For LetsEncrypt:
    location ~ /.well-known {
        root /var/www/html;
        allow all;
    }

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://localhost:3001;
        proxy_ssl_session_reuse off;
        proxy_set_header Host $http_host;
        proxy_cache_bypass $http_upgrade;
        proxy_redirect off;
    }
}
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.