做者:HelloGitHub-追梦人物css
文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库html
博客的基础功能已经开发的差很少了,虽然还有不少地方能够完善,但咱们仍是但愿早点把博客部署到服务器上,让他人能够经过外网访问。至于有待完善的地方,能够等部署完后一点点地迭代和改进。如今就让咱们来把博客部署到服务器上吧!python
↓↓↓ 视频在这里 ↓↓↓jquery
做者亲自录制的真机环境演示部署全过程,再不成功你打我!linux
B 站演示(阿里云 CentOS 7 系统)观看地址:www.bilibili.com/video/av680…nginx
注意:本文的每个步骤都在真实环境下验证无误。除非你知道本身在作什么,不然建议每一步均严格按照教程的指导来,这样能保证你顺利完成部署。git
咱们将使用比较流行的 Nginx + Gunicorn 的方式将 django 开发的博客部署到本身的服务器,让别人可以经过域名访问你的博客。至于 Nginx、Gunicorn 是什么暂时放到一边,读完本教程后你就会知道它们的做用和使用方法了。github
为了部署咱们的博客,须要知足如下两个条件:web
本教程使用的本地环境为 Windows 10,服务器环境为 CentOS 7(64 位)。若是你的环境和个人有所差别(好比 Ubuntu)致使一些命令没法执行,将这些命令转换为你所在环境的命令执行便可,重点在于理解每一步的做用,这样不管在何种环境你都能成功地完成部署,而不是机械地复制粘贴命令。sql
服务器一般位于云端,须要使用远程登陆工具登陆后才能对服务器进行操做。我使用的是 Xshell,Windows 下百度 Xshell 下载安装便可,软件对学校和我的用户是免费的。
如何远程登陆到服务器这里就不赘述了,相信你参考网上的一些教程确定可以顺利登陆。假如你和我同样使用 Xshell 的话,这里有一篇很详细的教程能够参考:教你怎么使用 xshell 远程链接 linux 服务器。
顺利链接到远程服务器了,若是是一台全新服务器的话,一般咱们是以 root 用户登陆的。在 root 下部署代码不够安全,最好是建一个新用户(若是你已经以非 root 用户登陆的话能够跳过这一步)。下面的一些列命令将建立一个拥有超级权限的新用户(把 yangxg 替换成你本身想要的用户名,我这里取个人名字拼音 yangxg):
# 在 root 用户下运行这条命令建立一个新用户,yangxg 是用户名
# 由于我叫杨学光,因此我取的用户名是 yangxg
# 选择一个你喜欢的用户名,不必定非得和个人相同
root@server:~# adduser yangxg
# 为新用户设置密码
# 注意在输密码的时候不会有字符显示,不要觉得键盘坏了,正常输入便可
root@server:~# passwd yangxg
# 把新建立的用户加入超级权限组
root@server:~# usermod -aG wheel yangxg
# 切换到建立的新用户
root@server:~# su - yangxg
# 切换成功,@符号前面已是新用户名而不是 root 了
yangxg@server:$
复制代码
新用户建立并切换成功了。若是是新服务器的话,最好先更新一下系统,避免由于版本太旧而给后面安装软件带来麻烦。运行下面的两条命令:
yangxg@server:$ sudo yum update
yangxg@server:$ sudo yum upgrade
复制代码
为了方便,咱们博客使用了 SQLite3 数据库,django 2.2 要求 SQLite3 数据库版本在 3.8.3 以上,而 CentOS 7 系统自带版本低于 django 2.2 所要求的最低版本,因此首先来更新 SQLite3 的版本。
注意
有可能你使用的服务器系统发行版 SQLite3 已经高于 3.8.3,这一步就能够跳过。如何查看 SQLite3 的版本呢?请执行 sqlite3 --version
首先登录到 sqlite 的官方下载地址,查看最新发布的版本,截止到本教程完成时,其最新版本为 3.29.0,找到该版本的源码压缩包,复制其下载连接,而后经过 wget 命令下载到服务器(我通常习惯将源码放在 ~/src 目录下。)
# 建立 src 目录并进到这个目录
yangxg@server:$ mkdir -p ~/src
yangxg@server:$ cd ~/src
# 下载 sqlite3 源码并解压安装
yangxg@server:$ wget https://sqlite.org/2019/sqlite-autoconf-3290000.tar.gz
yangxg@server:$ tar zxvf sqlite-autoconf-3290000.tar.gz
yangxg@server:$ cd sqlite-autoconf-3290000
yangxg@server:$ ./configure
yangxg@server:$ make
yangxg@server:$ sudo make install
复制代码
小贴士:
若是 wget 命令不存在,使用 sudo yum install -y wget 安装便可。
至此 SQLite3 更新完毕,接下来安装 Python3。
CentOS 7 自带的 Python 发行版为 2.7,所以须要安装 Python3,为了兼容性,咱们安装 Python 3.6.4。
首先安装可能的依赖:
yangxg@server:$ sudo yum install -y openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel
复制代码
而后下载 Python 3.6.4 的源码并解压:
yangxg@server:$ cd ~/src
yangxg@server:$ wget https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tgz
yangxg@server:$ tar -zxvf Python-3.6.4.tgz
复制代码
最后编译安装:
yangxg@server:$ cd Python-3.6.4
yangxg@server:$ ./configure LD_RUN_PATH=/usr/local/lib LDFLAGS="-L/usr/local/lib" CPPFLAGS="-I/usr/local/include"
yangxg@server:$ make LD_RUN_PATH=/usr/local/lib
yangxg@server:$ sudo make install
复制代码
注意这里安装 Python 时,Python 会依赖 SQLite3 的库,因此在 configure 时经过 LD_RUN_PATH 指定依赖的搜索目录(由于咱们以前更新了 SQLite3 的版本,指定依赖搜索目录确保使用新的 SQLite3 依赖库),另外两个参数做用相似。
而后输入 python3.6 -V 和 pip3.6 -V 命令测试安装结果,输出版本号说明安装成功了。
有了 pip,就能够安装 Pipenv 了:
yangxg@server:$ sudo pip3.6 install pipenv
复制代码
小贴士:
若是以上命令报错,多是由于 pip3.6 安装在当前用户的 bin 路径下(/usr/local/bin/),使用 pip3.6 install pipenv --users 命令也把 Pipenv 安装到当前用户的 bin 路径下就能够了。
接下来开始准备部署代码,让咱们的博客应用在服务上跑起来,这和在本地开发时的过程是如出一辙的。不过为了将应用部署到服务器上,咱们首先要对项目作一点配置,打开 settings.py,找到 ALLOWED_HOSTS
,将其修改成:
blogproject/settings.py
ALLOWED_HOSTS = ['127.0.0.1', 'localhost ', '.zmrenwu.com']
复制代码
指定了 ALLOWED_HOSTS
的值后,django 将只容许经过指定的域名访问咱们的应用,好比这里只容许经过 127.0.0.1,localhost 以及 zmrenwu.com 和其任意子域名(域名前加一个点表示容许访问该域名下的子域名)访问(即 HTTP 报文头部中 Host 的值必须是以上指定的域名,一般你在浏览器输入域名访问网站时,Host 的值就会被设置为网站的域名),这样能够避免 HTTP Host 头攻击。
Django 项目中会有一些 CSS、JavaScript 等静态文件,为了可以方便地让 Nginx 处理这些静态文件的请求,咱们把项目中的所有静态文件收集到一个统一的目录下,这个目录一般位于 django 项目的根目录,而且命名为 static。为了完成这些任务,须要在项目的配置文件里作一些必要的配置:
blogproject/settings.py
# 其余配置...
STATIC_URL = '/static/'
# 加入下面的配置
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
复制代码
STATIC_ROOT
即指定静态文件的收集路径,这里指定为 BASE_DIR(项目根目录,在 settings.py 文件起始处定义)下的 static 文件夹。
如今的关键是把代码传到服务器上来了,这里咱们使用 git。首先安装 git:
yangxg@server:$ sudo yum install -y git
复制代码
将代码上传到 GitHub 等代码托管平台,这样咱们就能够方便地把代码拉取到服务器了。Git 和 GitHub 的使用相信你已经很熟悉了,这里就不赘述过程。若是不知道如何使用地话能够自行百度相关教程。注意数据库文件不要上传!
我一般喜欢把应用代码放在 ~/apps/ 目录下,先来设置一下服务器的文件结构,用于存放应用代码等相关文件:
# 在用户目录下建立 apps 目录并进入
yangxg@server:$ mkdir -p ~/apps
yangxg@server:$ cd ~/apps
# 拉取博客代码
yangxg@server:$ git clone https://github.com/HelloGitHub-Team/HelloDjango-blog-tutorial.git
复制代码
而后进入到项目根目录,安装项目依赖:
yangxg@server:$ cd ~/apps/HelloDjango-blog-tutorial
yangxg@server:$ pipenv install --deploy --ignore-pipfile
复制代码
这里指定 --deploy
参数,Pipenv 将只会安装 Pipfile 中 [packages] 下指定的依赖。由于咱们如今是在线上环境进行部署,仅用于开发环境的相关依赖咱们并不须要。
--ignore-pipfile
将会使 Pipenv 从 Pipfile.lock 文件中安装项目依赖。Pipfile.lock 记录了项目依赖的精确信息,从这里读取依赖信息可以确保依赖信息被无心中修改或者破坏而使得运行环境由于依赖包的缘故出现不可预料的问题。
Pipenv 会自动帮咱们建立虚拟环境,而后将项目依赖安装到虚拟环境下。
而后建立一下数据库:
yangxg@server:$ pipenv run python manage.py migrate
复制代码
启动开发服务器:
yangxg@server:$ pipenv run python manage.py runserver 0.0.0.0:8000
复制代码
这里咱们启动开发服务器时指定了服务器运行的 ip 和端口,这将容许经过公网 ip 的 8000 端口访问咱们的博客。
访问 ip:8000,能够看到访问成功(其中 ip 为你服务器的公网 ip)。
Django 官方文档强调使用 runserver 开启的开发服务器仅用于开发测试,不建议用于生产环境。因此咱们使用流行的 Gunicorn 来启动能够用于线上环境的服务器。
首先进入到项目根目录,安装 Gunicorn:
yangxg@server:$ pipenv install gunicorn
复制代码
因为咱们在服务端修改安装了 gunicorn,代码中 Pipfile 文件和 Pipfile.lock 文件会被更新,所以别忘了把改动同步到本地,具体作法能够自行学习,如下是一个参考:
# 服务端提交代码
yangxg@server:$ git add Pipfile Pipfile.lock
yangxg@server:$ git commit -m "add gunicorn dependency"
yangxg@server:$ git push
# 本地拉取代码
git pull
复制代码
回到线上服务器,在项目根目录,执行下面的命令启动服务:
yangxg@server:$ pipenv run gunicorn blogproject.wsgi -w 2 -k gthread -b 0.0.0.0:8000
复制代码
来解释一下各个参数的含义。
`-w 2 表示启动 2 个 worker 用于处理请求(一个 worker 能够理解为一个进程),一般将 worker 数目设置为 CPU 核心数的 2-4 倍。
-k gthread
指定每一个 worker 处理请求的方式,根据你们的实践,指定为 gthread
的异步模式能获取比较高的性能,所以咱们采用这种模式。
-b 0.0.0.0:8000
,将服务绑定到 8000 端口,运行经过公网 ip 和 8000 端口访问应用。
访问 ip:8000(ip 为你服务器的公网 ip),应用成功访问了,可是咱们看到样式彻底乱了。别急,这不是 bug!此前咱们使用 django 自带的开发服务器,它会自动帮咱们处理静态样式文件,可是 Gunicorn 并不会帮咱们这么作。由于处理静态文件并非 Gunicorn 所擅长的事,应该将它交给更加专业的服务应用来作,好比 Nginx。
Nginx (engine x) 是一个高性能的 HTTP 和反向代理 web 服务器,它的功能很是多,这里咱们主要用它来处理静态文件以及将非静态文件的请求反向代理给 Gunicorn。
当咱们访问一个博客文章详情页面时,服务器会接收到下面两种请求:
对于前一种请求,博客文章的数据须要借助 django 从数据库中获取,Nginx 处理不了,它就会把这个请求转发给 运行在 Gunicorn 服务中的 django 应用,让 django 去处理。而对于后一种静态文件的请求,只须要去这些静态文件所在的文件夹获取,Nginx 就会代为处理,再也不麻烦 django。
用 django 去获取静态文件是很耗时的,但 Nginx 能够很高效地处理,这就是咱们要使用 Nginx 的缘由。
首先安装 Nginx:
yangxg@server:$ sudo yum install epel-release -y
yangxg@server:$ sudo yum install nginx -y
复制代码
运行下面的命令启动 Nginx 服务:
yangxg@server:$ sudo systemctl start nginx
复制代码
在浏览器输入 ip(不输入端口则默认为 80 端口,Nginx 默认在 80 端口监听请求),看到 Nginx 的欢迎界面说明 Nginx 启动成功了。
Nginx 的配置位于 /etc/nginx/nginx.conf 文件中,你能够打开这个文件看看里面的内容,下面是一些关键性的配置:
user nobody nobody;
...
http {
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
}
}
}
复制代码
首先是这个 user 配置,用于指定 Nginx 进程运行时的用户和组(分别为第一个和第二个参数),为了防止可能的权限问题,咱们改为当前系统用户(个人用户名是 yangxg,所属组 yangxg,记得改为你本身服务器中运行的用户和组,修改完后记得保存文件内容):
user yangxg yangxg;
复制代码
而后在 http 配置下有一个 server 模块,server 模块用于配置一个虚拟服务,使这个虚拟服务监听指定的端口和域名。你能够配置多个 server,这样就会启动多个虚拟服务,用于监听不一样端口,或者是同一个端口,可是不一样的域名,这样你就能够在同一服务器部署多个 web 应用了。
这个 server 的配置咱们下面会详细讲解,再来看看 server 下的 include,include 会将指定路径中配置文件包含进来,这样便于配置的模块化管理,例如咱们能够把不一样 web 应用的配置放到 /etc/nginx/conf.d/ 目录下,这样 nginx 会把这个目录下全部以 .conf 结尾的文件内容包含到 nginx.conf 的配置中来,而无需把全部配置都堆到 nginx.conf 中,使得配置文件十分臃肿。
咱们来配置博客应用,上面说了,为了模块化管理,咱们将配置写到 /etc/nginx/conf.d/ 目录下。先在服务器的 conf.d 目录下新建一个配置文件,我把它叫作 HelloDjango-blog-tutorial.conf。写入下面的配置内容:
server {
charset utf-8;
listen 80;
server_name hellodjango-blog-tutorial-demo.zmrenwu.com;
location /static {
alias /home/yangxg/apps/HelloDjango-blog-tutorial/static;
}
location / {
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8000;
}
}
复制代码
首先咱们配置了一个虚拟服务,编码方式为 utf-8,监听于 80 端口。
服务的域名为 hellodjango-blog-tutorial-demo.zmrenwu.com,因此来自这个域名的请求都会被这个服务所处理。
全部URL 匹配 /static 的请求均由 Nginx 处理,alias 指明了静态文件的存放目录,这样 Nginx 就能够在这个目录下找到请求的文件返回给客户端。
其它请求转发给运行在本机 8000 端口的应用程序处理,咱们会在这个端口启动 Gunicorn 用于处理 Nginx 转发过来的请求。
重启 nginx 使得配置生效:
yangxg@server:$ sudo systemctl restart nginx
复制代码
开发环境下,django 为了调试方便,会将 settings.py 文件中的 DEBUG 选项配置为 True,这样若是程序运行出错,调试信息将尽收眼底,这在开发时很方便,但部署到线上就会带来巨大安全隐患,因此咱们把 DEBUG 选项设置为 False,关闭调试模式,在本地将 settings.py 中的 DEBUG 为:
DEBUG=False
复制代码
线上服务器更新最新的代码,而后运行命令收集静态文件到以前配置的 STATIC_ROOT 目录下:
yangxg@server:$ pipenv run python manage.py collectstatic
复制代码
而后使用 Gunicorn 启动服务。
yangxg@server:$ pipenv run gunicorn blogproject.wsgi -w 2 -k gthread -b 127.0.0.1:8000
复制代码
如今,访问配置的域名 hellodjango-blog-tutorial-demo.zmrenwu.com(改为你本身在 Nginx 中配置的域名),能够看到博客成功部署!
如今 Gunicorn 是咱们手工启动的,一旦咱们退出 shell,服务器就关闭了,博客没法访问。就算在后台启动 Gunicorn,万一哪天服务器崩溃重启了又得从新登陆服务器去启动,很是麻烦。为此使用 Supervisor 来管理 Gunicorn 进程,这样当服务器从新启动或者 Gunicorn 进程意外崩溃后,Supervisor 会帮咱们自动重启 Gunicorn。
先按 Ctrl + C 中止刚才启动的 Gunicorn 服务进程。
首先安装 Supervisor 注意这里使用的是系统自带的 pip2,由于截至本教程书写时 Supervisor 还不支持 Python3,不过这并不影响使用。
yangxg@server:$ pip install supervisor
复制代码
为了方便,我通常会设置以下的目录结构(位于 ~/etc 目录下)来管理 Supervisor 有关的文件:
~/etc
├── supervisor
│ ├── conf.d
│ └── var
│ ├── log
└── supervisord.conf
复制代码
其中 supervisord.conf 是 Supervior 的配置文件,它会包含 conf.d 下的配置。var 目录下用于存放一些常常变更的文件,例如 socket 文件,pid 文件,log 下则存放日志文件。
首先来创建上述的目录结构:
yangxg@server:$ mkdir -p ~/etc/supervisor/conf.d
yangxg@server:$ mkdir -p ~/etc/supervisor/var/log
复制代码
而后进入 ~/etc 目录下生成 Supervisor 的配置文件:
yangxg@server:$ cd ~/etc
yangxg@server:$ echo_supervisord_conf > supervisord.conf
复制代码
修改 supervisor.conf,让 Supervisor 进程产生的一些文件生成到上面咱们建立的目录下,而不是其默认指定的地方。
首先找到 [unix_http_server] 版块,将 file 设置改成以下的值:
[unix_http_server]
file=/home/yangxg/etc/supervisor/var/supervisor.sock
复制代码
即让 socket 文件生成在 ~/etc/supervisor/var/ 目录下。注意 supervisor 不支持将 ~ 展开为用户 home 目录,因此要用绝对路径指定。
相似的修改 [supervisord] 板块下的 logfile 和 pidfile 文件的路径,还有 user 改成系统用户,这样 supervisor 启动的进程将以系统用户运行,避免可能的权限问题:
logfile=/home/yangxg/etc/supervisor/var/log/supervisord.log
pidfile=/home/yangxg/etc/supervisor/var/supervisord.pid
user=yangxg
复制代码
还有 [supervisorctl] 板块下:
serverurl=unix:///home/yangxg/etc/supervisor/var/supervisor.sock
复制代码
[include] 版块,将 /home/yangxg/etc/supervisor/conf.d/ 目录下全部以 .ini 结尾的文件内容包含到配置中来,这样便于配置的模块化管理,和以前 Nginx 配置文件的处理方式是相似的。
files = /home/yangxg/etc/supervisor/conf.d/*.ini
复制代码
而后咱们到 conf.d 新建咱们博客应用的配置:
[program:hellodjango-blog-tutorial]
command=pipenv run gunicorn blogproject.wsgi -w 2 -k gthread -b 127.0.0.1:8000
directory=/home/yangxg/apps/HelloDjango-blog-tutorial
autostart=true
autorestart=unexpected
user=yangxg
stdout_logfile=/home/yangxg/etc/supervisor/var/log/hellodjango-blog-tutorial-stdout.log
stderr_logfile=/home/yangxg/etc/supervisor/var/log/hellodjango-blog-tutorial-stderr.log
复制代码
说一下各项配置的含义:
[program:hellodjango-blog-tutorial] 指明运行应用的进程,名为 hellodjango-blog-tutorial。
command 为进程启动时执行的命令。
directory 指定执行命令时所在的目录。
autostart 随 Supervisor 启动自动启动进程。
autorestart 进程意外退出时重启。
user 进程运行的用户,防止权限问题。
stdout_logfile,stderr_logfile 日志输出文件。
启动 Supervisor
yangxg@server:$ supervisord -c ~/etc/supervisord.conf
复制代码
-c 指定 Supervisr 启动时的配置文件。
进入 supervisorctl 进程管理控制台:
yangxg@server:$ supervisorctl -c ~/etc/supervisord.conf
复制代码
执行 update 命令更新配置文件并启动应用。
浏览器输入域名,能够看到服务已经正常启动了。
咱们的项目使用了 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>
复制代码
本地修改代码后,将代码同步到线上服务器,执行下面的命令重启 hellodjango-blog-tutorial 应用进程:
yangxg@server:$ supervisorctl -c ~/etc/supervisord.conf restart hellodjango-blog-tutorial
复制代码
这样网站访问的速度将大大提高!
部署步骤不少且繁杂,由于每一个环境都不同,所以部署是最容易出错的步骤,必定要搞清楚每一步的做用,这样在遇到问题时,才能针对性地去解决,若是只知道一味地复制粘贴命令,而不知道本身在干吗,那么一旦出错将一筹莫展。
在整个部署过程当中咱们运行了十几条命令,手动输入了 N 个字符。若是每次更新代码都要远程链接到服务器执行这些命令的话将变得很是麻烦。接下来的教程咱们将介绍使用 Fabric 自动化整个部署过程。写好部署脚本后,只须要执行一条命令,就能够很是方便地自动完成整个部署。
『讲解开源项目系列』——让对开源项目感兴趣的人再也不畏惧、让开源项目的发起者再也不孤单。跟着咱们的文章,你会发现编程的乐趣、使用和发现参与开源项目如此简单。欢迎留言联系咱们、加入咱们,让更多人爱上开源、贡献开源~