使用比较流行的 Nginx + Gunicorn 的方式将 Django 开发的博客部署到自己的服务器,让别人能够通过域名访问你的博客。

环境说明

服务器: 阿里云 ECS 服务器
操作系统: Ubuntu 16.04 x86_64

用户创建

通常我们是以 root 用户登录的,而在 root 下部署代码并不安全,最好是建一个新用户用于部署。

  • 修改主机名
root@iZ8vbgxrlnet6jyi1l5crcZ:~# vim /etc/hostname
localhost
  • 重启生效
root@iZ8vbgxrlnet6jyi1l5crcZ:~# init 6
  • 创建用户
root@localhost:~# useradd -m -s /bin/bash allenli
  • 将新创建的用户加入超级权限组
root@localhost:~# usermod -a -G sudo allenli
  • 为新用户设置密码
root@localhost:~# passwd allenli
  • 切换到创建的新用户
root@localhost:~# su - allenli

安装 Python3.6

  • 添加 python3.6 安装包并安装
allenli@localhost:~$ sudo apt-get install software-properties-common -y
  • 修改系统默认 python 版本为 3.6
allenli@localhost:~$ sudo add-apt-repository ppa:jonathonf/python-3.6 -y
allenli@localhost:~$ sudo apt-get update -y
allenli@localhost:~$ sudo apt-get install python3.6 -y

allenli@localhost:~$ cd /usr/bin/
allenli@localhost:~$ sudo rm python
allenli@localhost:~$ sudo ln -s /usr/bin/python3.6m python

allenli@localhost:/usr/bin$ python
Python 3.6.5 (default, May  3 2018, 10:08:28) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
  • 安装并升级 pip 版本
allenli@localhost:~$ sudo apt install python3-pip -y
allenli@localhost:~$ pip -V
pip 8.1.1 from /usr/lib/python3/dist-packages (python 3.6)

allenli@localhost:~$ sudo pip install --upgrade pip
allenli@localhost:~$ pip3 -V
pip 18.0 from /usr/local/lib/python3.6/dist-packages/pip (python 3.6)
allenli@localhost:~$ pip3 list
Package             Version               
------------------- ----------------------
chardet             2.3.0                 
command-not-found   0.3                   
language-selector   0.1                   
pip                 18.0                  
pycurl              7.43.0                
pygobject           3.20.0                
python-apt          1.1.0b1+ubuntu0.16.4.1
requests            2.9.1                 
setuptools          20.7.0                
six                 1.10.0                
ssh-import-id       5.5                   
ufw                 0.35                  
unattended-upgrades 0.1                   
urllib3             1.13.1                
wheel               0.29.0  

创建虚拟环境

  • 安装虚拟环境包
allenli@localhost:~$ pip3 install virtualenv
allenli@localhost:~$ pip3 install virtualenvwrapper   # 用于管理虚拟环境
  • 创建虚拟环境目录
allenli@localhost:~$ mkdir virtualenv
  • 查看安装位置
allenli@localhost:~$ which virtualenvwrapper.sh
/usr/local/bin/virtualenvwrapper.sh
  • 添加至环境变量
allenli@localhost:~$ vim .bashrc

export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python
export WORKON_HOME=/home/allenli/virtualenv
source /usr/local/bin/virtualenvwrapper.sh

allenli@localhost:~$ source .bashrc
  • 创建虚拟环境
allenli@localhost:~$ mkvirtualenv opcoder
(opcoder) allenli@localhost:~$ workon
opcoder
  • 查看虚拟环境安装目录
(opcoder) allenli@localhost:~/virtualenv/opcoder/bin$ pwd
/home/allenli/virtualenv/opcoder/bin
  • 删除虚拟环境
allenli@localhost:~$ rmvirtualenv opcoder
  • 退出虚拟环境
(opcoder) allenli@localhost:~$ deactivate
  • 进入虚拟环境
allenli@localhost:~$ workon opcoder
  • 查看虚拟环境中安装的 python 包
(opcoder) allenli@localhost:~$ pip list

安装 MySQL 数据库

安装数据库

  • 更新系统
allenli@localhost:~$ sudo apt-get update
  • 安装 MySQL
allenli@localhost:~$ sudo apt-get install mysql-server mysql-client
  • 检查是否安装成功
allenli@localhost:~$ sudo netstat -tap | grep mysql

配置数据库连接

  • 本地连接
allenli@localhost:~$ sudo mysql -uroot -ppassword
  • 远程连接
# 1. MySQL 默认是只允许本地主机访问 127.0.0.1,并关闭了远程连接,所以安装之后需打开远程连接,并修改配置允许其他 ip 访问:
allenli@localhost:~$ sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
找到 bind-address = 127.0.0.1 这一行, 并注释

# 2. 重启 mysql 服务:
allenli@localhost:~$ sudo service mysql restart
allenli@localhost:~$ sudo service mysql status

# 3. 重新登录 MySQL 数据库:
allenli@localhost:~$ sudo mysql -uroot -ppassword
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)
mysql> use mysql;

# 4. 将 host 设置为 % 表示任何 ip 都能连接 mysql:
mysql> update user set host='%' where user='root' and host='localhost';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

# 5. 刷新权限表,使配置生效:
mysql> flush privileges; 
Query OK, 0 rows affected (0.00 sec)

# 6. 阿里云的服务器设置了安全组规则来限制 ecs 服务器的 ip,端口访问策略。因此需要修改:
登录阿里云 => 控制台 => 云服务器ECS => 网络和安全 => 安全组 => 配置规则 => 添加安全组规则

ECS_MySQL

创建 Django 项目

  • 虚拟环境下安装依赖包
(opcoder) allenli@localhost:~$ pip install Django==2.0.6
(opcoder) allenli@localhost:~$ pip install PyMySQL==0.8.1
  • 新建 Django Project
(opcoder) allenli@localhost:~$ django-admin.py startproject opcoder
  • 查看文件目录
(opcoder) allenli@localhost:~/opcoder$ tree
.
├── manage.py
└── opcoder
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py
1 directory, 5 files
  • 创建数据库 如果项目使用的是 MySQL 数据库的话,在项目运行之前需要先创建数据库:
allenli@localhost:~$ sudo mysql -uroot -ppassword

mysql> CREATE DATABASE opcoder DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
Query OK, 1 row affected (0.00 sec)

说明: 因为需用到 emoji 表情, 所以字符集指定为 utf8mb4。

  • 配置 Django 数据库连接
# 配置数据库连接

(opcoder) allenli@localhost:~$ vim opcoder/opcoder/settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',  
        'NAME': 'opcoder',
        'USER': 'root',
        'PASSWORD': 'password',
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'OPTIONS': {'charset': 'utf8mb4', }
    }
}
# 更改默认数据库连接为 Mysql

(opcoder) allenli@localhost:~$ vim opcoder/opcoder/__init__.py
import pymysql
pymysql.install_as_MySQLdb()
  • 生成数据库
(opcoder) allenli@localhost:~$ cd opcoder/
(opcoder) allenli@localhost:~/opcoder$ python manage.py makemigrations
(opcoder) allenli@localhost:~/opcoder$ python manage.py migrate
  • 创建超级管理员身份
(opcoder) allenli@localhost:~/opcoder$ python manage.py createsuperuser
  • 配置 HOSTS 默认使用 http://ip:8000 方式访问,如果要支持域名访问,需进行配置:
(opcoder) allenli@localhost:~$ vim opcoder/opcoder/settings.py
ALLOWED_HOSTS = ['47.92.145.59', '127.0.0.1', 'localhost', '.opcoder.cn']
  • 启动项目
(opcoder) allenli@localhost:~/opcoder$ python manage.py runserver 0.0.0.0:8000
说明: 
1. 47.92.145.59 为阿里云 ECS 服务器 IP 地址, 添加后可以使用 http://47.92.145.59:8000/ 方式访问

2. runserver 0.0.0.0:8000 表示开启 django dev server,不限制访问 ip

3. 需要确认阿里云 ECS 服务器是否已开通 8000 端口,如果未开通,可以按照如下操作开通:
登录阿里云 => 控制台 => 云服务器ECS => 网络和安全 => 安全组 => 配置规则 => 添加安全组规则

开通8000端口

部署 Nginx

Nginx 是用来处理静态文件请求的。比如当我们访问一个博客文章详情页面时,服务器会接收到下面两种请求:

  • 显示文章的详情信息,这些信息通常保存在数据库里,因此需要调用数据库获取数据
  • 图片、css、js 等存在服务器某个文件夹下的静态文件。

对于前一种请求,博客文章的数据需要借助 Django 从数据库中获取,Nginx 处理不了,它就会把这个请求转发给 Django,让 Django 去处理。
而对于后一种静态文件的请求,只需要去这些静态文件所在的文件夹获取,Nginx 就会代为处理,不再麻烦 Django,用 Django 去获取静态文件是很耗时的,但 Nginx 可以很高效地处理,这就是我们要使用 Nginx 的原因。

安装 Nginx

  • 安装Nginx
allenli@localhost:~$ sudo apt-get install nginx
  • 启动Nginx
allenli@localhost:~$ sudo service nginx start
  • 在浏览器中输入域名或 ip 检查是否安装成功 Nginx

收集静态文件

Django 项目中会有一些 CSS、JavaScript 等静态文件,为了能够方便地让 Nginx 处理这些静态文件的请求,我们把项目中的全部静态文件收集到一个统一的目录下。

  • 在 django 的 setting 文件中,添加下面一行内容:
(opcoder) allenli@localhost:~$ vim opcoder/opcoder/settings.py
STATIC_ROOT = os.path.join(BASE_DIR, 'static')  # 设置静态文件路径
  • 收集静态文件
(opcoder) allenli@localhost:~/opcoder$ python manage.py collectstatic

说明: 如果打开网站,发现 CSS 、JS 无法正常加载,可以重新收集静态文件。 静态文件

配置 Nginx

配置 Nginx 来处理用户请求。

  • 创建一个 Nginx 配置文件
allenli@localhost:~$ mkdir -p /home/allenli/opcoder/logs
allenli@localhost:~$ sudo vim /etc/nginx/sites-available/mynginx

server {
    # 字符集 端口 域名
    charset utf-8;
    listen 80;
    server_name www.opcoder.cn;
    # 日志
    access_log /home/allenli/opcoder/logs/nginx.access.log;
    error_log /home/allenli/opcoder/logs/nginx.error.log;
    # 不记录访问不到 favicon.ico 的报错日志
    location = /favicon.ico { access_log off; log_not_found off; }
    # static  media 的地址(与settings文件中保持一致)
    location /static/ {
        root /home/allenli/opcoder;
    }
    location /media/ {
        root /home/allenli/opcoder;
    }
    # gunicorn 中生成的文件的地址
    location / {
        include proxy_params;
        proxy_pass http://unix:/home/allenli/opcoder/opcoder.sock;
    }
}

server {
    listen 80;
    server_name opcoder.cn;
    rewrite ^(.*) http://www.opcoder.cn$1 permanent;
}
说明:
1. 第一个 server 是主要的配置,第二个 server 是实现 301 跳转,即让不带 www 的域名跳转到带有 www 的域名上面

2. /home/allenli/opcoder为Django 项目的主文件夹

3. roxy_pass 后面使用了 unix 套接字,其作用是防止端口冲突。

连接 Nginx 配置

上面的配置检查好之后,使用下面的命令来将这个配置跟 Nginx 建立连接。

  • 建立连接
allenli@localhost:~$ sudo ln -s /etc/nginx/sites-available/mynginx /etc/nginx/sites-enabled
  • 检查 Nginx 的运行情况
allenli@localhost:~$ sudo nginx -t
allenli@localhost:~$ sudo systemctl status nginx
  • 重启 Nginx
allenli@localhost:~$ sudo systemctl restart nginx

说明: 如果修改了 Nginx 的配置文件,那么需要依次执行下面两条语句去重启服务:

~$ sudo nginx -t
~$ sudo systemctl restart nginx

部署 Gunicorn

  • gunicorn是一个python Wsgi http server,能够与各种wsgi web框架协作
  • gunicorn 在你的 Web 服务器和 Django 之间作为中间服务器使用
  • Gunicorn 一般用来管理多个进程,有进程挂了Gunicorn 可以把它拉起来,防止服务器长时间停止服务,还可以动态调整 worker 的数量,请求多的时候增加 worker 的数量,请求少的时候减少。

安装和配置 Gunicorn

  • 在虚拟环境中安装 Gunicorn
(opcoder) allenli@localhost:~$ pip install gunicorn
  • 创建项目的 Gunicorn 配置文件(退出虚拟环境)
(opcoder) allenli@localhost:~$ deactivate 
allenli@localhost:~$ sudo vim /etc/systemd/system/gunicorn_opcoder.service

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=allenli
WorkingDirectory=/home/allenli/opcoder
ExecStart=/home/allenli/virtualenv/opcoder/bin/gunicorn --access-logfile - --workers 2 --bind unix:/home/allenli/opcoder/opcoder.sock opcoder.wsgi:application

[Install]
WantedBy=multi-user.target


说明:
1. User              表示当前用户名
2. WorkingDirectory  表示项目地址
3. ExecStart         表示虚拟环境中 gunicorn 的目录
4. workers 2         表示2个进程,可以自己更改
5. unix              表示生成一个 sock 文件的地址
6. opcoder.wsgi      表示项目中 wsgi.py 的地址

启动配置文件

  • 启动服务
allenli@localhost:~$ sudo systemctl start gunicorn_opcoder
  • 加入开机启动
allenli@localhost:~$ sudo systemctl enable gunicorn_opcoder
  • 检查服务状态
allenli@localhost:~$ sudo systemctl status gunicorn_opcoder
  • 检查项目的跟目录下面,是否会多一个 opcoder.sock 文件
说明:
1. 后续如果对 gunicorn 配置文件做了修改,那么应该先使用这个命令之后重启
allenli@localhost:~$ sudo systemctl daemon-reload

2. 然后再使用重启命令
sudo systemctl restart gunicorn_opcoder

注: 如果对生产环境 Django 代码进行变更,发现未生效,可以重启 gunicorn 服务。

代码迁移

将测试环境代码部署至生产环境后,部分代码需要进行相应的修改。

文件上传URL

将测试库代码部署至生产环境后,若发现用户头像不能显示,需进行如下配置。

  • urls.py
from django.conf.urls.static import static
from django.conf import settings
...

urlpatterns = [
    url(r'admin/', admin.site.urls),
    ...,
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)  # 加入这个才能显示media文件

全局404和500页面配置

  • 修改settings文件,将DEBUG模式设置为False
# settings.py
DEBUG = False
  • 创建全局404和500处理函数
# users/views.py

from django.shortcuts import render_to_response

def page_not_found(request):
    '''
    全局404处理函数
    '''
    return render_to_response('404.html')


def page_error(request):
    '''
    全局500处理函数
    '''
    return render_to_response('500.html')

404页面

访问页面

经过上述一系列操作后, 我们就可以正常访问页面了。 www.opcoder.cn

参考资料

http://www.tendcode.com/article/set-up-django-with-nginx-and-gunicorn/
https://www.cnblogs.com/justbreaking/p/7110447.html

原创文章,转载请注明出处:http://www.opcoder.cn/article/1/