如何在同一Web服务器部署多个Django应用并分配独立PostgreSQL权限
我完全懂你这种维护多个Apache实例的痛苦——零散的配置、不同的系统用户,时间长了确实会变成一团乱麻。咱们可以用「单Web服务器反向代理 + 独立应用进程 + 最小权限数据库用户」的架构来解决,既实现权限隔离,又能大幅降低维护成本。
放弃多Apache实例的模式,用**一台主Web服务器(Apache或Nginx)**做反向代理,每个Django应用通过独立的应用服务器进程(比如uWSGI或Gunicorn)运行,每个进程使用专属的系统用户,同时为每个应用分配仅能访问自身数据库的PostgreSQL用户,严格遵循最小权限原则。
1. 切换到反向代理架构
如果你还在用Apache直接跑Django,建议转向「Apache + uWSGI」的组合:Apache负责处理静态文件和反向代理请求,uWSGI负责运行Django应用。这样主Apache只需要一个实例,所有应用的请求都通过它转发。
首先启用Apache的必要模块:
sudo a2enmod proxy proxy_uwsgi rewrite
2. 为每个Django应用创建独立系统用户
每个应用用专属的系统用户运行,确保进程级别的隔离:
# 为app1创建用户,-m创建家目录,-s指定shell sudo useradd -m -s /bin/bash app1_user # 同理为其他应用创建,比如app2_user、app3_user
然后把应用代码目录的权限转移给这个用户:
sudo chown -R app1_user:app1_user /var/www/app1
3. 配置PostgreSQL最小权限用户
给每个应用创建专属的数据库和用户,只分配它需要的权限,绝对不给跨库访问的权限:
首先进入PostgreSQL命令行:
sudo -u postgres psql
然后执行以下SQL(替换对应的名称):
-- 创建应用专属数据库用户 CREATE USER app1_db_user WITH PASSWORD '你的强密码'; -- 创建应用专属数据库,并让该用户成为所有者 CREATE DATABASE app1_db OWNER app1_db_user; -- 仅授予该用户访问自身数据库的权限 GRANT CONNECT ON DATABASE app1_db TO app1_db_user; -- 授予schema的使用权限,以及表的必要操作权限(按需调整) GRANT ALL PRIVILEGES ON SCHEMA public TO app1_db_user; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app1_db_user; GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO app1_db_user;
最后在Django的settings.py里配置对应的数据库连接:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'app1_db', 'USER': 'app1_db_user', 'PASSWORD': '你的强密码', 'HOST': 'localhost', 'PORT': '', } }
4. 用uWSGI以专属用户运行Django应用
每个应用配置独立的uWSGI实例,指定运行的系统用户,确保进程权限隔离。
创建uWSGI配置文件/var/www/app1/app1_uwsgi.ini:
[uwsgi] project = app1 base = /var/www chdir = %(base)/%(project) # 指向你的虚拟环境路径 home = %(base)/%(project)/venv module = %(project).wsgi:application master = true processes = 2 # 指定运行该进程的系统用户和组 uid = app1_user gid = app1_user # 创建套接字文件,Apache通过这个套接字和uWSGI通信 socket = /run/uwsgi/%(project).sock # 设置套接字权限,让Apache的组能访问 chmod-socket = 660 vacuum = true die-on-term = true
然后创建systemd服务文件/etc/systemd/system/app1_uwsgi.service,让应用随系统启动:
[Unit] Description=uWSGI实例:运行app1应用 After=network.target [Service] User=root Group=root ExecStart=/var/www/app1/venv/bin/uwsgi --ini /var/www/app1/app1_uwsgi.ini [Install] WantedBy=multi-user.target
启动并启用服务:
sudo systemctl daemon-reload sudo systemctl start app1_uwsgi sudo systemctl enable app1_uwsgi
5. 配置Apache反向代理规则
为每个应用创建独立的Apache虚拟主机配置,把请求转发到对应的uWSGI套接字:
创建/etc/apache2/sites-available/app1.conf:
<VirtualHost *:80> ServerName app1.yourdomain.com # 静态文件直接由Apache处理,提升性能 Alias /static/ /var/www/app1/static/ <Directory /var/www/app1/static/> Require all granted </Directory> # 将动态请求转发到uWSGI套接字 ProxyPass / unix:/run/uwsgi/app1.sock|uwsgi://app1/ ProxyPassReverse / unix:/run/uwsgi/app1.sock|uwsgi://app1/ # 日志分离,方便排查问题 ErrorLog ${APACHE_LOG_DIR}/app1_error.log CustomLog ${APACHE_LOG_DIR}/app1_access.log combined </VirtualHost>
启用该站点并重启Apache:
sudo a2ensite app1.conf sudo systemctl reload apache2
- 权限完全隔离:每个应用有独立的系统用户和数据库用户,无法访问其他应用的资源
- 维护成本低:只有一个Apache实例需要维护,应用配置模块化,可复用
- 性能更优:应用服务器(uWSGI)专门处理Django请求,比Apache直接运行效率更高
- 扩展性强:后续新增应用只需要重复用户、数据库、uWSGI、Apache配置的步骤,非常清晰
内容的提问来源于stack exchange,提问作者obsi

