时至今日还能回忆起第一次自己部署网站的痛苦(笑),当时前后搞了一周多,记得当时有个非常神奇的bug困扰了我好久:网站部署后随机丢失css和js文件,当时左查右查,最后发现是Django的SECRET_KEY
字段,我是这样写的:SECRET_KEY = get_random_secret_key()
,看似没有问题,但是当uWSGI启动多线程时,线程之间的SECRET_KEY
却因此不同,导致了这样神奇的问题……
趁着暑假新造个博客轮子出来。本来想着来个前后端分离,用next.js
负责前端响应,Django
作为后端,提供RESTful API。吭哧吭哧学了next.js
几天后,感觉整个项目反而变麻烦了,nodejs确实有很诱人的生态,但是对我这样个人开发者且自用的简单产品而言,丰富的生态和优雅的解耦带来的好处并没有那么多,最后还是用了熟悉的Django
,一个下午和晚上就把基本的系统写完了。之后几天又零碎修修补补了一些。记录一下部署的一些细节。
Linux环境
服务器用的之前买的tx云的服务器,2C2G CentOS 7,重置密码,用ssh
连上
因为众所周知的原因,用git拉GitHub仓库一直有问题,最后改用rsync
来同步了代码。rsync
可以通过ssh连接到远程服务器,增量式地传输文件,更详细的介绍
# receive from server
rsync -av ./dirname root@x.x.x.x:/dirname
# send to server
rsync -av root@x.x.x.x:/dirname ./
之后开始安装环境
# nginx
yum install nginx
# CentOS 7 yum can't install python > 3.6
yum install python3
# 虚拟环境
pip install virtualenv
# 激活虚拟环境
source /dirname/bin/activate
# 安装项目依赖
# 试试用pipreqs来生成依赖
pip -r requirements.txt
# uWSGI
pip install uwsgi
配置Django
首先主要是settings.py
里面的一些配置
# ...
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY') or "django-insecure-#8p5gl1eoy_2--qhg%quq53+l9yxoy=dw4+2*)1azt=3g+z&v1"
DEBUG = os.environ.get('DJANGO_PROD_VALUE') != 'TRUE'
ALLOWED_HOSTS = [os.environ.get('DJANGO_HOST') or '*']
# ...
STATIC_ROOT = "/var/www/myblog/static/"
STATIC_URL = "static/"
MEDIA_ROOT = "/var/www/myblog/media/"
MEDIA_URL = "media/"
# ...
最好把SECRET_KEY
这样敏感的字段从环境变量里面读取,并且每次部署的时候重新生成新的,DEBUG
也可以从环境变量里面读取,这样开发环境(本地)和生产环境(服务器)里面的代码就可以保持一致,不需要每次都要改那个DEBUG = True
另外STATIC_ROOT
和MEDIA_ROOT
是用于生产环境里保存静态文件的地方,这两个路径会提供给nginx
,生产环境里,静态/媒体文件都会丢给nginx
而不是Django
来进行处理。
运行命令,让Django
自动整理静态文件并搬运到STATIC_ROOT
里面。
python manage.py collectstatic
配置nginx
找到nginx的配置文件进行编辑
vim /etc/nginx/nginx.conf
在http
块的最后加上一行(如果没有/etc/nginx/sites-enabled/
目录就mkdir -p
一下)
http{
# ...
# add this line
include /etc/nginx/sites-enabled/*;
}
这样nginx就会加载所有放在/etc/nginx/sites-enabled/
目录下的配置文件。
然后在项目目录下编写一个本项目的nginx配置文件nginx.conf
# the upstream component nginx needs to connect to
upstream django {
# server unix:///path/to/your/mysite/mysite.sock; # for a file socket
server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}
# configuration of the server
server {
# the port your site will be served on
listen 80;
# the domain name it will serve for
server_name x.x.x.x; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
autoindex on;
alias /var/www/myblog/media/; # your Django project's media files - amend as required
}
location /static {
autoindex on;
alias /var/www/myblog/static/; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /dirname/uwsgi_params; # the uwsgi_params file you installed
}
}
其中/dirname/uwsgi_params
指向的uwsgi_params
文件可以在/etc/nginx/
文件夹下或这里找到。而/var/www/myblog/static/
就是之前的STATIC_ROOT
。
这样媒体和静态文件就由nginx提供服务,其他的由Django通过uWSGI来提供服务。
然后将这个配置文件链接到/etc/nginx/sites-enabled/
ln -s /path/to/your/conf /etc/nginx/sites-enabled/
之后启动nginx即可,还没配置uWSGI,但是可以先测试一下静态文件是否能够访问到
配置uWSGI
一个web服务器面对的是外部世界。它能直接从文件系统提供文件 (HTML, 图像, CSS等等)。然而,它无法 直接与Django应用通信;它需要借助一些工具的帮助,这些东西会运行运用,接收来自web客户端(例如浏览器)的请求,然后返回响应。
一个Web服务器网关接口(Web Server Gateway Interface) - WSGI - 就是干这活的。 WSGI 是一种Python标准。
组件栈看起来将是这样的:
the web client <-> the web server <-> uwsgi <-> Django
项目目录下创建uWSGI的配置文件uwsgi.ini
[uwsgi]
# Django-related settings
# the base directory (full path)
chdir = /path/to/your/project
# Django's wsgi file
module = project.wsgi
# the virtualenv (full path)
home = /path/to/virtualenv
# process-related settings
# master
master = true
# maximum number of worker processes
processes = 2
# the socket (use the full path to be safe
socket = 127.0.0.1:8001
# ... with appropriate permissions - may be needed
# chmod-socket = 664
# clear environment on exit
vacuum = true
然后再启动uwsgi即可
uwsgi --ini uwsgi.ini
若修改项目代码后,杀掉uwsgi再重启uwsgi
pkill -f uwsgi -9