Je veux réécrire toutes les demandes http sur mon serveur Web pour être des demandes https, j'ai commencé par ce qui suit:
serveur { écouter 80; emplacement/{ réécrire ^ (. *) https: //mysite.com$1 permanent; } ...
.
Il s'est avéré que ma première réponse à cette question était correcte à un certain moment, mais elle s'est transformée en un autre piège - pour rester à jour, veuillez vérifier Taxing rewrite pitfalls
J'ai été corrigé par de nombreux utilisateurs de SE, donc le mérite leur revient, mais plus important encore, voici le bon 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;
[....]
}
REMARQUE: La meilleure façon de procéder a été fournie par https://serverfault.com/a/401632/3641 - mais est répétée ici:
server {
listen 80;
return 301 https://$Host$request_uri;
}
Dans le cas le plus simple, votre hôte sera fixé pour être le service auquel vous souhaitez les envoyer - cela fera une redirection 301 vers le navigateur et l'URL du navigateur sera mise à jour en conséquence.
Ci-dessous la réponse précédente, qui est inefficace en raison de l'expression rationnelle, un simple 301 est excellent comme le montre @kmindi
J'utilise nginx 0.8.39 et supérieur et j'ai utilisé ce qui suit:
server {
listen 80;
rewrite ^(.*) https://$Host$1 permanent;
}
Envoie une redirection permanente au client.
Je pense que la meilleure et la seule façon devrait être d'utiliser une redirection HTTP 301 déplacée en permanence comme ceci:
server {
listen [::]:80;
return 301 https://$Host$request_uri;
}
La redirection HTTP 301 déplacée de manière permanente est également la plus efficace car il n'y a pas d'expression régulière à évaluer, selon ce qui a déjà été mentionné pièges .
Le nouveau HTTP 308 déplacé en permanence préserve la méthode Request et est pris en charge par les principaux navigateurs . Par exemple, en utilisant 308
empêche les navigateurs de changer la méthode de demande de POST
à GET
pour la demande de redirection.
Si vous voulez conserver le nom d'hôte et le sous-domaine c'est la voie.
Cela fonctionne toujours si vous n'avez pas de DNS , car je l'utilise également localement. Je demande par exemple avec http://192.168.0.100/index.php
et sera redirigé exactement vers https://192.168.0.100/index.php
.
J'utilise listen [::]:80
sur mon hôte car j'ai bindv6only
défini sur false
, donc il se lie également au socket ipv4. changez-le en listen 80
si vous ne voulez pas IPv6 ou que vous souhaitez établir une liaison ailleurs.
La solution de Saif Bechan utilise le server_name
qui dans mon cas est localhost mais qui n'est pas accessible sur un réseau.
La solution de Michael Neale est bonne, mais selon les pièges, il existe une meilleure solution avec la redirection 301;)
Dans le bloc serveur, vous pouvez également effectuer les opérations suivantes:
# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
rewrite ^ https://$Host$uri permanent;
}
Ce qui précède n'a pas fonctionné avec de nouveaux sous-domaines étant créés tout le temps. par exemple. AAA.example.com BBB.example.com pour environ 30 sous-domaines.
J'ai finalement obtenu une configuration avec les éléments suivants:
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
# ...
}
J'ai posté un commentaire sur la bonne réponse il y a très, très longtemps avec une correction très importante, mais je pense qu'il est nécessaire de mettre en évidence cette correction dans sa propre réponse. Aucune des réponses précédentes ne peut être utilisée en toute sécurité si, à un moment donné, vous avez configuré HTTP non sécurisé et attendez du contenu utilisateur, avez des formulaires, hébergez une API ou avez configuré un site Web, un outil, une application ou un utilitaire pour parler votre site.
Le problème se produit lorsqu'une demande POST
est envoyée à votre serveur. Si la réponse du serveur avec un simple 30x
rediriger le contenu POST sera perdu. Ce qui se passe, c'est que le navigateur/client mettra à niveau la demande vers SSL mais rétrograder la requête POST
en requête GET
. Les paramètres POST
seront perdus et une requête incorrecte sera envoyée à votre serveur.
La solution est simple. Vous devez utiliser un HTTP 1.1 307
rediriger. Ceci est détaillé dans la 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).
La solution, adaptée de la solution acceptée, consiste à utiliser 307
dans votre code de redirection:
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";
[....]
}
Je lance ngnix derrière un AWS ELB. L'ELB parle à ngnix via http. Étant donné que l'ELB n'a aucun moyen d'envoyer des redirections aux clients, je vérifie l'en-tête X-Forwarded-Proto et redirige:
if ($http_x_forwarded_proto != 'https') {
return 301 "https://www.exampl.com";
}
J'ai réussi à le faire comme ça:
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;
}
}
Si vous return 301 https://$Host$request_uri;
comme réponse par défaut sur le port 80, alors votre serveur peut tôt ou tard obtenir une liste de proxys ouverts [1] et commencer à être abusé pour envoyer du trafic ailleurs sur Internet. Si vos journaux se remplissent de messages comme celui-ci, vous savez que cela vous est arrivé:
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)"
Le problème est que $Host
fera écho à tout ce que le navigateur envoie dans l'en-tête Host
ou même le nom d'hôte de la ligne d'ouverture de HTTP, comme celui-ci:
GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1
En raison de ce problème, d'autres réponses recommandent ici d'utiliser $server_name
au lieu de $Host
. $server_name
évalue toujours ce que vous mettez dans le server_name
déclaration. Mais si vous avez plusieurs sous-domaines ou utilisez un caractère générique, cela ne fonctionnera pas, car $server_name
n'utilise l'entrée premier qu'après server_name
déclaration et, plus important encore, ne fera que renvoyer un caractère générique (pas de le développer).
Alors, comment prendre en charge plusieurs domaines tout en maintenant la sécurité? Sur mes propres systèmes, j'ai résolu ce dilemme en premier listant un default_server
bloc qui n'utilise pas $Host
, puis répertoriant un bloc générique qui:
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;
}
(Vous pouvez également répertorier plusieurs domaines dans le deuxième bloc.)
Avec cette combinaison, les domaines inégalés seront redirigés quelque part codés en dur (toujours example.com
), et les domaines qui correspondent aux vôtres iront au bon endroit. Votre serveur ne sera pas utile en tant que proxy ouvert, vous n'attirerez donc aucun problème.
Si vous vous sentez énervé, je suppose que vous pourriez également faire le default_server
bloquer la correspondance aucun de vos domaines légitimes et servir quelque chose d'offensant. . . .
[1] Techniquement, "proxy" n'est pas le bon mot, car votre serveur ne sort pas et ne répond pas aux demandes des clients, il suffit d'envoyer une redirection, mais je ne sais pas quel serait le bon mot. Je ne sais pas non plus quel est l'objectif, mais cela remplit vos journaux de bruit et consomme votre processeur et votre bande passante, vous pouvez donc aussi y mettre un terme.
On dirait que personne n'a vraiment raison à 100%. Pour que les demandes du port 80 soient envoyées à leurs 443 équivalents pour un serveur Web entier, vous devez utiliser la directive Listen, pas la directive server_name pour spécifier le catch- tout nom. Voir aussi https://nginx.org/en/docs/http/request_processing.html
serveur { écouter 80 par défaut; écouter [::]: 80 par défaut; renvoyer 307 https: // $ Host $ request_uri; }
Et assurez-vous de vérifier ce qui est déjà dans /etc/nginx/conf.d/ parce que le plus souvent j'ai eu des problèmes où le default.conf a renvoyé un vhost existant. Mon ordre de travail avec les problèmes nginx commence toujours par déplacer le fichier par défaut, en le remettant en commentaire ligne par ligne pour voir où il va mal.