Como forçar ou redirecionar para SSL no nginx?

211

Eu tenho uma página de inscrição em um subdomínio como: https://signup.example.com

Ele só deve ser acessível via HTTPS, mas estou preocupado que as pessoas possam de alguma forma se deparar com isso via HTTP e obter um 404.

Meu bloco html / server no nginx tem esta aparência:

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

O que posso adicionar para que as pessoas que vão para http://signup.example.com sejam redirecionadas para https://signup.example.com ? (FYI eu sei que existem plugins Rails que podem forçar SSL , mas estava esperando para evitar isso)

    
por Callmeed 22.03.2011 / 19:45

8 respostas

138

De acordo com as armadilhas do nginx , é um pouco melhor omitir a captura desnecessária, usando $request_uri . Nesse caso, anexe um ponto de interrogação para impedir que o nginx duplique quaisquer argumentos de consulta.

server {
    listen      80;
    server_name signup.mysite.com;
    rewrite     ^   https://$server_name$request_uri? permanent;
}
    
por 22.03.2011 / 20:22
238

A melhor maneira descrita no manual oficial é usando return directiva:

server {
    listen      80;
    server_name signup.mysite.com;
    return 301 https://$server_name$request_uri;
}
    
por 04.09.2012 / 01:50
108

Esta é a maneira correta e mais eficiente se você quiser manter tudo em um bloco de servidor:

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

Tudo o mais acima, usando "reescrever" ou "se ssl_protocol", etc. é mais lento e pior.

Aqui está o mesmo, mas ainda mais eficiente, apenas executando a reescrita no protocolo http, evita ter que verificar a variável $ scheme em cada requisição. Mas, falando sério, é uma coisa tão pequena que você não precisa separá-los.

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;
}
    
por 31.01.2013 / 21:43
56

Se você estiver usando a nova definição de servidor dual HTTP e HTTPS, poderá usar o seguinte:

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

Isso parece funcionar para mim e não causa loops de redirecionamento.

Editar:

Substituído:

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

com a linha de reescrita de Pratik.

    
por 08.08.2011 / 13:12
27

Ainda outra variante, que preserva o cabeçalho de solicitação do Host: e segue o exemplo "GOOD" em armadilhas do nginx :

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

Aqui estão os resultados. Observe que usar $server_name em vez de $host sempre seria redirecionado para 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
    
por 11.04.2013 / 14:20
3

Certifique-se de definir "seguro" em todos os cookies, senão eles serão enviados na solicitação HTTP e poderão ser capturados por uma ferramenta como o Firesheep.

    
por 23.03.2011 / 01:40
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;
}

Isso funciona melhor, eu acho. x.x.x.x refere-se ao IP do seu servidor. Se você está trabalhando com o Plesk 12, você pode fazer isso alterando o arquivo "nginx.conf" no diretório "/var/www/vhosts/system/domain.tld/conf" para qualquer domínio que você queira. Não se esqueça de reiniciar o serviço nginx depois de salvar a configuração.

    
por 23.08.2014 / 21:40
0

Acho que esta é a solução mais simples. Força o tráfego não HTTPS e não WWW apenas para HTTPS e www.

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 - Abr. 2018: Solução sem IFs pode ser encontrada em minha postagem aqui: link

    
por 21.04.2016 / 20:30