Flask+nginx+uwsgi+Ubuntu tutorial

May 3, 2017 2.4k views
Nginx Ubuntu 16.04

My hopes are lost and so is my temper. I have followed the tutorial found here -
https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-uwsgi-and-nginx-on-ubuntu-16-04

I have reinstalled and started all over 10 times and still same PROBLEM. Is there another tutorial available because this only works to 80%.
All works fine up to a certain point but I always get a 502 gateway problem.

I created a new user belonging to sudo group.
Ssh:ed to server with this new user – all good.
Set up domain also and if I ping domainname.com the correct droplet ip gives reply – all good.

python myproject.py (to start flask) works perfect

uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app

Works perfect and site is accessible with IP http://server_IP:5000

Content of wsgi.py-

from myproject import app

if name == "_main":
app.run()

Content of myproject.ini looks like -

[uwsgi]

module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

die-on-term = true

Content of /etc/systemd/system/myproject.service:

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User = blizzard
Group = www-data
WorkingDirectory = /home/blizzard/myproject
Environment = "PATH=/home/blizzard/myproject/myprojectenv/bin" #IS THIS LINE WRONG??
ExecStart=/home/blizzard/myprojectenv/bin/uwsgi --ini myproject.ini

[Install]
WantedBy = multi-user.target

Content of /etc/nginx/available-sites/myproject

server {
listen 80;
server_name billigaflygtilllondon.com www.billigaflygtilllondon.com;

    location / {
    include uwsgi_params;
    uwsgi_pass unix:///home/blizzard/myproject/myproject.sock;
    }

}

If this tutorial is wrong why dont staff delete it or at least the author updates it since I am not the ONLY ONE having problems. If there is a helpful soul who could guide me I would be more than happy.

2 comments
  • Could it be a permission error since www-data has no permission inside homefolder ?
    Could this be the problem?

    Or is it a domain issue?

    Anyone ?

  • Think I have found the problem, or at least one of them.
    Did sudo systemctl status myproject.service
    And it returned FAILED....and now to the $10000000 question why?

    
    root@ubuntu-512mb-ams3-01-PYTHON:~/myproject/myprojectenv/bin# sudo systemctl status myproject.service
    ● myproject.service - uWSGI instance to serve myproject
       Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled)
       Active: failed (Result: exit-code) since Wed 2017-05-03 19:34:43 UTC; 5min ago
      Process: 8831 ExecStart=/home/root/myproject/myprojectenv/bin/uwsgi --ini myproject.ini (code=exited, status=200/CHDIR)
     Main PID: 8831 (code=exited, status=200/CHDIR)
    
    May 03 19:34:43 ubuntu-512mb-ams3-01-PYTHON systemd[1]: Started uWSGI instance to serve myproject.
    May 03 19:34:43 ubuntu-512mb-ams3-01-PYTHON systemd[1]: myproject.service: Main process exited, code=exited, status=200/CHDIR
    May 03 19:34:43 ubuntu-512mb-ams3-01-PYTHON systemd[1]: myproject.service: Unit entered failed state.
    May 03 19:34:43 ubuntu-512mb-ams3-01-PYTHON systemd[1]: myproject.service: Failed with result 'exit-code'.
    
    
4 Answers
jtittle1 May 3, 2017
Accepted Answer

@broodforge

Here's what I did, step-by-step, on a test Droplet with Ubuntu 16.04 64bit.

Update, Upgrade, Install

apt-get update \
&& apt-get -y dist-upgrade \
&& apt-get -y install python3-pip python3-dev nginx \
&& pip3 install virtualenv

Create New User + Directories

mkdir -p /home/sammy/myproject \
&& useradd -d /home/sammy sammy

Setup VirtualEnv

cd /home/sammy/myproject \
&& virtualenv myprojectenv

Source Env File

source /home/sammy/myproject/myprojectenv/bin/activate

Install Flask and UWSGI

pip install uwsgi flask

Create Project File

nano /home/sammy/myproject/myproject.py

Within it, I pasted:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:blue'>Hello There!</h1>"

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

Testing myproject.py

python myproject.py

I see the Hello There as I should, so let's move on...

Create the WSGI Entry Point

nano /home/sammy/myproject/wsgi.py

Within it, I pasted:

from myproject import app

if __name__ == "__main__":
    app.run()

Testing UWSGI

uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app

I see the Hello Three as I should, so let's move on.

Deactivate

deactivate

Creating a uWSGI Configuration File

nano /home/sammy/myproject/myproject.ini

Within it, I pasted:

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

die-on-term = true

Creating systemd Service File

nano /etc/systemd/system/myproject.service

Within it, I pasted:

[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

[Install]
WantedBy=multi-user.target

Setting Proper Permissions

Add sammy to www-data group:

usermod -aG www-data sammy
chown -R sammy:www-data /home/sammy/*

Starting and Enabling the Service

systemctl start myproject
systemctl enable myproject

Setting Up NGINX

nano /etc/nginx/sites-available/myproject

Within it, I pasted:

server {
    listen 80;
    server_name MY_DROPLET_IP;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:///home/sammy/myproject/myproject.sock;
    }
}

Created a symlink using:

ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

Restart NGINX:

systemctl restart nginx

...

For this particular setup, passing --uid and --gid isn't required and systemctl does handle the user and group permissions correctly.

  • And guess what - it works!!!!!!!!!!!!!!!!!!!! =)
    Why? I honestly dont know since I used everything almost the same. I did the setup with a new user with sudo rights and I did not dist-upgrade. Maybe this was causing it?
    Words can not explain how grateful I am and may your soul be blessed.
    THANK YOU!

    • @broodforge

      The update and dist-upgrade are something I do on every system and wouldn't alter the status of a script. That's just a part of updating the OS, Repositories, and Packages.

      The NGINX package that you install with apt-get -y install nginx uses www-data as the user which runs NGINX and in order to read/write to the socket, NGINX needs access to that file.

      If you use blizzard:blizzard or even sammy:sammy as the user:group, NGINX has no way of read/writing to the socket.

      To fix that, we add sammy, or in your case, blizzard, to the www-data group using:

      usermod -aG www-data sammy
      

      or

      usermod -aG www-data blizzard
      

      Followed by chown'ing the files and directories accordingly. Now, and only now, does NGINX have the permission to read/write to the socket as required.

      This differs from most setups, such as PHP-FPM, which uses fastcgi_pass as the user and the group need to be the user and group running the PHP process, not the user that NGINX is running as.

      So one slight difference, but that's enough to cause things not to work as expected :-).

      Glad I could help :-).

      • You have done more then just helped! You saved my laptop of being smashed to the floor and my marriage with wife =)

        One question that aroused from all this is what if I am planning to run several differendt server blocks? Then I have to do almost the same procedure again?
        Since myproject.sock and service is just for this host?
        Correct?

        • @broodforge

          Correct.

          You would need to repeat the above steps for each site, and change the main user each time -- as well as the paths.

          So in place of sammy or blizzard, you could use xuser, yuser, zuser (not those users exactly, of course -- just examples).

          So you'll basically run through the entire process each time and make changes as and where needed so that everything points to the new location of the new site.

          • Hello friend,
            Hmmm....are you sure? Why cant user blizzard have one folder for each project?
            And each folder(project) will have its own service started and sockets?

          • I have now pushed my way through the wall, a thick wall. Everything on this side is much better. =) Thank you again - a true friend and hero.
            I created new .service file for each user with a unique name, eg domain-name.service and everything looks OK. I have four domains up and running.
            Be blessed!

          • @broodforge

            Awesome :-). Glad I could help you with the setup!

@broodforge

One issue I've ran in to when responding to other questions dealing with the same overall issue here within the community is that the service file for systemd doesn't always seem to use the user/group that you define.

To work around that, you can try passing --uid and --gid through to ExecStart, which would look something like:

ExecStart=/home/blizzard/myprojectenv/bin/uwsgi --ini myproject.ini --uid blizzard --gid www-data

Changes to service files require a reload, so you may need to run:

systemctl daemon-reload

... after the above changes are made.

You will definitely need to make sure permissions are correct though. Neither your user or the user www-data can execute files owned by root or other users, so you'll want to make sure that the user and group are setup properly. If blizzard isn't a member of www-data, you'd need to add them if that is the group you wish to use.

Alternatively, you could just chown to your user only unless you need www-data.

i.e.

chown -R blizzard:blizzard /path

or

chown -R blizzard:www-data /path
  • Thank you for taking your time to help, wish the tutorial would be more correct in detail. Will now try again from the beginning with a new droplet. Will get back with progress. Cross my fingers and you gave me hope.
    If this does not work I am shutting everything down.
    God bless you!

  • And I get the same freaking 502 bad gateway.

    sudo systemctl status myapp.service
    
    
    myapp.service - uWSGI instance to serve myproject
       Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)
       Active: failed (Result: exit-code) since Wed 2017-05-03 20:42:37 UTC; 22min ago
     Main PID: 17909 (code=exited, status=1/FAILURE)
    
    
    -rw-rw-r-- 1 blizzard www-data  129 May  3 20:38 myapp.ini
    -rw-rw-r-- 1 blizzard www-data  186 May  3 20:32 myapp.py
    drwxrwxr-x 5 blizzard www-data 4096 May  3 20:29 myprojectenv
    drwxrwxr-x 2 blizzard www-data 4096 May  3 20:36 __pycache__
    -rw-rw-r-- 1 blizzard www-data   64 May  3 20:35 wsgi.py
    
    
    
    [uwsgi]
    module = wsgi:app
    
    master = true
    processes = 5
    
    socket = myapp.sock
    chmod-socket = 660
    vacuum = true
    
    die-on-term = true
    
    

    myapp.ini

    server {
        listen 80;
        server_name 178.62.255.33;
    
        location / {
            include uwsgi_params;
            uwsgi_pass unix:///home/blizzard/myproject/myapp.sock;
        }
    }
    

    /etc/systemd/system/myapp.service

    [Unit]
    Description=uWSGI instance to serve myproject
    After=network.target
    
    [Service]
    User=blizzard
    Group=www-data
    WorkingDirectory=/home/blizzard/myproject
    Environment="PATH=/home/blizzard/myproject/myprojectenv/bin"
    ExecStart=/home/blizzard/myproject/myprojectenv/bin/uwsgi --ini myapp.ini --uid blizzard --gid www-data
    
    [Install]
    WantedBy=multi-user.target
    
    

Hi @broodforge

There is a very big possibility that it's the Flask application that is crashing, which is why Nginx is returning 502, since it has nothing to connect to.

You need to enable logging in your application to see what is going on:

ExecStart=/home/blizzard/myproject/myprojectenv/bin/uwsgi --ini myapp.ini --uid blizzard --gid www-data --logto /home/blizzard/myproject/error.log

Otherwise you can enable debug logging if you don't see enough in the logs:
http://stackoverflow.com/questions/32722143/flask-application-traceback-doesnt-show-up-in-server-log

@broodforge

Starting a new reply as the other was at its max.

You could very well use the same user and group, though from a security standpoint, it's not the best method. Ideally, each project should run as an individual user (that isn't root or a sudo user).

  • Lets max out completely! Thanks for breaking the thick wall for me! Now I am hitting a new one but I think I solved to break this other one. For anyone reading this thread is that every change made to the app, in this case myproject.py you need to restart the service systemctl restart myservice for the changes to be viewable in browsers.

    Cheers

Have another answer? Share your knowledge.