博客网站开发完成后,最后一棒是将博客网站部署到公网服务器上,提供域名访问,能通过搜索引擎搜索到的博客网站才是真正的博客网站。
大家好,我是落霞孤鹜
,经过几个星期的努力,我们已经完成了博客的开发。这一章我们开始开始部署博客网站,通过公网服务器和域名访问我们的博客网站。
一、准备工作
为了能实现我们的网站能通过域名访问,我们需要具备几个条件:
- 购买云服务器,这里可以自行选择购买阿里、腾讯、华为、百度,各个平台都有自己特定的优惠,选择合适自己的一个平台即可。
- 安装服务器的操作系统,作为服务器,一般采用linux系统,ubuntu,cent os,debian都可以
- 购买一个域名,可以通过云服务器提供商平台上的域名,
.cn
和.com
都可以。 - 购买域名证书,只有具备了证书后,通过域名访问才会不被浏览器提示存在安全问题。
- 对网站进行备案,目前备案需要进行两次,一次是在工信部的平台进行 ICP 备案,通过这个备案后,还需要完成公安联网备案。
二、网站部署
在完成了准备工作后,正式开始我们的网站部署。
2.1 Python
由于我们的后端代码是Python
编写的,所以在服务器上部署的时候,需要安装Python
运行环境。
这里的安装方式,我采用官网的教程,版本是3.7。教程地址:https://docs.python.org/zh-cn/3.7/using/unix.html
安装完成后在命令行中运行如下命令验证是否安装成功
python -V
pip -V
2.2 代码发布
2.2.1 前端代码
2.2.1.1 编译
由于我们采用的是 Vue 和 TypeScript
编写的前端,因此在部署之前,需要编译成原生 Javascript
代码。
在前端代码根目录下,执行如下命令
yarn build
执行完成后,会在代码路径下生成 dist
文件夹,里面是编译后的代码,文件结构如下图
2.2.1.2 上传
在服务器中,Home
目录下,创建一个文件夹blog
,在blog下创建文件夹frontend
。
cd ~
mkdir blog
cd blog
mkdir frontend
然后将本地dist
文件夹下的前端文件通过FTP工具上传到~/blog/frontend
路径下,前端代码发布完成。
2.2.2 后端代码
由于 Python 是脚本语言,所以代码本身不需要经过编译,直接将源代码上传到服务器对应路径即可。
2.2.2.1 依赖安装
Python 的运行服务器,我们采用 uwsgi
,因此需要先在服务器上安装依赖,执行如下命令
pip install uwsgi
安装完成后,通过命令验证是否安装成功
uwsgi --version
2.2.2.2 编写 uwsgi
配置文件
在后端代码项目路径下新建文件uwsgi.ini
,我们通过socket的方式连接后端接口,配置信息如下:
[uwsgi]
socket = 127.0.0.1:8000
# 可以理解为此文件的绝对路径
chdir = ~/blog/backend/
# wsgi与chdir的相对路径
wsgi-file = project/wsgi.py
processes = 4
# 日志
daemonize = ~/blog/backend/logs/uwsgi.log
pidfile = ~/blog/backend/uwsgi.pid
master = True
在后端代码项目路径下新建文件uwsgi.param
,文件内容如下
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
2.2.2.3 上传代码
在服务器的~/blog
文件夹下,创建backend
文件夹
cd ~/blog
mkdir backend
通过 FTP 工具将后端代码上传到~/blog/backend
文件夹下,包括刚刚创建的uwsgi.ini
文件然后在backend文件夹下,创建logs
文件夹,用来记录日志
mkdir logs
至此,后端代码已经部署到位。
2.2.2.4 启动和停止后端服务
通过命令启动后端代码
uwsgi --ini ~/blog/backend/uwsgi.ini
测试可以通过日志文件查看启动后的服务器日志
tail -f ~/blog/backend/logs/uwsgi.log
停止命令如下:
uwsgi --stop ~/blog/backend/uwsgi.pid
后期如果后端代码更新,则需要先停止uwsgi
服务后,再启动代码的更新。
2.3 Nginx
在当前的网站部署中,Nginx作为反向代理服务器部署网站是主流操作,也已经是成熟的网站部署方案。
Nginx在网站部署中, 一般会有以下几个作用:
- 反向代理,通过代理内网服务器,从而让外网的客户端访问到内网服务器提供的能力和数据。
- 负载均衡,分担后端服务器的压力
- HTTP服务器,Nginx本身也是一个静态资源的服务器,且在处理静态资源的请求和响应,比老牌的 Web 服务器更优秀,性能更好。通过 Nginx 实现动态和静态的分离部署。
2.3.1 安装
网上有很多教程,我这里提供一个参考教程 Linux下nginx的安装 - 浊酒尽 - 博客园 (cnblogs.com)
2.3.2 证书文件
在前面的准备工作中,有提到域名证书,此时将域名证书提供商平台上提供的证书文件下载下来,解压后,将 Nginx 的证书上传到服务器的 Nginx 安装路径中的conf
文件下。
2.3.3 配置说明
Nginx 的配置文件一般存放在 Nginx 安装路径下的conf
文件夹中,名称是 nginx.conf
。
2.3.3.1 静态文件代理
这里有两部分静态文件,一部分是前端代码文件,一部分是通过上传接口获得的媒体文件
location / {
root ~/blog/frontend/dist;
index index.html index.htm;
if (!-e $request_filename) {
rewrite ^/(.*) /index.html last;
break;
}
}
location /upload/ {
root ~/blog/backend/;
expires 24h;
}
2.3.3.2 后端接口代理
在location
里面有很关键的两行配置uwsgi_pass blog
和include ~/blog/backend/uwsgi.param
,明确的是通过uwsgi
的方式代理 Python 的接口
# server
upstream blog{
server 127.0.0.1:8000;
}
location /api/ {
uwsgi_pass blog;
include ~/blog/backend/uwsgi.param;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header accept-encodeing 'gzip, deflate';
proxy_set_header content-type 'application/json';
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header authorization $http_authorization;
proxy_set_header accept '*/*';
proxy_set_header x-bce-date $http_x_bce_date;
}
2.3.3.3 静态文件Gzip
压缩
配置Gzip
压缩的原因是在前后端分离的场景下,网站首屏需要加载的内容很多,通过缩小网络传输过程中的文件大小,从而加快首屏渲染时的静态文件加载。
# Gzip
gzip on;
gzip_min_length 1k;
gzip_comp_level 3;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
gzip_buffers 32 4k;
gzip_http_version 1.0;
2.3.3.3 域名配置
server {
listen 80;
server_name www.longair.cn;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen 443 ssl;
server_name www.longair.cn;
root html;
index index.html index.htm;
}
2.3.3.3 Https
证书文件配置
ssl_certificate /etc/nginx/longair.cn_nginx/server.crt;
ssl_certificate_key /etc/nginx/longair.cn_nginx/server.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
2.3.3.3 Http
自动转 Https
在访问 80 端口时,重定向到 433 端口中。
server {
listen 80;
server_name www.longair.cn;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
2.3.3.3 博客文章详情跳转404问题配置
由于我们使用 Vue 框架编写的前端代码,路由模式采用的是 history
,这种模式的路由可读性强,但文章详情页面的路由如果通过新开页面的方式,会出现404的问题,因此我们需要对这种情况做处理,配置原理是,访问的路径如果不是文件结尾时,则自动重定向到首页,进入到index.html
后就可以通过路由变动进入到单页应用的路由,从而正确渲染详情页面。Vue-router 官网文档:HTML5 History 模式 | Vue Router (vuejs.org)
location / {
root ~/blog/frontend/dist;
index index.html index.htm;
if (!-e $request_filename) {
rewrite ^/(.*) /index.html last;
break;
}
}
2.3.4 完整配置
完整配置如下:
user root;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
keepalive_timeout 65;
client_max_body_size 200M;
# Gzip
gzip on;
gzip_min_length 1k;
gzip_comp_level 3;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
gzip_buffers 32 4k;
gzip_http_version 1.0;
# server
upstream blog{
server 127.0.0.1:8000;
}
# blog http
server {
listen 80;
server_name www.longair.cn;
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
server {
listen *:80;
listen *:443 ssl;
listen [::]:80;
listen [::]:443 ssl;
server_name longair.cn;
ssl_certificate /etc/nginx/longair.cn_nginx/server.crt;
ssl_certificate_key /etc/nginx/longair.cn_nginx/server.key;
return 301 https://www.longair.cn$request_uri;
}
# blog https
server {
listen 443 ssl;
server_name www.longair.cn;
root html;
index index.html index.htm;
ssl_certificate /etc/nginx/longair.cn_nginx/server.crt;
ssl_certificate_key /etc/nginx/longair.cn_nginx/server.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
root ~/blog/frontend/dist;
index index.html index.htm;
if (!-e $request_filename) {
rewrite ^/(.*) /index.html last;
break;
}
}
location /upload/ {
root /blog/backend/;
expires 24h;
}
location /api/ {
uwsgi_pass blog;
include ~/blog/backend/uwsgi.param;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header accept-encodeing 'gzip, deflate';
proxy_set_header content-type 'application/json';
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header authorization $http_authorization;
proxy_set_header accept '*/*';
proxy_set_header x-bce-date $http_x_bce_date;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location = /50x.html {
root ~/blog/frontend/dist;
}
}
}
三、网站的维护
3.1 Nginx的维护
3.1.1 启动命令
/usr/local/nginx/sbin/nginx -s start
3.1.2 停止命令
/usr/local/nginx/sbin/nginx -s stop
3.3.3 重启命令
/etc/nginx/sbin/nginx -s reload
3.3.4 日志查看命令
tail -f /etc/nginx/logs/access.log
tail -f /etc/nginx/logs/error.log
3.2 UWSGI的维护
3.2.1 启动命令
uwsgi --ini ~/blog/backend/uwsgi.ini
3.2.2 停止命令
uwsgi --stop ~/blog/backend/uwsgi.pid
3.3.3 日志查看命令
uwsgi --stop ~/blog/backend/uwsgi.pid
四、关于数据库
在开发阶段,我们采用的是非常方便的sqlite数据库,但是如果当网站部署到服务器上以后,再采用sqlite就会出现很多问题,比如数据安全问题,数据更新问题等,因此我们在博客部署上线时,需要切换成 Mysql
数据库。
4.1 Mysql
安装
我使用的5.7版本,安装操作,请依据自己的操作系统参考官网教程安装。MySQL :: MySQL 5.7 Reference Manual :: 2 Installing and Upgrading MySQL
4.2 数据库搭建
在服务器上,通过命令行完成数据库的搭建。
4.2.1 root登录
mysql -uroot -p
然后输入密码,回车,登录进入数据库。
4.2.2 创建数据库
- 创建数据库
create database blog character set utf8mb4;
- 创建用户
create user 'blog'@'%' identified by '12345678';
- 用户赋权
grant all privileges on blog.* to 'blog'@'%';
flush privileges;
4.3 后端配置调整
4.3.1 生产和开发环境隔离
在开发阶段,通过sqlite
数据库,调试方便,访问速度快,而生产环境上,使用 Mysql
会更安全。所以我们希望开发和生产环境使用不同的数据库配置。
因此我们通过在系统中的环境变量来判断是生产环境还是测试环境,此种方式代码可以保持一套,部署时不用做任何调整。
同时需要调整允许访问的 host 信息。
4.3.2 数据库密码保护
由于我们的代码可能会通过代码仓库管理,如果是Github
等仓库,可以会泄露自己的数据库密码,因此我们这里通过单独的配置文件来记录数据库账号信息,然后在Python中通过读取数据库账号配置文件来获取信息,从而实现数据库密码保护。
4.3.3 配置
4.3.3.1 project/settings.py
ALLOWED_HOSTS = ['www.longair.cn', '127.0.0.1', 'localhost', ]
ENV_PROFILE = os.getenv("PYTHON_ENV")
if ENV_PROFILE == "production":
import configparser
cf = configparser.ConfigParser()
cf.read('/blog/db.cnf') # 这个文件的内容在下一步会创建,至于路径是哪里都可以,只要下一步创建的文件是在这里写的路径下即可
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': cf.get('db', 'database'),
'USER': cf.get('db', 'user'), # 从配置文件中获取数据库用户名
'PASSWORD': cf.get('db', 'password'), # 从配置文件中获取数据库密码
'HOST': 'localhost',
'PORT': '3306'
}
}
DEBUG = False # 生产环境下关闭debug模式
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'data/db.sqlite3'),
}
}
DEBUG = True
4.3.3.2 配置环境变量
通过修改环境变量管理文件,设置环境变量,输入命令vi ~/.bashrc
,在里面添加一行:export PYTHON_ENV=production
,然后按 esc
,输入::wq
保存
最后输入source ~/.bashrc
4.3.3.3 增加数据库账号配置文件
在~/blog
下新增文件vi db.cnf
,然后增加如下内容:
[db]
database = blog
user = blog
password = 12345678
default-character-set = utf8
数据库、账号、密码和上面的数据库信息保持一致。
恭喜你,至此,博客网站部署完成,可以通过域名来访问你的博客网站了。
下一篇我将总结一下在整个博客开发过程中遇到的问题和解决方案。