Hoppo
Hoppo

Reputation: 1160

How to host multiple flask apps under a single domain hosted on nginx?

What I am trying to achieve:

I have an nginx web server hosting mydomain.com. When someone types my domain.com into their client I would like my server to serve index.html from /var/www/mydomain/ When they type mydomain.com/flaskapp1 they should see flaskapp1. When they type mydomain.com/flaskapp2 they should see flaskapp2.

I have managed to get one or the other flask apps served using the tutorial here http://www.markjberger.com/flask-with-virtualenv-uwsgi-nginx/ but when trying to implement serving two separate flask apps I run into difficulty. Instead of seeing the flask app I get a 404 message when I try to access either of the flask apps with mydomain.co.uk/flaskapp or mydomain.co.uk/flaskapp2 in a browser.

This is what I have so far:

cat /etc/nginx/sites-available/mydomain.co.uk

server {
       listen 80;

        server_name www.mydomain.co.uk mydomain.co.uk;

        location / {
               root /var/www/html/;
               index index.html index.htm;
        }

        location /flaskapp {
                include uwsgi_params;
                uwsgi_pass unix:/tmp/flaskapp.sock;
        }

         location /flaskapp2 {
              include uwsgi_params;
              uwsgi_pass unix:/tmp/flaskapp2.sock;
         }
 }

The above conf file has been sim linked into /etc/nginx/sites-enabled.

cat /etc/uwsgi/apps-available/flaskapp.ini

[uwsgi]
vhost = true
socket = /tmp/flaskapp.sock
venv = /var/www/flaskapp/venv
chdir = /var/www/flaskapp
module = flaskapp
callable = app

cat /etc/uwsgi/apps-available/flaskapp2.ini

[uwsgi]
vhost = true
socket = /tmp/flaskapp2.sock
venv = /var/www/flaskapp2/venv
chdir = /var/www/flaskapp2
module = flaskapp2
callable = app

Both .ini files have been symlinked into /etc/uwsgi/apps-enabled. UWSGI restarts fine without any issues and is up and running. Both flaskapp.sock and flaskapp2.sock are owned by www-data

cat /var/www/flaskapp/flaskapp.py

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World from flaskapp1!'

if __name__ == '__main__':
    app.run(host='0.0.0.0')

cat /var/www/flaskapp2/flaskapp2.py

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World from flaskapp2!'

if __name__ == '__main__':
    app.run(host='0.0.0.0')

cat /var/www/mydomain.co.uk/index.html

<!DOCTYPE html>
<html>
<body>

<h1>mydomain.co.uk</h1>

<p>This is the index page of my domain.co.uk</p>

</body>
</html>

Both virtual environments have flask installed and will run the flask apps using the development server.

I hope it's something simple that I've missed.

Upvotes: 20

Views: 17827

Answers (3)

DPalharini
DPalharini

Reputation: 513

Adding the mounting point worked for me.

/etc/uwsgi/apps-available/flaskapp.ini

callable = app
mount = /flaskapp=/var/www/flaskapp

/etc/uwsgi/apps-available/flaskapp2.ini

callable = app
mount = /flaskapp2=/var/www/flaskapp2

Source https://neginfinity.bitbucket.io/2017/09/hosting-multiple-flask-applications-in-nginx.html

Upvotes: 2

GwynBleidD
GwynBleidD

Reputation: 20539

The problem is here: both flask apps have no idea that they were served from subdirectory in your domain. Nginx is passing full URL to them, not URL relative to that directory, so every URL is dispatched relative to root. Let's see that in example:

Assume that you have 3 views in your flaskapp, served on urls /one/, /two/ and /three/. So when you're trying to access view on URL /one/, you are typing address: http://yourdomain.com/flaskapp/one/. Flask will receive from nginx URL /flaskapp/one/ but there is no such view in that app, so it will send 404 in response.

What you can do is inform each flaskapp that they aren't served on domain root, but on particular subdirectory. You can achieve this by sending SCRIPT_NAME uwsgi_param with subdirectory location in value, so your nginx config will have:

location /flaskapp {
    include uwsgi_params;
    uwsgi_pass unix:/tmp/flaskapp.sock;
    uwsgi_param SCRIPT_NAME /flaskapp;
}

location /flaskapp2 {
    include uwsgi_params;
    uwsgi_pass unix:/tmp/flaskapp2.sock;
    uwsgi_param SCRIPT_NAME /flaskapp2;
}

Upvotes: 7

Hoppo
Hoppo

Reputation: 1160

Looking at the uwsgi documentation for NGINX here.

Specifically:

Unfortunately nginx is not able to rewrite PATH_INFO accordingly to SCRIPT_NAME. For such reason you need to instruct uWSGI to map specific apps in the so called “mountpoint” and rewrite SCRIPT_NAME and PATH_INFO automatically:

Changing my flaskapp.ini and flaskapp2.ini files to contain the mount points for the apps and turning on the manage-script-name variable has worked.

cat /etc/uwsgi/apps-available/flaskapp.ini

[uwsgi]
vhost = true
socket = /tmp/flaskapp.sock
venv = /var/www/flaskapp/venv
chdir = /var/www/flaskapp
module = flaskapp
callable = app
mount = /flaskapp=flaskapp.py
manage-script-name = true

cat /etc/uwsgi/apps-available/flaskapp2.ini

[uwsgi]
vhost = true
socket = /tmp/flaskapp2.sock
venv = /var/www/flaskapp2/venv
chdir = /var/www/flaskapp2
module = flaskapp2
callable = app
mount = /flaskapp2=flaskapp2.py
manage-script-name = true

And now both flask apps are running via uwsgi through nginx as required.

Upvotes: 13

Related Questions