Apache Python 集成 #

WSGI 概述 #

什么是 WSGI? #

text
┌─────────────────────────────────────────────────────────────┐
│                    WSGI 概念                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  WSGI (Web Server Gateway Interface)                        │
│  Python Web 应用的标准接口                                  │
│                                                             │
│  作用:                                                     │
│  ├── 统一 Web 服务器与 Python 应用的通信                    │
│  ├── 解耦服务器和应用框架                                   │
│  └── 支持多种框架(Django、Flask 等)                       │
│                                                             │
│  架构:                                                     │
│  ┌─────────┐     WSGI      ┌─────────────┐                 │
│  │ Apache  │ ◄──────────► │ Python 应用  │                 │
│  │mod_wsgi │               │ Django/Flask│                 │
│  └─────────┘               └─────────────┘                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

mod_wsgi 模式 #

text
┌─────────────────────────────────────────────────────────────┐
│                    mod_wsgi 运行模式                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Embedded Mode(嵌入式)                                    │
│  ├── Python 解释器嵌入 Apache 进程                          │
│  ├── 性能较好                                               │
│  ├── 共享 Apache 进程                                       │
│  └── 适合简单应用                                           │
│                                                             │
│  Daemon Mode(守护进程)                                    │
│  ├── 独立的 Python 进程                                     │
│  ├── 进程隔离                                               │
│  ├── 可配置进程数量                                         │
│  ├── 支持不同用户权限                                       │
│  └── 推荐用于生产环境                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

安装 mod_wsgi #

Ubuntu/Debian #

bash
# 安装 mod_wsgi
sudo apt install libapache2-mod-wsgi-py3

# 启用模块
sudo a2enmod wsgi
sudo systemctl restart apache2

# 验证安装
apache2ctl -M | grep wsgi

CentOS/RHEL #

bash
# 安装 mod_wsgi
sudo yum install mod_wsgi

# 重启 Apache
sudo systemctl restart httpd

# 验证安装
httpd -M | grep wsgi

使用 pip 安装 #

bash
# 安装 mod_wsgi
pip install mod_wsgi

# 查看配置
mod_wsgi-express module-config

# 输出示例
# LoadModule wsgi_module "/usr/local/lib/python3.10/site-packages/mod_wsgi/server/mod_wsgi-py310.cpython-310-x86_64-linux-gnu.so"
# WSGIPythonHome "/usr/local"

基础 WSGI 配置 #

简单 WSGI 应用 #

python
# /var/www/wsgi/app.wsgi

def application(environ, start_response):
    status = '200 OK'
    output = b'Hello, World from WSGI!'
    
    response_headers = [
        ('Content-type', 'text/plain'),
        ('Content-Length', str(len(output)))
    ]
    start_response(status, response_headers)
    
    return [output]

Apache 配置 #

apache
# ============================================
# 基础 WSGI 配置
# ============================================

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/wsgi
    
    # WSGI 脚本别名
    WSGIScriptAlias / /var/www/wsgi/app.wsgi
    
    # WSGI 脚本目录权限
    <Directory /var/www/wsgi>
        Require all granted
    </Directory>
    
    # 日志
    ErrorLog ${APACHE_LOG_DIR}/wsgi-error.log
    CustomLog ${APACHE_LOG_DIR}/wsgi-access.log combined
</VirtualHost>

Daemon 模式配置 #

基础 Daemon 配置 #

apache
# ============================================
# WSGI Daemon 模式配置
# ============================================

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/app
    
    # 配置守护进程组
    WSGIDaemonProcess myapp \
        python-path=/var/www/app \
        python-home=/var/www/app/venv \
        processes=2 \
        threads=15 \
        maximum-requests=10000 \
        user=www-data \
        group=www-data
    
    # 将应用分配到守护进程组
    WSGIProcessGroup myapp
    
    # WSGI 脚本
    WSGIScriptAlias / /var/www/app/app.wsgi
    
    <Directory /var/www/app>
        WSGIProcessGroup myapp
        WSGIApplicationGroup %{GLOBAL}
        Require all granted
    </Directory>
</VirtualHost>

WSGIDaemonProcess 参数 #

text
┌─────────────────────────────────────────────────────────────┐
│                    WSGIDaemonProcess 参数                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  processes=N       进程数量                                 │
│  threads=N         每个进程的线程数                         │
│  maximum-requests=N 请求上限后重启进程                      │
│  user=USER         运行用户                                 │
│  group=GROUP       运行组                                   │
│  python-path=PATH  Python 模块搜索路径                      │
│  python-home=PATH  Python 虚拟环境路径                      │
│  socket-user=USER  Unix 套接字用户                          │
│  socket-group=GROUP Unix 套接字组                           │
│  socket-mode=MODE  Unix 套接字权限                          │
│  display-name=NAME 进程显示名称                             │
│  inactivity-timeout=N 空闲超时(秒)                        │
│  deadlock-timeout=N 死锁超时(秒)                          │
│  graceful-timeout=N 优雅关闭超时(秒)                      │
│  queue-timeout=N   队列超时(秒)                           │
│  request-timeout=N 请求超时(秒)                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Flask 应用部署 #

Flask 应用结构 #

text
/var/www/flaskapp/
├── app/
│   ├── __init__.py
│   ├── views.py
│   └── models.py
├── venv/
├── app.wsgi
└── requirements.txt

Flask 应用代码 #

python
# /var/www/flaskapp/app/__init__.py

from flask import Flask

app = Flask(__name__)

from app import views
python
# /var/www/flaskapp/app/views.py

from app import app

@app.route('/')
def index():
    return 'Hello, Flask!'

@app.route('/api/data')
def data():
    return {'message': 'Hello, API!'}

WSGI 入口文件 #

python
# /var/www/flaskapp/app.wsgi

import sys
import os

# 添加应用路径
sys.path.insert(0, '/var/www/flaskapp')

# 激活虚拟环境
activate_this = '/var/www/flaskapp/venv/bin/activate_this.py'
with open(activate_this) as file_:
    exec(file_.read(), dict(__file__=activate_this))

# 导入应用
from app import app as application

Apache 配置 #

apache
# ============================================
# Flask 应用配置
# ============================================

<VirtualHost *:80>
    ServerName flaskapp.example.com
    DocumentRoot /var/www/flaskapp
    
    # WSGI 守护进程
    WSGIDaemonProcess flaskapp \
        python-path=/var/www/flaskapp \
        python-home=/var/www/flaskapp/venv \
        processes=2 \
        threads=15 \
        user=www-data \
        group=www-data
    
    WSGIProcessGroup flaskapp
    WSGIScriptAlias / /var/www/flaskapp/app.wsgi
    
    <Directory /var/www/flaskapp>
        WSGIProcessGroup flaskapp
        WSGIApplicationGroup %{GLOBAL}
        Require all granted
    </Directory>
    
    # 静态文件
    Alias /static /var/www/flaskapp/app/static
    <Directory /var/www/flaskapp/app/static>
        Require all granted
    </Directory>
    
    ErrorLog ${APACHE_LOG_DIR}/flaskapp-error.log
    CustomLog ${APACHE_LOG_DIR}/flaskapp-access.log combined
</VirtualHost>

Django 应用部署 #

Django 应用结构 #

text
/var/www/djangoapp/
├── myproject/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── myapp/
├── static/
├── media/
├── venv/
└── requirements.txt

Django WSGI 配置 #

python
# /var/www/djangoapp/myproject/wsgi.py

import os
import sys
from django.core.wsgi import get_wsgi_application

# 添加项目路径
sys.path.insert(0, '/var/www/djangoapp')

# 设置 Django 配置模块
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

application = get_wsgi_application()

Apache 配置 #

apache
# ============================================
# Django 应用配置
# ============================================

<VirtualHost *:80>
    ServerName djangoapp.example.com
    ServerAdmin webmaster@example.com
    
    # WSGI 守护进程
    WSGIDaemonProcess djangoapp \
        python-path=/var/www/djangoapp:/var/www/djangoapp/venv/lib/python3.10/site-packages \
        python-home=/var/www/djangoapp/venv \
        processes=2 \
        threads=15 \
        maximum-requests=5000 \
        user=www-data \
        group=www-data
    
    WSGIProcessGroup djangoapp
    WSGIScriptAlias / /var/www/djangoapp/myproject/wsgi.py
    
    # WSGI 脚本目录
    <Directory /var/www/djangoapp/myproject>
        WSGIProcessGroup djangoapp
        WSGIApplicationGroup %{GLOBAL}
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>
    
    # 静态文件
    Alias /static/ /var/www/djangoapp/static/
    <Directory /var/www/djangoapp/static>
        Require all granted
    </Directory>
    
    # 媒体文件
    Alias /media/ /var/www/djangoapp/media/
    <Directory /var/www/djangoapp/media>
        Require all granted
    </Directory>
    
    # 日志
    ErrorLog ${APACHE_LOG_DIR}/djangoapp-error.log
    CustomLog ${APACHE_LOG_DIR}/djangoapp-access.log combined
</VirtualHost>

Django settings.py 配置 #

python
# /var/www/djangoapp/myproject/settings.py

# 允许的主机
ALLOWED_HOSTS = ['djangoapp.example.com', 'localhost']

# 静态文件
STATIC_URL = '/static/'
STATIC_ROOT = '/var/www/djangoapp/static/'

# 媒体文件
MEDIA_URL = '/media/'
MEDIA_ROOT = '/var/www/djangoapp/media/'

# 调试模式(生产环境关闭)
DEBUG = False

# 安全设置
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True

多应用配置 #

多个 WSGI 应用 #

apache
# ============================================
# 多个 WSGI 应用配置
# ============================================

<VirtualHost *:80>
    ServerName example.com
    
    # 应用 1
    WSGIDaemonProcess app1 python-path=/var/www/app1 processes=2 threads=10
    WSGIScriptAlias /app1 /var/www/app1/app.wsgi
    
    <Location /app1>
        WSGIProcessGroup app1
    </Location>
    
    # 应用 2
    WSGIDaemonProcess app2 python-path=/var/www/app2 processes=2 threads=10
    WSGIScriptAlias /app2 /var/www/app2/app.wsgi
    
    <Location /app2>
        WSGIProcessGroup app2
    </Location>
    
    <Directory /var/www/app1>
        Require all granted
    </Directory>
    
    <Directory /var/www/app2>
        Require all granted
    </Directory>
</VirtualHost>

性能优化 #

进程和线程配置 #

apache
# ============================================
# 性能优化配置
# ============================================

# 高并发配置
WSGIDaemonProcess myapp \
    processes=4 \
    threads=25 \
    maximum-requests=10000 \
    deadlock-timeout=60 \
    inactivity-timeout=300

# 低内存配置
WSGIDaemonProcess myapp \
    processes=2 \
    threads=10 \
    maximum-requests=5000

# CPU 密集型
WSGIDaemonProcess myapp \
    processes=8 \
    threads=5 \
    maximum-requests=5000

# I/O 密集型
WSGIDaemonProcess myapp \
    processes=2 \
    threads=50 \
    maximum-requests=10000

守护进程组共享 #

apache
# 共享守护进程组
WSGIDaemonProcess shared processes=2 threads=15

<VirtualHost *:80>
    ServerName app1.example.com
    WSGIProcessGroup shared
    WSGIScriptAlias / /var/www/app1/app.wsgi
</VirtualHost>

<VirtualHost *:80>
    ServerName app2.example.com
    WSGIProcessGroup shared
    WSGIScriptAlias / /var/www/app2/app.wsgi
</VirtualHost>

调试技巧 #

启用调试日志 #

apache
# 启用 WSGI 调试日志
LogLevel wsgi:trace3

# 在 WSGI 脚本中
import logging
logging.basicConfig(filename='/var/log/wsgi-debug.log', level=logging.DEBUG)

常见问题 #

text
┌─────────────────────────────────────────────────────────────┐
│                    常见问题                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 模块导入错误                                            │
│     检查 python-path 配置                                   │
│     确认虚拟环境路径                                        │
│                                                             │
│  2. 权限问题                                                │
│     检查 user/group 配置                                    │
│     确认文件权限                                            │
│                                                             │
│  3. 静态文件 404                                            │
│     检查 Alias 配置                                         │
│     确认目录权限                                            │
│                                                             │
│  4. 内存泄漏                                                │
│     设置 maximum-requests                                   │
│     监控进程内存                                            │
│                                                             │
│  5. 超时问题                                                │
│     调整 request-timeout                                    │
│     检查应用性能                                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

下一步 #

掌握了 Python 集成后,继续学习 Docker 部署,了解如何使用 Docker 部署 Apache!

最后更新:2026-03-29