Vraag Verwijder "www" en leid om naar "https" met nginx


Ik wil een regel maken in nginx die twee dingen doet:

  1. Verwijdert het "www." van de aanvraag URI
  2. Omleidingen naar 'https' als de aanvraag-URI 'http' is

Er zijn veel voorbeelden van hoe elk van deze dingen afzonderlijk te doen, maar ik kan geen oplossing bedenken die beide correct doet (dat wil zeggen, maakt geen omleidingslus en behandelt alle zaken op de juiste manier).

Het moet al deze gevallen behandelen:

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

Deze zouden allemaal moeten eindigen https://example.com/path (# 4) zonder looping. Om het even welke ideeën?


42
2018-04-11 16:37


oorsprong


Ik heb www.mydomain.com zojuist omgeleid naar mijndomein.com op DNS-niveau en een 301 toegevoegd voor niet-https naar https in nginx. Het lijkt erop dat dat prima is ¯ \ _ (ツ) _ / ¯ - jonathanbell


antwoorden:


De beste manier om dit te bereiken is het gebruik van drie serverblokken: één om http om te leiden naar https, één om de https www-naam om te leiden naar no-www en één om verzoeken daadwerkelijk af te handelen. De reden voor het gebruik van extra serverblokken in plaats van ifs is dat serverselectie wordt uitgevoerd met behulp van een hash-tabel en zeer snel is. Het gebruik van een server-niveau betekent dat de if wordt uitgevoerd voor elk verzoek, wat verspilling is. Het vastleggen van de gevraagde uri in het herschrijven is ook verspillend, omdat nginx deze informatie al heeft in de variabelen $ uri en $ request_uri (zonder en met queryreeks, respectievelijk).

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

61
2018-04-11 18:21



Is het middenblok nodig? Is het eerste blok dat al herschrijft van www naar niet-www niet? - pbreitenbach
Het eerste blok verwerkt alleen http. Het middelste blok is nodig om https-verzoeken om te leiden van https: // www.example.com/ naar https: // example.com/. (Sorry voor de extra spaties, ik kan het anders niet laten zien aan de https) - kolbyjack
slechts een kleine opmaaknotitie - als u een koppeling wilt vermijden, kunt u commentaartekst plaatsen in de achteraanhalingstekens `, die onder tilde. Het zou verschijnen als: https://example.com/ - Cyclops
het tweede blok heeft ook cert-info nodig. - ricka
Ik probeerde dit antwoord en kwam een ​​ander probleem tegen. Ik dacht dat ik er 301 van kon omleiden www.sub.example.com naar sub.example.com en verkrijg dan alleen een SSL-certificaat voor sub.example.com Nu weet ik dat SSL-controle plaatsvindt vóór de 301-omleiding, dus het kan niet werken. Meer uitleg hier: serverfault.com/a/358625/144811 - Gruzzles


Dit werkt voor mij:

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
}

Onthoud dat beide  yourdomain.com  en  www.yourdomain.com  moet in uw SSL-certificaat staan. Dit is mogelijk met een wildcard-certificaat of met een Server Alternate Name zoals uitgelegd hier. Controleren https://www.startssl.com voor leuke en gratis certificaten die dit doen. (Edith: beginnend met Chrome-versie 56 worden startssl-certificaten niet meer vertrouwd. Proberen https://letsencrypt.org/ in plaats daarvan.)


8
2018-05-09 15:45



Deze werkt echt, maar ik dacht dat het op een meer heldere manier kon worden gedaan zonder veel dubbele configuratie-regels. - zloynemec
@zloynemec U kunt de SSL-dingen in een afzonderlijk .conf-bestand plaatsen en de include regel om deze toe te voegen aan beide SSL-serverblokken. - Igettäjä
Ook als u cloudflare gebruikt, moet u de $ 10 / mo cert betalen om de twee subdomeinen (www + iets) te kunnen omleiden en proxyen. Laat me weten of er een oplossing is. - Freedo


Na zoveel tijd met honderden vergelijkbare zaken doorgebracht te hebben, heb ik het bedacht het volgende fragment. Het is kort en kan gemakkelijk worden aangepast om in alles te passen.

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 / {
    # ...
}

Oh maar if is slecht!

Ja het kan worden. Maar het bestaat om een ​​reden, en zou geen kwaad moeten doen aan degenen die weet hoe je het goed moet gebruiken. ;)


6
2018-01-24 14:11



Ik vind dit leuk, maar heb je gegevens over de prestatieshit? Dank je! - Freedo
Eerlijk gezegd heb ik dat nooit gebenchmarkt, maar ik geloof dat er nauwelijks een effect zal zijn in vergelijking met afzonderlijke regels omdat het effect vrijwel hetzelfde is. - emyller


Ik geef de voorkeur om terug te keren met een responscode, zodat de browser weet dat je hem naar een andere URL doorverwijst.

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

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

dan blokkeren een andere serverconfiguraties voor de https

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

3
2017-09-18 12:16





hoe zit het met het creëren van een serverblok voor dit doel:

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

vervolgens nginx opnieuw opstarten


0
2018-04-11 16:45



Ik krijg de foutmelding "conflicterende servernaam" bij opnieuw opstarten. Ook zal die opdracht niet luisteren op poort 443 voor SSL en moet ik me zorgen maken over omleidingen https://www.example.com naar https://example.com ook. - Devin


Ik denk dat dit zou moeten werken.

Op uw eenvoudige HTTP-serverdefinitie suggereerde zoiets als anthonysomerset, dat is:

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

Dan op uw SSL-serverdefinitie:

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

Op deze manier zou de omleiding slechts eenmaal per aanvraag moeten plaatsvinden, ongeacht naar welke URL de gebruiker oorspronkelijk gaat.


0
2018-04-11 17:56



Dat werkte, bedankt. Ik moest je voorwaardelijke veranderen in if ($host = 'www.example.com') { omdat je regex voor mij niet werkte. Geen idee waarom, omdat het er goed uitziet. - Devin
Let wel op als is het kwaad en het is over het algemeen beter om een ​​declaratieve manier te gebruiken. - Blaise


Dit is het volledige voorbeeld dat voor mij werkte. Het probleem was dat ik de SSL-details niet had (ssl_certificate, enz.) in het www-omleidblok. Vergeet niet om uw logboeken te controleren (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;
    }
}

0
2018-02-07 03:58