Ubuntu下的Nginx + Uwsgi + Django项目部署详细流程

前言

这篇博客主要介绍标题中写明的项目部署流程,以及解决部署过程中可能遇到的一些问题,在开始之前,墙裂推荐这篇文档:
Setting up Django and your web server with uWSGI and nginx
看完这篇文档,你可能已经能够解决90%(甚至100%)的问题了,剩下10%的问题(我所遇到的)将穿插在我部署的过程中进行解决。

(第一次部署的过程十分粗糙,遇到的很多问题都没有妥善记录下来,现在另起一个比较干净的服务器,重新部署一下,好把之前的坑过一遍,另外对配置进行一些优化)

如果按照本文流程,仍然配置不成功的话,请按照以下几点排除问题:

  1. 检查服务器端口配置
  2. 检查配置文件是否正确
  3. 检查部署过程中各个项目的版本是否和本文一致(版本更新后可能导致配置变化)
  4. 检查防火墙(我配置时没有遇到这个问题)
  5. google…
  6. 欢迎留言,一起解决问题~

环境

阿里云: Ubuntu 14.04 64位

本机:windows10

python:3.6.6

工具

IDE:Pycharm(代码部署功能比较好用)

(可选)文件图形化客户端:WinSCP(查看服务器文件结构)

申请一个服务器

这里在阿里云上申请注册了一个Ubuntu服务器……个人喜好,可自行更换

获取服务器实例

获取IP

配置安全组(配置放行端口

连接服务器

连接服务器的方法很多,不一一赘述了,这里使用ssh直连

安装ssh

sudo apt-get install ssh

连接目标服务器

ssh [email protected]

xxx部分为服务器的公网IP地址,root为用户名(不推荐使用root账户进行后续部署操作)

配置用户

给服务器系统添加自定义用户,后面的操作都在该用户下(本文中添加并使用账户名为breavo,账户名可任意取)
sudo adduser breavo

详细过程可以自行google,这里贴出一个简单的方法:linux给用户添加sudo权限

(创建用户后请务必添加sudo权限,避免后续出现权限问题)

使用pyenv管理python版本

由于各个项目之间存在python的版本问题,而服务器中自带的python2(现在也自带python3了,但是版本可能不符合需求)是远远无法满足需求的,导致的结果就是你的服务器中安装了多个python版本,每个项目依赖不同的版本运行。那么管理的必要性是不言而喻的了,另外每个项目需要一个独立的运行环境(项目依赖需要分开管理,否则会变成噩梦),这一点通过创建虚拟环境来解决。

下载pyenv

首先对系统环境进行一下更新,确保后面的操作不会因为缺少某个工具导致失败

sudo apt-get update

安装curl,git

sudo apt-get install curl git-core

安装pyenv

curl -L https://raw.github.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash

这个命令会把pyenv安装到当前用户的~/.pyenv目录下.(本文中为/home/breavo/.pyenv)

同样,在用户目录下找到.bashrc文件,将下面的代码添加至文件内容末尾(本文中bashrc文件路径在/home/breavo下,可自行对应到自己的路径)

export PYENV_ROOT="${HOME}/.pyenv"

if [ -d "${PYENV_ROOT}" ]; then
  export PATH="${PYENV_ROOT}/bin:${PATH}"
  eval "$(pyenv init -)"
fi

或者

export PATH="/home/breavo/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

修改后保存~

这段代码的作用主要是指明pyenv的位置,以便以后可以直接在命令行里面运行pyenv命令。 保存在~/.bashrc 文件中是为了每次用户登陆后自动生效。

所以如果你是第一次运行命令并且没有注销的话, 这一段是不会生效的, 我们还需要运行下面的命令令其生效

source ~/.bashrc

然后就可以直接在命令行里面敲pyenv了。

安装pyenv参考文章:点击这里

Python安装

pyenv安装完了,接下来安装我们需要的python版本,首先查看一下目前python有哪些版本可以安装

pyenv install --list

会打印一串很长的列表,网上滑一滑,可以看下如下图所示。

1536573344011

我们就安装图中画圈的这个版本

pyenv install 3.6.6 -v

(注:这里install的时候最好加一个 -v,否则安装过程信息是不会打印在控制台的,看上去就好像安装进度卡住了一样,首次安装可能会引起疑惑)

1536574049017

安装失败 = =,原因是一些依赖还没有装上

sudo apt-get install make build-essential libssl-dev zlib1g-dev
sudo apt-get install libbz2-dev libreadline-dev libsqlite3-dev wget
sudo apt-get install llvm libncurses5-dev libncursesw5-dev

依赖安装完毕之后,再次pyenv install 3.6.6 -v

顺利完成~

注:到这一步为止有一个坑,很多人喜欢安装最新的版本(python 3.7.0+),在依赖全部安装完毕的情况下,依旧会出现下图提示。

1536580977191

问题是Open SSL已经安装过了(就是这个libssl-dev),当时排查这个问题排查了很久,到最后,发现是因为没有配置的情况下,OpenSSL根本没有支持到python3.7.0+

pyenv builds/installs openssl into a sub-directory of a new installation prefix, but Python is not configured to use it. Without ./configure --with-openssl=${somewhere}
it will favor the system’s OpenSSL. In the case of Darwin, this always
fails because the version of OpenSSL is no longer supported (Python >=3.7.0).

问题链接:Python 3.7.0 :: The Python ssl extension was not compiled. Missing the OpenSSL lib?

前面排查的时候根本没往那方面想,结果悲剧了,浪费了很多时间 = =~

pyenv基本操作

安装完成,查看一下

pyenv versions

发现python3.6.6已经安装进系统了~

切换系统默认python环境

pyenv global 3.6.6

当前系统默认python版本已经变成3.6.6了,可以输入python命令check一下

卸载某个python版本

pyenv uninstall x.x.x

另外pyenv还有各种其他命令行操作,可自行google了解~

重新打开远程SSH窗口可能会遇到pyenv command not found问题,重新source一下.bashrc文件

或者

查看解决方案:戳这里

配置虚拟环境

准备

开始配置之前,不妨阅读一下pyenv-virtualenv ReadMe

**(可选 + 推荐)**自动激活虚拟环境

通过pyenv安装完成后,连带着virtualenv也安装完成了,我们可以通过pyenv命令完成虚拟环境的配置

在 pyenv-virtualenv中,由于需要从根本上处理一些已知的问题(关于$PATH和shell提示符),activate/deactivate提示符将会在未来的版本中移除(目前依然可以使用,但是会弹出warning,我是觉得不爽啦~)

问题链接:Question regarding prompt changing

根据作者的建议,我们可以如下方式完成虚拟环境的配置和激活

运行

$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile

重启一下shell

$ exec "$SHELL"

运行

pyenv virtualenv 3.6.6 eshop

其中3.6.6是需要指定的python版本, eshop是虚拟环境的名称(随便起的~)

此时,虚拟环境已经创建完成并自动激活,可以通过pyenv versions查看,如下图所示。

1536634825198

通过 pyenv shell xxx(xxx为python版本号或者虚拟环境名称)切换环境,效果如下图

1536635052166

原有的激活方式

运行

pyenv virtualenv 3.6.6 eshop

激活/反激活虚拟环境

pyenv activate eshop

pyenv deactivate

最后

卸载虚拟环境

pyenv uninstall

至此,虚拟环境的搭建就算完成了~

Nginx基本配置

sudo apt-get install nginx

运行

sudo /etc/init.d/nginx start    # start nginx

如果出现sudo: unable to resolve host问题,参考这里

如果出现端口占用情况,通过修改配置文件换用其他端口(如8000)

如果出现端口没被占用但无法访问,请回到配置安全组出查看端口策略是否配置完备

打开浏览器访问 xx.xx.xxx.xxx:80,其中xxxx是你的公网IP,80是Nginx默认监听的端口号

出现

1536637144080

这个表示Nginx已经成功安装并运行起来了

(可选)服务端配置数据库

本文以postgresql为例进行安装配置

基本配置

参考文章:Ubuntu 安装和配置postgresql

安装postgresql

sudo apt-get install postgresql

安装完成后服务器系统会自动创建一个名为postgres的账户(数据库超级用户),密码为空

切换到postgres

sudo su postgres

登陆postgresql

psql postgres

在postgresql界面继续输入如下命令(注意末尾加分号)

ALTER USER postgres with PASSWORD 'postgres'

修改成功后输入’\q’ 退出postgresql

退出postgres账户可以直接输入exit后回车或者ctrl + d

上述流程正确的情况下如下图所示。

1536649149847

远程登陆

编辑pgsql配置文件,运行

sudo vim /etc/postgresql/9.1/main/postgresql.conf

修改配置文件如下:

监听任何地址访问,修改连接权限

# listen_addresses = ‘localhost’
改为 
listen_addresses = ‘*’

启用密码验证

# password_encryption = on 
改为 
password_encryption = on

编辑 /etc/postgresql/9.1/main/pg_hba.conf,
sudo vim /etc/postgresql/9.1/main/pg_hba.conf
在文件末尾添加

# to allow your client visiting postgresql server
host all all 0.0.0.0 0.0.0.0 md5

保存上述修改

最后,重启数据库

sudo service postgresql restart

1536650507525

至此,数据库配置完成了

可以通过登陆测试一下,直接登陆或者使用PgAdmin都可以,不再赘述

Django项目代码上传

上传

前面配置了这么多,Django项目还没有上传到服务器呢,确保本地有一个可运行Django项目

上传方式很多

  1. 通过WinSCP直接上传
  2. 通过pycharm进行代码部署(推荐)
  3. 其他

新建的用户可能会遇到上传的权限问题,解决方法戳Permissions on /var/www/html for uploading web site files via SFTP

查看用户xxx所在组以及组内成员

groups xxx

更改文件上传目录的用户和用户组

sudo chown breavo:breavo /file/upload/path

为用户组添加写权限

sudo chmod -R 775 /file/upload/path

项目试运行

设置django settings.py

ALLOWED_HOSTS = ['*']

安装项目依赖(依赖写入requirements.txt中,每个依赖注意添加版本号)

cd 到你存放requirement.txt的目录, 运行

pip install -r requirements.txt

等待依赖安装完成,cd到项目目录下,运行

python manage.py runserver 0.0.0.0:8000

打开浏览器输入服务器地址,查看

xx.xx.xxx.xxx:8000 (xxx为服务器公网IP地址)

项目正常运行~(如果settings.py文件中的DEBUG设置为False,会观察到静态资源无法加载)

Nginx代理

在项目中配置Nginx

在项目目录下添加一个config文件夹,后面的配置文件都统一放到该文件夹下(配置文件存放路径不统一会导致输入提示符时运行不成功)

config文件下新建mysite_nginx.conf文件,内容如下(将路径替换成你自己的项目路径或者对应文件):

# mysite_nginx.conf

# the upstream component nginx needs to connect to
upstream django {
    # unix:///home/breavo/PyWorkSpace/mysite_code_shuffle/config/eshop.sock
    # server unix:///path/to/your/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 server
server {
    # the port your site will be served on
    listen      8000;
    # the domain name it will serve for
    server_name xx.xx.xxx.xxx; # 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  {
        # /home/breavo/PyWorkSpace/mysite_code_shuffle/meida;
        alias /path/to/your/mysite/media; # your Django project's media files - amend as required
    }

    location /static {
        # /home/breavo/PyWorkSpace/mysite_code_shuffle/static
        alias /path/to/your/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/breavo/PyWorkSpace/mysite_code_shuffle/config/uwsgi_params; # the uwsgi_params file you installed
    }
}

/etc/nginx/sites-enabled中创建一个链接,这样Nginx能够发现并启用我们的配置,运行

sudo ln -s ~/path/to/your/mysite/mysite_nginx.conf /etc/nginx/sites-enabled/

部署静态文件

在运行Nginx之前,需要将django项目中的所有静态文件放入static文件夹,在mysite/settings.py中添加

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

然后运行

python manage.py collectstatic

启动(重启)Nginx

sudo /etc/init.d/nginx start
sudo /etc/init.d/nginx restart

简单测试

往服务器项目的media文件夹里丢一个图片(这里以test.png为例)

1536723380612

访问

xx.xx.xxx.xxx:8000/media/test.png

1536723433733

图片正确显示~

至此,静态文件部署算是完成了

Uwsgi安装及配置

接下来我们需要使用Uwsgi来处理项目中的动态请求

基本配置

虚拟环境下运行

pip install uwsgi

在之前创建的config文件夹下新建一个hello.py用来做测试,写入以下内容

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

接下来运行

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

打开浏览器查看

1536734803098

出现上图,说明Uwsgi已经初步运行成功

运行项目

上述步骤没有出问题的话,我们就可以使用Uwsgi启动项目了,项目根目录下运行

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

其中mysite.wsgi(mysite替换成自己的项目名称)会自动搜索项目中的wsgi.py文件

如果正常运行~恭喜

如果浏览器出现Internal Server Error

  1. 检查命令提示符是否输入正确
  2. 检查是否项目根目录下运行
  3. 其他情况,查看命令行输出或者log

至此Uwsgi基本配置算是完成了~~

Nginx + Uwsgi + django

Nginx访问hello.py

现在我们使用socket通信来通过Nginx访问hello.py,(确保Nginx已经启动)config文件夹下运行

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

好了,就这么现在访问浏览器

xx.xx.xxx.xxx:8000

1536736332744

成功访问~

其中8000是Nginx监听的端口(mysite_nginx.conf文件中配置),–socket :8001是用于socket通信的端口(两个端口都可以替换~)

使用Unix sockets替换端口

编辑mysite_nginx.conf文件,将原来内容修改成如下

server unix:///path/to/your/mysite/mysite.sock; # for a file socket
# server 127.0.0.1:8001; # for a web port socket (we'll use this first)

保存后,config文件夹下运行

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

依旧打开浏览器访问xx.xx.xxx.xxx:8000,屏幕出现hello world,说明一切正常

如果出现502 Bad Getway

查看你的Nginx error log(/var/log/nginx/error.log)

如果出现

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

则说明是权限问题,运行

uwsgi --socket mysite.sock --wsgi-file hello.py --chmod-socket=666

或者

uwsgi --socket mysite.sock --wsgi-file hello.py --chmod-socket=664 (推荐,但是我用了没成功)

log如果打印了其他问题,请仔细检查配置~

使用Nginx + Uwsgi运行项目

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

注意这里有个小坑,mysite_nginx.conf中我配置的mysite.sock在config文件夹下,而这条命令需要在项目根目录下运行,这里可以:

  1. 修改mysite_nginx.conf下sock文件路径到根目录下
  2. 使用配置文件启动(推荐)
编辑配置文件

config文件夹下新建mysite_uwsgi.ini,输入以下内容

# mysite_uwsgi.ini file
[uwsgi]

# Django-related settings
# the base directory (full path)
chdir           = /path/to/your/project
# Django's wsgi file
module          = project.wsgi
# the virtualenv (full path)
home            = /path/to/virtualenv

# process-related settings
# master
master          = true
# maximum number of worker processes
processes       = 10
# the socket (use the full path to be safe
socket          = /path/to/your/project/mysite.sock
# ... with appropriate permissions - may be needed
chmod-socket    = 666
# clear environment on exit
vacuum          = true

stats           = %(chdir)/config/uwsgi.status           

pidfile         = %(chdir)/config/uwsgi.pid

用自己的路径替换其中对应的配置~

保存后,运行(确保在mysite_uwsgi.ini目录下)

uwsgi --ini mysite_uwsgi.ini

打开浏览器访问xx.xx.xxx.xxx:8000

项目这时候应该完美运行了~~

大功告成~:)

最后

重新一步一步的部署了一遍之后,强迫症终于舒服了~~文章中还是有很多地方不(没)够(有)完(写)善(全),后面有时间继续补一补~:)

其他实用技巧

nginx配置文件语法高亮

使用screen在远程连接窗口关闭后保持服务运行

Ubuntu screen实用命令

发布了19 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/breavo_raw/article/details/82665978