blog
blog copied to clipboard
部署Django项目(Ubuntu + conda + uWSGI + Nginx)
环境:
- macOS 10.12.6(本地开发主机)
- Ubuntu 16.04 LTS(服务器,以装在本地开发主机上的虚拟机代替)
- conda环境(Django 2.2、Python 3.7.3)
- 数据库:sqlite 3.29.0(Django默认数据库)
- uWSGI + Nginx
注:生产环境上需要设置 MySQL、https 等,这里不作介绍。
部署步骤:
- 配置SSH、安装Git;
- 传输代码到服务器;
- 在服务器上克隆开发时的 conda 环境;
- 安装并配置uWSGI;
- 安装并配置Nginx。
注:更优的部署方式是使用 Docker 容器实现自动化部署,这里不作介绍。
参考:
- Django官方文档 - 部署 Django
- uWSGI官方文档 - Setting up Django and your web server with uWSGI and nginx
- 刘江的博客教程 - 部署 Django
- 向东的笔记本 - Django线上部署教程:腾讯云+Ubuntu+Django+Uwsgi
the web client <-> the web server(Nginx) <-> the socket <-> uwsgi <-> Django
整个部署的链路是 Nginx -> uWSGI -> Python Web 程序。
当一个访问进来的时候,首先到 Nginx,Nginx 会把请求(HTTP协议)转换 uwsgi 协议传递给 uWSGI ,uWSGI 通过 WSGI 规范和 Web Server 进行通信取到响应结果,再通过 uwsgi 协议发给 Nginx,最终 Nginx 以 HTTP 协议发送响应给用户。
一、配置SSH、安装Git
1.1 配置 SSH
用于 $ ssh username@server
登录服务器。
参考:SSH登录远程主机:https://github.com/FatliTalk/blog/issues/130
1.2 安装 Git
安装 Git 以使用 Git 传输代码。
macOS 安装 Git :参考 Git_1 了解 Git(git --version)
Ubuntu 安装 Git:参考 Ubuntu搭建Git服务器
二、传输代码到服务器
传输代码到服务的方式,例如:使用 FileZilla 图形化软件 的 SFTP 传输;或使用 scp 与服务器传输文件。
git部署项目代码至服务器的三种方式,这里使用第三种:「本地开发主机 => 提交代码到GitHub => 服务器Git拉取代码」的形式进行代码传输。
本地开发主机提交代码到 GitHub 后,服务器 $ git clone
克隆代码仓库,或 $ git pull
(等价于 $ git fetch
+ $ git merge
)拉取并合并代码。
拉取并合并本地代码实例:
# 查看远程仓库
fatli@fatli-vm-ubuntu:~/github/mysite$ git remote -v
origin [email protected]:FatliTalk/mysite.git (fetch)
origin [email protected]:FatliTalk/mysite.git (push)
# 拉取远程仓库
fatli@fatli-vm-ubuntu:~/github/mysite$ git fetch
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 2), reused 3 (delta 2), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:FatliTalk/mysite
c756d23..5a5494e master -> origin/master
# 对比本地分支和远程分支(这也是使用GitHub管理代码的好处,可以对比修改内容)
fatli@fatli-vm-ubuntu:~/github/mysite$ git diff master origin/master
# 合并分支
fatli@fatli-vm-ubuntu:~/github/mysite$ git merge
注意:
在服务器 $ git clone
GitHub 上的代码前,先将 ssh 公钥复制到 GitHub 的 SSH keys 。参考:SSH登录远程主机 - SSH登录(公钥登录),免得每次要输入密码。
不要在服务器上直接修改代码,不然 $ git pull
会失败。假如真的修改过,下次更新代码时,请删除服务器仓库的代码,重新 $ git clone
GitHub 上的代码。(在服务器项目文件下新增文件,并且不使用 $ git add
跟踪新文件,则使用 $ git pull
拉取合并代码时不会出现冲突。使用 $ git status
可查看新文件状态为未被跟踪。)
三、在服务器上克隆开发时的 conda 环境
3.1 安装 conda
在服务器上克隆开发时的 conda 环境,即使用 conda 安装相应的包。首先要安装conda。
此处使用安装 Miniconda 的形式安装 conda,参考:
-
Linux 上安装 conda(miniconda):https://github.com/FatliTalk/blog/issues/133
-
Miniconda 介绍和安装说明:https://docs.conda.io/en/latest/miniconda.html
3.2 克隆conda环境
有多种方式可以共享 conda 环境:Moving Conda Environments
这里使用 Environment.yml 的方式进行 conda 环境共享。
通过平台(platforms)和操作系统之间共享项目环境,可以使用
export
选项生成一个 environment.yml 文件。 environment.yml 文件不是特定于操作系统的,并且使用 YAML 进行了格式化。该文件仅列出了软件包(package)的名称和一些说明。
另外,
export
导出的软件包还包括使用 pip 安装的软件包(部分包 conda 无法安装,只能使用 pip 安装)。
3.2.1.在本地开发主机导出environment.yml文件
(conda-env) $ conda env export --file environment_<platform>.yml
# 推荐导出no-builds版本(Remove build specification规范 from dependencies):
(conda-env) $ conda env export --no-builds --file environment_<platform>.yml
3.2.2 在服务器(包含environment.yml的目录中)创建condo环境
$ conda env create --file environment_<platform>.yml
注意:
报错如下时,再次执行 $ conda env create --file environment_<platform>.yml
会报错 Segmentation fault (core dumped)
,此时等 5 分钟左右再次执行 $ conda env create --file environment_<platform>.yml
就可以把没安装成功的 Python 包安装好。
("read error: Error([('SSL routines', 'ssl3_read_n', 'unexpected eof while reading')])",)
3.3 附:创建环境 ResolvePackageNotFound 问题
参考:https://stackoverflow.com/questions/49154899/resolvepackagenotfound-create-env-using-conda-and-yml-file-on-macos
注意:
- 导出
--no-builds
版本(Remove build specification规范 from dependencies)一般不会出现该问题。 例如从 macOS 导出 .yml 配置文件(conda-env) $ conda env export --file environment_<platform>.yml
,此时 .yml 配置文件中的 Python 包会依赖 macOS 平台,这时候到 Ubuntu 上进行安装,就会出现 ResolvePackageNotFound 问题。 - 此外,还可以导出
--from-history
版本,即只导出使用$ conda install
命令主动安装的 Python 包(不包括其附带安装的依赖包),不会导出依赖包。 - 参考:https://stackoverflow.com/questions/55554431/conda-fails-to-create-environment-from-yml
# 使用本地开发主机(这里是macOS)导出的environment.yml,在服务器上创建conda环境的实例
fatli@fatli-vm-ubuntu:~/github/mysite$ conda env create --file environment-from-macos.yml
Collecting package metadata (repodata.json): done
Solving environment: failed
ResolvePackageNotFound:
- xz==5.2.4=h1de35cc_1001
- openssl==1.1.1c=h01d97ff_0
- bzip2==1.0.8=h01d97ff_1
- python==3.7.3=h93065d6_1
# ...
建议建立 2 个不同平台的 yml 文件:
- 在本地开发主机(这里是 macOS )上导出 conda 环境的文件名:environment-from-macos.yml
- 在服务器(这里是 Ubuntu )上用以创建 conda 环境的文件名:environment-for-ubuntu.yml
# 服务器(这里是Ubuntu)environment-for-ubuntu.yml文件实例
# 此文件在macOS上导出,在Ubuntu上创建环境后,创建的环境默认会安装到miniconda3/envs的目录下
# 如果报ResolvePackageNotFound,请把该部分的包放在 `- pip:` 下
# 安装后使用conda list也可以查看到在 `- pip:` 下的包
# conda环境名称,可修改
name: py37_dj_env
# 自动使用conda-forge源进行安装(即使未配置conda-forge源:conda config --add channels conda-forge)
channels:
- conda-forge
- defaults
dependencies:
# ...
- django=2.2=py37_0
# ...
- pip:
- xz==5.2.4=h1de35cc_1001
- openssl==1.1.1c=h01d97ff_0
- bzip2==1.0.8=h01d97ff_1
- python==3.7.3=h93065d6_1
# ...
prefix: /anaconda3/envs/py37_dj_env
修改 yml 文件后,在服务器再次执行 $ conda env create --file environment-for-ubuntu.yml
即可安装全部环境依赖包(dependencies),并成功创建好 conda 环境。
注意: 激活虚拟环境(否则使用conda安装在虚拟环境的包无法找到,后续部分命令无法被执行,影响项目部署):
fatli@fatli-vm-ubuntu:~/github/mysite$ conda info --envs
# conda environments:
#
base * /home/fatli/miniconda3
py37_dj_env /home/fatli/miniconda3/envs/py37_dj_env
fatli@fatli-vm-ubuntu:~/github/mysite$ conda activate py37_dj_env
(py37_dj_env) fatli@fatli-vm-ubuntu:~/github/mysite$
附:Django 项目配置 MySQL - pymysql 版本报错解决方案
四、安装并配置uWSGI
参考:
.ini
文件配置:
- Django官网 - 如何用 uWSGI 托管 Django
- uWSGI官方文档 - Quickstart for Python/WSGI applications - Deploying Django
- uWSGI官方文档 - Setting up Django and your web server with uWSGI and nginx
WSGI(Web Server Gateway Interface)规范,WSGI 规定了Python Web 应用和 Python Web 服务器之间的通讯方式。Django 的主要部署平台是 WSGI,它是 Web 服务器和 Web 应用的 Python 标准。
Django 的管理命令
$ django-admin startproject project_name
创建项目的同时,生成了一个简单的默认 WSGI 配置(wsgi.py
)。
uWSGI是WSGI实现。uWSGI 是一个快速的,自我驱动的,对开发者和系统管理员友好的应用容器服务器(对比Apache Tomcat,在接受和转发的容器意义上,两者很相似),完全由 C 编写。uWSGI 是实现了 WSGI 的工具,可以用 uWSGI 托管(整合/集成) Django。除此之外,还可以使用 Gunicorn 托管 Django ,或使用 Apache 和 mod_wsgi 托管 Django 。
uWSGI 以客户端-服务端模式运行。Web 服务器(例如 Nginx,Apache)与 django-uwsgi "worker" 进程进行通信(交互)以提供动态内容。
4.1 安装uWSGI
# You can use pip to install uWSGI (it will build a binary with python support).
# Install the latest stable release:
$ pip install uwsgi
# ... or if you want to install the latest LTS (long term support) release,
$ pip install https://projects.unbit.it/downloads/uwsgi-lts.tar.gz
# 查看官网uwsgi-docs.readthedocs.io/en/latest/Download.html安装最新Stable/LTS版,此时是2.0.18
$ pip install https://projects.unbit.it/downloads/uwsgi-2.0.18.tar.gz
# Remember that you will need to have Python development packages installed. In the case of Debian, or Debian-derived systems such as Ubuntu, what you need to have installed is pythonX.Y-dev, where X.Y is your version of Python.
# ------------分割线------------
# 使用conda安装uWSGI,查看anaconda.org/conda-forge/uwsgi,此时uWSGI版本为2.0.18,与官网最新版一致
# 此处使用该安装方式(conda会顺便安装好uWSGI的依赖包)
$ conda install -c conda-forge uwsgi
# 安装完毕后,尝试运行一下uwsgi,输出类似以下信息则证明安装成功了。
$ uwsgi
*** Starting uWSGI 2.0.18 (64bit) on [Wed Nov 27 20:56:47 2019] ***
compiled with version: 7.3.0 on 22 July 2019 16:51:41
os: Linux-4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:33:37 UTC 2016
nodename: fatli-vm-ubuntu
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 1
current working directory: /home/fatli/github/polls
detected binary path: /home/fatli/miniconda3/envs/py37_dj_env/bin/uwsgi
*** WARNING: you are running uWSGI without its master process manager ***
your processes number limit is 3737
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
The -s/--socket option is missing and stdin is not a socket.
4.2 配置并启动用于托管Django的uWSGI服务器
作用类似于本地开发时使用
$ python manage.py runserver
命令启动服务器。
4.2.1 直接使用uwsgi命令运行项目
安装完之后,可以用 uwsgi
来测试网站是否能成功运行:
# 实例
$ uwsgi --http :8001 --chdir /home/fatli/github/mysite --module mysite.wsgi:application
the web client <-> uWSGI <-> Django
-
--http
:指定端口,这里指定8001
(请确保服务器安全组中已开放此端口)。 -
--chdir
:指定 Django 项目目录路径。 -
--module
:指定要使用的 WSGI 模块——django-admin startproject djangoProject
创建项目时自动生成的包含一个 WSGIapplication
对象的djangoProject.wsgi
模块。djangoProject.wsgi
指的是djangoProject/wsgi.py
文件。
此时,在浏览器地址中输入 http://服务器IP地址:8001
。这里是: http://服务器IP地址:8001/polls
或 http://服务器IP地址:8001/admin
(对比访问原来本地开发环境的 8000
端口地址: http://localhost:8000/polls
),可以看到一个没有 css
样式的页面(页面内容和 http://localhost:8000/polls
相同)。
之所以看不到样式,是因为 uWSGI
只能提供动态连接服务,访问静态文件需要安装配置 Nginx
这类 Web 服务器。
**注意:**进行上述服务器访问,需要先将服务器 IP 地址配置到项目的 settings.py
的 ALLOWED_HOSTS = []
中。如果服务器有可视化界面(例如此处的 Ubuntu 桌面版),可以在服务器浏览器直接访问 http://localhost:8001/polls
或 http://localhost:8001/admin
。
4.2.2 使用.ini 配置文件运行项目
注意:以下配置因为涉及到 web server(Nginx)通过 socket 与 uWSGI 通讯,所以需要先配置 Nginx ,请跳到“五、安装并配置Nginx”。
the web client <-> the web server <-> the socket <-> uWSGI <-> Django
# 运行socket可能失败
$ uwsgi --socket :8001 --chdir /home/fatli/github/mysite --module mysite.wsgi:application
# 运行socket成功。chmod-socket是设置套接字权限,以允许nginx使用它
# $ uwsgi --socket 0.0.0.0:8001 --chdir /home/fatli/github/mysite --module mysite.wsgi:application --chmod-socket=664
运行上面的 uwsgi
命令太麻烦了,还容易造成错误输入,可以将上面的命令,做成一个用于保存 uwsgi
配置选项的 yourfile.ini
配置文件。然后,只需要执行以下命令即可:
$ uwsgi --ini yourfile.ini
注意:该 .ini
文件不一定要放置在项目目录中。因为服务器使用的代码同步方式是:在服务器上 $ git pull
拉取 GitHub 上的代码。所以请不要把 .ini
文件放置在项目目录中,避免代码同步时与远程 GitHub 仓库代码冲突导致同步失败。
建议在项目的同级目录中,新建一个 djangoProject_uwsgi
目录(这里是 mysite_uwsgi
),把 .ini
文件(这里是 mysite.ini
)还有后续生成的一些日志文件等放置在该目录中:
# 实例
(py37_dj_env) fatli@fatli-vm-ubuntu:~/github$ ls
mysite
(py37_dj_env) fatli@fatli-vm-ubuntu:~/github$ mkdir mysite_uwsgi
fatli@fatli-vm-ubuntu:~/github$ ls
mysite mysite_uwsgi
(py37_dj_env) fatli@fatli-vm-ubuntu:~/github$ cd mysite_uwsgi
(py37_dj_env) fatli@fatli-vm-ubuntu:~/github/mysite_uwsgi$ vim mysite.ini
(py37_dj_env) fatli@fatli-vm-ubuntu:~/github/mysite_uwsgi$ ls
mysite.ini
uWSGI 配置文件 mysite.ini
实例:
.ini
文件配置:
文件中每个选项的作用:
- https://uwsgi-docs.readthedocs.io/en/latest/Options.html
- https://www.cnblogs.com/zhouej/archive/2012/03/25/2379646.html
[uwsgi]
# 项目根目录
chdir = /home/fatli/github/mysite
# 要使用的WSGI模块
module = mysite.wsgi:application
# the virtualenv (full path)
# 不在此处指定虚拟环境,而在命令行直接激活虚拟环境 $ conda activate
# home=/home/ubuntu/miniconda3/envs/lottery_env # 无效。
# 以主进程模式运行。 a master process (will respawn your processes when they die)
# uWSGI’s built-in prefork+threading multi-worker management mode, activated by flicking the master
# switch on. For all practical serving deployments it is generally a good idea to use master mode.
master = true
# 在失去权限前,创建pidfile文件,将pid写到指定的pidfile文件中。
# 通过pid该文件可以控制uwsgi的重启和停止。
# 实例,重启uwsgi:uwsgi --reload /home/ubuntu/github/project_lottery_uwsgi/project_lottery.pid
pidfile = /home/fatli/github/mysite_uwsgi/mysite.pid
# 退出、重启uwsgi是否清理(环境临时生成的)文件,包含pid、sock和status文件
vacuum = true
# 为每个工作进程(processes/workers)设置请求数的上限。达到这个值,该工作进程就会被回收重用(重启)。防止内存泄漏
# 你可以使用这个选项来默默地对抗内存泄漏(尽管这类情况使用reload-on-as和reload-on-rss选项更有用)。
# max-requests = 5000
max-requests = 1000
# daemonize:守护。使进程在后台运行,并将日志打印到指定的日志文件
daemonize = /home/fatli/github/mysite_uwsgi/mysite.log
# 如果上传的文件名包含非 ASCII 字符时,可能抛出 UnicodeEncodeError,进行修复:
# env = LANG=en_US.UTF-8
# ===========================================================================
# 以上配置参考:https://docs.djangoproject.com/zh-hans/2.2/howto/deployment/wsgi/uwsgi/
# 以下配置参考:https://uwsgi-docs.readthedocs.io/en/latest/WSGIquickstart.html#deploying-django
# https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html
# ===========================================================================
# maximum number of worker processes
# processes = workers, spawn the specified number of workers/processes. 能实现简单并且安全的并发能力,
# 简单理解:processes应对CPU-bound(计算密集型)场景;threads应对I/O bound场景。注意:进程数如果设置太多,有可能导致系统崩溃。
# 简单理解:uwsgi设置master=true后,processes=?是子进程,uwsgi可以Respawn子进程。uwsgi创建n个子进程,就有n个解释器实例在工作。
# There is no magic rule for setting the number of processes or threads to use. It is very much application and system
# dependent. Simple math like `processes = 2 * cpucores` will not be enough. 可以使用 uwsgitop (pip install)工具进行性能监控测试。
# processes = 10
processes = 4
# spawn 4 processes, each with 2 threads:
# threads = 2 # 不设置固定线程数。下面配置了 enable-threads = true,会自动产生线程。
# bind to the specified(指定) UNIX/TCP socket(套接字) using default protocol(协议,这里指的是uwsgi协议).
# 最多可以同时指定8个socket选项。
# socket = 127.0.0.1:8001
# socket = 0.0.0.0:8001
# A socket(套接字) consists of three things: A transport protocol, An IP address, A port number .
# e.g., (TCP , 10.1.1.2 , port 1030) is a socket. 1030 is a port.
# UNIX Socket 是一种进程间的通信机制,它允许在同一机器上进行进程之间的双向数据交换。
# TCP/IP Socket 是一种允许进程通过网络进行通信的机制(一般用于多台服务器之间的进程通信,也可用于同一服务器的不同进程间的通信)。
# 在同一机器内进行进程间的通信,使用 UNIX Socket 会比 TCP/IP Socket 更高效,因为前者可以避免进行某些检查和操作(like routing)。
# 此时 Nginx 配置的 server 也需更改为此 UNIX Socket file 。
socket = /home/fatli/github/mysite_uwsgi/mysite.sock
# 设置套接字权限,以允许nginx使用它,may be needed(根据文件对应的用户的权限判断)
# chmod-socket = 664
# others you ought to look at for a deployment in production include :
# set an environment variable(应该是Django<1.4才使用)
# env = DJANGO_SETTINGS_MODULE=project_lottery.settings
# 请求超时,这个请求会被丢弃,并且当前处理这个请求的工作进程会被回收再利用(即重启),避免阻塞:
harakiri = 30 # respawn processes taking more than 30 seconds
# 通过使用POSIX/UNIX的setrlimit()函数来限制每个uWSGI进程的虚拟内存使用数,
# 如果当前进程的虚拟内存已经达到128M,并继续申请虚拟内存则会使程序报内存错误,本次的http请求将返回500错误:
# limit-as = 128 # limit processes address space/vsz(虚拟内存)
# ===========================================================================
# 以下为参考其他配置方案,自定义的设置
# ===========================================================================
# 不记录请求信息的日志。只记录错误以及uWSGI内部消息到日志中,避免日志很快就爆满
disable-logging = true
# Disable built-in logging, but log 4xx's anyway, and 5xx's
log-4xx = true
log-5xx = true
# 因为项目中有 app (lottery)使用了 APScheduler 定时调度任务(使用了线程),访问报错:
# The scheduler seems to be running under uWSGI, but threads have been disabled.
# You must run uWSGI with the --enable-threads option for the scheduler to work.
# 解决方案:启用(多)线程。参考:
# https://uwsgi-docs.readthedocs.io/en/latest/WSGIquickstart.html#a-note-on-python-threads
# 中文文档:https://uwsgi-docs-cn.readthedocs.io/zh_CN/latest/WSGIquickstart.html#python
# https://uwsgi-docs.readthedocs.io/en/latest/ThingsToKnow.html
# https://apscheduler.readthedocs.io/en/latest/faq.html#how-can-i-use-apscheduler-with-uwsgi
# Python 多线程与 GIL:https://github.com/FatliTalk/blog/issues/96
enable-threads = true
管理 uWSGI server:
# Managing the uWSGI server:
# https://uwsgi-docs.readthedocs.io/en/latest/Management.html
$ uwsgi --ini /home/fatli/github/mysite_uwsgi/mysite.ini # 启动
[uWSGI] getting INI configuration from ../mysite_uwsgi/mysite.ini
$ ps -aux | grep uwsgi # 查看uwsgi进程状态(Process Status)
# a: Show processes for all users
# u: Display the user who is using the process
# x: Show all processes. (Without this, ps won’t show processes running in a GUI environment.)
$ sudo lsof -i :8001 # 查看8001端口被哪个进程使用中。如果不显示内容,则未被使用
$ uwsgi --reload /home/fatli/github/mysite_uwsgi/mysite.pid # 重启
$ uwsgi --stop /home/fatli/github/mysite_uwsgi/mysite.pid # 关闭
$ kill -INT `cat /home/fatli/github/mysite_uwsgi/mysite.pid` # 关闭
查看 uWSGI (报错)日志路径:
/home/fatli/github/mysite_uwsgi/mysite.log
五、安装并配置Nginx
Nginx 是一个Web服务器,是一个反向代理工具,我们通常用它来部署静态文件(需要与数据库进行交互的动态内容由 Django 处理,图片、css、js 等静态内容则交由 Nginx 处理)。
uWSGI 通过 WSGI 规范和我们编写的服务进程通信,然后通过自带的高效的 uwsgi 协议和 Nginx 进行通信,最终 Nginx 通过 HTTP 协议将服务对外透出。
5.1 安装并运行Nginx
参考:
the web client <-> the web server
# Ubuntu官方列表的Nginx版本不一定是最新的。所以请添加Nginx安装列表:
# 这一步不是必须的,但建议执行,不然安装的Nginx版本会挺旧的。
$ sudo add-apt-repository ppa:nginx/stable
# 更新列表
$ sudo apt-get update
$ sudo apt-get install nginx
$ nginx -v # 查看Nginx版本号
$ dpkg -L nginx # 查看Nginx安装位置,输出/usr/share/doc/nginx。其他文件在/etc/nginx
$ dpkg --list # 查看已安装的包
$ sudo apt-get remove nginx nginx-common # 删除Nginx(保留配置文件)
$ sudo apt-get purge nginx nginx-common # 删除Nginx(且不保留配置文件)
$ sudo apt-get autoremove # 删除依赖(dependencies)
$ service nginx status # 查看Nginx状态,默认在运行ing(按q返回命令行)
# 此时访问服务器的IP地址即可看到"Welcome to nginx!"的页面
# the web client <-> the web server
# Nginx默认使用80端口,请确保80端口未被其他程序占用,使用 `sudo lsof -i:80` 查看
$ sudo /etc/init.d/nginx start # start nginx
$ sudo /etc/init.d/nginx restart # Restart nginx
$ service nginx start # Nginx启动命令
$ service nginx stop # Nginx停止命令
$ service nginx restart # Nginx重启命令
5.2 配置Nginx
参考:
the web client <-> the web server <-> the socket <-> uwsgi <-> Django
在 /etc/nginx/sites-available
目录中创建一个名为 mysite_nginx.conf
的文件,并写入以下内容(这个conf文件告诉nginx从文件系统提供媒体和静态文件,以及处理需要Django介入的请求):
# mysite_nginx.conf
# the upstream component nginx needs to connect to
upstream django {
# 此处的 “django” 可以随意命名为其他名字,例如命名为 “django_02”,下面的配置也统一使用 “django_02” 即可,
# 注意:如果有多个工程项目,此处的命名不能和其他的项目的配置命名一样,否则:
# $ sudo nginx -t nginx 报错:[emerg] duplicate upstream "django" in /etc/nginx/sites-enabled/other.conf:4
# 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)
# 在同一机器内进行进程间的通信,使用 UNIX Socket 会比 TCP/IP Socket 更高效,因为前者可以避免进行某些检查和操作(like routing)。
server unix:///home/fatli/github/mysite_uwsgi/mysite.sock;
}
# configuration of the server
server {
# the port your site will be served on
# nginx meanwhile has been configured to communicate with uWSGI on that port(8001), and with the outside world on port 8000.
# 指定端口,nginx默认端口为80。使用80端口可以通过IP/域名直接访问,不需要在IP/域名后追加 `:<your_port>` 进行访问。
listen 8000; # listen 80; # 正式上线后请使用 80 端口
# the domain name it will serve for
# server_name example.com; # substitute your machine's IP address or FQDN
# 因为在mysite/setting.py中的ALLOWED_HOST设置了这两个ip,所以设置任意一个,局域网内都可以访问到项目:
server_name 127.0.0.1; # 局域网内服务器IP:192.168.31.126 # 正式上线后请使用域名如example.com
charset utf-8;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
# alias /path/to/your/mysite/media; # your Django project's media files - amend as required
alias /home/fatli/github/mysite/media; # 存放图片等媒体文件,对外使用Nginx析出。
}
location /static {
# alias /path/to/your/mysite/static; # your Django project's static files - amend as required
# alias /home/fatli/github/mysite/polls/static; # 此时,访问http://ip:8000/admin页面将不显示任何静态文件,例如CSS样式、图片等。因为此时的通信路径是:web client-web server(Nginx)-the socket-uwsgi-Django,静态文件由Nginx对外提供。
alias /home/fatli/github/mysite/static; # 需要收集所有静态文件到static目录,才能如此配置。
}
# Finally, send all non-media requests to the Django server.动态文件交给uwsgi处理
location / {
# uwsgi_pass unix:///tmp/uwsgi.sock; # 设置uWSGI生成的Unix套接字文件的路径
# uwsgi_pass 127.0.0.1:8001; # 或者使用TCP端口套接字
uwsgi_pass django; # 复用upstream django的配置即可
# include /path/to/your/mysite/uwsgi_params; # the uwsgi_params file you installed
# uwsgi_params文件在/etc/nginx/目录中。如有需要,可以复制到项目路径下(此处不复制),避免产生读取权限问题。该文件也可从github.com/nginx/nginx/blob/master/conf/uwsgi_params下载。
include /etc/nginx/uwsgi_params; # 此时权限为root用户
}
}
创建软链接:Symlink to this file from /etc/nginx/sites-enabled
so nginx can see it :
注意:请删除 /etc/nginx/sites-enabled
原有的软链接 default
。
$ sudo ln -s /etc/nginx/sites-available/mysite_nginx.conf /etc/nginx/sites-enabled/
测试 Nginx 配置文件是否正确:
$ nginx -t
$ sudo nginx -t
查看 Nginx 报错日志路径:
/var/log/nginx/error.log
nginx.conf 配置文件 /etc/nginx/nginx.conf
用户名默认为 www-data
不用改:
# uWSGI官方文档:add your user to nginx’s group (www-data), or vice-versa, so that nginx can read and write to your socket properly.
# 某博客:将启动nginx的用户改为root,要不然会出现403 forbidden的错误
# user www-data; ==> # 运行$ nginx -t:the "user" directive(指示) makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf
# www-data是debian中默认的nginx用户,其他发行版使用不同的用户(例如:http或nginx)。
user www-data; # 运行$ ps faux | grep nginx: root - nginx: master process ; www-data - nginx: worker process
5.3 管理静态文件
参考:
此时,访问
http://ip:8000/admin
进行测试时,页面将不显示任何静态文件,例如CSS样式、图片等。因为此时的通信路径是:the web client <-> the web server <-> the socket <-> uwsgi <-> Django ,静态文件由 web server(这里是 Nginx )对外提供。
在运行 Nginx 对外提供服务之前,必须将所有 Django 静态文件收集到静态文件夹中。
开发时,因为默认使用了 INSTALLED_APPS = [django.contrib.staticfiles]
管理静态文件的框架,这会在 DEBUG = True
情况下由 ``django-admin runserver [addrport]` 自动完成静态文件管理。
该方法极度低效且不怎么安全,所以这不适合生产环境。
**收集到静态文件:**在 mysite/settings.py
设置静态文件(这里包括 polls APP 的静态文件、Django admin管理后台的静态文件)存放路径:
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
# 然后运行 $ python manage.py collectstatic 收集所有静态文件到 static 目录中。
# 收集静态文件的时间如果过长,10分钟后还在收集ing,可中断,因为实际上已收集完成。
此时,重启 Nginx 服务器,访问 http://ip:8000/admin
即可访问到静态文件。如有其他修改,例如设置了 mysite/setting.py
中的 DEBUG = False
或修改了 ALLOWED_HOST
,需要也重启一下 uWSGI 后才能生效。
不再需要通过执行 $ python manage.py runserver 0.0.0.0:<your port>
的命令形式运行项目了。
附:部署成功后常用命令:
# 本地上传代码到 GitHub,服务器端拉取-合并:
$ git fetch
$ git merge
# 重启 uwsgi (需要先 cd 到项目路径下,激活虚拟环境 conda activate xxx_env 。这里请使用你自己具体的进程ID文件路径):
$ uwsgi --reload /home/fatli/github/mysite_uwsgi/mysite.pid
# uwsgi --ini /home/fatli/github/mysite_uwsgi/mysite.ini # 启动uwsgi
# 重启 nginx :
$ sudo /etc/init.d/nginx restart
# sudo /etc/init.d/nginx start # 启动nginx
# 测试 nginx :
$ sudo nginx -t