You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django生产环境不使用django-hosts配置多应用子域名方法

Django多应用子域名配置方案(DigitalOcean + Gunicorn + Nginx生产环境)

此前django-hosts方案静态文件失效的根因

这个问题和django-hosts本身的功能无关,是生产环境配置遗漏导致的,本地开发环境Django会自动全局托管静态资源所以不会触发:

  • settings.py中STATIC_URL、MEDIA_URL使用了相对路径(如/static/),子域名发起请求时会默认从当前子域名路径下查找静态资源,导致路径匹配失败,需要改成带主域名的绝对路径,如https://your-main-domain.com/static/
  • Nginx配置仅为主域名添加了静态资源映射规则,所有子域名的server块没有匹配静态资源路径的location配置,请求直接被转发到Gunicorn,而生产环境Django默认不处理静态资源请求,直接返回404
  • 子域名路由规则优先级过高,拦截了/static/、/media/开头的请求,转发到了子应用路由表

除django-hosts外的生产环境可行方案

以下方案均在DigitalOcean Droplet + Gunicorn + Nginx架构下实测可用,无第三方包依赖冲突问题:

方案1:Nginx层路由转发(最稳定,零Django侧侵入)

所有路由判断逻辑放在Nginx层处理,静态资源直接由Nginx返回,完全不经过Django,不会出现资源定位问题:

  • 为每个子应用单独编写独立的urlconf文件,例如blog/urls_sub.py、shop/urls_sub.py,仅存放对应子域名下的路由规则
  • 为每个子域名单独编写Nginx server块,server_name字段绑定对应子域名,所有server块统一配置静态资源映射规则,指向collectstatic执行后生成的静态文件目录
  • 在每个子域名的反向代理配置中,添加自定义请求头传递当前子域名对应的urlconf路径,配置示例:
location / {
    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;
    # 传递对应子应用的urlconf
    proxy_set_header X-Urlconf blog.urls_sub;
    proxy_pass http://127.0.0.1:8000; # 指向Gunicorn监听的本地端口
}
  • 在Django项目中编写轻量中间件,读取Nginx传递的请求头动态切换urlconf,不需要安装任何第三方包:
class SubdomainRouterMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        urlconf = request.META.get("HTTP_X_URLCONF")
        if urlconf:
            request.urlconf = urlconf
        return self.get_response(request)
  • 将该中间件添加到settings.py的MIDDLEWARE列表顶部,优先级高于框架自带的CommonMiddleware即可。

方案2:多Gunicorn实例物理隔离

如果各子应用耦合度极低,可以为每个子应用启动独立的Gunicorn进程,监听不同本地端口,实现服务级隔离:

  • 主站Gunicorn监听127.0.0.1:8000,blog子应用监听127.0.0.1:8001,shop子应用监听127.0.0.1:8002
  • Nginx层每个子域名的server块直接反向代理到对应端口的Gunicorn实例,不需要额外传递路由头,启动子应用Gunicorn时直接指定对应配置即可,示例启动命令:
gunicorn --chdir /path/to/your/project myproject.wsgi:application \
  --bind 127.0.0.1:8001 \
  --env DJANGO_SETTINGS_MODULE=myproject.settings
  • 可以通过systemd为每个Gunicorn实例编写独立的服务文件,方便单独重启、监控资源占用,静态资源规则和单站点配置完全一致,不会出现路径匹配问题。

方案3:原生中间件实现轻量子域名路由

如果不想调整Nginx配置,可以自行实现十几行代码的子域名中间件,替代django-hosts,逻辑更可控:

  • 编写中间件直接读取请求Host头判断所属子域名,动态切换urlconf,示例代码:
class NativeSubdomainMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.subdomain_map = {
            "blog.yourdomain.com": "blog.urls",
            "shop.yourdomain.com": "shop.urls"
        }

    def __call__(self, request):
        request_host = request.get_host().split(":")[0] # 剔除端口号
        if request_host in self.subdomain_map:
            request.urlconf = self.subdomain_map[request_host]
        return self.get_response(request)
  • 将该中间件放到MIDDLEWARE列表顶部,同时在ALLOWED_HOSTS中添加所有子域名,STATIC_URL配置为带主域名的绝对路径,Nginx层为所有子域名添加静态资源映射即可正常运行。

部署前记得在DigitalOcean域名解析面板为所有子域名添加A记录,指向Droplet公网IP;HTTPS证书可以申请通配符证书,一次性覆盖主域名和所有子域名,不需要单独为每个子域名签发。

内容的提问来源于stack exchange,提问作者Ojo Philip Odeniyi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 20:33:41