Django 博客开发教程 14 - 使用 Nginx 和 Gunicorn 部署 Django 博客
我们博客的基础功能已经开发的基本差不多了,虽然还有很多地方可以完善,但我们还是希望早点把博客部署到服务器上,让他人可以通过外网访问。至于有待完善的地方,可以等部署完后一点点地迭代和改进。现在就让我们来把博客部署到服务器上吧!
注意:本文的每一个步骤都在真实环境下验证无误。除非你知道自己在做什么,否则我们建议每一步均严格按照教程的指导来,这样能保证你顺利完成部署。
部署前准备
我们将使用比较流行的 Nginx + Gunicorn 的方式将 Django 开发的博客部署到自己的服务器,让别人能够通过域名访问你的博客。至于 Nginx、Gunicorn 是什么暂时放到一边,读完本教程后你就会知道它们的作用和使用方法了。
为了部署我们的博客,需要满足以下两个条件:
有一台可以通过外网访问的服务器。
有一个域名。
如果你已经满足以上条件,可以直接跳到后面的搭建服务器部分。这里简单介绍一下我目前所知的以最低成本满足以上两个条件的方式。
购买服务器
如果你是学生,推荐购买阿里云服务器,学生优惠价是 9.9 元/月,而且服务器性能比较高。购买地址:阿里云服务器学生专区。具体的购买步骤这里就不赘述了,根据网站的指引相信你肯定能够购买成功。只是注意一点的是在选服务器类型的时候选择公共镜像,这样系统比较纯净。操作系统建议选 ubuntu 14.04 64位,这是本教程使用的服务器环境。
如果你不是学生,推荐购买搬瓦工 vps。目前最便宜的是 19.9美元/年,缺点是服务器性能没有阿里云高,但优点是顺带可以用它来搭梯子,从此访问 google、youtube 不是梦(基于 shadowsocks 只需简单几步就可以搭建起自己的梯子服务器)。同样购买的过程就不赘述了,搬瓦工 vps 中文网 有超级详细的指引。只是注意安装操作系统时建议选 ubuntu 14.04 64位,这是本教程使用的服务器环境。
如果你不差那点钱,随意选择一个云服务器提供商购买一个云服务器即可。
购买域名
域名服务商很多,我这里使用的是 阿里云域名注册系统。域名是网站的门牌,如果打算长期运营这个网站建议多考虑考虑,选一个适当的域名。如果只是为了测试,随便注册一个域名即可,一些非常见后缀的域名非常便宜,一般 10元/年就能搞定。但注意一点根据工信部规定,以下后缀的域名需要实名认证后才能使用:
.cn/.com/.net/.top/.xyz/.vip/.club/.ren/.wang/.shop/.xin/.中国/.信息/.公司/.网络/.广东/.佛山
如果你购买的是上述后缀的域名,意味着需要提交个人的身份资料实名认证后才能正常使用,这通常需要花费几天的时间。所以如果只为了测试和学习部署的话,最好避开上述后缀的域名。
搭建服务器
本教程使用的本地环境为 Windows 10,服务器环境为 ubuntu 14.04(64 位)。如果你的环境和我的有所差异导致一些命令无法执行,将这些命令转换为你所在环境的命令执行即可。
### 远程登录到服务器
服务器通常位于云端,需要使用远程登录工具登录后才能对服务器进行操作。我使用的是 Xshell,Windows 下百度 Xshell 下载安装即可,软件对学校和个人用户是免费的。
如何远程登录到服务器这里就不赘述了,相信你参考网上的一些教程肯定能够顺利登录。假如你和我一样使用 Xshell 的话,这里有一篇很详细的教程可以参考:教你怎么使用xshell远程连接linux服务器。
安装软件
顺利连接到远程服务器了。如果是一台全新服务器的话,通常我们是以 root 用户登录的。在 root 下部署代码不安全,最好是建一个新用户(如果你已经以非 root 用户登录的话可以跳过这一步)。下面的一些列命令将创建一个拥有超级权限的新用户:
# 在 root 用户下运行这条命令创建一个新用户,yangxg 是用户名 # 因为我叫杨学光,所以我取的用户名是 yangxg # 选择一个你喜欢的用户名,不一定非得和我的相同 root@localhost:~# useradd -m -s /bin/bash yangxg # 把新创建的用户加入超级权限组 root@localhost:~# usermod -a -G sudo yangxg # 为新用户设置密码 # 注意在输密码的时候不会有字符显示,不要以为键盘坏了,正常输入即可 root@localhost:~# passwd yangxg # 切换到创建的新用户 root@localhost:~# su - yangxg # 切换成功,@符号前面已经是新用户名而不是 root 了 yangxg@localhost:~$
新用户创建并切换成功了。如果是新服务器的话,最好先更新一下系统,避免因为版本太旧而给后面安装软件带来麻烦。运行下面的两条命令:
yangxg@localhost:~$ sudo apt-get update yangxg@localhost:~$ sudo apt-get upgrade
接下来就可以安装必要的软件了,这里我们需要用到的软件有 Nginx、Pytohn3、Git、pip 和 virtualenv。
yangxg@localhost:~$ sudo apt-get install nginx yangxg@localhost:~$ sudo apt-get install git python3 python3-pip yangxg@localhost:~$ sudo pip3 install virtualenv
解析域名到服务器的 IP 地址
将域名和服务器的 IP 地址绑定后,用户就可以通过在浏览器输入域名来访问服务器了。
各大域名服务商都提供了域名解析服务,但其配置界面各有差异,请依据其指引完成域名解析。下面是我使用的阿里云域名解析页面。
启动 Nginx 服务
Nginx 是用来处理静态文件请求的。比如当我们访问一个博客文章详情页面时,服务器会接收到下面两种请求:
显示文章的详情信息,这些信息通常保存在数据库里,因此需要调用数据库获取数据。
图片、css、js 等存在服务器某个文件夹下的静态文件。
对于前一种请求,博客文章的数据需要借助 Django 从数据库中获取,Nginx 处理不了,它就会把这个请求转发给 Django,让 Django 去处理。而对于后一种静态文件的请求,只需要去这些静态文件所在的文件夹获取,Nginx 就会代为处理,不再麻烦 Django。
用 Django 去获取静态文件是很耗时的,但 Nginx 可以很高效地处理,这就是我们要使用 Nginx 的原因(当然其功能远不止这些)。
通过前面的步骤我们已经安装了 Nginx,并且已经把域名和服务器 IP 绑定了。运行下面的命令启动 Nginx 服务:
yangxg@localhost:~$ sudo service nginx start
在浏览器输入域名,看到如下页面说明 Nginx 启动成功了。
部署代码
部署前的项目配置
Django 项目中会有一些 CSS、JavaScript 等静态文件,为了能够方便地让 Nginx 处理这些静态文件的请求,我们把项目中的全部静态文件收集到一个统一的目录下,这个目录通常位于 Django 项目的根目录,并且命名为 static。为了完成这些任务,需要在项目的配置文件里做一些必要的配置:
blogproject/settings.py # 其他配置... STATIC_URL = '/static/' # 加入下面的配置 STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_ROOT 指明了静态文件的收集目录,即项目根目录(BASE_DIR)下的 static 文件夹。
为了安全起见,在生产环境下需要关闭 DEBUG
选项以及设置允许访问的域名。打开 settings.py 文件,找到 DEBUG
和 ALLOWED_HOSTS
这两个选项,将它们设置成如下的值:
blogproject/settings.py DEBUG = False ALLOWED_HOSTS = ['127.0.0.1', 'localhost ', '.zmrenwu.com']
ALLOWED_HOSTS
是允许访问的域名列表,127.0.0.1 和 localhost 是本地访问的域名,.zmrenwu.com 是访问服务器的域名(换成你自己的域名)。域名前加一个点表示允许访问该域名下的子域名,比如 www.zmrenwu.com、test.zmrenwu.com 等二级域名同样允许访问。如果不加前面的点则只允许访问 zmrenwu.com。
项目还会依赖一些第三方 Python 库,为了方便在服务器上一次性安装,我们将全部依赖写入一个叫 requirements.txt 的文本文件中。激活本地的虚拟环境(如果你使用了虚拟环境的话),并进入项目的根目录,运行 pip freeze > requirements.txt
命令:
(blogproject_env) C:\Users\yangxg\Workspace\blogproject> pip freeze > requirements.txt
这时项目根目录下会生成了一个 requirements.txt 的文本文件,其内容记录了项目的全部依赖。
将代码上传到 GitHub
将代码上传到 GitHub 等代码托管平台,这样我们就可以方便地把代码拉取到服务器了。Git 和 GitHub 的使用相信你已经很熟悉了,这里就不赘述过程。如果不知道如何使用地话可以自行百度相关教程。
注意数据库文件不要上传!
设置服务器目录结构
接下来需要把代码上传到服务器了。我服务器上存放代码的目录结构一般是这样的:
/home/yangxg/ sites/ demo.zmrenwu.com/ env/ django-blog-tutorial/
一台服务器可能部署多个网站,所有网站代码都放在 sites/ 目录下。demo.zmrenwu.com/ 这个文件夹以网站的域名命名,便于区分。env/ 是 python 虚拟环境目录。django-blog-tutorial/ 是 Django 博客项目目录。
因此先来创建这个目录结构,注意目录名替换为你自己的域名,以后涉及到 demo.zmrenwu.com 的地方通常都要替换你自己的域名,后面就不再一一指出了,运行下面的命令,
yangxg@localhost:~$ mkdir -p ~/sites/demo.zmrenwu.com
这里 ~ 代表当前用户的 home 目录,即 /home/yangxg/。
接下来创建虚拟环境,先进入到 demo.zmrenwu.com 目录下,然后运行 virtualenv 命令创建虚拟环境:
yangxg@localhost:~$ cd ~/sites/demo.zmrenwu.com yangxg@localhost:~/sites/demo.zmrenwu.com$ virtualenv --python=python3 env
注意这里使用 --python=python3 来指定克隆 Python3 的环境。因为 ubuntu 系统默认安装了 Python2,如果不特别指定的话 Virtualenv 默认克隆的是 Python2 的环境。
检查一下虚拟环境是否创建成功,运行 ls 命令列出当前目录下的文件和文件夹,看到 env 这个文件夹说明虚拟环境创建成功。
yangxg@localhost:~/sites/demo.zmrenwu.com$ ls env
接着再从代码仓库把项目代码拉取过来,把 git clone 后的地址换成你自己的 GitHub 仓库地址!
yangxg@localhost:~/sites/demo.zmrenwu.com$ git clone https://github.com/zmrenwu/django-blog-tutorial.git
运行 ls 命令检查一下是否拉取成功:
yangxg@localhost:~/sites/demo.zmrenwu.com$ ls django-blog-tutorial env
多了 django-blog-tutorial 文件夹(文件夹名称由你的 GitHub 仓库名决定),说明拉取成功了。
安装项目依赖
激活虚拟环境,再进入到项目根目录,即 requirements.txt 所在的目录,安装项目的全部依赖:
yangxg@localhost:~/sites/demo.zmrenwu.com$ source env/bin/activate (env) yangxg@localhost:~/sites/demo.zmrenwu.com$ cd django-blog-tutorial/ (env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ pip install -r requirements.txt
收集静态文件
虚拟环境下继续运行 python manage.py collectstatic
命令收集静态文件到 static 目录下:
(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ python manage.py collectstatic
生成数据库
虚拟环境下继续运行 python manage.py migrate
命令创建数据库文件:
(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ python manage.py migrate
创建超级用户
虚拟环境下继续运行 python manage.py createsuperuser
命令创建一个超级用户,方便我们进入 Django 管理后台。这和本地开发时是一样的,具体请参照:在 Django Admin 后台文章。
(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ python manage.py createsuperuser
配置 Nginx
接下是配置 Nginx 来处理用户请求。
先在服务器的 /etc/nginx/sites-available/ 目录下新建一个配置文件,文件名我一般就设置为域名。写上下面的配置内容:
/etc/nginx/sites-available/demo.zmrenwu.com server { charset utf-8; listen 80; server_name demo.zmrenwu.com; ① location /static { ② alias /home/yangxg/sites/demo.zmrenwu.com/django-blog-tutorial/static; } location / { ③ proxy_set_header Host $host; proxy_pass http://unix:/tmp/demo.zmrenwu.com.socket; } }
① 服务的域名为 demo.zmrenwu.com。
② 所有URL 带有 /static 的请求均由 Nginx 处理,alias 指明了静态文件的存放目录。
③ 其它请求转发给 Django 处理。proxy_pass 后面使用了 unix 套接字,其作用是防止端口冲突,这里就不再详述。
至于怎么在服务器新建文件和写文件,请自行学习一点点 vi 编辑器的用法,这里也不一一讲解了。
我们在 /etc/nginx/sites-available/ 放置了配置文件,接下来需要创建一个符号链接,把这个配置文件加入到启用的网站列表中去,被启用网站的目录在 /etc/nginx/sites-enabled/,你可以理解为从 sites-available/ 目录下发送了一个配置文件的快捷方式到 sites-enabled/ 目录。具体命令如下:
(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ sudo ln -s /etc/nginx/sites-available/demo.zmrenwu.com /etc/nginx/sites-enabled/demo.zmrenwu.com
使用 Gunicorn
Gunicorn 一般用来管理多个进程,有进程挂了Gunicorn 可以把它拉起来,防止服务器长时间停止服务,还可以动态调整 worker 的数量,请求多的时候增加 worker 的数量,请求少的时候减少。
在虚拟环境下,安装 Gunicorn:
(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ pip install gunicorn
用 Gunicorn 启动服务器进程:
(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ gunicorn --bind unix:/tmp/demo.zmrenwu.com.socket blogproject.wsgi:application
浏览器输入域名,可以看到访问成功了!
自动启动 Gunicorn
现在 Gunicorn 是我们手工启动的,万一哪天服务器崩溃重启了又得重新手工启动。为此我们写一个自动启动脚本,这样当服务器重新启动后,脚本会帮我们重启 Gunicorn。先按 Ctrl + c 停止刚才启动的服务器进程。
写一个启动脚本,这样当服务器重启后能自动引导 Gunicorn 的启动。脚本位于 /etc/init/ 目录下,且脚本文件名必须以 .conf 结尾:
/etc/init/gunicorn-demo.zmrenwu.com.conf start on net-device-up ① stop on shutdown respawn ② setuid yangxg ③ chdir /home/yangxg/sites/demo.zmrenwu.com/django-blog-tutorial ④ exec ../env/bin/gunicorn --bind unix:/tmp/demo.zmrenwu.com.socket blogproject.wsgi:application ⑤
① start on net-device-up 确保只在服务器联网时才启动 Gunicorn。
② 如果进程崩溃了(比如服务器重启或者进程因为某些以外情况被 kill),respawn 将自动重启 Gunicorn。
③ setuid 确保以 yangxg 用户的身份(换成你自己的用户名)运行 Gunicorn 进程。
④ chdir 进入到指定目录,这里进入项目的根目录。
⑤ exec 执行进程,即开启服务器进程。
现在可以用 start 命令启动 Gunicorn 了:
sudo start gunicorn-demo.zmrenwu.com
以后如果更新了代码,只要运行下面的命令重启一下 Nginx 和 Gunicorn 就可以使新的代码生效了:
sudo service nginx reload sudo restart gunicorn-demo.zmrenwu.com
使用 CDN 加快 Bootstrap 和 jQuery 的加载速度
我们的项目使用了 Bootstrap 和 jQuery,这两个文件我们是从本地加载的。如果服务器性能比较差的话,加载需要耗费很长的时间,网站打开的速度就变得无法忍受。我们使用 CDN 来加快加载速度。具体来说,替换 base.html 的几个静态文件的加载标签:
base.html - <link rel="stylesheet" href="{% static 'blog/css/bootstrap.min.css' %}"> - <script src="{% static 'blog/js/jquery-2.1.3.min.js' %}"></script> - <script src="{% static 'blog/js/bootstrap.min.js' %}"></script> + <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> + <script src="https://cdn.bootcss.com/jquery/2.1.3/jquery.min.js"></script> + <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
这样网站访问的速度将大大提升!
部署过程自动化
在整个部署过程中我们运行了十几条命令,手动输入了 N 个字符。如果每次更新代码都要远程连接到服务器执行这些命令的话将变得非常麻烦。接下来的教程我们将介绍使用 Fabric 自动化整个部署过程。写好部署脚本后,只需要执行一条命令,就可以非常方便地自动完成整个部署。
总结
本章节的代码位于:Step14: deploy using nginx and gunicorn。
如果遇到问题,请通过下面的方式寻求帮助。
将问题的详细描述通过邮件发送到 [email protected],一般会在 24 小时内回复。
更多Django 教程,请访问 追梦人物的博客。