如果是新服务器先要进行基本的配置
部署前应用配置
开发环境与生产环境中的应用一般会有两套不同的配置。比如 DEBUG 选项,数据库配置等。
对于 setting.py 文件, 在生产环境中我们要设置 DEBUG, SECRET_KEY 以及数据库密码等私密的设置。为了项目的安全这些设置应该最好从环境变量加载,或从仅供服务的文件中读取。
为了更好的统一线上和线下两个环境, 我们使用python-dotenv
工具. 有了这个工具, 我们可以将配置信息写在.env
文件中,然后使用下面的代码加载配置信息到环境变量中:
# settings.pyfrom dotenv import load_dotenvload_dotenv()
具体配置方法:
进入虚拟环境, 安装 python-dotenv
pip install python-dotenv
在 Django 项目根目录处建立.env
文件(与manage.py 同目录), 并添加配置
DJANGO_DEBUG=Ture
修改 setting.py 文件,将一些关键配置改成从环境变量中读取, 没有就设为默认值
import osfrom dotenv import load_dotenvload_dotenv()SECRET_KEY = os.environ.get('SECRET_KEY', 'mzi&f@)*4985)m19oj+x-hg4$hi!478v)+dz)bh+mgiz!zjg9n')DEBUG = os.environ.get('DJANGO_DEBUG', False)# 当 DEBUG=Flase 时, 设置的能够访问的主机ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '.xxmblog.top', '<服务器的IP地址>']# 数据库设置, 便于在生产环境中直接改为 MySQL 数据库DATABASES = {'default': {'ENGINE': os.environ.get('DATABASE_ENGINE') or 'django.db.backends.sqlite3','NAME': os.environ.get('DATABASE_NAME') or os.path.join(BASE_DIR, 'db.sqlite3'),'USER': os.environ.get('DATABASE_USER'),# 用户名,可以自己创建用户'PASSWORD': os.environ.get('DATABASE_PASSWORD'), # 密码'HOST': os.environ.get('DATABASE_HOST'), # mysql服务所在的主机ip'PORT': os.environ.get('DATABASE_PORT'), # mysql服务端口}}# ...STATIC_URL = '/static/'# 增加下面的, 便于在生产环境中收集静态文件STATIC_ROOT = os.path.join(BASE_DIR, 'static')
接下来,关键的是,.env
保存一些私密的配置,不要添加到git中。
开发环境的.env
:
DJANGO_DEBUG 为非空字符串时为 Ture, 不设置默认为 Flase# 其他一些数据库配置
生产环境中的.env
设置后面单独说明。
当有其他生产环境和开发环境不同的配置时,都让Django从环境变量中读取,我们就写在.env
文件中。这样部署的时候就不用修改源代码了。
其他配置:
静态文件收集
为了使 Nginx 方便的处理静态文件的请求,生产环境中需要将全部静态文件收集到一个统一的目录下。
先添加如下配置:
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_ROOT 指明了静态文件的收集目录,到生产环境中有用
导出依赖库
进入虚拟环境, 执行下列命令
pip freeze > requirements.txt
会生成一个 requirements.txt 文件, 里面包含了虚拟环境中安装的所有依赖。
到了服务器上,只需要执行
pip install -r requirements.txt
就能安装里面列的所有库了。
上传到 Github
注意到
.env
文件不能上传,服务器应该自己建一个
db.sqlite3
不上传, 因为这是本地的测试数据库, 到了生产环境, 应该用其他的数据库了
venv
文件夹不上传
在服务器上安装应用
在自己的家目录下(如home/xxm/
) 创建文件夹
➜ ~ mkdir sites➜ ~ mkdir sites/
所有的网站放在 sites 目录中,网站的项目以域名区分, 进入目录。
通过git clone
将应用下载到该目录中
然后进入项目目录并创建虚拟环境:
$ python3 -m venv venv$ source venv/bin/activate
此时的项目结构:
home/xxm/sites/www.xxmblog.top/blog-django/blogproject/venv/.gitignorerequirements.txt
安装项目依赖
先安装必要的包
(venv) $ pip install -r requirements.txt
除了requirements.txt中的包之外,还要安装生产部署需要的两个包。gunicorn软件包是Python应用程序的生产Web服务器。 mysqlclient 软件包包含MySQL驱动程序
(venv) $ pip install gunicorn mysqlclient
如果安装 mysqlclient 出现错误, 运行下面的命令。
sudo apt-get install python-dev python3-devsudo apt-get install libmysqlclient-devpip install pymysqlpip install mysqlclient
配置 MySQL
MySQL 的安装不做说明, 具体讲述如何让 Django 使用 MySQL 数据库。
下列命令创建名为 blog-django 的新数据库,并创建一个具有完全访问权限的同名用户:
mysql> create database blogdjango character set utf8 collate utf8_bin;mysql> create user 'blogdjango'@'localhost' identified by '<db-password>';mysql> grant all privileges on blogdjango.* to 'blogdjango'@'localhost';mysql> flush privileges;mysql> quit;
需要用你选择的密码来替换<db-password>
, 这将是 blogdjango 数据库用户的密码,所以不要使用你已为root用户选择的密码
接下来就是修改 setting.py 文件,让 Django 使用刚刚创建的数据库。但是由于我们前面使用了 dotenv,seeting.py 的一些配置已经从环境变量中读取, 所以我们只需配置.env
文件即可
配置.env
创建一个.env
文件, 与 manage.py 同目录。
在里面输入:
SECRET_KEY=<随机字符串>DATABASE_ENGINE=django.db.backends.mysqlDATABASE_NAME=blogdjangoDATABASE_USER=blogdjangoDATABASE_PASSWORD=<刚刚创建用的密码>DATABASE_HOST=localhostDATABASE_PORT=3306
SECRET_KEY 使用一个随机字符串
DJANGO_DEBUG 不设置时,DEBUG为FALSE
其他为MySQL的数据库配置
收集静态文件
虚拟环境下继续运行python manage.py collectstatic
命令收集静态文件到 static 目录下:
数据库迁移
虚拟环境下继续运行 python manage.py migrate 命令创建数据库文件:
python manage.py makemigrationspython manage.py migrate
创建超级用户
虚拟环境下继续运行 python manage.py createsuperuser 命令创建一个超级用户,方便我们进入 Django 管理后台
尝试运行一下应用
python manage.py runserver
如果上面的命令没有出错的话,一般就没有问题了。
设置 Gunicorn 和 Supervisor
当使用python manage.py runserver
运行服务器时, 我们使用的是 Django 自带的Web服务器。这个服务器在开发过程中很有用,但并不适用于生产环境,所以我们改用 Gunicorn, 它是一个纯粹的Python Web服务器, 并且支持高并发。
尝试在 gunicorn 下启动 blogproject:
gunicorn -b localhost:8000 -w 4 blogproject.wsgi:application
-b
告诉 gunicorn 在哪里监听请求,我在8000端口上监听了内部网络接口。在没有外部访问的情况下,运行 Python Web 服务器很快。当有外部请求的时候,我们就需要一个更快的Web服务器,比如 nginx,它可以优化客户端的所有静态文件的请求,并将任何请求转发到内部服务器。后面我们会设置 nginx。
-w
配置gunicorn将运行多少worker
blogproject.wsgi:application
告诉gunicorn如何加载应用程序实例. 冒号前的名称是包含应用程序的模块,冒号后面的名称是此应用程序的名称。
运行了上面的命令后,我们看到:
(venv) ➜ blogproject git:(master) ✗ gunicorn -b localhost:8000 -w 4 blogproject.wsgi:application[-08-16 11:18:50 +0800] [5674] [INFO] Starting gunicorn 19.9.0[-08-16 11:18:50 +0800] [5674] [INFO] Listening at: http://127.0.0.1:8000 (5674)[-08-16 11:18:50 +0800] [5674] [INFO] Using worker: sync[-08-16 11:18:50 +0800] [5677] [INFO] Booting worker with pid: 5677[-08-16 11:18:50 +0800] [5678] [INFO] Booting worker with pid: 5678[-08-16 11:18:50 +0800] [5680] [INFO] Booting worker with pid: 5680[-08-16 11:18:50 +0800] [5679] [INFO] Booting worker with pid: 5679
gunicorn 监听 http://127.0.0.1:8000, 并启动了4个worker.
[Ctrl+C]
退出进程。
可以看到,目前我们想要启动服务器,每次都要输入一遍上面的命令,如果进程崩溃了,还要手动输入上面的命令让服务器重新启动。这真的很傻,所以我们使用一个 supervisor 的应用。
supervisor 的功能:
可以让这个进程后台运行,并持续监控如果服务器崩溃退出,这个进程可以重新自动启动而且如果机器重新启动,服务器在启动时自动运行,而无需人工登录和启动
安装:
sudo apt-get install supervisor
supervisor 使用配置文件来告诉它要监视什么程序以及如何在必要时重新启动它们
配置文件必须存储在/etc/supervisor/conf.d
中
对于我们这个 blogproject 应用,我们创建一个 blogproject.conf 配置文件:
/etc/supervisor/conf.d/blogproject.conf:Supervisor配置。
[program:blogproject]command=/home/xxm/sites//blog-django/venv/bin/gunicorn -b localhost:8000 -w 4 blogproject.wsgi:applicationdirectory=/home/xxm/sites//blog-django/blogprojectuser=xxmautostart=trueautorestart=truestopasgroup=truekillasgroup=true
command
,directory
和user
设置告诉supervisor如何运行应用程序。 如果计算机启动或崩溃,autostart
和autorestart
设置会使microblog自动重新启动。stopasgroup
和killasgroup
选项确保当supervisor需要停止应用程序来重新启动它时,它仍然会调度成顶级gunicorn进程的子进程。
编写此配置文件后,必须重载supervisor服务的配置才能导入它:
$ sudo supervisorctl reload
像这样,这个gunicorn web服务器就已经启动和运行,并处于监控之中!
查看状态:
sudo supervisorctl status
如果出现下面的内容,可能是配置文件出错了
blogproject FATALExited too quickly (process log may have details)
如果是下面表示正在运行:
blogproject RUNNING pid 5865, uptime 0:00:03
其他命令
sudo supervisorctl stop xxx # 关闭 xxxsudo supervisorctl restart xxx # 重启 xxx
配置 Nginx
由 gunicorn 启动的 blogproject 应用服务器现在运行在本地端口8000. 我们想要让服务器能够被外部世界访问。
首先打开两个端口 80 和 443 用来处理应用程序的 Web 通讯。如果是阿里云服务器需要在控制台上配置安全组。
我们直接使用 https, 配置端口80将所有流量转发到将要加密的端口443.
首先创建一个 SSL 证书, 这个证书只能用来测试,当用户访问的时候, Web 浏览器会警告用户证书不是由可信证书颁发机构颁发的。
mkdir certsopenssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \-keyout certs/key.pem -out certs/cert.pem
生成的时候填写的信息,将包含在 SSL 证书中, 用户在浏览器访问的时候可以查看。
命令的结果将生成名为key.pem和cert.pem的两个文件。
为了使用 nginx, 为我们就要编写一个配置文件,这个文件位于/etc/nginx/sites-enabled
中,
通常刚安装完 Ngnix,在这个位置有一个默认的测试站点, 我们将其删除:
$ sudo rm /etc/nginx/sites-enabled/default
然后创建 blogproject 配置文件:
/etc/nginx/sites-enabled/blogproject:Nginx配置。
server {# 监听 80 端口listen 80;server_name _;location / {# redirect any requests to the same URL but on httpsreturn 301 https://$host$request_uri;}}server {# 监听 443 端口listen 443 ssl;# 服务器域名server_name _;# 刚刚生成的自签名ssl证书的位置ssl_certificate /home/xxm/sites//blog-django/certs/cert.pem;ssl_certificate_key /home/xxm/sites//blog-django/certs/key.pem;# 将访问和错误日志写入 /var/logaccess_log /var/log/microblog_access.log;error_log /var/log/microblog_error.log;location / {# forward application requests to the gunicorn serverproxy_pass http://localhost:8000;proxy_redirect off;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}# 所有URL 带有 /static 的请求均由 Nginx 处理,alias 指明了静态文件的存放目录。location /static {alias /home/xxm/sites//blog-django/blogproject/static;expires 30d;}}
添加此文件后,你需要告诉nginx重新加载配置以激活它:
$ sudo service nginx reload
浏览器输入域名或者服务器的IP地址,应该可以看到访问成功了。
应用更新
当应用更新的时候,往往需要重复下列的过程:
从 github 中拉取应用
git pull
可能需要修改.env
文件, 增加环境变量进入虚拟环境, 安装额外的依赖
pip install -r requirements.txt
收集静态文件
python manage.py collectstatic
数据库迁移
python manage.py makemigrationspython manage.py migrate
重启进程
sudo supervisorctl restart blogproject
重启nginx
sudo service nginx reload