Running 2 Gunicorn Apps and Nginx with Supervisord

2020-07-24 04:04发布

问题:

This problem has admittedly stumped me for months. I've just procrastinated fixing other bugs and putting this aside until now where it HAS to be fixed --

I am trying to run 2 separate gunicorn apps and start nginx within the same supervisord.conf file. When I start supervisor, I am able to successfully run the handlecalls app but when I go to the website that commentbox is responsible for loading, I get an internal service error (500).

When I run the handlecalls and commentbox apps separately with the commands following the command field, the apps run fine. Why is the commentbox program giving me a 500 error when I try to run both with supervisord?

my supervisord script:

[program:nginx]
directory = /var/www/vmail
command = service nginx start -g "daemon off;"
autostart = True

[program:commentbox]
directory = /var/www/vmail
command = gunicorn app:app -bind 0.0.0.0:8000
autostart = True

[program:handlecalls]
directory = /var/www/vmail
command = gunicorn handle_calls:app --bind 0.0.0.0:8000
autostart = True

[supervisord]
directory = /var/www/vmail
logfile = /var/www/vmail/supervisorerrs.log
loglevel = trace

回答1:

This has nothing to do with supervisord. Supervisord is just a way for you to start/stop/restart your server. This has more to do with your server's configuration.

The basic: To serve two gunicorn apps with nginx, you have to run them on two different ports, then config nginx to proxy_pass the request to their respective ports. The reson is: once a process is running on a port, that port cannot be used by another process.

So change the configuration in your supervisord script to:

[program:commentbox]
directory = /var/www/vmail
command = gunicorn app:app --bind 0.0.0.0:8000
autostart = True

[program:handlecalls]
directory = /var/www/vmail
command = gunicorn handle_calls:app --bind 0.0.0.0:8001
autostart = True

Then in your nginx server's configuration for handlecalls

proxy_pass 127.0.0.1:8081

Update: Here is the basics of deploying a web application

  1. As mentioned above, one port can only be listened by a process.
  2. You can use nginx as a http server, listening to port 80 (or 443 for https), then passing the request to other applications listening to other ports (for example, commentbox on port 8000 and handlecalls on port 8001)
  3. You can add rules to nginx as how to serve your application by adding certain server configuration files in /etc/nginx/sites-available/ (by default. It is different in some cases). The rules should specify a way for nginx to know which application it should send the request to, for example:

    • To reuse the same http port (80), each application should be assigned to a different domain. i.e: commentbox.yourdomain.com for commentbox and handlecalls.yourdomain.com for handlecalls
    • A way to serve two different apps on the same domain, is for them to serve on different ports. For example: yourdomain.com would serve commentbox and yourdomain.com:8080 would serve handlecalls
    • A way to serve two different apps on the same domain and the same ports, is for them to serve on two different endpoints. For example yourdomain.com/commentbox would serve commentbox and yourdomain.com/handlecalls would serve handlecalls
  4. After adding configuration files to /etc/nginx/sites-available/, you must symlink those files to /etc/nginx/sites-enabled/, well, to tell nginx that you want to enable them. You can add the files directly to /etc/nginx/sites-enabled/, but I don't recommend it, since it doesn't give you a convenient way to enable/disable your application.

Update: Here is how to config nginx to serve gunicorn applications using two different subdomains:

  1. Add two subdomains commentbox.yourdomain.com and handlecalls.yourdomain.com, and point them both to your server's IP.
  2. Create a a configuration file for commentbox at /etc/nginx/sites-available/commentbox with the following content (edit as fit):

    server {
        listen 80; 
    
        server_name           commentbox.yourdomain.com;
    
        root                  /path/to/your/application/static/folder;    
        location / {
            try_files         $uri @app;
        }
    
        location @app {
            proxy_set_header   Host $http_host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    
            proxy_redirect     off;
            proxy_pass         http://127.0.0.1:8000;
        }
    }
    
  3. Create a configuration file for handlecalls at /etc/nginx/sites-available/handlecalls with the following content (edit as fit):

    server {
        listen 80; 
    
        server_name           handlecalls.yourdomain.com;
    
        root                  /path/to/your/application/static/folder;    
        location / {
            try_files         $uri @app;
        }
    
        location @app {
            proxy_set_header   Host $http_host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    
            proxy_redirect     off;
            proxy_pass         http://127.0.0.1:8001;
        }
    }
    
  4. Create symlinks to enable those servers:

    sudo ln -s /etc/nginx/sites-available/commentbox /etc/nginx/sites-enabled/
    sudo ln -s /etc/nginx/sites-available/handlecalls /etc/nginx/sites-enabled/
    
  5. Restart nginx to take effect

    sudo service nginx restart