本来想着直接学习用Docker部署,不过考虑了下,还是得先尝试下常规部署方式。先熟悉下经典的流程,才能更好的了解新工具的优势。话不多说,开干。
首先我们需要理解下,部署到底需要做什么以及为什么做。
Gunicorn:这是一个WSGI服务器,专门用来和Python Web框架沟通,能够高效启动和管理多个Django进程(毕竟不可能就一个人用我们的网站应用吧)。
Nginx:高性能的Web服务器,负责接收用户请求,处理高并发问题。如果请求一些动态数据,需要Django处理,那么就会将请求转发到Gunicorn,Gunicorn在给到Django去做。这就叫反向代理。而如果是静态数据,Nginx可以直接获取的,就不会再让Django去做。此外,Nginx起到了安保作用,具备各类安全规则。
大体流程:用户请求 > DNS解析到服务器IP > 服务器防火墙 > Nginx > Nginx判断为动态请求 > 转发给Gunicorn > Gunicorn调用Django处理 > Django返回响应 > Gunicorn拿到响应 > Nginx拿到响应 > 返回用户浏览器。
0. 准备工作
虽然我们的程序没问题,不过搞python懂得都懂,环境要老命了。所以得在本地准备个requirements.txt文档,便于服务器环境得安装。
django
djangorestframework
drf-spectacular
mysqlclient
服务器上有宝塔面板,所以我们也就没必要从指令搞了。有些地方能图形化操作就图形化操作了。
1. 上传代码+数据库创建
在服务器上新建一个文件夹/www/wwwroot/miaomiaocrm,点击上传,把打包的整个项目上传上来。打包时候注意,.git和.idea啥的就不用打包进去了,主要是主程序、app文件夹、静态文件等。
然后我们在服务器上创建个新的MySQL数据库,记得数据库名称、用户和密码,同步修改到/www/wwwroot/miaomiaocrm/mycrm/setting.py文件。
2. Django项目配置
除了刚才的数据库配置,还需要修改/www/wwwroot/miaomiaocrm/mycrm/setting.py文件下的DEBUG = False,关闭测试模型,防止敏感信息的泄露。
还有ALLOWED_HOSTS=[‘文件夹名,’‘网站域名’,‘服务器IP地址’]
添加配置静态文件设置,STATIC_ROOT = BASE_DIR 'collected_static'以便告诉Nginx去哪里找静态文件。
3. 使用python项目管理器创建项目

我们打开项目的终端(也就是项目的右侧那个终端),然后pip install -r requirements.txt。如果报错,那可能是服务器追求简约,缺失编译工具箱,我们安装下就好yum install gcc python3-devel mariadb-devel -y。然后执行数据迁移python manage.py migrate,创建管理员账号python manage.py createsuperuser,收集静态文件python manage.py collectstatic。
数据迁移错误处理:
(1)django.db.utils.OperationalError: (2002, "Can't connect to local server through socket '/var/lib/mysql/mysql.sock' (2)")好像是丢了一个连接文件,导致无法和MySQL数据库连接,我搜了下服务器上,似乎没有这个文件,所以我就直接把setting.py里数据库HOST改为127.0.0.1了。
(2)django.db.utils.NotSupportedError: MySQL 8.0.11 or later is required (found 5.7.40).一看就是版本不对……没找到宝塔的切换数据库版本按钮,只能临时备份、删除数据库,重新下载了。记得改数据库密码~
4. 配置Nginx
折腾了一会,发现有点复杂……具体问题在于我只有一个域名,hcblj.top,但是这个是绑定博客的。似乎可以通过修改Nginx配置来让crm成为一个子程序,比如hcblj.top/crm/就可以进入我的喵喵CRM系统了。这个操作叫分发。
我们以博客网站作为“主”网站,然后在这个主网站的配置里,添加一个规则来把 /crm/ 的所有流量“代理”给Django 应用。
在博客的配置文件里加入如下代码
#CRM系统访问
location /crm/ {
proxy_pass http://127.0.0.1:8866/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
然后CRMsetting文件里,修改:
ALLOWED_HOSTS = ['hcblj.top', 'www.hcblj.top']
STATIC_URL = '/crm/static/'
然后重新给静态文件指定目录:
python manage.py collectstatic
记住路径,然后博客的配置文件里加入如下代码
location /crm/static/ {
alias 路径(比如/www/wwwroot/miaomiaocrm/staticfiles/);
}
终于可以访问了,不过主页绑定到了/crm/home/路径下。不过还有很多地方不太明白,再说把。
hcblj.top/crm/home/就是主页。
hcblj.top/crm/register/就是注册。
hcblj.top/crm/login/就是登录。
分发错误
昨天测试好好的,今天登陆了下又发现问题了……
上述问题确实能够访问CRM,但是仍然有个问题……就是我直接访问,比如再网页浏览器地址栏输入上述网址没毛病,但是网页内点击跳转,比如主页点击注册,就会失败。比如hcblj.top/crm/home/变成hcblj.top/home/。
最初我单纯以为是程序内路由的问题。后来测试了一下,似乎也不太行。查了下,问题大体是这样的:
- 浏览器向 https://hcblj.top/crm/home/发出请求
- Nginx 接待,看到 URL 以 /crm/ 开头,它知道这个请求应该交给 Django 处理。于是它根据 proxy_pass 指令,把请求转发给后端的 Django 程序(运行在 127.0.0.1:8866)
- 在转发的时候,因为我们的配置是 location /crm/ { proxy_pass …:8866/; }(注意两个末尾的斜杠),Nginx 会“剥掉” /crm/ 这个前缀,只把后面的 /home/ 发送给 Django
- Django 收到的请求路径是 /home/。它完全不知道自己是活在 /crm/ 这个目录下的。它认为自己就是网站的根目录。
- 当 Django 的模板(比如通过 {% url ‘home_page’ %})或者后端代码(通过 redirect(‘home_page’))需要生成一个指向“主页”的链接时,它会根据自己的视角,生成 /home/ 这个路径。
- 浏览器收到了这个 /home/ 的路径,就会去请求 https://hcblj.top/home/。而这个地址,Nginx 并没有配置给 Django,而是交给了你的博客主程序,所以就出错了。
简单来说,Nginx 知道有 /crm/,但 Django 不知道。信息不对等导致了链接生成错误。
所以我们得让Django知道,实际上有个/crm/。两种解决方法,一种是Django内处理,一种是Nginx内处理。
Django内处理:
# setting.py文件下修改
FORCE_SCRIPT_NAME = '/crm'
这种处理解决了一些基本网页跳转的问题,但是涉及到API的调用,比如新增客户,似乎还有问题。可能是前端问题,这个问题等下排查,我们先采用Nginx处理的方法。
Nginx方案不行……我们回到这个方案。这个方案目前的问题主要是API调用出了问题,网页之间的跳转完全正常。应该是前端JS代码那儿出了问题,某些跳转给写死了。
TMD……我发现AI就是个傻逼,Gemini采用了一个{{request.get_script_prefix}}来获取“/crm”,我非常怀疑这个获取是错误的。ctrl+u看源代码,明显是获取失败。结果Gemini死活不认,非要认为是setting.py文件没有读取或者重启的问题。然而setting.py如果没有读取,肯定是网页内跳转都是失败的,不可能单独一个API调用出问题。改了半天都是错的。吊毛AI,真TM傻逼。气死我了,浪费我半天时间。我改成硬编码,立马就对了。我真的艹了。
TMD……又有问题了。改成硬编码’/crm’确实可以写入数据了,但是TMD一刷新页面又没有数据了。我检查了下服务器数据库,写入是正确是,数据成功存入了数据库。所以问题八成就是在前端或者展示这一块。检查了下view视图函数,果然有问题,api_url = request.build_absolute_uri(‘/api/customers/’),获取域名,拼接。成功丢失“/crm”,操了。直接TM查询数据库就行,调用个勾八API啊。改了,圆满解决问题。
TMD……又又又有问题了。这次是删除失败,删除客户出现问题。我TM就是改了个访问路径,加了个/crm/,怎么这么多吊毛事。哦,单纯代码写错了$写成了s。
当前代码修改全是在服务器上,事后还要返回修改我的本地代码,真蠢啊~
OK,问题解决,网站成功上线!后续继续增加权限控制和一些功能。
Nginx处理:
这是一种标准的做法。修改 Nginx 配置,让它在每次转发请求时,都加一个特殊的“信封”,告诉后端程序它的子路径是什么。登录宝塔面板,到博客网站的【设置】->【配置文件】。
修改后的代码块应该是这样的:
# CRM系统访问
location /crm/ {
proxy_pass http://127.0.0.1:8866/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Script-Name /crm;
}
然而TMD也有问题……页内跳转还是报错,这有可能是中间Gunicorn出了问题,不过尝试修改了Gunicorn配置文件,然而还是不行,该方案放弃。