Can I run two server applications on port 80?

I am currently running nginx on port 80, with the configured server names as example.com and www.example.com.

I also have a Flask application that I would like to have accessible through port 80, but using the hostname app.example.com.

Since nginx is already using port 80, how exactly would I route app.example.com requests to Flask application?

Note that the server only has one IPv4 address.


Solution 1:

Should be fairly easy.

Make sure that Flask itself is running on a port other than 80.

Then use NginX as a reverse proxy (and webserver) to handle, a subdomain for app.example.com, and secondly handle that as a proxy for localhost:8080 (or wherever your flask application is bound).

upstream flask  {
      server 127.0.0.1:8080; #Flask
}

server {
    listen       YOUR_PUBLIC_IP:80;
    server_name  app.example.com;

location / {
     proxy_pass  http://flask;
     proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
     proxy_redirect off;
     proxy_buffering off;
     proxy_set_header        Host            $host;
     proxy_set_header        X-Real-IP       $remote_addr;
     proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
   }

}

You can have many server{} blocks, all on port 80, as long as server_name varies, and use them just like Apache VirtualHosts.

Solution 2:

It's not a good idea to directly serve the application on port 80. It's much better to have a standard HTTP server listening on port 80 and forwarding requests to your Python (Flask) application's WSGI server.

You should configure nginx to send all requests for app.example.com to your WSGI (Python Application Server). This way the requests for http://example.com:80 will be served directly by nginx and all requests for the virtual host app.example.com:80 will be forwarded to your Python Application server. Depending on your preference you can run your Python/Flask application using either uWSGI or gunicorn.

To configure app.example.com as a virtual host you will need to create a file (eg. /etc/nginx/sites-available/app.example.com if you're using a Debian based distro) that will contain something like this:

server { 
  server_name app.example.com; 
  access_log /var/log/nginx/app-access.log; 
  error_log /var/log/nginx/app-error.log; 
  location /static { 
    root /var/www/app.example.com/static; # adjust to fit your path here 
  } 
  location / { 
    uwsgi_pass unix:/tmp/uwsgi_app.sock; 
    include /etc/nginx/conf.d/uwsgi_params; 
  } 
}

The content of the location / section need to be adjusted, depending on the specific WSGI server you choose to use - see bellow.

Then you need to symlink the new virtual host config to sites-enabled and restart nginx:

ln -sf /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
/etc/init.d/nginx restart

See this document for more information about configuring nginx to serve multiple sites (virtual hosts) on the same IP address and TCP port.

Here are two blog entries describing how to configure nginx with uWSGI: Deploying Flask With Nginx and uWSGI Setting up Flask with nginx and uWSGI. If you prefer gunicorn (a Python WSGI port of Ruby's unicorn Application server) you can check this SO question: Running a Flask App with nginx and gunicorn and Serving Flask Applications with Nginx and gunicorn