Por que o nginx está respondendo a qualquer nome de domínio?

139

Eu tenho o nginx instalado e funcionando com um aplicativo Ruby / Sinatra e está tudo bem. No entanto, agora estou tentando ter um segundo aplicativo em execução no mesmo servidor e notei algo estranho. Primeiro, aqui está o meu nginx.conf:

pid /tmp/nginx.pid;
error_log /tmp/nginx.error.log;

events {
  worker_connections 1024;
  accept_mutex off;
}

http {
  default_type application/octet-stream;
  access_log /tmp/nginx.access.log combined;

  sendfile on;
  tcp_nopush on;
  tcp_nodelay off;

  gzip on;
  gzip_http_version 1.0;
  gzip_proxied any;
  gzip_min_length 500;
  gzip_disable "MSIE [1-6]\.";
  gzip_types text/plain text/xml text/css
             text/comma-separated-values
             text/javascript application/x-javascript
             application/atom+xml;

  upstream app {
    server unix:/var/www/app/tmp/sockets/unicorn.sock fail_timeout=0;
  }

  server {
    listen 80;
    client_max_body_size 4G;
    server_name FAKE.COM;

    keepalive_timeout 5;

    root /var/www/app/public;

    location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;

      if (!-f $request_filename) {
        proxy_pass http://app;
        break;
      }
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/app/public;
    }
  }
}
                                                          68,0-1        B

Observe como server_nameestá definido como FAKE.COMainda o servidor está respondendo a todos os hosts que atingem esse servidor por outros nomes de domínio. Como posso fazer com que esse servidor específico responda apenas a solicitações de FAKE.COM?

Martin
fonte
o listen fake.com | something.com:80 comando filtra, não server_name.
27480 Alexei Martchenko #

Respostas:

202

O primeiro bloco de servidor na configuração do nginx é o padrão para todas as solicitações que atingem o servidor para o qual não há nenhum bloco de servidor específico.

Portanto, na sua configuração, assumindo que o seu domínio real é REAL.COM, quando um usuário digita isso, ele será resolvido para o servidor e, como não há nenhum bloco de servidor para essa configuração, o bloco do servidor para FAKE.COM, sendo o primeiro bloco de servidor (somente bloco de servidor no seu caso), processará essa solicitação.

É por isso que as configurações adequadas do Nginx têm um bloco de servidor específico para os padrões antes de seguir com outros para domínios específicos.

# Default server
server {
    return 404;
}

server {
    server_name domain_1;
    [...]
}

server {
    server_name domain_2;
    [...]
}

etc

** EDIT **

Parece que alguns usuários estão um pouco confusos com este exemplo e pensam que está limitado a um único arquivo conf etc.

Observe que o acima é um exemplo simples para o OP se desenvolver conforme necessário.

Pessoalmente, uso arquivos separados de vhost conf com isso da seguinte maneira (CentOS / RHEL):

http {
    [...]
    # Default server
    server {
        return 404;
    }
    # Other servers
    include /etc/nginx/conf.d/*.conf;
}

/etc/nginx/conf.d/ conterá domain_1.conf, domain_2.conf ... domain_n.conf, que será incluído após o bloco do servidor no arquivo nginx.conf principal, que sempre será o primeiro e sempre será o padrão, a menos que seja substituído pelo default_server directiva noutro local.

A ordem alfabética dos nomes dos arquivos conf para os outros servidores se torna irrelevante nesse caso.

Além disso, esse arranjo oferece muita flexibilidade, pois é possível definir vários padrões.

No meu caso específico, eu tenho o Apache ouvindo na porta 8080 apenas na interface interna e proxy os scripts PHP e Perl para o Apache.

No entanto, eu executo dois aplicativos separados que retornam links com ": 8080" no html de saída anexado, pois detectam que o Apache não está sendo executado na porta 80 padrão e tentam "me ajudar".

Isso causa um problema em que os links se tornam inválidos, pois o Apache não pode ser acessado a partir da interface externa e os links devem apontar para a Porta 80.

Eu resolvo isso criando um servidor padrão para a porta 8080 redirecionar essas solicitações.

http {
    [...]
    # Default server block for undefined domains
    server {
        listen 80;
        return 404;
    }
    # Default server block to redirect Port 8080 for all domains
    server {
        listen my.external.ip.addr:8080;
        return 301 http://$host$request_uri;
    }
    # Other servers
    include /etc/nginx/conf.d/*.conf;
}

Como nada nos blocos regulares de servidor escuta na porta 8080, o bloco de servidor padrão de redirecionamento lida de forma transparente com essas solicitações devido à sua posição no nginx.conf.

Na verdade, tenho quatro desses blocos de servidor e este é um caso de uso simplificado.

Dayo
fonte
1
O Nginx requer distinção entre maiúsculas e minúsculas - "Servidor" deve ser servidor e "Retorno" deve ser retornado. Espero que isso evite alguns problemas ao copiar esse código.
25413 Capaj
2
estático, consulte a resposta de Oleg Neumyvkin - se você tiver vários arquivos de configuração nos sites disponíveis, o primeiro servidor no primeiro arquivo, em ordem alfabética, é o padrão. Eu suspeito que isso possa ser um problema. Além disso, muitas distribuições executam um 'nginx -t' para testar a configuração antes de reiniciar - você pode ter um erro ao impedir uma reinicialização.
jwhitlock
2
Isso está incompleto e não deve ser a resposta aceita. Para que isso funcione, você também precisará remover o default_server de qualquer diretiva de escuta.
Ben
@ben Em primeiro lugar, o OP não tinha "default_server" em seu exemplo de problema e a resposta é adaptada às especificidades dessa pergunta. Em segundo lugar, por que alguém definiria default_server em um local de servidor separado ao seguir instruções para tornar o primeiro servidor definido o padrão está além de mim. De qualquer forma, se um servidor padrão foi definido especificamente, esse conjunto de perguntas e respostas não é o que deve ser observado para resolver quaisquer problemas que possam estar tendo.
Dayo
1
@Dayo Você está correto ao abordar a configuração específica publicada pelo OP. Mas, para obter uma resposta completa da pergunta, acho necessário mencionar o servidor_servidor padrão. É muito possível ler sua resposta e não perceber como o default_server interferiria nela. É ainda mais provável, porque algumas distros são enviadas com o default_server definido em um arquivo que pode não ser óbvio para o usuário.
Ben
61

Você deve ter um servidor padrão para pegar tudo , pode retornar 404ou, melhor, não responder (economizará largura de banda) retornando a 444resposta HTTP específica do nginx que simplesmente fecha a conexão e não retorna nada

server {
    listen       80  default_server;
    server_name  _; # some invalid name that won't match anything
    return       444;
}
iTech
fonte
Trabalhou para mim para o nginx 1.8.0. O que server_name _;eu não tinha nas versões anteriores do nginx, mas funcionou. Agora, para as versões mais recentes do nginx, parece que você precisa do server_name _;. Graças
daniel
Resolvido. Esqueci um ponto-e-vírgula; _;
user1201917
2
@ iTech: Por alguma razão, está retornando 444 para todas as solicitações. Alguma pista?
Divick
Ótima dica sobre o 444, e imho uma solução muito mais limpa do que retornar um código de erro.
qqilihq
1
É importante especificar um certificado / chave; caso contrário, todas as conexões SSL corresponderão e falharão, conforme apontado por @AndreyT em sua resposta abaixo.
Mark Fletcher
35

Não consegui resolver meu problema com nenhuma das outras respostas. Resolvi o problema, verificando se o host correspondia e retornando um 403, caso contrário. (Eu tinha um site aleatório apontando para o conteúdo dos meus servidores da Web. Suponho que sequestrar a classificação da pesquisa)

server {
    listen 443;
    server_name example.com;

    if ($host != "example.com") {
        return 403;
    }

    ...
}
Matt Carrier
fonte
1
Se for uma má prática: nginx.com/resources/wiki/start/topics/depth/ifisevil
Esolitos
1
Há casos em que você simplesmente não pode evitar o uso de um if, por exemplo, se você precisar testar uma variável que não possui diretiva equivalente.
Edward
4
@Esolitos Literalmente, a terceira linha desse artigo diz que esse caso de uso está correto. Entendo a necessidade de ser cauteloso, mas não vamos mexer os dedos em casos de uso razoáveis.
mpowered
Na minha opinião, a solução mais fácil e concisa, pois requer apenas 3 linhas de código, você pode colar com prazer em qualquer arquivo vhost, alterando apenas o host $ comparado posteriormente.
Akito
28

Para responder sua pergunta - o nginx escolhe o primeiro servidor se não houver correspondência. Veja a documentação :

Se o seu valor não corresponder a nenhum nome de servidor ou a solicitação não contiver esse campo de cabeçalho, o nginx encaminhará a solicitação para o servidor padrão dessa porta. Na configuração acima, o servidor padrão é o primeiro ...

Agora, se você deseja ter um servidor catch-all padrão que, digamos, responda com 404 a todas as solicitações, veja como fazê-lo:

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_certificate <path to cert>
    ssl_certificate_key <path to key>
    return 404;
}

Observe que você precisa especificar o certificado / chave (que pode ser autoassinado); caso contrário, todas as conexões SSL falharão, pois o nginx tentará aceitar a conexão usando esse servidor_servidor padrão e não encontrará o certificado / chave.

andreycpp
fonte
3
Não faço ideia por que essa resposta está tão longe na lista. É esse que responde à pergunta sem se distrair com as coisas brilhantes ao longo do caminho.
mmc
Isso me ajudou a resolver um problema em que eu estava tentando redirecionar de não-www para www e tive que incluir meu certificado ssl nessa rota de redirecionamento, caso contrário, estava tentando obter meu certificado SSL padrão que era para um domínio diferente.
endyourif 7/02/19
1
Essa parece ser a melhor resposta para a maioria das configurações ... não tenho certeza de quem está usando o nginx sem SSL atualmente, mas o fato de ser o único que cobre o SSL é extremamente revelador.
mpowered
Parece que isso server_name _;nem é necessário.
Julien Salinas
26

Existem algumas maneiras de especificar o servidor padrão.

Primeira maneira - especifique o servidor padrão primeiro na lista, se você mantiver as configurações do servidor em um arquivo de configuração, como Dayo mostrou acima.

Segunda maneira (melhor) Mais flexível - forneça default_serverparâmetros para listeninstruções, por exemplo:

server {
    listen  *:80 default_server;
    root /www/project/public/;
}

Mais informações aqui: Nginx doc / Listen

Dessa forma, é mais útil quando você mantém as configurações do servidor em arquivos separados e não deseja nomear esses arquivos em ordem alfabética.

Pavel
fonte
3
Essa deve ser a resposta correta. A resposta aceita é enganosa. Simplesmente adicionar outro servidor à configuração não resolverá o problema se outro servidor estiver configurado para ser o servidor padrão.
Ben
1
@Pavel, não há razão para que a resposta fornecida não funcione com vários arquivos vhost separados. Além disso, com isso, sei que meu servidor padrão está sempre no arquivo nginx.conf principal e não preciso lembrar qual dos meus muitos arquivos vhost separados contém isso.
Dayo
Não esqueça de ouvir também o 443 do ssl (consulte a resposta de @ AndreyT abaixo).
Constantinos
8

Pouco comentário para responder:

se você tiver vários hosts virtuais em vários IPs em vários arquivos de configuração em sites disponíveis /, o domínio "padrão" do IP será obtido do primeiro arquivo por ordem alfabética.

E, como Pavel disse, há um argumento "default_server" para a diretiva "listen" http://nginx.org/en/docs/http/ngx_http_core_module.html#listen

Oleg Neumyvakin
fonte