cundi / blog

push issues as a blog
2 stars 0 forks source link

如何在Ubuntu 14.04上使用uWSGI和Ngnix伺服Django应用[翻译] #38

Open cundi opened 8 years ago

cundi commented 8 years ago

原始链接:https://www.digitalocean.com/community/tutorials/how-to-serve-django-applications-with-uwsgi-and-nginx-on-ubuntu-14-04

How To Serve Django Applications with uWSGI and Nginx on Ubuntu 14.04

Introduction 简介

Django is a powerful web framework that can help you get your Python application or website off the ground. Django includes a simplified development server for testing your code locally, but for anything even slightly production related, a more secure and powerful web server is required.

Django是一个能够过帮助你从零开始构建Python应用或者网站。Django包含了一个可以测试本地代码的简单开发服务器,不过对于稍微和生产环境沾边的事情来说,这就要求使用更安全、更强大的web服务器了。

In this guide, we will demonstrate how to install and configure some components on Ubuntu 14.04 to support and serve Django applications. We will configure the uWSGI application container server to interface with our applications. We will then set up Nginx to reverse proxy to uWSGI, giving us access to its security and performance features to serve our apps.

本指南将说明如何在Ubuntu14.04上安装和配置一些组建,以支持并对Django应用提供伺服。我们将配置uWSGI应用容器服务器与我们的Django应用进行对接。然后,我们设置Nginx来对uWSGI进行反向代理,以此,让我们使用Nginx的安全和性能上的特性来为应用服务。

Prerequisites and Goals 前置知识和目标

In order to complete this guide, you should have a fresh Ubuntu 14.04 server instance with a non-root user with sudo privileges configured. You can learn how to set this up by running through our initial server setup guide.

为了读完本指南,您应该拥有一台新的Ubuntu 14.04服务器,以及一个非root的,启用了sudo权限的用户。您可以学习如何通过我们的初始化设置指南来进行服务器的设置。(译注:这里是指DigitalOcean的VPS设置指南)

We will be installing Django within two different virtual environments. This will allow your projects and their requirements to be handled separately. We will be creating two sample projects so that we can run through the steps in a multi-project environment.

我们将在两个不同的虚拟环境内安装Django。这样您就可以单独地来处理项目以及项目所需的依赖包。我们将创建两个简单的项目,以此在多项目环境中执行这些步骤。

Once we have our applications, we will install and configure the uWSGI application server. This will serve as an interface to our applications which will translate client requests using HTTP to Python calls that our application can process. We will then set up Nginx in front of uWSGI to take advantage of its high performance connection handling mechanisms and its easy-to-implement security features.

只要创建了应用,我们就可以安装、配置uWSGI应用服务器了。这个应用服务器作为一个应用提供服务的接口,它使用HTTP将客户端的请求传递到应用能够处理Python调用。然后,我们在uWSGI之前设置Nginx以获得Nginx的高性能连接处理机制和易于实现的安全功能带来的好处。

Let's get started.

现在,我们开干吧!

Install and Configure VirtualEnv and VirtualEnvWrapper 安装和配置VirtualEnv和VirtualEnvWrapper

We will be installing our Django projects in their own virtual environments to isolate the requirements for each. To do this, we will be installing virtualenv, which can create Python virtual environments, and virtualenvwrapper, which adds some usability improvements to the virtualenv work flow.

我们会将Django 项目安装在各自的虚拟环境中,以此来隔离彼此的依赖包冲突。 这样,我们就可以去安装virtualenv了,它能够创建Python虚拟环境;以及虚拟环境包装器,它可以对虚拟工作流程添加一些有用的改进。

We will be installing both of these components using pip, the Python package manager. This can be acquired from the Ubuntu repositories:

我们使用pip——Python包管理器——来安装这些组件,这些包可以从Ubuntu仓库中取得:

sudo apt-get update
sudo apt-get install python-pip

In this guide, we are using Python version 2. If your code uses Python 3, you can install the python3-pip package. You will then have to substitute the pip commands in this guide with the pip3 command when operating outside of a virtual environment.

本指南中,我们使用的是Python2。如果你使用Python3编写代码,你可以安装包python3-pip。然后,在虚拟环境之外进行操作的话你必须使用pip3命令来替换本指南中的pip命令。

Now that you have pip installed, we can install virtualenv and virtualenvwrapper globally by typing:

先你已经安装了pip,我们通过输入如下命令来全局安装 virtualenv 和 virtualenvwrapper:

sudo pip install virtualenv virtualenvwrapper

With these components installed, we can now configure our shell with the information it needs to work with the virtualenvwrapper script. Our virtual environments will all be placed within a directory in our home folder called Env for easy access. This is configured through an environmental variable called WORKON_HOME. We can add this to our shell initialization script and can source the virtual environment wrapper script.

在这些组件安装完毕之后,现在我们可以去配置需要同 virtualenvwrapper脚本交互的shell信息了。为了便于访问,我们的虚拟环境会被放到用户的家目录中的一个称作Env的文件夹中。你可以通过使用一个称作WORKON_HOME的环境变量来完成配置。我们添加这些内容到shell的初始化脚本,便可以索引虚拟环境包装器脚本了。

If you are using Python 3 and the pip3 command, you will have to add an additional line to your shell initialization script as well:

如果你正在使用的是Python3和pip3命令,你必须另外添加一行到初始化shell脚本:

echo "export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3" >> ~/.bashrc

Regardless of which version of Python you are using, you need to run the following commands:

不管你现在使用的哪一个版本的Python,你都需要运行下面的命令:

echo "export WORKON_HOME=~/Env" >> ~/.bashrc
echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.bashrc

Now, source your shell initialization script so that you can use this functionality in your current session:

现在,索引初始化shell脚本,这样你就一在当前的shell回话中使用这个功能了:

source ~/.bashrc

You should now have directory called Env in your home folder which will hold virtual environment information.

现在,你应该在自己的家目录文件夹中直接调用Env,它将显示所拥有的虚拟环境信息。

Create Django Projects 创建Django项目

Now that we have our virtual environment tools, we will create two virtual environments, install Django in each, and start two projects.

Create the First Project 创建第一个项目

We can create a virtual environment easily by using some commands that the virtualenvwrapper script makes available to us.

Create your first virtual environment with the name of your first site or project by typing:

mkvirtualenv firstsite

This will create a virtual environment, install Python and pip within it, and activate the environment. Your prompt will change to indicate that you are now operating within your new virtual environment. It will look something like this: (firstsite)user@hostname:~$. The value in the parentheses is the name of your virtual environment. Any software installed through pip will now be installed into the virtual environment instead of on the global system. This allows us to isolate our packages on a per-project basis.

Our first step will be to install Django itself. We can use pip for this without sudo since we are installing this locally in our virtual environment:

pip install django

With Django installed, we can create our first sample project by typing:

cd ~
django-admin.py startproject firstsite

This will create a directory called firstsite within your home directory. Within this is a management script used to handle various aspects of the project and another directory of the same name used to house the actual project code.

Move into the first level directory so that we can begin setting up the minimum requirements for our sample project.

cd ~/firstsite

Begin by migrating the database to initialize the SQLite database that our project will use. You can set up an alternative database for your application if you wish, but this is outside of the scope of this guide:

./manage.py migrate

You should now have a database file called db.sqlite3 in your project directory. Now, we can create an administrative user by typing:

./manage.py createsuperuser

You will have to select a username, give a contact email address, and then select and confirm a password.

Next, open the settings file for the project with your text editor:

nano firstsite/settings.py

Since we will be setting up Nginx to serve our site, we need to configure a directory which will hold our site's static assets. This will allow Nginx to serve these directly, which will have a positive impact on performance. We will tell Django to place these into a directory called static in our project's base directory. Add this line to the bottom of the file to configure this behavior:

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

Save and close the file when you are finished. Now, collect our site's static elements and place them within that directory by typing:

./manage.py collectstatic

You can type "yes" to confirm the action and collect the static content. There will be a new directory called static in your project directory.

With all of that out of the way, we can test our project by temporarily starting the development server. Type:

./manage.py runserver 0.0.0.0:8080

This will start up the development server on port 8080. Visit your server's domain name or IP address followed by 8080 in your browser:

http://server_domain_or_IP:8080

You should see a page that looks like this:

sample_site

Add /admin to the end of the URL in your browser's address bar and you will be taken to the admin login page:

admin_login

Using the administrative login credentials you selected with the createsuperuser command, log into the server. You will then have access to the administration interface:

admin_interface

After testing this functionality out, stop the development server by typing CTRL-C in your terminal. We can now move on to our second project.

Create the Second Project 创建第二哥项目

The second project will be created in exactly the same way as the first. We will abridge the explanation in this section, seeing as how you have already completed this once.

Move back to your home directory and create a second virtual environment for your new project. Install Django inside of this new environment once it is activated:

cd ~
mkvirtualenv secondsite
pip install django

The new environment will be created and changed to, leaving your previous virtual environment. This Django instance is entirely separate from the other one you configured. This allows you to manage them independently and customize as necessary.

Create the second project and move into the project directory:

django-admin.py startproject secondsite
cd ~/secondsite

Initialize the database and create an administrative user:

./manage.py migrate
./manage.py createsuperuser

Open the settings file:

nano secondsite/settings.py

Add the location for the static files, just as you did in the previous project:

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

Save and close the file. Now, collect the static elements into that directory by typing:

./manage.py collectstatic

Finally, fire up the development server to test out the site:

./manage.py runserver 0.0.0.0:8080

You should check the regular site at:

http://server_domain_or_IP:8080

Also log into the admin site:

http://server_domain_or_IP:8080/admin

When you've confirmed that everything is working as expected, type CTRL-C in your terminal to stop the development server.

Backing Out of the Virtual Environment 退出虚拟环境

Since we are now done with the Django portion of the guide, we can deactivate our second virtual environment:

因为,现在我们已经完成指南中的Django部分,我们可以销毁第二个虚拟环境了:

deactivate

If you need to work on either of your Django sites again, you should reactivate their respective environments. You can do that by using the workon command:

若是你需要再次使用Django站点中的任何一个,你都应该重新激活它们自己的专有环境。你可以透过workon命令来实现这个目的。

workon firstsite

Or:

workon secondsite

Again, deactivate when you are finished working on your sites:

再说一遍,当你结束对站点的使用你需要运行这个命令:

deactivate

Setting up the uWSGI Application Server 设置uWSGI应用服务器

Now that we have two Django projects set up and ready to go, we can configure uWSGI. uWSGI is an application server that can communicate with applications over a standard interface called WSGI. To learn more about this, read this section of our guide on setting up uWSGI and Nginx on Ubuntu 14.04.

现在,我们设置好了两个Django项目,也可以去做配置uWGI的准备了。uWSGI是一个能够通过称作WSGI的标准接口来和应用通信。要学习更多相关知识,请阅读本指南的设置uWSGI应用服务器部分。

Installing uWSGI 安装uWSGI

Unlike the guide linked above, in this tutorial, we'll be installing uWSGI globally. This will create less friction in handling multiple Django projects. Before we can install uWSGI, we need the Python development files that the software relies on. We can install this directly from Ubuntu's repositories:

和指南上面给出的内容不同,在这份学习指南中,我们会全局安装uWSGI。这样做可以在处理多个Django项目时减少摩擦。在安装uWSGI之前,我们需要先安装软件所依赖的Python开发文件。我们可以直接从U Ubuntu仓库安装:

sudo apt-get install python-dev

Now that the development files are available, we can install uWSGI globally through pip by typing:

现在,开发文件可以使用了,我们通过pip输入以下命令来全局安装uWSGI:

sudo pip install uwsgi

We can quickly test this application server by passing it the information for one of our sites. For instance, we can tell it to serve our first project by typing:

我们可以通过传递uwsgi的信息到其中一个站点来快速测试应用。例如,我们可以通过输入以下内容来告诉uwsgi对我们的第一个项目进行伺服:

uwsgi --http :8080 --home /home/user/Env/firstsite --chdir /home/user/firstsite -w firstsite.wsgi

Here, we've told uWSGI to use our virtual environment located in our ~/Env directory, to change to our project's directory, and to use the wsgi.py file stored within our inner firstsite directory to serve the file. For our demonstration, we told it to serve HTTP on port 8080. If you go to server's domain name or IP address in your browser, followed by :8080, you will see your site again (the static elements in the /admin interface won't work yet). When you are finished testing out this functionality, type CTRL-C in the terminal.

这里,我们高速uWSGI使用位于 ~/Env目录中的虚拟环境,以改变我们的项目,然后使用存储在firstsite目录内部里面的wsgi.py文件来对文件伺服。就像我们所说的那样,我们高速uWSGI在8080端口提供HTTP服务。如果在浏览器中输入的浏览服务器的域名或者IP地址,以8080结尾,那么你可以在此见到自己的网站(在admin接口中的静态内容还未起作用)。当你结束这个功能测试之后,请在终端中输入CTRL-C。

Creating Configuration Files 创建配置文件

Running uWSGI from the command line is useful for testing, but isn't particularly helpful for an actual deployment. Instead, we will run uWSGI in "Emperor mode", which allows a master process to manage separate applications automatically given a set of configuration files.

在测试的时候,从命令行运行uWSGI是非常有用的,不过在实际的部署中却不是特别好用。相反,我们以“帝王模式”来运行uWSGI,它允许主进程通过一组给定的配置文件来自动地管理独立的应用。

Create a directory that will hold your configuration files. Since this is a global process, we will create a directory called /etc/uwsgi/sites to store our configuration files. Move into the directory after you create it:

请创建一个可以包含配置的目录。因为,这是一个全局进程,所以我们会创建一个称作 /etc/uwsgi/sites的目录来存储配置文件。在您创建这个目录之后请切换它:

sudo mkdir -p /etc/uwsgi/sites
cd /etc/uwsgi/sites

In this directory, we will place our configuration files. We need a configuration file for each of the projects we are serving. The uWSGI process can take configuration files in a variety of formats, but we will use .ini files due to their simplicity.

在这个目录中,我们放置了配置文件。我们需要为正在使用的每个项目都创建一个配置文件。uWSGI进程可以处理多种格式的配置文件,不过为了简单起见,我们会使用.ini 文件。

Create a file for your first project and open it in your text editor:

在文本编辑器中为第一个项目创建一个文件,然后打开它:

sudo nano firstsite.ini

Inside, we must begin with the [uwsgi] section header. All of our information will go beneath this header. We are also going to use variables to make our configuration file more reusable. After the header, set a variable called project with the name of your first project. Add a variable called base with the path to your user's home directory:

在这里,我们必须使用以 [uwsgi] 这个区域首部开始。我们所有的信息都要放在这个首部之下。我们也会使用变量将配置更加具有重复使用性。在首部之后,设置一个称作project的变量,并将第一个项目的名称赋值给它。添加一个称作base的,拥有到用户家目录路径的变量。

[uwsgi]
project = firstsite
base = /home/user

Next, we need to configure uWSGI so that it handles our project correctly. We need to change into the root project directory by setting the chdir option. We can combine the home directory and project name setting that we set earlier by using the %(variable_name) syntax. This will be replaced by the value of the variable when the config is read.

接下来,我们需要配置uWSGI,这样它就一正确地处理项目了。我们需要透过设置chdir选项来切换到root目录。我们合并家目录和之前使用%(变量名称)语法设置的项目名称。在配置读取时,变量的值将替换它。

In a similar way, we will indicate the virtual environment for our project. By setting the module, we can indicate exactly how to interface with our project (by importing the "application" callable from the wsgi.py file within our project directory). The configuration of these items will look like this:

同样地,我们指明了项目的虚拟环境。通过设置这个模块,我们可以准确地指出如何对接项目(通过从项目目录中的wsgi.py文件导入可调用的“application”)。这些选项的配置如下:

[uwsgi]
project = firstsite
base = /home/user

chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application

We want to create a master process with 5 workers. We can do this by adding this:

我们想创建一个使用5个worker的主进程。您可以通过添加以下内容来完成目的:

[uwsgi]
project = firstsite
base = /home/user

chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application

master = true
processes = 5

Next we need to specify how uWSGI should listen for connections. In our test of uWSGI, we used HTTP and a network port. However, since we are going to be using Nginx as a reverse proxy, we have better options.

接下来,我们需要指定uWSGI如何侦听连接。在对uWSGI的测试中,我们使用了HTTP和一个网络端口。不过,因为我们要将Nginx用作反向代理,我们可以有更好的选择。

Instead of using a network port, since all of the components are operating on a single server, we can use a Unix socket. This is more secure and offers better performance. This socket will not use HTTP, but instead will implement uWSGI's uwsgi protocol, which is a fast binary protocol for designed for communicating with other servers. Nginx can natively proxy using the uwsgi protocol, so this is our best choice.

与使用网络端口相反,我们可以书用Unix套接字,因为我们所有的组件都是运行在一台服务器上面的。套接字更安全而且还提供了更优良的性能。这个套接字并不使用HTTP,相反它是用uWSGI的uwsgi协议实现的,该协议是一个快速的被设计成与其他服务器通信的二进制协议。Nginx可以

We will also modify the permissions of the socket because we will be giving the web server write access. We'll set the vacuum option so that the socket file will be automatically cleaned up when the service is stopped:

[uwsgi]
project = firstsite
base = /home/user

chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application

master = true
processes = 5

socket = %(base)/%(project)/%(project).sock
chmod-socket = 664
vacuum = true

With this, our first project's uWSGI configuration is complete. Save and close the file.

The advantage of setting up the file using variables is that it makes it incredibly simple to reuse. Copy your first project's configuration file to use as a base for your second configuration file:

sudo cp /etc/uwsgi/sites/firstsite.ini /etc/uwsgi/sites/secondsite.ini

Open the second configuration file with your text editor:

sudo nano /etc/uwsgi/sites/secondsite.ini

We only need to change a single value in this file in order to make it work for our second project. Modify the project variable with the name you've used for your second project:

[uwsgi]
project = secondsite
base = /home/user

chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application

master = true
processes = 5

socket = %(base)/%(project)/%(project).sock
chmod-socket = 664
vacuum = true

Save and close the file when you are finished. Your second project should be ready to go now.

Create an Upstart Script for uWSGI 为uWSGI创建一个开机启动脚本

We now have the configuration files we need to serve our Django projects, but we still haven't automated the process. Next, we'll create an Upstart script to automatically start uWSGI at boot.

We will create an Upstart script in the /etc/init directory, where these files are checked:

sudo nano /etc/init/uwsgi.conf

Start by setting a description for your uWSGI service and indicating the runlevels where it should automatically run. We will set ours to run on runlevels 2, 3, 4, and 5, which are the conventional multi-user runlevels:

description "uWSGI application server in Emperor mode"

start on runlevel [2345]
stop on runlevel [!2345]

Next, we need to set the username and group that the process will be run as. We will run the process under our own username since we own all of the files. For the group, we need to set it to the www-data group that Nginx will run under. Our socket settings from the uWSGI configuration file should then allow the web server to write to the socket. Change the username below to match your username on the server:

description "uWSGI application server in Emperor mode"

start on runlevel [2345]
stop on runlevel [!2345]

setuid user
setgid www-data

Finally, we need to specify the actual command to execute. We need to start uWSGI in Emperor mode and pass in the directory where we stored our configuration files. uWSGI will read the files and serve each of our projects:

description "uWSGI application server in Emperor mode"

start on runlevel [2345]
stop on runlevel [!2345]

setuid user
setgid www-data

exec /usr/local/bin/uwsgi --emperor /etc/uwsgi/sites

When you are finished, save and close the file. We won't start uWSGI yet since we will not have the www-data group available until after we install Nginx.

Install and Configure Nginx as a Reverse Proxy

With uWSGI configured and ready to go, we can now install and configure Nginx as our reverse proxy. This can be downloaded from Ubuntu's default repositories:

sudo apt-get install nginx

Once Nginx is installed, we can go ahead and create a server block configuration file for each of our projects. Start with the first project by creating a server block configuration file:

sudo nano /etc/nginx/sites-available/firstsite

Inside, we can start our server block by indicating the port number and domain name where our first project should be accessible. We'll assume that you have a domain name for each:

server {
    listen 80;
    server_name firstsite.com www.firstsite.com;
}

Next, we can tell Nginx not to worry if it can't find a favicon. We will also point it to the location of our static files directory where we collected our site's static elements:

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

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/user/firstsite;
    }
}

After that, we can use the uwsgi_pass directive to pass the traffic to our socket file. The socket file that we configured was called firstproject.sock and it was located in our project directory. We will use the include directive to include the necessary uwsgi parameters to handle the connection:

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

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/user/firstsite;
    }

    location / {
        include         uwsgi_params;
        uwsgi_pass      unix:/home/user/firstsite/firstsite.sock;
    }
}

That is actually all the configuration we need. Save and close the file when you are finished.

We will use this as a basis for our second project's Nginx configuration file. Copy it over now:

sudo cp /etc/nginx/sites-available/firstsite /etc/nginx/sites-available/secondsite

Open the new file in your text editor:

sudo nano /etc/nginx/sites-available/secondsite

Here, you'll have to change any reference to firstsite with a reference to secondsite. You'll also have to modify the server_name so that your second project responds to a different domain name. When you are finished, it will look something like this:

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

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/user/secondsite;
    }

    location / {
        include         uwsgi_params;
        uwsgi_pass      unix:/home/user/secondsite/secondsite.sock;
    }
}

Save and close the file when you are finished.

Next, link both of your new configuration files to Nginx's sites-enabled directory to enable them:

sudo ln -s /etc/nginx/sites-available/firstsite /etc/nginx/sites-enabled
sudo ln -s /etc/nginx/sites-available/secondsite /etc/nginx/sites-enabled

Check the configuration syntax by typing:

sudo service nginx configtest

If no syntax errors are detected, you can restart your Nginx service to load the new configuration:

sudo service nginx restart

If you remember from earlier, we never actually started the uWSGI server. Do that now by typing:

sudo service uwsgi start

You should now be able to reach your two projects by going to their respective domain names. Both the public and administrative interfaces should work as expected.

Conclusion 结论

In this guide, we've set up two Django projects, each in their own virtual environments. We've configured uWSGI to serve each project independently using the virtual environment configured for each. Afterwards, we set up Nginx to act as a reverse proxy to handle client connections and serve the correct project depending on the client request.

Django makes creating projects and applications simple by providing many of the common pieces, allowing you to focus on the unique elements. By leveraging the general tool chain described in this article, you can easily serve the applications you create from a single server.