HOWTO - Install Nginx + uWSGI + Django

来源:互联网 发布:全国道路矢量数据 编辑:程序博客网 时间:2024/05/16 14:14

The basics are almost identical with the uWSGI official document. Here I would like to note a few important points when setting up Nginx + uWSGI + Django on CentOS 7.

Concept

A web server faces the outside world. It can serve files (HTML, images, CSS, etc) directly from the file system. However, it can’t talk directly to Django applications; it needs something that will run the application, feed it requests from web clients (such as browsers) and return responses.

A Web Server Gateway Interface - WSGI - does this job. WSGI is a Python standard.

uWSGI is a WSGI implementation. In this tutorial we will set up uWSGI so that it creates a Unix socket, and serves responses to the web server via the WSGI protocol. At the end, our complete stack of components will look like this:

the web client <-> the web server <-> the socket <-> uwsgi <-> Django

Before you start setting up uWSGI

Create a user web dedicated for running uwsgi and Django

As root:

useradd web

virtualenv

As user web, make sure you are in your home directory

cd ~

Make sure you are in a virtualenv for the software we need to install (we will describe how to install a system-wide uwsgi later):

virtualenv uwsgi-tutorialcd uwsgi-tutorial

Django

As user web, install Django into your virtualenv, create a new project, and cd into the project:

pip install Djangodjango-admin.py startproject mysitecd mysite

Basic uWSGI installation and configuration

Install uWSGI into your virtualenv

pip needs to compile some sources to install uwsgi, so you need development tools (gcc, make, …), libxml2 header and python headers.

As root:

yum groupinstall "Development Tools"yum install python2.7-devel libxml2-devel

As user web, install uWSGI into your virtualenv

pip install uwsgi

Basic test

Create a file called test.py:

# test.pydef application(env, start_response):    start_response('200 OK', [('Content-Type','text/html')])    # return [b"Hello World"] # python3    return ["Hello World"] # python2

Run uWSGI:

uwsgi --http :8000 --wsgi-file test.py

This should serve a ‘hello world’ message directly to the browser on port 8000. Visit:

http://127.0.0.1:8000

to check. If so, it means the following stack of components works:

the web client <-> uWSGI <-> Python

Test your Django project

Now we want uWSGI to do the same thing, but to run a Django site instead of the test.py module.

If you haven’t already done so, make sure that your mysite project actually works:

python manage.py runserver 0.0.0.0:8000

And if it that works, run it using uWSGI (make sure your current working directory is /home/web/uwsgi-tutorial/mysite):

uwsgi --http :8000 --module mysite.wsgi

Point your browser at the server; if the site appears, it means uWSGI is able to serve your Django application from your virtualenv, and this stack operates correctly:

the web client <-> uWSGI <-> Django

Now normally we won’t have the browser speaking directly to uWSGI. That’s a job for the webserver, which will act as a go-between.

Basic nginx

Install nginx

You won’t find nginx in the official CentOS 7 repositories, but there is an official repository provided by the nginx-developers. Add the following file to your /etc/yum.repos.d/ directory:

As root

vim /etc/yum.repos.d/nginx.repo[nginx]name=nginx repobaseurl=http://nginx.org/packages/centos/7/$basearch/gpgcheck=0enabled=1

Then proceed with nginx installation and start the service

yum install nginxsystemctl start nginx

And now check that the nginx is serving by visiting it in a web browser on port 80 - you should get a message from nginx: “Welcome to nginx!”. That means these components of the full stack are working together:

the web client <-> the web server

Configure nginx for your site

You will need the uwsgi_params file, which is available in the /etc/nginx directory or https://github.com/nginx/nginx/blob/master/conf/uwsgi_params

Copy it into your project directory, which should be /home/web/uwsgi-tutorial/mysite/

Now create a file called mysite_nginx.conf in your project directory, and put this in it:

#mysite_nginx.conf# the upstream component nginx needs to connect toupstream django {    #server unix:///home/web/uwsgi-tutorial/mysite/mysite.sock; # for a file socket    server 127.0.0.1:8001; # for a web port socket (we'll use this first)}# configuration of the serverserver {    # the port your site will be served on    listen      8000;    # the domain name it will serve for    server_name 127.0.0.1; # substitute your machine's IP address or FQDN    charset     utf-8;    # max upload size    client_max_body_size 75M;   # adjust to taste    # Django media    location /media  {        alias /home/web/uwsgi-tutorial/mysite/media/;  # your Django project's media files - amend as required    }    location /static {        alias /home/web/uwsgi-tutorial/mysite/static/; # your Django project's static files - amend as required    }    # Finally, send all non-media requests to the Django server.    location / {        uwsgi_pass  django;        include     /home/web/uwsgi-tutorial/mysite/uwsgi_params; # the uwsgi_params file you installed    }}

IMPORTANT
Unlike Ubuntu distribution, the installed nginx doesn’t has /etc/ngix/sites-available (optional, because in the next step we won’t include this folder in nginx.conf) or /etc/nginx/sites-enabled created for you by default. So you need to manually create these two folders.
As root:

mkdir /etc/nginx/sites-availablemkdir /etc/nginx/sites-enabled

Then add the following into the bottom of http section of /etc/nginx/nginx.conf:

include /etc/nginx/sites-enabled/*.conf;

This tells nginx to check and load configuration in any file ended with .conf inside /etc/nginx/sites-enabled/


Then symlink to /home/web/uwsgi-tutorial/mysite/mysite_nginx.conf file from /etc/nginx/sites-enabled so nginx can see it:

ln -s /home/web/uwsgi-tutorial/mysite/mysite_nginx.conf /etc/nginx/sites-enabled/

IMPORTANT
Make sure you are using absolute path when doing the symbolic link. Otherwise, the linked file in /etc/nginx/sites-enabled will raise “Too many level of symbolic links” error.


Deploying static files

Before running nginx, you have to collect all Django static files in the static folder. First of all you have to edit mysite/settings.py adding:

STATIC_ROOT = os.path.join(BASE_DIR, "static/")

and then run

python manage.py collectstatic

IMPORTANT
From another online article, it suggests to remove the added STATIC_ROOT statement in mysite/settings.py once the collection is done, because otherwise the django project may experience problem.
In my current configuration, I followed the suggestion. But I will verify whether leaving the statement in the configuration will actually causing problem.


Basic nginx test

Restart nginx:

systemctl restart nginx

To check that media files are being served correctly, add an txt called media.txt to the /home/web/uwsgi-tutorial/mysite/media directory, then visit http://127.0.0.1:8000/media/media.txt- if this works, you’ll know at least that nginx is serving files correctly.

It is worth not just restarting nginx, but actually stopping and then starting it again, which will inform you if there is a problem, and where it is.

nginx and uWSGI and test.py

Let’s get nginx to speak to the “hello world” test.py application.

uwsgi --socket :8001 --wsgi-file test.py

This is nearly the same as before, except this time one of the options is different:

socket :8001: use protocol uwsgi, port 8001

nginx meanwhile has been configured to communicate with uWSGI on that port, and with the outside world on port 8000. Visit: http://example.com:8000/

to check. And this is our stack:

the web client <-> the web server <-> the socket <-> uWSGI <-> Python

Using Unix sockets instead of ports

So far we have used a TCP port socket, because it’s simpler, but in fact it’s better to use Unix sockets than ports - there’s less overhead.

Edit mysite_nginx.conf, changing it to match:

server unix:///home/web/uwsgi-tutorial/mysite/mysite.sock; # for a file socket# server 127.0.0.1:8001; # for a web port socket (we'll use this first)

and restart nginx.

Run uWSGI again:

uwsgi --socket mysite.sock --wsgi-file test.py

This time the socket option tells uWSGI which file to use.

Try http://example.com:8000/ in the browser.

If that doesn’t work

Check your nginx error log(/var/log/nginx/error.log). If you see something like:

connect() to unix:///path/to/your/mysite/mysite.sock failed (13: Permission denied)

then probably you need to manage the permissions on the socket so that nginx is allowed to use it.

Try:

uwsgi --socket mysite.sock --wsgi-file test.py --chmod-socket=666 # (very permissive)

or:

uwsgi --socket mysite.sock --wsgi-file test.py --chmod-socket=664 # (more sensible)

You may also have to add your user to nginx’s group, or vice-versa, so that nginx can read and write to your socket properly.

It’s worth keeping the output of the nginx log running in a terminal window so you can easily refer to it while troubleshooting.

Running the Django application with uwsgi and nginx

Let’s run our Django application:

uwsgi --socket mysite.sock --module mysite.wsgi --chmod-socket=666

Now uWSGI and nginx should be serving up not just a “Hello World” module, but your Django project.


IMPORTANT
I’m having problem running uwsgi with --chmod-socket=664. It will still generate Permission denied error. I will verify whether adding nginx to web group can solve this.


Configuring uWSGI to run with a .ini file

We can put the same options that we used with uWSGI into a file, and then ask uWSGI to run with that file. It makes it easier to manage configurations.

Create a file called /home/web/uwsgi-tutorial/mysite/mysite_uwsgi.ini:

# mysite_uwsgi.ini file[uwsgi]# Django-related settings# the base directory (full path)chdir           = /home/web/uwsgi-tutorial/mysite# Django's wsgi filemodule          = mysite.wsgi# the virtualenv (full path)home            = /home/web/uwsgi-tutorial# process-related settings# mastermaster          = true# maximum number of worker processesprocesses       = 10# the socket (use the full path to be safesocket          = /home/web/uwsgi-tutorial/mysite/mysite.sock# ... with appropriate permissions - may be neededchmod-socket    = 666# clear environment on exitvacuum          = true

And run uswgi using this file:

uwsgi --ini mysite_uwsgi.ini # the --ini option is used to specify a file

Once again, test that the Django site works as expected.

Emperor mode

uWSGI can run in ‘emperor’ mode. In this mode it keeps an eye on a directory of uWSGI config files, and will spawn instances (‘vassals’) for each one it finds.

Whenever a config file is amended, the emperor will automatically restart the vassal.

# create a directory for the vassalsmkdir /etc/uwsgimkdir /etc/uwsgi/vassals# symlink from the default config directory to your config fileln -s /home/web/uwsgi-tutorial/mysite/mysite_uwsgi.ini /etc/uwsgi/vassals/# run the emperoruwsgi --emperor /etc/uwsgi/vassals --uid web --gid web

You may need to run uWSGI with root privilege:

sudo uwsgi --emperor /etc/uwsgi/vassals --uid web --gid web

The options mean:

emperor: where to look for vassals (config files)uid: the user id of the process once it’s startedgid: the group id of the process once it’s started

Check the site; it should be running.

Make uWSGI startup when the system boots using systemd

The configuration below use systemd configuration from uWSI official doc as a guide.

Creating emperor.ini

Creating the file /etc/uwsgi/emperor.ini with the content:

[uwsgi]emperor = /etc/uwsgi/vassalsuid = webgid = web

NOTE: DO NOT daemonize the Emperor (or the master) unless you know what you are doing!!!

If you want to allow each vassal to run under different privileges, remove the uid and gid options from the emperor configuration (and please read the Emperor docs!)

Adding the Emperor to systemd

The best approach to integrate uWSGI apps with your init system is using the Emperor.

Your init system will talk only with the Emperor that will rule all of the apps itself.

Create a systemd service file (you can save it as /etc/systemd/system/emperor.uwsgi.service)

[Unit]Description=uWSGI EmperorAfter=syslog.target[Service]ExecStart=/home/web/uwsgi-tutorial/bin/uwsgi --ini /etc/uwsgi/emperor.iniRestart=alwaysKillSignal=SIGQUITType=notifyStandardError=syslogNotifyAccess=all[Install]WantedBy=multi-user.target

Then run it

systemctl start emperor.uwsgi.service

And check its status.

systemctl status emperor.uwsgi.service

You can stop the Emperor (and all the apps it governs) with

systemctl stop emperor.uwsgi.service

To make the Emperor start automatically after the server reboots

systemctl enable emperor.uwsgi.service

Further work

  1. Ensure ngnix has proper r-x rights on necessary directories, otherwise it will not able to serve the file in /home/web/uwsgi-tutorial/mysite
  2. Currently I’m using absolute path in mysite_nginx.conf. I need to check whether relevant path can also work.
0 0
原创粉丝点击