Vraag Hoe kan ik in Nginx alle http-verzoeken naar https herschrijven met behoud van het subdomein?


Ik wil alle http-verzoeken op mijn webserver herschrijven als https-verzoeken. Ik begon met het volgende:

server {
    luister 80;

    plaats / {
      herschrijven ^ (. *) https: //mijnsite.com$1 permanent;
    }
...


Een probleem is dat dit alle subdomeininformatie weghaalt (bijv. Node1.mijnsite.com/map), hoe kan ik het bovenstaande herschrijven om alles om te leiden naar https en het subdomein te onderhouden?


495
2017-09-21 14:04


oorsprong


Overweeg om het 'geaccepteerde antwoord' te verplaatsen naar serverfault.com/a/171238/90758. Dat is de juiste. - olafure
Gebruik gewoon $ server_name in plaats van hardcoded mysite.com - Fedir RYKHTIK


antwoorden:


Juiste manier in nieuwe versies van nginx

Mijn eerste antwoord op deze vraag bleek op een bepaald moment correct, maar het veranderde in een andere valkuil - om op de hoogte te blijven, kijk alstublieft Belasting van herschrijf valkuilen

Ik ben door veel SE-gebruikers gecorrigeerd, dus het krediet gaat naar hen, maar wat nog belangrijker is, hier is de juiste code:

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

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000" always; 

       [....]
}

737
2017-12-05 20:43



Je zou dit echter per domein moeten doen op basis van een domein - niet? Wat als je het zou willen toepassen op elk domein op je server? - JM4
@ JM4: als u $ host $ gebruikt in de rewrite in plaats van server_name en default_server toevoegt aan de luisterrichtlijn, werkt deze voor elk domein op uw server. - Klaas van Schelven
Het is belangrijk om te vermelden dat de 301 is opgeslagen in uw lokale cache zonder vervaldatum. Niet erg handig als de configuratie verandert - Trefex
@everyone Gebruik een 307-omleiding om POST-inhoud te behouden. - Mahmoud Al-Qudsi
Merk op dat je moet gebruiken $host in plaats van $server_name als u subdomeinen gebruikt. - Catfish


OPMERKING: De beste manier om dit te doen, werd geleverd door https://serverfault.com/a/401632/3641 - maar wordt hier herhaald:

server {
    listen         80;
    return 301 https://$host$request_uri;
}

In het eenvoudigste geval wordt uw host gerepareerd om uw service te zijn waarnaar u deze wilt verzenden - dit doet een 301-omleiding naar de browser en de browser-URL wordt dienovereenkomstig bijgewerkt.

Hieronder staat het vorige antwoord, dat inefficiënt is als gevolg van regex, een eenvoudige 301 is geweldig zoals wordt getoond door @kmindi

Ik heb nginx 0.8.39 en hoger gebruikt en het volgende gebruikt:

 server {
       listen 80;
       rewrite ^(.*) https://$host$1 permanent;
 }

Verzendt een permanente omleiding naar de client.


269
2017-08-17 03:07



Ik denk dat het 80 zou moeten zijn - omdat dit naar http luistert en vervolgens de klant vertelt terug te komen als https (443). - Michael Neale
Dit zou het beste antwoord moeten zijn! - Nathan
Dit is het meest belastende antwoord. - Case
dit is de gemakkelijkste, maar de minst veilige - op deze manier staat u uw server toe om een ​​gebruiker naar elke pagina door te sturen, zonder te controleren of deze zelfs op uw server mag worden gebruikt. Als uw server mydomain.co ondersteunt, kunnen kwaadwillende gebruikers uw server nog steeds gebruiken om gebruikers om te leiden naar andere domeinen zoals mijndomein.co, zoals google.com. - friedkiwi
@ cab0lt er is hier geen beveiligingsprobleem. Het omzetten van een omleiding levert geen beveiligingsrisico op. Als er vereisten voor toegangscontrole zijn, moeten die worden gecontroleerd op het moment dat de browser de nieuwe URL opvraagt. De browser krijgt geen toegang alleen op basis van de omleiding, noch hebben ze de omleiding nodig om de nieuwe URL aan te vragen. - mc0e


Ik denk dat de beste en enige manier zou moeten zijn om een ​​te gebruiken HTTP 301 permanent verplaatst omleiden als volgt:

server {
    listen         [::]:80;
    return 301 https://$host$request_uri;
}

De HTTP 301 permanent verplaatst omleiding is ook de meest efficiënte omdat er geen regex is die moet worden geëvalueerd, volgens eerder genoemd pitfails.


De nieuwe HTTP 308 permanent verplaatst behoudt de Verzoekmethode en is ondersteund door belangrijke browsers. Gebruik bijvoorbeeld 308 voorkomt dat browsers de aanvraagmethode veranderen van POST naar GET voor het omleidingsverzoek.


Als je wilt bewaar de hostnaam en het subdomein dit is de weg.

Deze werkt nog steeds als u geen DNS heeft, aangezien ik het ook lokaal gebruik. Ik verzoek bijvoorbeeld om http://192.168.0.100/index.php en wordt doorgestuurd naar precies https://192.168.0.100/index.php.

ik gebruik listen [::]:80 op mijn gastheer omdat ik het heb bindv6only ingesteld op false, dus het bindt ook aan de ipv4-socket. verander het in listen 80 als je IPv6 niet wilt of ergens anders wilt binden.

De oplossing van Saif Bechan maakt gebruik van de server_name wat in mijn geval localhost is, maar dat is niet bereikbaar via een netwerk.

De oplossing van Michael Neale is goed, maar volgens de pitfails is er een betere oplossing met omleiding 301;)


121
2018-06-23 17:19



Leuk dat je het probeert te citeren, maar 301 werkt niet op HTTPS. - Case
wat werkt niet? de aangegeven serversectie is voor niet-gecodeerd http (zonder s) verkeer om permanent te worden omgeleid naar een versleutelde server (die sectie die luistert op 443 (https) wordt niet vermeld) - kmindi
Ik heb gecontroleerd of dit prima werkt met https en alles - @kmindi Ik heb mijn antwoord bijgewerkt met verwijzing naar het jouwe - omdat ik denk dat het de juiste manier is en dit blijft opduiken! Goed werk. - Michael Neale
Als ik een domein (niet-ip) gebruik, werkt het niet tenzij ik '[::]: 80' in '80' verander. - Joseph Lust
dat zou het verwachte gedrag kunnen zijn: trac.nginx.org/nginx/ticket/345. Ik heb het antwoord bijgewerkt om de luisteroptie te beschrijven. - kmindi


Het bovenstaande werkte niet omdat er steeds nieuwe subdomeinen werden gemaakt. bijv. AAA.example.com BBB.example.com voor ongeveer 30 subdomeinen.

Eindelijk heb ik een configuratie die werkt met het volgende:

server {
  listen 80;
  server_name _;
  rewrite ^ https://$host$request_uri? permanent;
}
server {
  listen  443;
  server_name example.com;
  ssl on;
  ssl_certificate /etc/ssl/certs/myssl.crt;
  ssl_certificate_key /etc/ssl/private/myssl.key;
  ssl_prefer_server_ciphers       on;
# ...
# rest of config here
# ...
}

17
2018-06-25 04:29



dank je! nginx zou of terugkeren 301 https://*/ of annuleer het verzoek hier voortijdig in de andere antwoorden. server_name _; met $host was het antwoord dat het lukte. 1 - zamnuts
Deze is optimaal! Ik raad echter aan om sommige te vervangen _ met het feitelijke domein, b.v. .domain.com Ik had twee servers en nginx leidde per ongeluk een van mijn servers naar de standaardserver. - zzz
Dit is het enige antwoord dat voor me werkte, bedankt! - Snowman
Heel erg bedankt maatje. Ik heb veel van de oplossingen geprobeerd, maar het lukte niet. Deze oplossing is geweldig en het werkte voor mij. server naam _; wat is dit bedoeld voor .. ik begreep het niet. Leg me dit alstublieft uit. - Pavan Kumar


Binnen het serverblok kunt u ook het volgende doen:

# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
    rewrite ^ https://$host$uri permanent;
}

16
2017-07-31 19:50



Deze configuratie zorgde ervoor dat mijn server een omleidingslus produceerde - Corkscreewe
Misschien is er een andere omleiding op zijn plaats of is https niet ingeschakeld in uw site / app - Oriol
Geen van de anderen leek te werken behalve deze. Nginx-versie gebruiken: nginx / 1.10.0 (Ubuntu) - ThatGuy343
upmeld voor https: // $ host $ uri - AMB
Dit is de manier om te gaan als je achter een loadbalancer zit! - Antwan


Ik heb lang geleden een opmerking over het juiste antwoord geplaatst met een zeer belangrijke correctie, maar ik vind dat het noodzakelijk is om deze correctie in zijn eigen antwoord te benadrukken. Geen van de vorige antwoorden kan veilig worden gebruikt als u op enig moment onbeveiligde HTTP hebt ingesteld en gebruikersinhoud verwacht, formulieren hebt, een API host of een website, tool, toepassing of hulpprogramma hebt geconfigureerd om met uw site te spreken.

Het probleem treedt op wanneer een POST er wordt een aanvraag ingediend bij uw server. Als de server reageert met een standaard 30x redirect de POST-inhoud zal verloren gaan. Wat er gebeurt, is dat de browser / client de aanvraag zal upgraden naar SSL maar downgrade de POST naar een GET verzoek. De POST parameters gaan verloren en er wordt een onjuiste aanvraag naar uw server gedaan.

De oplossing is eenvoudig. Je moet een gebruiken HTTP 1.1 307 omleiden. Dit is gedetailleerd in RFC 7231 S6.4.7:

  Note: This status code is similar to 302 (Found), except that it
  does not allow changing the request method from POST to GET.  This
  specification defines no equivalent counterpart for 301 (Moved
  Permanently) ([RFC7238], however, defines the status code 308
  (Permanent Redirect) for this purpose).

De oplossing, aangepast vanuit de geaccepteerde oplossing, is om te gebruiken 307 in uw omleidingscode:

server {
       listen         80;
       server_name    my.domain.com;
       return         307 https://$server_name$request_uri;
}

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000"; 

       [....]
}

6
2018-03-19 20:24



heel, heel erg handig commando. bedankt! - Denis Matafonov


Ik heb het als volgt kunnen doen:

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

https://stackoverflow.com/a/36777526/6076984


4
2018-04-21 18:27



Bijgewerkte versie, zonder IF: paste.debian.net/plain/899679 - stamster


Ik gebruik ngnix achter een AWS ELB. De ELB praat met ngnix via http. Omdat de ELB geen mogelijkheid heeft om omleidingen naar clients te verzenden, controleer ik de X-Forwarded-Proto-header en redirect:

if ($http_x_forwarded_proto != 'https') {
    return 301 "https://www.exampl.com";
}

3
2018-01-04 17:09





als jij return 301 https://$host$request_uri; als het standaardantwoord op poort 80, kan uw server vroeg of laat een lijst met open proxies [1] krijgen en misbruik maken om elders op internet internetverkeer te verzenden. Als uw logboeken vollopen met berichten zoals deze, weet u dat het u is overkomen:

42.232.104.114 - - [25/Mar/2018:04:50:49 +0000] "GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1" 301 185 "http://www.ioffer.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; RogueCleaner; Alexa Toolbar)"

Het probleem is dat $host echo terug wat de browser verzendt in de Host header of zelfs de hostname van de openingsregel van HTTP, zoals deze:

GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1

Vanwege dat probleem, raden sommige andere antwoorden hier het gebruik aan $server_name in plaats van $host. $server_name evalueert altijd naar wat u zet in de server_name verklaring. Maar als u daar meerdere subdomeinen heeft of een joker gebruikt, zal dat niet werken, omdat $server_name gebruikt alleen de eerste toegang na de server_name verklaring, en wat nog belangrijker is, zal gewoon een wildcard terug echoën (niet uitbreiden).

Dus hoe kunt u meerdere domeinen ondersteunen met behoud van beveiliging? Op mijn eigen systemen heb ik dit dilemma behandeld door eerste lijst een default_server blok dat niet gebruikt $hosten vervolgens een blok met jokertekens te plaatsen dat:

server {
  listen 80 default_server;
  server_name example.com;
  return 301 https://example.com$request_uri;
}
server {
  listen 80;
  server_name *.example.com;
  return 301 https://$host$request_uri;
}

(U kunt ook meer dan één domein in het tweede blok weergeven.)

Met die combinatie worden ongeëvenaarde domeinen ergens hard-gecodeerd doorgeleid (altijd example.com) en domeinen die overeenkomen met die van uzelf, gaan naar de juiste plaats. Uw server zal niet nuttig zijn als open proxy, dus u zult geen problemen ondervinden.

Als je je goed voelt, denk ik dat je ook de default_server blok match geen van uw legitieme domeinen en dient iets aanstootgevends. . . .

[1] Technisch gesproken is "proxy" het verkeerde woord, omdat je server niet uitgaat en verzoeken voor de clients uitvoert, alleen maar een omleiding, maar ik weet niet zeker wat het juiste woord zou zijn. Ik weet ook niet zeker wat het doel is, maar het vult je logs met ruis en verbruikt je CPU en bandbreedte, dus je kunt er net zo goed een eind aan maken.


0
2018-03-25 05:58





rewrite ^!https https://$host$request_uri permanent;

-1
2018-06-29 04:33