Nginx web服务器+uWSGI web服务器+Django生产环境部署

1.服务器选择原因:

uWSGI web服务器+Django其实也可以满足web服务器的要求,那么再接上nginx web服务器的原因?

首先Nginx服务器处理静态网页的能力特别强,起码比uWSGI web服务器好。所以可以两个服务器结合,做好动静服务的分离。即是Nginx提供静态服务,uWSGI服务器+Django提供动态服务,这样可以大大的提高响应效率。

2.安装配置uWSGI服务:

2.1安装uWSGI:

pip install uWSGI

2.2 终端命令启动uwsgi服务

Django应用可以单独跑起来(Django也带有web服务功能,但是比较差,可以验证开发)

Django 起服务的命令如下:python3 manage.py runserver 0.0.0.0:9000,如果这个可以通过浏览器验证通过,说明自己开发服务端程序没问题。

在之前验证通过的前提下,在Django项目目录中,执行一下命令,验证uwsgi服务器。

uwsgi --http 0.0.0.0:9000 --file form_demo/wsgi.py --static-map=/static=static

--file form_demo/wsgi.py: Django的form_demo项目名称,wsgi.py指定协议的名称即是wsgi协议。

--static-map=/static=static: 静态文件,可以不写。在浏览器刷新时会找不到。

以上是命令行启动,实际项目中更多的使用配置文件启动。

2.3使用配置文件启动uWSGI [ini 格式]

如下文件uwsgi.ini

[uwsgi]

#项目目录,根据自己项目来定

chdir=/data/Project/python/django_project/form_demo

#启动uwsgi的用户名和用户组

uid=root

gid=root

#指定项目的application

moudle=for_demo.wsgi

#指定sock的文件路径,相对路径有时会出现无法创建文件的情况.

socket=/data/Project/python/django_project/script/uwsgi.sock

#http = :8080 # 如果需要同时提供HTTP服务(如直接对外),此处配合nginx,未用

#启用主进程

master=true

#进程个数

worker=2

#每个进程的线程数

threads=3

#记录进程ID文件

pidfile=/data/Project/python/django_project/script/uwsgi.pid

#当uwsgi服务停止的时候,是否自动删除socket和pid

vacuum=true

#启用 thunder-lock 功能,当设置为 true 时,uWSGI 会使用全局文件锁来处理资源竞争问题。你也可以将其设置为 false 来禁用该功能

thunder-lock = true

#允许多线程(需配合'threads'使用)

enable-threads = true

#请求超时时间(秒),超时自动重启进程

harakiri = 30

#post-buffering 设置为 65536 字节(即 64KB),意味着 uWSGI 会将 POST 请求数据# 缓冲到 64KB 后再传递给应用程序,当 post-buffering 设置为 0 时,uWSGI 会采用流# 式处理的方式,将客户端发送的 POST 请求数据逐块传递给应用程序,而不会进行缓冲

post_buffering = 4096

日志配置

daemonize = /data/Project/python/django_project/script/uwsgi.log # 后台运行并输出日志

#logto = /var/log/uwsgi.log # 等同于 daemonize(二者选一)

#disable-logging = true # 关闭请求日志(仅记录错误)

#下述配置将 URL 中以 /static 开头的请求映射到服务器文件系统中的 /path/to/#static/files 目录。例如,当客户端请求 http://example.com/static/#style.css 时,uWSGI 会尝试从 /path/to/static/files/style.css 文件中读取#内容并返回给客户端

#static-map = /static=/path/to/static/files #此处暂时不用

虚拟环境(如果使用)

#virtualenv = /path/to/venv # (本项目Python虚拟环境路径,未使用)

  • socket

    指定与Web服务器(如Nginx)通信的地址。可以是端口(如 :8000)或Unix Socket文件(如 /tmp/uwsgi.sock)。

    • 使用Nginx时通常选择Unix Socket(性能更好)。

    • 直接对外提供HTTP服务时用 http 代替 socket

  • module

    指定WSGI入口,例如Django项目的 myapp.wsgi:application

  • virtualenv / home

    指定Python虚拟环境路径,确保uWSGI使用项目依赖。

  • processesthreads

    根据服务器CPU核心数调整进程和线程数(如 processes = 2 * CPU核心数)。

  • master

    启用主进程管理子进程,提高稳定性。

  • harakiri

    防止请求阻塞,超时自动终止并重启进程。

  • vacuum

    退出时自动清理临时文件(避免残留Socket文件导致重启失败)。

2.4生产环境建议

  • 使用 Nginx 反向代理到uWSGI的Socket。

  • Supervisorsystemd 管理uWSGI进程。

  • 日志分割:使用 logrotatedaemonize 结合日志文件路径

可以把uwsgi服务的配置文件和一些服务产生的log信息等放到一个统一目录管理。

我这里是创建一个script文件夹和Django项目同级目录。

常用命令:

uwsgi --ini uwsgi.ini通过配置文件启动wsgi服务

ps -ef | grep -i uwsgi 查看uwsgi服务是否启动?

uwsgi --stop uwsgi.pid 关闭uwsgi服务。

以上命令在创建的script文件夹下执行即可

3.安装配置Nginx

3.1安装Nginx

sudo apt install nginx

也可以用yum源管理安装nginx。

3.2Nginx配置:

server{

#监听端口

listen 8080;

#建议使用域名

server_name 10.2.6.161;

日志配置

access_log /data/Project/python/django_project/nginx_file/form_demo.log;

error_log /data/Project/python/django_project/nginx_file/form_demo_error.log;

启用 Gzip 压缩功能

gzip on;

设置允许压缩的最小响应体大小,单位为字节,小于该值的响应不会被压缩

gzip_min_length 1000;

设置允许压缩的 MIME 类型,只有匹配这些类型的响应才会被压缩

gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

处理静态文件请求

静态文件由 Nginx 直接处理(无需经过 uWSGI)

location /static/ {

静态文件的实际存储路径

必须以 `/` 结尾

指定静态文件的根目录。当客户端请求 /static/style.css 时,Nginx 会尝试从

/data/Project/python/django_project/nginx_file/static/style.css

文件中读取内容并返回给客户端

#root /data/Project/python/django_project/nginx_file/static/;

alias 指令会将 location 匹配的部分替换为指定的路径。

当客户端请求 /static/style.css 时,Nginx 会直接从

/data/Project/python/django_project/nginx_file/static/style.css

文件中读取内容

alias /data/Project/python/django_project/nginx_file/static/;

index index.html;

}

location / {

包含uWSGI参数配置

include uwsgi_params;

使用 Unix 套接字通信,需与 uWSGI 配置一致

uwsgi_pass unix:/data/Project/python/django_project/script/uwsgi.sock;

连接 uWSGI 的超时时间(默认 60s)

uwsgi_connect_timeout 70;

等待 uWSGI 响应的超时时间(重要!)

uwsgi_read_timeout 300s;

发送请求到 uWSGI 的超时时间

uwsgi_send_timeout 300s;

保持的长连接数量,版本过低会提示错误,需升级nginx版本

uwsgi_keepalive 32;

连接保持时间(秒)

keepalive_timeout 65;

设置请求头信息

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;

}

}

配置参数解释

全局配置部分
  • listen:指定 Nginx 服务器监听的端口,可以是具体的端口号(如 80),也可以是 [::]:80 同时监听 IPv4 和 IPv6。
  • server_name:定义服务器的名称,可以是域名(如 example.com)、IP 地址或通配符(如 *.example.com),用于匹配客户端请求的域名。
日志配置部分
  • access_log:指定访问日志的存储路径,记录客户端的访问信息,如请求的 URL、请求方法、响应状态码等。
  • error_log:指定错误日志的存储路径,记录 Nginx 运行过程中出现的错误信息,方便排查问题。
静态文件处理部分
  • location /static/:定义一个匹配以 /static/ 开头的 URL 请求的位置块,用于处理静态文件请求。
  • root:指定静态文件的实际存储路径,Nginx 会根据请求的 URL 在该路径下查找对应的文件并返回给客户端。
  • alias 指令会将 location 匹配的部分替换为指定的路径当客户端请求 /static/style.css 时,Nginx 会直接从/data/Project/python/django_project/nginx_file/static/style.css文件中读取内容
动态请求处理部分
  • include uwsgi_params:包含 Nginx 自带的 uwsgi_params 文件,该文件定义了一系列 uWSGI 相关的参数,如请求的方法、URL、头部信息等,确保请求能正确传递给 uWSGI 服务器。
  • uwsgi_pass:指定 uWSGI 服务器的地址和端口,Nginx 会将匹配该 location 块的请求转发到指定的 uWSGI 服务器进行处理。
  • uwsgi_read_timeout:设置 Nginx 从 uWSGI 服务器读取响应的超时时间(单位:秒),如果在该时间内没有收到响应,Nginx 会终止连接。
  • uwsgi_send_timeout:设置 Nginx 向 uWSGI 服务器发送请求的超时时间(单位:秒),如果在该时间内没有发送完请求,Nginx 会终止连接。
  • uwsgi_connect_timeout:设置 Nginx 与 uWSGI 服务器建立连接的超时时间(单位:秒),如果在该时间内无法建立连接,Nginx 会返回错误信息。
  • proxy_set_header:用于设置转发请求时的请求头信息,常见的设置包括 Host(客户端请求的主机名)、X-Real-IP(客户端的真实 IP 地址)、X-Forwarded-For(客户端的真实 IP 地址及经过的代理服务器 IP 地址)和 X-Forwarded-Proto(客户端请求使用的协议,如 httphttps),这些信息可以帮助 uWSGI 服务器获取客户端的真实信息。

nginx在测试验证中常用的命令等:

sudo service nginx start开启nginx服务

sudo service nginx stop关闭nginx服务

sudo systemctl reload nginx动态加载nginx的配置文件,适用于nginx服务未停止而修改了配置参数

sudo systemctl status nginx 查看nginx服务运行状态,

4.验证服务

建议先启动uwsgi服务再启动nginx服务,关闭时则相反即可.

4.1验证静态网页服务:

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>Welcome</title>
</head>
<body>
    <h1>Hello, World!</h1>
    <p>This is a static webpage served by Nginx.</p>
</body>
</html>

创建以上的index.html,文件路径:/data/Project/python/django_project/nginx_file/static。

根据nginx服务配置:

。。。

#监听端口

listen 8080;

#建议使用域名

server_name 10.2.6.161;

location /static/ {

alias /data/Project/python/django_project/nginx_file/static/;

index index.html;

}

。。。

在ubuntu终端先后执行命令如下:

可以在同一个pc上的浏览器直接输入地址:http://0.0.0.0:8080/static/

4.2动态服务请求验证:

贴上具体的uwsgi.ini文件:

[uwsgi]

chdir=../form_demo

uid=root

gid=root

socket = /data/Project/python/django_project/script/uwsgi.sock

chmod-socket = 666

module = form_demo.wsgi

master = true

workers = 2

threads = 3

pidfile=./uwsgi.pid

logto = ./uwsgi.log

daemonize = ./uwsgi.log

vacuum = true

自己撰写的Nginx confgi文件,路径:/etc/nginx/conf.d/form_demo.conf。最终的配置结果可以通过命令: sudo nginx -T查看有效的配置.

server{

#监听端口

listen 8080;

#建议使用域名

server_name 10.2.6.161;

日志配置

access_log /data/Project/python/django_project/nginx_file/form_demo.log;

error_log /data/Project/python/django_project/nginx_file/form_demo_error.log;

启用 Gzip 压缩功能

#gzip on;

设置允许压缩的最小响应体大小,单位为字节,小于该值的响应不会被压缩

#gzip_min_length 1000;

设置允许压缩的 MIME 类型,只有匹配这些类型的响应才会被压缩

#gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

处理静态文件请求

静态文件由 Nginx 直接处理(无需经过 uWSGI)

location /static/ {

静态文件的实际存储路径

必须以 `/` 结尾

alias /data/Project/python/django_project/nginx_file/static/;

index index.html;

}

location / {

包含uWSGI参数配置

include uwsgi_params;

连接 uWSGI 的超时时间(默认 60s)

uwsgi_connect_timeout 70;

uwsgi_pass unix:/data/Project/python/django_project/script/uwsgi.sock;

等待 uWSGI 响应的超时时间(重要!)

#uwsgi_read_timeout 300s;

发送请求到 uWSGI 的超时时间

#uwsgi_send_timeout 300s;

保持的长连接数量

#uwsgi_keepalive 32;

连接保持时间(秒)

#keepalive_timeout 65;

设置请求头信息

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;

}

}

nginx配置包含哪些路径配置可以查看:/etc/nginx/nginx.conf,通常自己写的配置文件可以放在目录:/etc/nginx/conf.d。

操作命令:

Django项目名字form_demo,目录结果如下:

form_demo->urls.py 代码如下:

python 复制代码
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    # 新增
    path('front/',include('front.urls')),
]

front->urls.py代码如下:

python 复制代码
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index,name = 'index_view'),
    path('register', views.register_view,name = 'register_view'),
    path('article', views.article_view,name = 'article_view'),
]

front->views.py代码如下:

python 复制代码
from django.shortcuts import render,HttpResponse

from .forms import MessageBoardForm,RegisterForm,ArticleForm

# Create your views here.

#请求的method
#1 Get 请求
#2 Post 请求

def index(request):
    #如果是get请求就返回一个模板:
    if request.method == 'GET':
        form = MessageBoardForm()
        return render(request,'index.html',context={'form':form})
    elif request.method == 'POST':
        # 对用post提交的数据进行数据验证
        form = MessageBoardForm(request.POST)
        if form.is_valid():
            #验证通过:
            content = form.cleaned_data.get('content')
            title = form.cleaned_data.get('title')
            email = form.cleaned_data.get('email')
            return HttpResponse(f'{content},{title},{email}')
        else:
            #表单验证失败:
            print(form.errors)
            return HttpResponse('表单验证失败')


def register_view(request):
    if request.method == 'GET':
        return render(request,'register.html')
    elif request.method == 'POST':
        form = RegisterForm(request.POST)
        if form.is_valid():
            phone = form.cleaned_data.get('phone')
            print('phone is %s'%phone)
            return HttpResponse(f'{phone}')
        else:
            print(form.errors)
            return HttpResponse('表单验证失败')

def article_view(request):
    if request.method == 'GET':
        return render(request,'article.html')
    elif request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.is_valid():
            title = form.cleaned_data.get('title')
            content = form.cleaned_data.get('content')
            return HttpResponse(f'{title},{content}')
        else:
            print(form.errors)
            return HttpResponse('表单验证失败')

front->form.py代码如下:

python 复制代码
from django import forms
from django.core.validators import RegexValidator
from .models import Article
#留言板的表单

class MessageBoardForm(forms.Form):
    title = forms.CharField(max_length=100,min_length=2,label='标题',error_messages=
                            {'required':'标题不能为空','min_length':'标题不能小于2个字符','max_length':'标题不能大于100个字符'})
    content = forms.CharField(widget=forms.Textarea,label='内容')
    email = forms.EmailField(label='邮箱')

class RegisterForm(forms.Form):
    phone = forms.CharField(validators=[RegexValidator(r'^1[3-8]\d{9}$',message='电话手机号格式不正确')])

    def clean_phone(self):
        phone = self.cleaned_data.get('phone')
        return phone
    

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = '__all__'
        #fields = ['title','content']
        # 测试fields = '__all__' 时 category字段 blank=False,提示信息。
        error_messages = {
            'category':{'required':'分类字段不能为空'}
        }

form->settings.py配置如下:

python 复制代码
"""
Django settings for form_demo project.

Generated by 'django-admin startproject' using Django 4.2.18.

For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-6@rc#x8(#!x5*r#ol6cj$u()^7d28*0^k#qj*%_*ojbc303t8b'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'front',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'form_demo.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'form_demo.wsgi.application'


# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = 'static/'

# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

新建的templates文件夹下是存放的模板html:

index.html文件如下:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Front页面</title>
</head>
<body>
    <h1>留言板</h1>
    <form action="" method="post">
        {{ form }}
        <input type="submit" value="提交">
    </form>
    
</body>
</html>

article.html如下:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>article</title>
</head>
<body>
    <form action="" method="post">
        <div>
            <input type="text" name="title" placeholder="请输入标题">
        </div>

        <div>
            <textarea name="content" id="" cols="30" rows="10" placeholder="请输入内容"></textarea>
        </div>
        <div>
            <input type="submit" value="提交">
        </div>
    </form>
</body>
</html>

article.html如下:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>注册</title>
</head>
<body>
    <form action="" method="post">
        <input type="text" name="phone">
        <input type="submit" value="提交">
    </form>
</body>
</html>

在浏览器验证结果(http://localhost:8080/front/),不是专业的html人员,凑合看,勿喷!

验证(http://localhost:8080/front/article

以上是操作nginx,uwsgi,django的基本操作,不够全面与细致,仅供参考!

相关推荐
招风的黑耳41 分钟前
使用Nginx本地部署Axure生成的HTML文件,局域网内浏览器通过IP和地址访问
nginx·html·axure·本地部署
anyup_前端梦工厂2 小时前
了解几个 HTML 标签属性,实现优化页面加载性能
前端·html
小金的学习笔记2 小时前
如何在本地和服务器新建mysql用户和密码
运维·服务器·mysql
s_fox_2 小时前
nginx ngx_http_module(7) 指令详解
运维·nginx·http
EasyNVR2 小时前
EasyRTC智能硬件:实时畅联、沉浸互动、消音护航
运维·服务器·网络·安全·音视频·webrtc·p2p
前端御书房2 小时前
前端PDF转图片技术调研实战指南:从踩坑到高可用方案的深度解析
前端·javascript
2301_789169542 小时前
angular中使用animation.css实现翻转展示卡片正反两面效果
前端·css·angular.js
若云止水3 小时前
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_process_options
运维·nginx
s_fox_3 小时前
nginx ngx_http_module(9) 指令详解
运维·nginx·http
风口上的猪20153 小时前
thingboard告警信息格式美化
java·服务器·前端