Skip to content

before

部署项目是一个复杂且麻烦的过程:

  • 平台不同,ubuntu、Windows iis、centos7;
  • 项目不同,它依赖的三方软件也不同,要求也不同;
  • 大家的水平也不同,小白的话,有点难;
    • 对于云服务器也不太了解,设置安全组/防火墙;
    • 对于MySQL软件的用户、权限设置不清楚;
  • 对于Linux、云服务器、nginx,都要有了解。
  • 对于查看各种日志不了解;500 ERROR
    • 项目本身在本地都跑不通的这些bug,没有解决完,就上线;
    • 项目开发中,在某些具体功能中把代码写死的,比如连接127.0.0.1的本地开发环境的配置;

务必要记住

  • 本地开发环境,在把项目代码上传到云服务器之前;要在本地进行足够的测试;而且,要把所有连接本地的一些配置,都要改为线上环境的;在项目中,写死的路径、连接,一定要统一的放到配置文件中。
  • 尽量避免出现中文路径和中文文件名。包括一些特殊字符。

物料准备

基于centos7 + nginx + mysql + redis + uwsgi + django + vue3 + ssl + 备案好的域名完成的部署。

所以需要准备:

  • 一个云服务器,配置要求:2核2G内存,带宽,阿里1M;腾讯300M/400M都行;硬盘40G+;系统是cnetos7.x(7.3/7.5/7.6)。
    • 云服务器这块,一般新用户优惠一年100元左右;但如果续费可就不是这个价了。
  • 申请并购买域名,域名和云服务器厂家选择一致就行。
  • 本地要安装xshell、xftp,个人免费版本,连接:https://www.xshell.com/zh/xshell/
  • 本地准备并调试好你的项目。

部署架构

如果是小型项目,访问量、数据量都不大,买个稍微好点轻量级的云服务器就完了,比如4核8G,当然个人学习用2核2G内存也不是不能用。

直接将前后端项目、数据库、NGINX都部署一个服务器上就完了。

1832669525120647168.png

如果是中大型项目,就需要考虑前后端项目分开来部署了:

1832669525317779456.png

本篇演示第一种部署方式,前后端都部署到一台云服务器上。

后端部署

本地准备

本地:生成requirements.txt文件

更新requirements.txt文件,如果没有就是生成,项目根目录终端执行命令:

bash
pip freeze > requirements.txt

PS:如果你的项目没有requirements.txtreadme.md说明文件,基本算是不太成熟的开发人员。相当于卖电脑,不附带说明书。

借用别的项目的截图额外的说下可能遇到的情况,如下图,生成的requirements.txt中,看看是不是有不合法的格式,比如有些时候用的是conda下载的包,有可能就不太合法,如果我们不注意的话,线上pip下载时就报错了,我们这里要提前避开这个问题。

1832669526001451008.png

bash
# 合法的
async-timeout==4.0.2

# 不合法的,我们可以终端执行下pip list,然后定位到这个不合法的包,看它的版本,然后手动调整下就好了
# certifi @ file:///C:/b/abs_85o_6fm0se/croot/certifi_1671487778835/work/certifi  # 把原来的不合法的注释掉就完了
# 根据pip list 结果,手动修改之后如下所示
certifi==2022.12.7

1832669526802563072.png

OK,到这一步,本地要做的操作,基本上完事了。

本地:导出表结构

有兴趣可以参考:https://www.cnblogs.com/Neeo/articles/11303149.html#普通参数

bash
# 同时备份数据库、表和数据
mysqldump -uroot -p --default-character-set=utf8 -B 要备份的数据库 >要保存的数据文件名.sql

# 如果项目用到多个数据库,那么需要把多个数据库都备出来,多个库以空格分隔
mysqldump -uroot -p --default-character-set=utf8 -B db1,db2,dbn >db.sql

# 只备份数据库和表,不包含数据
mysqldump -uroot -p --default-character-set=utf8 --opt -d db1 >db.sql

我的项目用到的数据库是supplier,所以,我只需要将这一个数据库备份出来即可。在项目根目录下执行下面的命令:

bash
mysqldump -uroot -p --default-character-set=utf8 -B supplier >data.sql

备份数据,我不推荐用navicat,因为sql不全,推荐mysqldump命令。

本地:调整配置文件

把项目中所有的数据库连接、或者其他连接本地的,都需要调整为线上环境的。

settings.py

python
# 这种写法适用于多种不同的环境,你可以一套环境一个配置文件,根据ENV_的值的不同,导入不同的配置项
# 项目如果是线上环境是,那么ENV_的值可以是pro,如果是测试环境,那么ENV_的值可以是test,这个你可以自己约定,主要是用于灵活的加载各种配置
# ENVS_ = 'local'
# ENVS_ = 'test'
ENVS_ = 'pro'

try:
    if ENVS_ == 'local':
    # 放到最后,是为了将前面的覆盖
        from .local_settings import *
    elif ENVS_ == 'pro':
        from .pro_settings import *
except ImportError as e:
    print(f'------------> 项目导入{ENVS_}环境配置报错 <------------>', e)

线上环境配置pro_settings.py

python
# -*- coding = utf-8 -*-
import os

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# debug先暂时为True,方便调试时排除一些报错
DEBUG = True

# ALLOWED_HOSTS这里也要改,因为将来这个后端要单独对外提供服务,所以,列表中我写了个"*"
ALLOWED_HOSTS = ["*"]

# Redis配置
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",  # 安装redis的主机的 IP 和 端口
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {
                "max_connections": 1000,
                "encoding": 'utf-8'
            },
            "PASSWORD": "*****"  # redis密码
        }
    }
}

# MySQL数据库配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'supplier',  # 你的数据库名称
        'USER': 'zhangkai',  # 你的数据库用户名
        'PASSWORD': '******',  # 你的数据库密码
        'HOST': "localhost",  # 你的数据库主机,留空默认为localhost
        'PORT': '3306',  # 你的数据库端口
    }
}

# 支付相关配置
ALI_APP_PRI_KEY_PATH = os.path.join(BASE_DIR, 'files', '应用私钥_new.txt')
ALI_PUB_KEY_PATH = os.path.join(BASE_DIR, 'files', '支付宝公钥_new.txt')
ALI_APPID = "9021001231312313"
# 前后端的本地ip和端口都改为对应线上的
ALI_GATEWAY = "https://openapi-sandbox.dl.alipaydev.com/gateway.do"
ALI_RETURN_URL = "https://api.neeo.cc/api/wallet/charge/notify/"
ALI_NOTIFY_URL = "https://api.neeo.cc/api/wallet/charge/notify/"
CLIENT_WALLET_URL = "https://web.neeo.cc/front/wallet/"

# 收集静态文件,需要指定STATIC_ROOT
STATIC_ROOT = "/scm3/allstatic/"

都调整完了之后,就可以把项目打个zip压缩包等待上传到云服务器了。

线上环境准备

云服务器准备

硬件要求:一个云服务器,配置要求:2核2G内存,将来根据访问量可以调整,带宽,阿里1M;腾讯1M带宽以上,300M/400M月流量都行,将来根据访问量可以调整;硬盘40G+,将来根据访问量可以调整;系统是cnetos7.x(7.3/7.5/7.6)。

选择阿里、华为、腾讯、都可以。我这里以腾讯云为例,演示线上部署。

如果你是刚入门接触这块内容,可以直接通过这个链接购买:https://cloud.tencent.com/act/cps/redirect?redirect=5990&cps_key=ea649ffd54f16822874e728926cba400&from=console,或者去看看腾讯云的最新的活动,选个轻量应用服务器,配置不用那么高,价位100元左右的即可。

1832669527280713728.png

1832669527901470720.png

买完之后,进入控制台,创建远程root账号的密码:

1832669528950046720.png

我个人喜欢通过xshell连接云服务器操作。所以这里讲下xshell如何连接云服务器,xshell官网下载: https://www.xshell.com/zh/xshell/ ,你留个姓名和邮箱即可使用正版的个人免费版。安装就默认就行了。连接参考下图:

1832669529663078400.png

1832669530917175296.png

1832669531777007616.png

云服务器控制台:放开云服务器的安全组

这个步骤很重要,好多同学都会忘记这个,搞的项目部署好了没法访问。

安全组或者叫做防火墙是云服务器厂家在你买的服务器之外套的安全壳。

云服务器控制台中,找到你的实例对应的安全组。

1832669532557148160.png

等项目完整的部署好了之后,为了保证数据安全,你应该检查安全组,将这些3306,6379,8000这些端口都应该在安全组中再删掉,因为将来我们服务器只对外提供域名访问,也就是只对外提供80和443端口,这两个端口我们都有NGINX进行接受处理,其他端口,尤其是数据库相关的端口,千万不能直接对外提供远程访问,因为容易被黑。

但也要保证80和443在安全组中是开放的。

线上:关闭防火墙

服务器有了,执行下面的命令,关闭防火墙,然后安装一些必要的工具插件。

bash
systemctl stop firewalld.service
systemctl disable firewalld.service
systemctl status firewalld.service
sed -i.ori 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
yum update -y
yum -y install gcc automake autoconf libtool make
yum -y install net-tools
yum -y install vim
yum -y install wget
yum install lrzsz


# ........解释........
# 查看防火墙状态
systemctl status firewalld.service
# 关闭防火墙
systemctl stop firewalld.service
# 禁止开机启动防火墙
systemctl disable firewalld.service
# 启动防火墙
systemctl start firewalld.service
# 防火墙随系统开启启动
systemctl enable firewalld.service
# 关闭selinux,提高了系统的安全性,但关闭它可以释放系统资源,提高服务器的性能,避免一些程序的兼容性问题等等
[root@r ~]# sed -i.ori 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config

线上:Python3.9.9解释器安装

Python3.6/Python3.11参考:https://www.cnblogs.com/Neeo/articles/12829625.html#编译安装python36

演示cenots7中安装Python3.9,参考:https://www.cnblogs.com/Neeo/articles/12829625.html#编译安装python311

bash
yum install -y epel-release
yum update -y
yum install gcc patch libffi-devel python-devel  zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel -y


cd /opt/
wget https://cdn.npmmirror.com/binaries/python/3.9.9/Python-3.9.9.tgz
tar -zxvf Python-3.9.9.tgz
cd /opt/Python-3.9.9
./configure --prefix=/opt/python399/  && make && make install

配置环境变量:

bash
echo "export PATH=/opt/python399/bin:\$PATH" >> /etc/profile
cat /etc/profile
source /etc/profile

# 添加软连接
ln -s /opt/python399/bin/python3.9 /usr/bin/python3.9
ln -s /opt/python399/bin/pip3.9 /usr/bin/pip3.9

任意路径测试:

bash
[root@cs opt]# python3.9 -V
Python 3.9.9
[root@cs opt]# pip3.9 -V
pip 21.2.4 from /opt/python399/lib/python3.9/site-packages/pip (python 3.9)

线上:MySQL8.0安装

https://www.cnblogs.com/Neeo/articles/17135006.html#for-centos7x

线上:nginx安装

下载依赖

bash
yum update -y
yum -y install gcc gcc-c++ pcre pcre-devel  zlib zlib-devel openssl openssl-devel libxml2-devel libxslt-devel gd-devel GeoIP-devel jemalloc-devel libatomic_ops-devel perl-devel  perl-ExtUtils-Embed
 
#安装Nginx需要先将官网下载的源码进行编译,依赖gcc环境
 
# PCRE是一个perl库,包括perl兼容的正则表达式库。Nginx的http模块使用pcre库来解析正则表达式 
 
# zlib库提供很多种压缩解压缩方式,Nginx使用zlib对http包的内容进行gzip
 
# OpenSSL是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的秘钥和证书封装管理功能及
#SSL协议,并提供丰富的应用程序供测试或其它目的使用。Nginx不仅支持http协议,还支持HTTPS协议(即在SSL协议上传输http)。

下载

去这个链接:https://nginx.org/en/download.html

1832669533018521600.png

bash
cd /opt
wget https://nginx.org/download/nginx-1.24.0.tar.gz
ls

[root@cs opt]# ls
nginx-1.24.0.tar.gz

解压

bash
cd /opt
tar -zxvf nginx-1.24.0.tar.gz

编译安装

注意:nginx的解压目录和编译目录不能是同一文件夹。

bash
cd /opt
mkdir nginx
cd /opt/nginx-1.24.0
./configure --prefix=/opt/nginx

没有报错的情况:

bash
Configuration summary
  + using threads
  + using system PCRE library
  + using system OpenSSL library
  + using system zlib library

  nginx path prefix: "/opt/my_nginx"
  nginx binary file: "/opt/my_nginx/sbin/nginx"
  nginx modules path: "/opt/my_nginx/modules"
  nginx configuration prefix: "/opt/my_nginx/conf"
  nginx configuration file: "/opt/my_nginx/conf/nginx.conf"
  nginx pid file: "/opt/my_nginx/logs/nginx.pid"
  nginx error log file: "/opt/my_nginx/logs/error.log"
  nginx http access log file: "/opt/my_nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

接下来进行编译安装:

bash
make -j$(nproc) && make install -j$(nproc)

看下安装目录:

bash
cd /opt/my_nginx
ls

[root@cs my_nginx]# ls
client_body_temp  fastcgi_temp  logs     proxy_temp  scgi_temp
conf              html          modules  sbin        uwsgi_temp

在nginx的安装目录中:

  • conf:存放nginx配置文件目录。
  • logs:存放nginx日志目录。
  • sbin:存放nginx可执行脚本目录。
  • html:存放nginx的网站站点,静态资源的目录。

知道主要的目录作用,我们也就可以启动nginx了。

bash
cd /opt/my_nginx/sbin
./nginx
ps -ef|grep nginx

[root@cs sbin]# ps -ef|grep nginx
root      39441      1  0 22:37 ?        00:00:00 nginx: master process ./nginx
nobody    39442  39441  0 22:37 ?        00:00:00 nginx: worker process
root      39444  73894  0 22:37 pts/1    00:00:00 grep --color=auto nginx

浏览器直接访问你的ip地址就可以看到了,这个ip应该改为你的云服务器ip,我这是从别处找的图。

1832669533509255168.png

如果想要在任意目录输入nginx即可启动,那还需要配置nginx的环境变量。

配置nginx环境变量

bash
echo "export PATH=/opt/my_nginx/sbin:\$PATH" >> /etc/profile
source /etc/profile

此时,就可以在任意位置启动nginx了。

配置启动方式

直接nginx命令启动

bash
# 直接输入nginx来启动,但只能首次启动nginx使用,因为重复启动的话,会提示80端口已被占用
nginx

# 查看nginx相关进程
ps -ef | grep nginx

# 查看NGINX监听的端口
netstat -tunlp | grep nginx

# 平滑重启nginx,也就是重新读取nginx的配置文件,而不是重启进程
nginx -s reload

# 确认nginx配置文件中配置项是否正确
nginx -t 

# 停止nginx, 杀死nginx进程
nginx -s stop

配置systemctl管理nginx

systemd 配置文件说明:

  • 每一个 Unit 都需要有一个配置文件用于告知 systemd 对于服务的管理方式。
  • 配置文件存放于 /usr/lib/systemd/system/,设置开机启动后会在 /etc/systemd/system 目录建立软链接文件。
  • 每个Unit的配置文件配置默认后缀名为.service。
  • 在 /usr/lib/systemd/system/ 目录中分为 system 和 user 两个目录,一般将开机不登陆就能运行的程序存在系统服务里,也就是 /usr/lib/systemd/system。
  • 配置文件使用方括号分成了多个部分,并且区分大小写。

我们来配置下:

bash
cat >/lib/systemd/system/nginx.service<< \EOF
[Unit]
Description=nginx
After=network.target
 
[Service]
Type=forking
ExecStartPre=/opt/my_nginx/sbin/nginx -t -c /opt/my_nginx/conf/nginx.conf
ExecStart=/opt/my_nginx/sbin/nginx -c /opt/my_nginx/conf/nginx.conf
ExecReload=/opt/my_nginx/sbin/nginx -s reload
ExecStop=/opt/my_nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
cat /lib/systemd/system/nginx.service

解释版:

bash
cat >/lib/systemd/system/nginx.service<< \EOF
[Unit]     # 记录service文件的通用信息
Description=nginx    # Nginx服务描述信息
After=network.target    # Nginx服务启动依赖,在指定服务之后启动
[Service]    # 记录service文件的service信息
Type=forking    # 标准UNIX Daemon使用的启动方式
ExecStartPre=/opt/my_nginx/sbin/nginx -t -c /opt/my_nginx/conf/nginx.conf
ExecStart=/opt/my_nginx/sbin/nginx -c /opt/my_nginx/conf/nginx.conf
ExecReload=/opt/my_nginx/sbin/nginx -s reload
ExecStop=/opt/my_nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]    # 记录service文件的安装信息
WantedBy=multi-user.target    # 多用户环境下启用
EOF
cat /lib/systemd/system/nginx.service

然后执行如下命令:

bash
pkill nginx
systemctl daemon-reload
systemctl start nginx
systemctl status nginx
systemctl stop nginx

线上:Redis安装

redis安装:https://www.cnblogs.com/Neeo/articles/17609004.html#redis507-for-centos79

注意,生产中, 如果你bind 0.0.0.0或者bind公网IP,那就意味着你的Redis服务将直面外网环境,随时面临着被攻击的危险。所以要注意设置一个极其复杂的密码,且应该定期更换,防止被人攻击成功。

由于我的后端Django项目和Redis服务部署到了一个服务器上,那么你可以的关于Redis的配置参考如下,此时云服务器的安全组不需要放开Redis监听的6379端口,因为它内部是通过本地的127.0.0.1连接通信的。

python
# session配置
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'session'  # 对应CACHES中的session配置项
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7

# 云服务器中的Redis配置
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/0",  
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {
                "max_connections": 1000,
                "encoding": 'utf-8',
                "decode_responses": True
            },
            "PASSWORD": "1234"  # redis密码
        }
    },
    ,
    "session": {  # 专门存session的数据
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/2",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {
                "max_connections": 100,
                # 注意,如果你的session是存储到redis中的话,这个参数要注释掉,否则内部出现问题,导致存储session失败,你很难查出来
                # "decode_responses": True,
            },
            "PASSWORD": "1234",
        }
    }
}
bash
daemonize yes
bind 127.0.0.1
port 6379
pidfile /opt/redis6379/pid/redis6379.pid
logfile /opt/redis6379/logs/redis6379.log
dir "/data/redis6379"
save 900 1
save 300 10
save 60 10000
dbfilename "redis.rdb"
appendonly yes
appendfilename "redis.aof"
appendfsync everysec
requirepass 1234

下面的配置支持下面两种部署情况:

  1. 你的Redis要支持外部访问,同时后端Django项目和Redis服务又都在同一个服务器,那么你的配置应该是这样的,此时云服务器的安全组需要放开Redis监听的6379端口。
  2. Redis服务和后端Django项目不在同一个服务器上,那么你的配置应该是这样的,此时云服务器的安全组需要放开Redis监听的6379端口。
python
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://Redis所在公网IP:6379",  # 直接通过公网IP连接Redis服务,特别注意检查安全组是否放开6379端口
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {
                "max_connections": 1000,
                "encoding": 'utf-8'
            },
            "PASSWORD": "abc123"  # redis密码
        }
    }
}
bash
daemonize yes
bind 0.0.0.0
port 6379
pidfile /opt/redis6379/pid/redis6379.pid
logfile /opt/redis6379/logs/redis6379.log
dir "/data/redis6379"
save 900 1
save 300 10
save 60 10000
dbfilename "redis.rdb"
appendonly yes
appendfilename "redis.aof"
appendfsync everysec
requirepass 1234

想要配置持久化,参考:<https://www.cnblogs.com/Neeo/articles/17609006.html

线上部署步骤

开始上正菜了!!!

线上:本地项目上传到云服务器

目录规划

bash
# 所有项目部署相关的东西都在/scm3 目录内,而软件都安装到了/opt目录内
mkdir -p /scm3
mkdir -p /scm3/allstatic
mkdir -p /scm3/script
mkdir -p /scm3/logs
cd /scm3

本地相关压缩包上传到云服务器

至于你本地是通过scp命令、xftp、还是别的手段将压缩包上传到云服务器都是你的事儿了。

这里演示下使用scp命令上传压缩包:

bash
# 本地电脑打开终端
# scp命令使用方法:scp 源文件路径 账户@地址:目的路径
# 然后回车输入密码即可
C:\Users\12061>scp D:\code\supplier.zip root@www.neeo.cc:/scm3/
C:\Users\12061>scp C:\Users\12061\Downloads\api.neeo.cc_nginx.zip root@www.neeo.cc:/scm3/
C:\Users\12061>scp C:\Users\12061\Downloads\web.neeo.cc_nginx.zip root@www.neeo.cc:/scm3/

云服务器上就有了:

bash
[root@cs /]# cd /scm3
[root@cs scm3]# ls
api.neeo.cc_nginx.zip     # 后端ssl证书文件夹
supplier.zip  			  # 后端项目代码压缩包
web.neeo.cc_nginx.zip     # 前端ssl证书文件夹

# 解压缩并删除掉压缩包
unzip api.neeo.cc_nginx.zip
unzip web.neeo.cc_nginx.zip
unzip supplier.zip			  
rm -rf *.zip


[root@cs scm3]# ls
api.neeo.cc_nginx  supplier  web.neeo.cc_nginx

# 相关目录和终点文件介绍
[root@cs scm3]# ls
allstatic  			# 静态文件收集的目录
venv				# 项目所用的虚拟环境目录
logs				# 日志相关目录
script			    # 各种脚本所在的目录
supplier/  		    # 后端项目根目录
	/api
	/supplier
		settings.py
		pro_settings.py
	requests.txt
	data.sql
web.neeo.cc_nginx    # 前端证书文件夹
api.neeo.cc_nginx    # 后端证书文件夹

[root@cs scm3]# ls api.neeo.cc_nginx/
api.neeo.cc_bundle.crt      # 证书文件,我们用得上
api.neeo.cc_bundle.pem      # 证书文件(可忽略该文件)
api.neeo.cc.csr             # CSR 文件是申请证书时由您上传或系统在线生成的,提供给 CA 机构。安装时可忽略该文件。
api.neeo.cc.key				# 私钥文件,我们用得上

线上:数据库迁移

之前在本地备份出来data.sql已经在云服务器上的项目根目录下了,所以在/scm3/supplier目录下执行:

sql
cd /scm3/supplier
mysql -uroot -p <data.sql


# 去数据库中验证下
[root@cs supplier]# mysql -uroot -p123
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 22513
Server version: 8.0.33 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use supplier;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+----------------------------+
| Tables_in_supplier         |
+----------------------------+
| api_address                |
| api_administrator          |
| api_driver                 |
| api_driverauth             |
| api_order                  |
| api_orderrecord            |
| api_transactionrecord      |
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| company                    |
| companyauth                |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
+----------------------------+
19 rows in set (0.00 sec)

mysql> select * from company;
+----+--------------+-------------+----------------------------------+-----------+----------------------------+---------+----------------+
| id | name         | mobile      | password                         | auth_type | ctime                      | balance | freeze_balance |
+----+--------------+-------------+----------------------------------+-----------+----------------------------+---------+----------------+
|  1 | 大和实业     | 182111xxx | f9aad8001813efeb7855d5e50df698e8 |         2 | 2023-06-12 18:48:08.820118 |  280.00 |           0.00 |
|  2 | 大江实业     | 1821110xxx | f9aad8001813efeb7855d5e50df698e8 |         1 | 2024-04-24 13:54:59.750165 |    0.00 |           0.00 |
+----+--------------+-------------+----------------------------------+-----------+----------------------------+---------+----------------+
2 rows in set (0.00 sec)

-- 创建一个普通用户专门服务于这个项目,这个账号只能云服务器本地操作supplier数据库,这样搞比较安全
-- 补一个删除用户的命令,drop user 'zhangkai'@'localhost';
mysql> create user zhangkai@'localhost' identified with mysql_native_password by "zhangkai12340";
i12340";
Query OK, 0 rows affected (0.01 sec)

mysql> grant all on supplier.* to zhangkai@'localhost';
Query OK, 0 rows affected (0.01 sec)

注意检查确认你的Django的线上配置中的MySQL相关账号密码什么的必须和这个一致。

线上:创建虚拟环境并测试项目能否运行(重要的一步)

创建虚拟环境并且下载依赖包:

bash
cd /scm3
# 解释器安装好了之后,可以直接下载virtualenv模块
pip3 install virtualenv
# 创建虚拟机换
virtualenv venv
# 激活虚拟环境
source /scm3/venv/bin/activate

[root@cs scm3]# source /scm3/venv/bin/activate
(venv) [root@cs scm3]# pip -V
pip 24.0 from /scm3/venv/lib/python3.9/site-packages/pip (python 3.9)

# 升级pip和下载相关模块
pip install --upgrade pip
pip install uwsgi
pip install -r /scm3/supplier/requirements.txt

线上服务器上,先把项目跑起来。

激活虚拟环境之后,通过下面的命令运行Django项目,再次注意检查云服务器的安全组中放开了8000端口。

bash
cd /scm3/supplier/
python3 manage.py  runserver 0.0.0.0:8000

然后本地电脑就可以通过postman访问测试了:

bash
# 请求方式:POST 
# 请求URL:http://82.157.21.45:8000/api/login/

# 请求body
{
    "mobile":"18211101111",
    "password": 123
}

# 响应结果,说明成功了
{
    "code": 0,
    "msg": "success",
    "data": {
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6Imp3dCJ9.eyJ1c2VyX2lkIjoxLCJuYW1lIjoiXHU1OTI3XHU1NDhjXHU1YjllXHU0ZTFhIiwibW9iaWxlIjoiMTgyMTExMDE3NDIiLCJhdXRoX2lkIjoxLCJleHAiOjE3MTM5NjczODN9.n0XTgcJWubvr-4UXcRDkPxfipMNSexnmTUfniQg9oTo",
        "name": "大江实业",
        "id": 1,
        "mobile": "18211101111",
        "auth_id": 1
    }
}

测完没问题,再往下走。

线上:配置uwsgi

创建uwsig.ini文件:

bash
# 确认虚拟环境已经激活,且下载好了uwsgi模块
cd /scm3
source /scm3/venv/bin/activate
pip install uwsgi

# 确认创建脚本所在目录和uwsgi日志所在目录
cd /scm3
touch script/uwsgi.ini

文件内容,注意,uwsgi.ini文件可以写注释内容,但注释内容应该写在配置项的上面或者下面,而不是和配置项的后面,错误示范:

ini
[uwsgi]
chdir=/scm3/supplier/  # 填写订单项目的根目录

正确的配置:

ini
cat >/scm3/script/uwsgi.ini<< \EOF

[uwsgi]

# 填写订单项目的根目录
chdir=/scm3/supplier/

# 填写与项目同名的目录,这是个相对路径,主要就是找到其内的wsgi.py这个文件
module=supplier.wsgi

# 虚拟环境的根目录,也就是工作目录
home=/scm3/venv/

# uwsgi的主进程,其他的uwsgi的进程都是这个主进程的子进程,当你kill时,杀掉的也是这个master主进程
master=true

# uwsgi并发时的工作进程的数量,官网的建议是:2 * cup核数 + 1
# 由这几个进程来分摊并发请求
processes=3

# 临时使用http,实际部署时,通过nginx反向代理,就要把http换成socket,这点别忘了改
http=0.0.0.0:8000
# socket=127.0.0.1:8000

# 当服务器退出时,自动删除unix socket文件和pid文件
vacuum=true

# 默认的请求的大小为4096,如果你接收到了一个更大的请求 (例如,带有大cookies或者查询字符串),那么超过4096的限制就会报错invalid request block size: 4547 (max 4096)...skip,所以我们这里提前调整下
# https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/Options.html#buffer-size
buffer-size=32768

# uwsgi的日志文件,开始我也是先把日志配置注释掉,任其先直接输出到控制台,方便观察是否有报错,等整个项目各项部署都么问题了,在启用这个配置也不晚。
# logto=/scm3/logs/uwsgi.log

EOF

运行uwsgi测试:

bash
# 确认虚拟环境已经激活,且下载好了uwsgi模块
cd /scm3
source /scm3/venv/bin/activate
pip install uwsgi

# 执行下面的命令,结束进程的话,连续输入ctrl+c即可
/scm3/venv/bin/uwsgi --ini /scm3/script/uwsgi.ini

(venv) [root@cs scm3]# /scm3/venv/bin/uwsgi --ini /scm3/script/uwsgi.ini
[uWSGI] getting INI configuration from /scm3/script/uwsgi.ini
*** Starting uWSGI 2.0.25.1 (64bit) on [Tue Apr 23 22:12:03 2024] ***
compiled with version: 4.8.5 20150623 (Red Hat 4.8.5-44) on 23 April 2024 13:57:54
os: Linux-3.10.0-1160.102.1.el7.x86_64 #1 SMP Tue Oct 17 15:42:21 UTC 2023
nodename: cs
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 2
current working directory: /scm3
detected binary path: /scm3/venv/bin/uwsgi
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
chdir() to /scm3/supplier/
your processes number limit is 7906
your memory page size is 4096 bytes
detected max file descriptor number: 100001
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uWSGI http bound on 0.0.0.0:8000 fd 4
uwsgi socket 0 bound to TCP address 127.0.0.1:42847 (port auto-assigned) fd 3
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
Python version: 3.9.9 (main, Nov 19 2023, 16:29:16)  [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
PEP 405 virtualenv detected: /scm3/venv/
Set PythonHome to /scm3/venv/
*** Python threads support is disabled. You can enable it with --enable-threads ***
Python main interpreter initialized at 0x11cc190
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 406368 bytes (396 KB) for 3 cores
*** Operational MODE: preforking ***
WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x11cc190 pid: 21821 (default app)
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) *** 
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 21821)
spawned uWSGI worker 1 (pid: 21847, cores: 1)
spawned uWSGI worker 2 (pid: 21848, cores: 1)
spawned uWSGI worker 3 (pid: 21849, cores: 1)
spawned uWSGI http 1 (pid: 21850)
111 {'Host': '82.157.21.45:8000', 'User-Agent': 'PostmanRuntime/7.26.8', 'Content-Length': '54', 'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br', 'Authorization': '', 'Cache-Control': 'no-cache', 'Content-Type': 'application/json', 'Postman-Token': 'e6ca2d77-2787-4cee-8e5c-1f31e3dc43b9'}
[pid: 21849|app: 0|req: 1/1] 106.112.42.246 () {40 vars in 526 bytes} [Tue Apr 23 22:12:09 2024] POST /api/login/ => generated 323 bytes in 94 msecs (HTTP/1.1 200) 10 headers in 300 bytes (1 switches on core 0)

然后postman中再次测试登录接口,拿到正确的结果表示uwsgi这一步也没问题了。

那么就把uwsig.ini文件的参数调整一下,这个参数取消注释socket=0.0.0.0:8000

ini
cat >/scm3/script/uwsgi.ini<< \EOF

[uwsgi]

# 填写订单项目的根目录
chdir=/scm3/supplier/

# 填写与项目同名的目录,这是个相对路径,主要就是找到其内的wsgi.py这个文件
module=supplier.wsgi

# 虚拟环境的根目录,也就是工作目录
home=/scm3/venv/

# uwsgi的主进程,其他的uwsgi的进程都是这个主进程的子进程,当你kill时,杀掉的也是这个master主进程
master=true

# uwsgi并发时的工作进程的数量,官网的建议是:2 * cup核数 + 1
# 由这几个进程来分摊并发请求
processes=3

# 临时使用http,实际部署时,通过nginx反向代理,就要把http换成socket,这点别忘了改
# http=0.0.0.0:8000
socket=127.0.0.1:8000

# 当服务器退出时,自动删除unix socket文件和pid文件
vacuum=true

# 默认的请求的大小为4096,如果你接收到了一个更大的请求 (例如,带有大cookies或者查询字符串),那么超过4096的限制就会报错invalid request block size: 4547 (max 4096)...skip,所以我们这里提前调整下
# https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/Options.html#buffer-size
buffer-size=32768

# uwsgi的日志文件,开始我也是先把日志配置注释掉,任其先直接输出到控制台,方便观察是否有报错,等整个项目各项部署都么问题了,在启用这个配置也不晚。
# logto=/scm3/logs/uwsgi.log

EOF

补充,uwsgi相关命令:

bash
# 相对路径启动,指定配置文件启动后端
uwsgi --ini ./uwsgi.ini    # 启动
    # 启动时会生成两个文件,分别为:
    # PID文件 标识这个程序所处的状态
    # SOCK文件  用来和其他程序通信的
uwsgi --stop uwsgi.pid     # 停止
uwsgi --reload uwsgi.ini   # 重置


# 绝对路径启动,就是要找到uwsgi的绝对路径和uwsig.ini的绝对路径
(venv) [root@cs smc3]# which uwsgi
/smc3/venv/bin/uwsgi

# uwsig.ini的绝对路径是 /smc3/venv/bin/uwsgi

# 所以,绝对路径启动就是下面的样子
/smc3/venv/bin/uwsgi --ini /smc3/script/uwsgi.ini

# 关闭uwsgi进程,一键杀死所有与uwsgi相关的进程
pkill -9 uwsgi

# 你也可以先过滤出来,在根据pid进行kill
ps -ef |grep uwsgi   # 查看进程,找到pid
pkill -9 uwsgi       # -9强制杀死叫做uwsgi的进程

线上:配置nginx

首先保证你的uwsgi程序在运行着。

一个xshell窗口,运行着uwsgi,注意将来测试时,留意输出的日志是否有报错。

bash
# 确认虚拟环境已经激活,且下载好了uwsgi模块
cd /scm3
source /scm3/venv/bin/activate
pip install uwsgi

# 执行下面的命令,结束进程的话,连续输入ctrl+c即可
cd /scm3
/scm3/venv/bin/uwsgi --ini /scm3/script/uwsgi.ini

再打开一个新的窗口,编辑nginx配置文件:

bash
cd /scm3
vim /opt/my_nginx/conf/nginx.conf

文件内容,主要是里面有注释的那个include配置。

bash
#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '

                               '$status $body_bytes_sent "$http_referer" '

                               '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log  main;
    # NGINX在启动时,会自动加载include指定的目录内的以.conf结尾的配置文件
    # 我们可以在那里写关于该项目的配置,这样做的好处,这个nginx.conf总配置文件很干净
    # 想要写什么项目的配置,都在include指定的目录内的以.conf结尾的配置文件中写就完了
    # 分门别类,比较清晰
    include /opt/my_nginx/conf/conf.d/*.conf;
}

书写关于当前项目的配置文件:

bash
cat >/opt/my_nginx/conf/conf.d/supplier.conf<< \EOF

# --------supplier项目的后端配置--------
server {
    listen       80;
    server_name  localhost;
    charset utf-8;
    gzip on;
    gzip_static on;
    gzip_min_length 1k;
    gzip_vary on; 
    gzip_proxied any;
    gzip_comp_level 9;
    gzip_buffers 4 16k;
    gzip_http_version 1.0;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/jpeg image/gif image/png image/svg+xml;
    # 所有访问80端口的请求,都转发给8000端口的服务器,即uwsgi服务
    location / {
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:8000;
    }
    # 静态文件代理,location /static 最后不加 /
    location /static {
    	# 路径最后要加上 /
        alias /scm3/allstatic/;
    }
}
EOF

nginx -t
nginx -s reload

然后postman继续访问,观察是否得到了正确的响应。

bash
# 请求方式:POST 
# 请求URL:http://82.157.21.45/api/login/

# 请求body
{
    "mobile":"18211101111",
    "password": 123
}

# 响应结果,说明成功了
{
    "code": 0,
    "msg": "success",
    "data": {
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6Imp3dCJ9.eyJ1c2VyX2lkIjoxLCJuYW1lIjoiXHU1OTI3XHU1NDhjXHU1YjllXHU0ZTFhIiwibW9iaWxlIjoiMTgyMTExMDE3NDIiLCJhdXRoX2lkIjoxLCJleHAiOjE3MTM5NzA0NjZ9.I3Goqo834MSIMo0Zop6hC24hMv0RQfCaQoqcnh2Y9lk",
        "name": "大江实业",
        "id": 1,
        "mobile": "18211101111",
        "auth_id": 1
    }
}

没问题,说明nginx和uwsgi以及项目整体上运行良好。

线上:静态文件收集(可选操作)

这一步是可选的,因为是前后端分离的项目,后端不处理静态文件,但以防万一用到Django的admin了(前提是你启用了admin组件),这里也就演示下静态文件收集吧。

将项目的线上配置pro_settings.py中确认是否有如下参数:

python
# 收集静态文件,需要指定STATIC_ROOT, /scm3路径是将来我要在云服务器上项目部署的所在目录
STATIC_ROOT = "/scm3/allstatic/"

也应该检查下settings.py中媒体文件的配置:

python
# 媒体文件
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
UPLOAD_PATH = 'upload'
FILE_SIZE = 1024 * 1024 * 10  # 限制上传文件(图片大小),默认是10兆

都没问题的话,执行下面的命令:

bash
# 确认虚拟环境已经激活,且下载好了uwsgi模块
cd /scm3
source /scm3/venv/bin/activate

# 免交互收集静态文件
cd /scm3
echo "yes"|python3 /scm3/supplier/manage.py collectstatic

(venv) [root@cs scm3]# echo "yes"|python3 /scm3/supplier/manage.py collectstatic

163 static files copied to '/scm3/allstatic'.

OK,没问题。

你可以创建个超级管理员,检查下admin后台管理页面是否可用。

bash
# 确认虚拟环境已经激活,且下载好了uwsgi模块
cd /scm3
source /scm3/venv/bin/activate

# 创建超级管理员
cd /scm3/supplier
python3 manage.py createsuperuser

(venv) [root@cs supplier]# python3 manage.py createsuperuser

You have 13 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth.
Run 'python manage.py migrate' to apply them.
用户名: zhangkai
电子邮件地址: zhangkai@qq.com
Password: 							# 账号是zhangkai,密码是1234
Password (again): 
密码长度太短。密码必须包含至少 8 个字符。
这个密码太常见了。
密码只包含数字。
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

然后浏览器访问http://82.157.21.45/admin/就能登录进来啦,这说明静态文件nginx也正确处理了。

1832669533731553280.png

线上:ssl配置

腾讯云ssl配置参考:https://cloud.tencent.com/document/product/400/35244?from_cn_redirect=1

想要网站支持https,就需要:

  1. 白嫖云服务器的小老弟可能要失望了,腾讯云的我不知道,但比如类似于阿里云3个月免费的云服务器就不能备案,所以想要整备案,还是花钱买个服务器吧。
  2. 没有域名的话,就需要购买域名,然后进行域名备案,比如我的域名是neeo.cc
  3. 备案好了之后,将这个域名和你买的云服务器进行解析,也就是将来可以通过域名访问我们的云服务器了。
  4. 然后在域名解析列表中就有有个解析好的主域名www.neeo.cc
  5. 如果需要多个域名的话,除了在申请一个域名,也可以选择在现有主域名的基础上添加多个二级域名来达到目的:
    • 比如在域名解析列表中添加api前缀(云服务器厂商会自动解析),这样就有了api.neeo.cc域名可用。
    • 比如在域名解析列表中添加web前缀(云服务器厂商会自动解析),这样就有了web.neeo.cc域名可用。
  6. 申请ssl证书。注意,必须是在域名解析列表中存在的这些域名,后续才可以为它们申请ssl证书,申请成功并审核成功,就可以下载证书文件到本地了。
    • 免费证书,有效期在申请时可以看到。
    • 收费证书,有效期在申请时可以看到。
  7. 在NGINX或者其他web服务器的配置中,进行ssl证书文件和其它参数的配置。
  8. 对于前后端分离的项目中,必须前后端都是https的形式进行数据交互,不能说前端https,后端是http,这样的话,你前端默认是不能发送数据的到后端的,会报错,如下图,原因是不安全,浏览器阻止了。除非你进行额外的比如NGINX代理,但这么做,还不如再搞个域名来的方便。

1832669534188732416.png

域名备案和解析

1. 购买域名

购买域名,一般原则是你买个哪个厂家的云服务器,就也买哪个厂家提供的域名,后续用起来也比较方便。

我之前从阿里云迁移到腾讯云的时候,在阿里那边备案好的域名要迁移到腾讯云,阿里云官网做域名迁出动作,腾讯云官网做域名迁入动作,麻烦!

迁入腾讯云的域名要从新备案,更麻烦。费事,所以,你要整域名的话,要考虑好你用哪个厂家的云服务器,尽量买个久点服务器。

参考:https://buy.cloud.tencent.com/domain

1832669534377476096.png

你可以输入你心仪的域名,至于想要什么后缀,你可以参考https://baike.baidu.com/item/域名后缀/667641?fr=ge_ala,看下不同的后缀都是啥意思。

1832669535358943232.png

输入好域名,且没有被别人注册,你就可以付钱了。

2. 域名备案

备案的话,分ICP和公安备案:

  • ICP备案是指互联网信息服务提供者备案,是指在中国大陆地区从事互联网信息服务的单位或个人必须提交的备案手续,目的是为了规范互联网信息服务的管理。ICP备案是由国家互联网信息办公室负责管理的,包括主要内容、网站备案号等信息。
  • 网站公安备案是指在中国大陆地区,网站必须向当地公安部门提交备案申请,以便公安部门能够监管网站的内容和活动,防止网络违法犯罪活动的发生。网站公安备案需要提供的信息包括网站的基本情况、负责人信息、服务器信息、网站域名等。

总的来说,ICP备案是针对互联网信息服务提供者的备案,而网站公安备案则是针对网站内容的备案。两者的目的和管理机构也不同。

1832669536499793920.png

我这里的域名主要用于平常教学用,没有特定的网站要跑,所以只进行了ICP备案,没有进行公安备案,如果你将来要跑某个个人或者公司的项目,你可以自行去这个地址完成公安备案:https://beian.mps.gov.cn/#/

接着说ICP备案。

买完了域名,然后就要去其官网找域名备案功能,备案这个流程顺利的话需要十天半个月的。

你可以在手机上下载云服务器的微信小程序,在小程序上搜索"腾讯云备案小程序",然后开始按提示操作即可。

微信搜索备案小程序:

1832669536730480640.png

然后按照指引进行备案。

下面是腾讯云的域名备案流程示例。

整个备案过程也是很麻烦的,大概的流程就是填写备案申请,让你提交啥材料你就提交啥材料,然后提交到云服务器厂家审核,有问题的话会有小姐姐电话联系你说你哪里需要修改,然后你就修改之后,继续提交申请,继续审核,然后这个云服务器厂家审核通过了,会给你发短信提醒:

bash
【腾讯云】尊敬的用户,恭喜您提交的(主办单位名称: xxx,备案订单号:3016xxxxxxxxxxxx)备案订单通过腾讯云备案初审,您的备案信息已提交管局审核。管局受理后,备案负责人(xxx)将会收到管局下发短信核验通知,请收到短信后在24小时内按照短信提示登录工信部网站进行短信核验。超时未验证导致备案订单被退回:https://mc.tencent.com/ldERfhrH。审核期间,请勿调整网站内容和域名信息,并保持电话畅通。登录控制台:https://mc.tencent.com/rExpTtQF 。您的账号(账号ID:10001xxxxxx,昵称:xxxxxx)。

这个时候,你按照短信提醒去对应的网址上登录短信中的账号和昵称,进行短信验证,这一步很重要。

然后继续等待,因为要把你的备案申请提交到国家工业和信息化部进行审核。这个阶段可能会有电话垂询,问你为啥备案之类的,不过一般良民应该接不到这个电话。

国家工业和信息化部审核通过之后,会给你发短信,由于我在阿里备过案,迁移到腾讯云之后,只能从新备案,所以短信提示是下面这样的。

bash
【工业和信息化部】尊敬的用户xxx,您的备案信息已被变更,详情请咨询您的接入服务提供商。【工信部ICP备案】

总之,现在域名备案搞定了.....

3. 域名解析

这一步相当于让域名和你云服务器的公网IP做个映射,让浏览器通过访问域名的方式就能解析到你的云服务器公网IP上去。

ICP备案成功之后,登录云服务器控制台,找到域名解析,将备案好的域名和你的服务器进行解析,腾讯云是这个地址:https://console.cloud.tencent.com/cns

1832669537586118656.png

添加域名解析:

1832669537909080064.png

解析成功之后,你可以查看一下:

1832669538211069952.png

1832669538588557312.png

bash
# 我备案好的域名是www.neeo.cc
# 公网IP是82.157.21.45
# 那么腾讯云这边直接给我提供好了两个域名都可以解析到公网IP
# 即www开头的和api开头的都可以
# 但我这里www.neeo.cc用于别的项目了,所以,我还需要创建一个二级域名,即web.neeo.cc
www.neeo.cc  # 我的被别的项目占用,你的话,可以用这个作为前端域名
api.neeo.cc  # 作为本次部署的drf后端用
web.neeo.cc  # 作为本次部署的vue前端用,也就是客户通常浏览器访问的这个地址

# 如果是阿里云的,只有一个www的,那么你可以手动添加需要的两个二级域名,这个不懂可以百度了

参考上一张图,由于我的解析列表中没有web开头的域名记录,我需要手动添加一个二级域名,然后腾讯云内部会自动进行域名解析,我只要有这条记录就行了,如下图:

1832669538999599104.png

搞定了web.neeo.cc这个二级域名的解析,那么就可以为这个二级域名创建对应的ssl证书文件。

PS:如果你控制台的域名解析列表中没有api.neeo.cc这个记录,也需要按照上述方式弄出来。总之,一个域名解析记录,对应的可以创建一个ssl证书文件。

这里演示下申请证书,然后将ssl文件下载到本地待用,这个地址:https://console.cloud.tencent.com/ssl,我这里申请免费的,有钱大佬请上正式证书。

1832669539377086464.png

填写web.neeo.cc这个域名的相关信息申请信息。

1832669540241113088.png

等审核:

1832669540845092864.png

很快的就通过的,会有短信提示:

bash
# 购买免费的证书短信提醒
【腾讯云】尊敬的腾讯云用户,您购买的域名为 web.neeo.cc 的 TrustAsia TLS RSA CA 证书(年限:1年,证书ID:EJEojlNV)现已进入审核验证阶段。请您耐心等待系统自动完成DNS验证,验证通过后证书将会颁发。域名验证方式可参考:https://mc.tencent.com/GhB9OLKA 。登录证书控制台:https://mc.tencent.com/hmpuWwkI 。您的腾讯云账号(账号ID:10001123131,昵称:听xxx)

# 审核通过的短信提醒
【腾讯云】尊敬的用户,您的域名 web.neeo.cc 的 TrustAsia TLS RSA CA(1年)证书已审核通过并成功颁发。登录控制台查看证书:https://mc.tencent.com/g9algEWM 。证书部署可参考文档:https://mc.tencent.com/ZKGAc9go 。您的腾讯云账号(账号ID:10001371213,昵称:听xxx)。

完事就可以在证书列表中,将这两个证书文件下载到本地待用。

1832669541314854912.png

本地长这样:

1832669541876891648.png

证书文件上传到服务器

在之前的步骤中,我们也已经将证书文件上传到服务器了:

bash
(venv) [root@cs supplier]# cd /scm3/
(venv) [root@cs scm3]# ls
allstatic  
api.neeo.cc_nginx     # 先搞这个后端的证书
logs  
script  
supplier  
venv  
web.neeo.cc_nginx

nginx中配置后端ssl

配置参考腾讯云官网:https://cloud.tencent.com/document/product/400/35244?from_cn_redirect=1

注意,云服务器中的安全组注意放开443端口。

1832669541990137856.png

首先要拿到后端ssl两个文件的绝对路径:

bash
(venv) [root@cs scm3]# cd /scm3/api.neeo.cc_nginx/
(venv) [root@cs api.neeo.cc_nginx]# pwd
/scm3/api.neeo.cc_nginx
(venv) [root@cs api.neeo.cc_nginx]# ls
api.neeo.cc_bundle.crt  api.neeo.cc_bundle.pem  api.neeo.cc.csr  api.neeo.cc.key


# 接下来手动拼接出来这俩文件的绝对路径
/scm3/api.neeo.cc_nginx/api.neeo.cc_bundle.crt
/scm3/api.neeo.cc_nginx/api.neeo.cc.key

编辑nginx的配置文件:

bash
mv /opt/my_nginx/conf/conf.d/supplier.conf /opt/my_nginx/conf/conf.d/supplier.conf.bak
cat >/opt/my_nginx/conf/conf.d/supplier.conf<< \EOF

# --------supplier项目的后端配置--------
server {
    listen 80;
    #请填写绑定证书的域名,即api.neeo.cc
    server_name api.neeo.cc; 
    #把http的域名请求转成https
    return 301 https://$host$request_uri; 
}
server {
    #SSL 默认访问端口号为 443
    listen 443 ssl; 
    #请填写绑定证书的域名,即api.neeo.cc
    server_name api.neeo.cc; 
    #请填写证书文件的相对路径或绝对路径
    ssl_certificate /scm3/api.neeo.cc_nginx/api.neeo.cc_bundle.crt; 
    #请填写私钥文件的相对路径或绝对路径
    ssl_certificate_key /scm3/api.neeo.cc_nginx/api.neeo.cc.key; 
    ssl_session_timeout 5m;
    #请按照以下协议配置
    ssl_protocols TLSv1.2 TLSv1.3; 
    #请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 
    ssl_prefer_server_ciphers on;
    gzip on;
    gzip_static on;
    gzip_min_length 1k;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 9;
    gzip_buffers 4 16k;
    gzip_http_version 1.0;
    # 进行压缩的文件类型
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/jpeg image/gif image/png image/svg+xml;
    # 访问https://api.nee.cc的请求转发给uwsgi
    location / {
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:8000;
    }
    location /static {
        alias /scm3/allstatic/;
    }
 }
EOF

nginx -t
nginx -s reload

完事你可以访问https://api.neeo.cc/admin/login/?next=/admin/观察,此时就是https的了,然后所有http的请求也会被301重定向到https。

1832669542120161280.png

至此,后端部署就完了。

线上:让程序实现后台运行

方式1,通过nohup命令

每一次项目代码迭代更新,都可以直接覆盖掉/scm3目录下面的supplier项目,然后重新执行下面的命令即可。

bash
cd /scm3
source /scm3/venv/bin/activate
pip install -r scm3/requirements.txt
pkill -9 uwsgi
nohup /scm3/venv/bin/uwsgi --ini /scm3/script/uwsgi.ini >/dev/null 2>&1 &

主要用的是nohup命令。

方式2,通过三方监控软件

其原理就是,通过三方软件监控uwsgi的进程,发现uwsgi的进程挂掉了,监控软件自动重启uwsgi进程。

直接使用使用yum命令即可直接安装即可:

bash
yum install -y supervisor

生成supervisor的配置文件:

javascript
echo_supervisord_conf >  /etc/supervisord.conf

这里贴个supervisor的示例,编辑supervisord.conf配置文件vim /etc/supervisord.conf,追加如下内容:

ini
[program:scm3]
command=/scm3/venv/bin/uwsgi --ini /scm3/script/uwsgi.ini
autostart=true       ; 在supervisord启动的时候也自动启动
startsecs=10         ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
autorestart=true     ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启
stopasgroup=true     ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程
killasgroup=true     ;默认为false,向进程组发送kill信号,包括子进程

然后就可以尝试通过supervisor命令启动uwsgi,注意,要先杀掉之前启动uwsgi相关进程:

bash
cd /scm3
pkill -9 uwsgi
pkill -9 supervisord
# 根据配置文件启动supervisord进程,同时也会启动监控的uwsgi进程
supervisord -c /etc/supervisord.conf
# 通过supervisorctl终端可以方便查询到监控的所有的进程,然后你可以指定启动/停止/重启某个进程
supervisorctl -c /etc/supervisord.conf
[root@cs scm3]# pkill -9 uwsgi
[root@cs scm3]# pkill -9 supervisord
[root@cs scm3]# supervisord -c /etc/supervisord.conf
[root@cs scm3]# supervisorctl -c /etc/supervisord.conf
od                               BACKOFF   Exited too quickly (process log may have details)
scm3                             STARTING  
supervisor> stop scm3
scm3: stopped
supervisor> start scm3
scm3: started
supervisor> status scm3
scm3                             RUNNING   pid 12120, uptime 0:00:14

更多参考:https://www.cnblogs.com/Neeo/p/8651136.html

线上:后端项目收尾

检查确认各个配置文件的配置项是否正确

比如把pro_settings.py文件中的debug模式改为False,检查其它配置项也都没问题才行。

python
DEBUG = False

根据需要决定是否启用uwsgi日志文件,配置在/scm3/script/uwsgi.ini中:

ini
# uwsgi的日志文件,开始我也是先把日志配置注释掉,任其先直接输出到控制台,方便观察是否有报错,等整个项目各项部署都么问题了,在启用这个配置也不晚。
# logto=/scm3/logs/uwsgi.log

前端部署

前端部署就比较简单一些了。

本地:修改axios请求URL

把vue项目中所有请求后端的api,都要改为刚刚部署好的那个地址。

我这里只有axios的配置文件中这一处需要更改:

javascript
import axios from 'axios'
import router from '../router/index'
import store from '../store/index'
import {ElMessage} from 'element-plus'


let config = {
    // baseURL: "http://127.0.0.1:8200/",   // 最开始本地开发用的
    baseURL: "https://api.neeo.cc",  		// 现在要改为这个了
    // timeout: 3000
}
const $axios = axios.create(config)

然后编译项目,把dist打包上传。

bash
# 前端项目根目录执行
npm run build

# 然后本地文件夹中打包并上传到服务器/scm3目录下
# 本地终端把dist压缩成zip并上传
C:\Users\12061>scp C:\Users\12061\Downloads\dist.zip root@www.neeo.cc:/scm3/

# 远程服务器解压即可
cd /scm3/
unzip dist.zip

线上:配置nginx和ssl

直接一步到位配置上ssl。

先把前端需要的两个证书文件的绝对路径拿到:

bash
[root@cs scm3]# cd /scm3/web.neeo.cc_nginx/
[root@cs web.neeo.cc_nginx]# pwd
/scm3/web.neeo.cc_nginx
[root@cs web.neeo.cc_nginx]# ls
web.neeo.cc_bundle.crt  web.neeo.cc_bundle.pem  web.neeo.cc.csr  web.neeo.cc.key

# 接下来手动拼接出来这俩文件的绝对路径
/scm3/web.neeo.cc_nginx/web.neeo.cc_bundle.crt
/scm3/web.neeo.cc_nginx/web.neeo.cc.key

编辑nginx的配置文件:

bash
mv /opt/my_nginx/conf/conf.d/supplier.conf /opt/my_nginx/conf/conf.d/supplier.conf.bak2
cat >/opt/my_nginx/conf/conf.d/supplier.conf<< \EOF
# --------supplier项目的前端配置--------
server{
    listen 80;
    #请填写绑定证书的域名,即web.neeo.cc
    server_name web.neeo.cc;
    #把http的域名请求转成https
    # rewrite ^(.*)$  https://web.neeo.cc permanent;  
    return 301 https://$host$request_uri; 
}
server {
    #SSL 默认访问端口号为 443
    listen 443 ssl; 
    server_name web.neeo.cc; 
    ssl_certificate /scm3/web.neeo.cc_nginx/web.neeo.cc_bundle.crt; 
    ssl_certificate_key /scm3/web.neeo.cc_nginx/web.neeo.cc.key; 
    ssl_session_timeout 5m;
    ssl_protocols TLSv1.2 TLSv1.3; 
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 
    ssl_prefer_server_ciphers on;
    gzip on;
    gzip_static on;
    gzip_min_length 1k;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 2;
    gzip_buffers 4 16k;
    gzip_http_version 1.1;
    gzip_disable "MSIE [1-6]\.";
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/jpeg image/gif image/png image/svg+xml;
    add_header Cache-Control "max-age=31536000,immutable";
    location / {
        try_files \$uri \$uri/ @rewrites;
        root  /scm3/dist;
        index index.html;
        autoindex on;
    }
    location @rewrites {
        rewrite ^.*$ /index.html last;
    }
}

# --------supplier项目的后端配置--------
server {
    listen 80;
    #请填写绑定证书的域名,即api.neeo.cc
    server_name api.neeo.cc; 
    #把http的域名请求转成https
    return 301 https://$host$request_uri; 
}
server {
    #SSL 默认访问端口号为 443
    listen 443 ssl; 
    #请填写绑定证书的域名,即api.neeo.cc
    server_name api.neeo.cc; 
    #请填写证书文件的相对路径或绝对路径
    ssl_certificate /scm3/api.neeo.cc_nginx/api.neeo.cc_bundle.crt; 
    #请填写私钥文件的相对路径或绝对路径
    ssl_certificate_key /scm3/api.neeo.cc_nginx/api.neeo.cc.key; 
    ssl_session_timeout 5m;
    #请按照以下协议配置
    ssl_protocols TLSv1.2 TLSv1.3; 
    #请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 
    ssl_prefer_server_ciphers on;
    gzip on;
    gzip_static on;
    gzip_min_length 1k;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 9;
    gzip_buffers 4 16k;
    gzip_http_version 1.0;
    # 进行压缩的文件类型
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/jpeg image/gif image/png image/svg+xml;
    # 访问https://www.nee.cc的请求转发给uwsgi
    location / {
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:8000;
    }
    location /static {
        alias /scm3/allstatic/;
    }
 }
EOF
nginx -t
nginx -s reload

完事,浏览器访问:https://web.neeo.cc/login,登录都正常。

1832669542623477760.png

直接访问后端的admin站点也是没问题的:

1832669543579779072.png

前端也部署好了。

最后的收尾

最后的叮嘱:

  • 前后端都部署好了之后,应该充分检查前后端各项目的配置是否正确:
    • debug模式是否改为False
    • uwsgi的日志要不要开启。
  • 如果开启相关日志,在日常维护中,要留意日志文件的大小,小心文件过大,及时清理。
  • 应该把部署流程和相关命令都记录一下,将来维护时也方便复制粘贴命令,也能快速帮你回忆部署过程。
  • 如果使用git管理项目的话,要注意打tag,遇到灾难性的bug,好回滚,如果没有用git管理,也应该自己在本地自己打个压缩包,记录一下,也方便回滚,但建议使用git管理。
  • 检查你的云服务器控制台,把安全组中的80和443端口之外的端口,比如3306、6379这些端口,该删就删掉,保护数据安全,禁止数据库直接对外,且考虑定期更换数据库密码并足够复杂。
  • 另外不要给开发人员任何管理员权限的账号,删库跑路、服务器被恶意登录这些,平常没问题都好说,出了问题,也麻烦。