Kika's
Blog
图片简介 | CC BY 4.0 | 换一张

博客网站部署杂记

2023-08-08

时至今日还能回忆起第一次自己部署网站的痛苦(笑),当时前后搞了一周多,记得当时有个非常神奇的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_ROOTMEDIA_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

参考