Ubuntu 18.04上mod_wsgi适配双Python版本部署Django应用问题
核心问题原因
mod_wsgi与编译时指定的Python版本强绑定,单个mod_wsgi模块只能适配一个Python版本,因此无法同时兼容Python3.6和Python3.11的虚拟环境。以下提供两种可行方案:
方案一:编译多个mod_wsgi实例,分虚拟主机加载
为每个Python版本单独编译mod_wsgi,在对应虚拟主机中加载适配的模块,实现版本隔离。
1. 编译不同版本的mod_wsgi
编译Python3.6适配的mod_wsgi
激活Pyenv的Python3.6.8环境,下载mod_wsgi/4.6.5源码后编译安装到独立目录:pyenv activate 3.6.8 ./configure --with-python=$(pyenv which python3.6) --prefix=/usr/local/mod_wsgi-py36 make && sudo make install编译Python3.11适配的mod_wsgi
激活Pyenv的Python3.11+环境,下载mod_wsgi/4.9.4源码后编译安装到独立目录:pyenv activate 3.11.x # 替换为实际3.11版本号 ./configure --with-python=$(pyenv which python3.11) --prefix=/usr/local/mod_wsgi-py311 make && sudo make install
2. 配置Apache虚拟主机
先注释掉全局的LoadModule wsgi_module配置(通常在/etc/apache2/mods-available/wsgi.load或主配置文件中),然后为两个应用分别配置虚拟主机:
旧应用(Python3.6)虚拟主机配置
<VirtualHost *:80> ServerName old-app.example.com # 加载Python3.6对应的mod_wsgi模块 LoadModule wsgi_module /usr/local/mod_wsgi-py36/lib/apache2/modules/mod_wsgi.so WSGIDaemonProcess old-app python-home=/home/ubuntu/.pyenv/versions/3.6.8/envs/old-app-env WSGIProcessGroup old-app WSGIScriptAlias / /var/www/old-app/wsgi.py process-group=old-app <Directory /var/www/old-app> Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/old-app-error.log CustomLog ${APACHE_LOG_DIR}/old-app-access.log combined </VirtualHost>新应用(Python3.11)虚拟主机配置
<VirtualHost *:80> ServerName new-app.example.com # 加载Python3.11对应的mod_wsgi模块 LoadModule wsgi_module /usr/local/mod_wsgi-py311/lib/apache2/modules/mod_wsgi.so WSGIDaemonProcess new-app python-home=/home/ubuntu/.pyenv/versions/3.11.x/envs/new-app-env WSGIProcessGroup new-app WSGIScriptAlias / /var/www/new-app/wsgi.py process-group=new-app <Directory /var/www/new-app> Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/new-app-error.log CustomLog ${APACHE_LOG_DIR}/new-app-access.log combined </VirtualHost>
3. 验证并重启服务
sudo apache2ctl configtest sudo systemctl restart apache2
方案二:uWSGI+Apache反向代理(推荐长期方案)
将每个Django应用通过uWSGI运行(绑定各自的Python虚拟环境),Apache作为反向代理转发请求,实现完全的版本隔离。
1. 为每个应用安装uWSGI
在各自的虚拟环境中安装uWSGI:
# 旧应用虚拟环境 pyenv activate old-app-env pip install uwsgi # 新应用虚拟环境 pyenv activate new-app-env pip install uwsgi
2. 编写uWSGI配置文件
旧应用uwsgi.ini
[uwsgi] chdir = /var/www/old-app module = wsgi:application home = /home/ubuntu/.pyenv/versions/3.6.8/envs/old-app-env socket = /tmp/old-app.sock chmod-socket = 666 master = true processes = 4 vacuum = true新应用uwsgi.ini
[uwsgi] chdir = /var/www/new-app module = wsgi:application home = /home/ubuntu/.pyenv/versions/3.11.x/envs/new-app-env socket = /tmp/new-app.sock chmod-socket = 666 master = true processes = 4 vacuum = true
3. 配置systemd管理uWSGI进程
创建服务文件确保应用开机自启:
旧应用服务文件
/etc/systemd/system/old-app-uwsgi.service[Unit] Description=uWSGI instance for old Django app After=network.target [Service] User=ubuntu Group=www-data WorkingDirectory=/var/www/old-app Environment="PATH=/home/ubuntu/.pyenv/versions/3.6.8/envs/old-app-env/bin" ExecStart=/home/ubuntu/.pyenv/versions/3.6.8/envs/old-app-env/bin/uwsgi --ini uwsgi.ini [Install] WantedBy=multi-user.target新应用服务文件
/etc/systemd/system/new-app-uwsgi.service[Unit] Description=uWSGI instance for new Django app After=network.target [Service] User=ubuntu Group=www-data WorkingDirectory=/var/www/new-app Environment="PATH=/home/ubuntu/.pyenv/versions/3.11.x/envs/new-app-env/bin" ExecStart=/home/ubuntu/.pyenv/versions/3.11.x/envs/new-app-env/bin/uwsgi --ini uwsgi.ini [Install] WantedBy=multi-user.target
启动并启用服务:
sudo systemctl daemon-reload sudo systemctl start old-app-uwsgi new-app-uwsgi sudo systemctl enable old-app-uwsgi new-app-uwsgi
4. 配置Apache反向代理
先启用必要模块:
sudo a2enmod proxy proxy_http proxy_uwsgi
然后配置虚拟主机:
旧应用虚拟主机
<VirtualHost *:80> ServerName old-app.example.com ProxyPass / unix:/tmp/old-app.sock|uwsgi://localhost/ ProxyPassReverse / unix:/tmp/old-app.sock|uwsgi://localhost/ ErrorLog ${APACHE_LOG_DIR}/old-app-error.log CustomLog ${APACHE_LOG_DIR}/old-app-access.log combined </VirtualHost>新应用虚拟主机
<VirtualHost *:80> ServerName new-app.example.com ProxyPass / unix:/tmp/new-app.sock|uwsgi://localhost/ ProxyPassReverse / unix:/tmp/new-app.sock|uwsgi://localhost/ ErrorLog ${APACHE_LOG_DIR}/new-app-error.log CustomLog ${APACHE_LOG_DIR}/new-app-access.log combined </VirtualHost>
重启Apache生效:
sudo systemctl restart apache2
方案对比
- 多mod_wsgi实例:无需额外进程管理,但编译和配置复杂度高,Apache版本需兼容不同mod_wsgi版本。
- uWSGI反向代理:应用完全隔离,升级或修改单个应用不影响其他服务,排查问题更便捷,适合长期维护。
内容的提问来源于stack exchange,提问作者Balaji Gandham

