Como executar o Gunicorn upstream com uma configuração Nginx SSL?

5

Eu tenho um servidor nginx com um certificado SSL instalado. Eu quero passar quaisquer solicitações para o meu servidor Gunicorn rodando em 0.0.0.0:8000 . No entanto, sempre que eu executo o servidor Gunicorn, ocorre um erro dizendo que há muitos loops de redirecionamento. Se eu rodar gunicorn sobre https, a conexão se tornará segura, mas não se conectará ao servidor gunicorn e só dirá bad gateway . Além disso, aqui está o erro que recebo ao tentar conectar-se ao executar o gunicorn com https:

Traceback (most recent call last):
  File "/opt/bitnami/python/lib/python2.7/site-packages/gunicorn/arbiter.py", line 515, in spawn_worker
    worker.init_process()
  File "/opt/bitnami/python/lib/python2.7/site-packages/gunicorn/workers/base.py", line 126, in init_process
    self.run()
  File "/opt/bitnami/python/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 119, in run
    self.run_for_one(timeout)
  File "/opt/bitnami/python/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 66, in run_for_one
    self.accept(listener)
  File "/opt/bitnami/python/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 30, in accept
    self.handle(listener, client, addr)
  File "/opt/bitnami/python/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 141, in handle
    self.handle_error(req, client, addr, e)
  File "/opt/bitnami/python/lib/python2.7/site-packages/gunicorn/workers/base.py", line 213, in handle_error
    self.log.exception("Error handling request %s", req.uri)
AttributeError: 'NoneType' object has no attribute 'uri'
[2016-01-01 15:37:45 +0000] [935] [INFO] Worker exiting (pid: 935)
[2016-01-01 20:37:45 +0000] [938] [INFO] Booting worker with pid: 938
[2016-01-01 15:37:46 +0000] [938] [ERROR] Exception in worker process:

Aqui está minha configuração nginx:

  server {
    # port to listen on. Can also be set to an IP:PORT
    listen 80;
    listen 443 ssl;
    ssl_certificate /etc/ssl/pyhub_crt.crt;
    ssl_certificate_key /etc/ssl/pyhub.key;
    server_name www.pyhub.co;
    server_name_in_redirect off;
    access_log /opt/bitnami/nginx/logs/access.log;
    error_log /opt/bitnami/nginx/logs/error.log;
    location /E0130777F7D5B855A4C5DEB138808515.txt {
        root /home/bitnami;
    }

    location / {
    proxy_pass_header Server;
    proxy_set_header Host $host;
    proxy_set_header X-Scheme $scheme;
    proxy_set_header X-SSL-Protocal $ssl_protocol;
    proxy_connect_timeout 10;
    proxy_read_timeout 10;
    proxy_redirect http:// $scheme://;
    proxy_pass http://localhost:8000;
    }
    
por Dorian Dore 01.01.2016 / 21:45

3 respostas

6

Se o gunicorn estiver ligado a 0.0.0.0, ele está vinculado a todas as interfaces, portanto ele já está exposto à interface externa. Se o nginx tentar ligar-se a qualquer interface na mesma porta, ele falhará.

Gunicorn deve ser ligado a um ip específico ou melhor 127.0.0.1, portanto, ele é ligado apenas ao ip interno.

Sesond, você diz que quer passar o https para o gunicorn, mas o tráfego é protegido com SSL para o seu proxy que possui os certificados, que é o ngninx. Depois disso, o tráfego é claro internamente (ou seja, é http) para o gunicorn, a menos que você também tenha configuração SSL no gunicorn.

Então, sua configuração do nginx deve ter:

  • Um servidor upstream para gunicorn com ip 127.0.0.1 porta 8080 ou o que você quiser.
  • Uma diretiva do servidor ouvindo na porta 80 para http e 443 para https
  • uma diretiva de passagem de proxy no bloco de servidores para encaminhar para o upstream

minha configuração do proxy nginx para SSL é algo assim:

upstream website    {
    ip_hash;                        # for sticky sessions, more below
    server                          website:8000 max_fails=1 fail_timeout=10s;
}

server {
    # only listen to https here
    listen                          443 ssl http2;
    listen                          [::]:443 ssl http2;
    server_name                     yourdomain.here.com;

    access_log                      /var/log/nginx/yourdomain.here.com.access.log;
    error_log                       /var/log/nginx/yourdomain.here.com.error.log;
    ssl                             on;
    ssl_certificate                 /etc/nginx/certs/ca-cert.chained.crt;
    ssl_certificate_key             /etc/nginx/certs/cert.key;
    ssl_session_cache               shared:SSL:5m;
    ssl_session_timeout             10m;
    ssl_protocols                   TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers       on;
    #ssl_dhparam                     /etc/nginx/certs/dhparams.pem;
    # use the line above if you generated a dhparams file 
    ssl_ciphers                     'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_buffer_size                 8k;

    location / {
        proxy_pass                  http://website;
        proxy_set_header            Host $host;
        proxy_set_header            X-Real-IP $remote_addr;
        proxy_http_version          1.1;

        proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header            X-Forwarded-Proto http;
        proxy_redirect              http:// $scheme://;
    }
}

# redirect http to https here
server {
    listen                          80;
    listen                          [::]:80;
    server_name                     yourdomain.here.com;
    return                          301 https://$server_name/;
}
    
por 02.01.2016 / 22:55
3

Tente isto:

upstream app_server {
    server 127.0.0.1:8000 fail_timeout=0;
}

server {
    # port to listen on. Can also be set to an IP:PORT
    listen 80;
    listen 443 ssl;

    ssl_certificate /etc/ssl/pyhub_crt.crt;
    ssl_certificate_key /etc/ssl/pyhub.key;

    server_name www.pyhub.co;
    server_name_in_redirect off;

    access_log /opt/bitnami/nginx/logs/access.log;
    error_log /opt/bitnami/nginx/logs/error.log;

    location /E0130777F7D5B855A4C5DEB138808515.txt {
        root /home/bitnami;
    }

    location / {
        try_files @proxy_to_app;
    }

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

        proxy_pass http://app_server;

        proxy_pass_header Server;
        proxy_set_header Host $host;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header X-SSL-Protocol $ssl_protocol;
    }
}

Observe que isso terminará (corretamente) o SSL em nginx em vez de gunicorn . Você também digitou incorretamente Protocal in X-SSL-Protocal ; corrigido no meu exemplo:)

Consulte aqui para obter informações canônicas sobre a implantação de gunicorn com nginx .

    
por 02.01.2016 / 10:31
2

Eu deveria ter postado essa resposta há muito tempo, já que meu site já está funcionando há algum tempo. Mas aqui está como eu configurei minha configuração.

Depois de brincar muito com a configuração do Nginx, fiquei muito frustrada e desisti. Então, eu deletei esse servidor, fiz um novo, com novas instalações de tudo, e clonei o código fonte do meu site a partir do repositório que o hospeda. Depois de fazer isso, usei essa configuração do Nginx para funcionar:

  upstream djangosite {
    server 127.0.0.1:8000 fail_timeout=2s;
  }
  server {
    # port to listen on. Can also be set to an IP:PORT
    listen 443 ssl;
    server_name pyhub.co;
    ssl_certificate /etc/ssl/pyhub.crt;
    ssl_certificate_key /etc/ssl/pyhub.key;
    location / {
      proxy_pass http://djangosite;
    }
  server {
    listen 80;
    server_name pyhub.co;
    return 301 https://$server_name$request_uri;
  }

Até hoje eu ainda não sei o que estava me causando problemas com a minha configuração, ou porque eu tive que pegar outro servidor com uma instalação completamente nova, mas estou feliz que funcione. Eu selecionaria uma das duas excelentes respostas já fornecidas, mas nenhuma delas me deu a solução, e eu não quero escolher a minha, porque eu acredito que é muito específico de um problema que eu tive e selecionar essa resposta pode não será capaz de ajudar muitas pessoas no futuro.

    
por 26.01.2016 / 13:23