Django部署到Windows IIS实战:static与web.config配置详解
1. 为什么要在 Windows IIS 上部署 Django这不是“倒退”而是现实刚需Django 项目默认用runserver启动开发阶段够用但一到上线就露馅——它不是生产级服务器扛不住并发没 HTTPS 支持不支持多进程隔离更没法和 Windows 域环境、AD 认证、现有 IIS 管理体系打通。很多政企、教育、医疗类客户内网环境清一色是 Windows Server IIS SQL Server 组合服务器上不允许装 Linux 虚拟机也不允许开额外端口跑 Nginx 或 Gunicorn。这时候硬推 Docker 或 WSL2不是技术不行是流程过不了审批IT 运维只认 IIS 管理器里的“应用程序池”和“网站绑定”安全审计只查C:\inetpub\wwwroot下的配置文件和权限日志。我去年帮某省疾控中心部署疫情数据上报后台就是卡在这一关——他们连 Python 解释器安装都要走三重审批但 IIS 的“添加网站”按钮点一下就能进白名单。所以“Django 部署到 Windows IIS”不是技术怀旧而是把 Django 的业务逻辑能力塞进 Windows 生态的合规管道里。核心目标就三个让manage.py runserver能被 IIS 接管、让/static/路径下的 CSS/JS/图片真能加载出来、让所有页面样式不崩、字体不乱、图标不缺。别小看最后这点——我见过太多团队花三天调通 WSGI结果首页背景图死活 404排查半天发现是web.config里staticContent没开.woff2类型浏览器直接拒收字体文件。这根本不是 Django 问题是 IIS 的 MIME 类型白名单太保守。关键词里反复出现的static和web.config恰恰暴露了最大痛点Django 的collectstatic生成的文件IIS 默认当“静态资源”处理但默认配置只认.css.js.png这几类遇到.svg.woff.ttf就返回 404而web.config这个 XML 文件本质是 IIS 的“本地路由规则模块开关静态文件开关”三合一配置中心不是可有可无的装饰品。它得写对位置必须放在STATIC_ROOT目录下、写对节点staticContent和handlers必须共存、写对顺序remove fileExtension.svg /必须在mimeMap之前否则 IIS 会静默忽略。下面我就从零开始带你把这套组合拳打扎实。2. 整体架构设计为什么选 FastCGI 而不是 HTTPPlatformHandler部署 Django 到 IIS主流方案就两个HTTPPlatformHandler微软官方推荐和FastCGI老牌稳定方案。网上很多教程直接抄微软文档用 HTTPPlatformHandler结果在 Windows Server 2016 上跑崩——因为它的底层依赖httpPlatformHandler.dll而这个 DLL 在 Server 2016 默认没启用手动启用又常和 .NET Framework 版本冲突。我实测过 7 个不同补丁版本的 Server 2016有 4 个会报错0x80070005访问被拒绝根源是httpPlatformHandler尝试以ApplicationPoolIdentity身份读取python.exe的注册表权限但默认策略禁止跨用户读取。FastCGI 就稳得多。它本质是 IIS 和 Python 进程之间的“翻译官”IIS 把 HTTP 请求打包成 FastCGI 协议发给 Python 进程Python 处理完再按协议回传响应。整个过程不碰注册表不依赖 .NET只靠wfastcgi.py这个轻量脚本桥接。微软自己也承认“FastCGI 是目前 Windows 上最兼容、最可控的 Python Web 应用托管方式”。关键它还能和virtualenv完美共存——你完全可以在C:\myproject\venv\Scripts\python.exe下运行IIS 只需指定这个路径不用全局装 Python。所以我的架构选型是IIS 作为反向代理和静态文件服务层接管所有/static/和/media/请求直接返回文件不走 PythonFastCGI 作为动态请求处理器只处理/admin/、/api/、/login/这类需要 Django 逻辑的路径web.config作为总开关用location pathstatic显式声明静态目录用handlers指定.py文件由 FastCGI 处理用staticContent开放所有前端需要的 MIME 类型。这个设计的好处是静态资源 100% 由 IIS 原生服务速度比 DjangoStaticFilesHandler快 3 倍以上实测 TTFB 从 80ms 降到 22ms动态请求全走 FastCGI避免httpPlatformHandler的权限坑web.config一文件管所有运维改个 MIME 类型不用重启 Python 进程。提示别信“用 Nginx 做反向代理”的方案。在纯 Windows 环境里多装一个 Nginx 不仅增加运维复杂度还会让安全审计多出一条“未授权第三方服务”的扣分项。IIS 本身就有成熟的 URL 重写、SSL 终止、IP 限制功能何必画蛇添足3. 核心细节解析STATIC_ROOT、STATIC_URL 和 web.config 的三角关系Django 的静态文件机制表面看就三个配置项STATIC_URL、STATICFILES_DIRS、STATIC_ROOT。但放到 IIS 环境里它们的关系就变成“三方博弈”。STATIC_URL /static/这是 Django 模板里{% static css/app.css %}生成的 URL 前缀告诉浏览器“去/static/css/app.css拿文件”。它必须和 IIS 绑定的物理路径一致否则浏览器发错请求。STATICFILES_DIRS [BASE_DIR / static]这是开发时存放原始 CSS/JS 的目录collectstatic会把这里和各 App 的static目录合并拷贝到STATIC_ROOT。STATIC_ROOT BASE_DIR / staticfiles这是collectstatic最终输出的“成品静态文件仓库”IIS 必须把这个目录设为网站的物理路径或者用虚拟目录映射过去。很多人部署失败就是因为STATIC_ROOT指向C:\myproject\staticfiles但 IIS 网站根目录却指向C:\myproject导致/static/请求找不到文件。web.config就是协调这三方的“裁判”。它必须放在STATIC_ROOT目录下即C:\myproject\staticfiles\web.config内容分三块第一块handlers告诉 IIS“.py文件别自己处理转给 FastCGI”handlers add namePython FastCGI path* verb* modulesFastCgiModule scriptProcessorC:\myproject\venv\Scripts\python.exe|C:\Python39\Lib\site-packages\wfastcgi.py resourceTypeUnspecified requireAccessScript / /handlers注意scriptProcessor的路径前半段是你的虚拟环境python.exe后半段是wfastcgi.py的绝对路径。wfastcgi必须用pip install wfastcgi安装不能用conda因为 conda 安装的路径常含空格IIS 解析会失败。第二块staticContent开放 MIME 类型这是页面样式不崩的关键staticContent remove fileExtension.svg / remove fileExtension.woff / remove fileExtension.woff2 / remove fileExtension.ttf / remove fileExtension.eot / mimeMap fileExtension.svg mimeTypeimage/svgxml / mimeMap fileExtension.woff mimeTypeapplication/font-woff / mimeMap fileExtension.woff2 mimeTypefont/woff2 / mimeMap fileExtension.ttf mimeTypeapplication/octet-stream / mimeMap fileExtension.eot mimeTypeapplication/vnd.ms-fontobject / /staticContent为什么先remove再mimeMap因为 IIS 有内置 MIME 类型列表.woff2默认不在其中直接mimeMap会被忽略。必须先删掉如果存在再重新加。mimeTypefont/woff2是 W3C 标准别写成application/font-woff2Chrome 会拒收。第三块location pathstatic是保险丝确保/static/请求绝不进 Pythonlocation pathstatic system.webServer handlers clear / add nameStaticFile path* verb* modulesStaticFileModule resourceTypeFile requireAccessRead / /handlers /system.webServer /locationclear /是重点——它清空所有 handler强制 IIS 用StaticFileModule直接读文件不经过 FastCGI。没有这行.css文件可能被当成 Python 脚本执行返回 500 错误。注意web.config必须用 UTF-8 无 BOM 编码保存。Windows 记事本默认存为 ANSI用 VS Code 或 Notepad 打开右下角确认编码是 “UTF-8”再保存。否则 IIS 加载时会报Configuration error: unrecognized element configuration。4. 实操全流程从 Python 环境准备到 IIS 网站上线4.1 Python 环境与依赖安装避开 Windows 权限雷区第一步不是写代码是搞定 Python 安装路径。绝对不要装在C:\Program Files\Python39。原因IIS 应用程序池默认以ApplicationPoolIdentity用户运行这个用户对Program Files有写权限限制pip install时会卡在Permission denied。正确路径是C:\Python39或C:\myproject\venv。我推荐用pyenv-win管理多版本比官方安装包更干净# 以管理员身份打开 PowerShell Invoke-WebRequest -UseBasicParsing -Uri https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1 -OutFile ./install-pyenv-win.ps1; ./install-pyenv-win.ps1 # 重启 PowerShell然后安装 Python 3.9.13LTS 版本兼容性最好 pyenv install 3.9.13 pyenv global 3.9.13验证python --version输出3.9.13再创建项目虚拟环境cd C:\myproject python -m venv venv venv\Scripts\activate.bat pip install django4.2.7 wfastcgi # 固定 Django 版本避免 4.3 的 ASGI 兼容问题wfastcgi安装后运行wfastcgi-enable它会输出一行注册表路径比如HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\PYTHON\WFASTCGI\{GUID}。记下这个 GUID后面 IIS 配置要用。4.2 Django 项目配置STATIC_ROOT 必须绝对路径在settings.py里STATIC_ROOT不能用Path对象或相对路径import os from pathlib import Path BASE_DIR Path(__file__).resolve().parent.parent.parent # 错误写法相对路径IIS 无法解析 # STATIC_ROOT BASE_DIR / staticfiles # 正确写法绝对路径IIS 认得 STATIC_ROOT os.path.join(BASE_DIR, staticfiles) STATIC_URL /static/ # 开发时的静态目录collectstatic 会合并到这里 STATICFILES_DIRS [ os.path.join(BASE_DIR, static), ]然后执行python manage.py collectstatic --noinput。你会看到Copying static\css\app.css to C:\myproject\staticfiles\css\app.css。检查C:\myproject\staticfiles目录下是否有完整的css/、js/、images/子目录——这是 IIS 的“粮仓”必须满员。4.3 IIS 配置四步法从应用池到网站绑定第一步创建专用应用池打开 IIS 管理器 → “应用池” → 右键“添加应用池”名称填MyDjangoAppPool.NET 版本选“无托管代码”Django 不用 .NET托管管道模式选“集成”点击“高级设置” → “标识” → 点击右侧“...” → 选择“自定义账户” → 输入.\IIS_IUSRS不是ApplicationPoolIdentity因为IIS_IUSRS对C:\myproject有读取权限ApplicationPoolIdentity默认没有第二步创建网站并绑定“网站” → 右键“添加网站”网站名称MyDjangoSite物理路径C:\myproject\staticfiles注意是staticfiles不是myproject绑定类型httpIP 地址全部未分配端口8000别用 80避免和默认网站冲突主机名留空应用程序池选刚建的MyDjangoAppPool第三步配置 FastCGI 设置IIS 管理器 → 左侧“连接”树 → 选中服务器名 → 双击“FastCGI 设置”右键“添加应用程序” → “完整路径”填C:\myproject\venv\Scripts\python.exe“参数”填C:\Python39\Lib\site-packages\wfastcgi.py“监视句柄”填wfastcgi.handle“活动状态”勾选“启用”第四步设置网站权限Windows 资源管理器 → 右键C:\myproject→ “属性” → “安全” → “编辑” → “添加”输入IIS_IUSRS→ 点击“检查名称” → 确定勾选“读取 执行”、“列出文件夹内容”、“读取”同样给IIS_IUSRS添加对C:\myproject\venv的“读取 执行”权限Python 解释器需要读取.pyd文件4.4 web.config 编写与验证三分钟定位 404web.config必须放在C:\myproject\staticfiles目录下内容如下已整合前文所有要点?xml version1.0 encodingUTF-8? configuration system.webServer handlers add namePython FastCGI path* verb* modulesFastCgiModule scriptProcessorC:\myproject\venv\Scripts\python.exe|C:\Python39\Lib\site-packages\wfastcgi.py resourceTypeUnspecified requireAccessScript / /handlers staticContent remove fileExtension.svg / remove fileExtension.woff / remove fileExtension.woff2 / remove fileExtension.ttf / remove fileExtension.eot / mimeMap fileExtension.svg mimeTypeimage/svgxml / mimeMap fileExtension.woff mimeTypeapplication/font-woff / mimeMap fileExtension.woff2 mimeTypefont/woff2 / mimeMap fileExtension.ttf mimeTypeapplication/octet-stream / mimeMap fileExtension.eot mimeTypeapplication/vnd.ms-fontobject / mimeMap fileExtension.png mimeTypeimage/png / mimeMap fileExtension.jpg mimeTypeimage/jpeg / mimeMap fileExtension.css mimeTypetext/css / mimeMap fileExtension.js mimeTypeapplication/javascript / /staticContent /system.webServer location pathstatic system.webServer handlers clear / add nameStaticFile path* verb* modulesStaticFileModule resourceTypeFile requireAccessRead / /handlers /system.webServer /location appSettings add keyWSGI_HANDLER valuemyproject.wsgi.application / add keyPYTHONPATH valueC:\myproject / add keyDJANGO_SETTINGS_MODULE valuemyproject.settings / /appSettings /configuration关键点验证打开浏览器访问http://localhost:8000/static/css/app.css应该直接下载 CSS 文件不是 404访问http://localhost:8000/admin/应该显示 Django 登录页不是 500查看浏览器开发者工具 Network 标签所有.css.js.woff2请求状态码都是200Size 列有实际字节数。如果static文件 40490% 是web.config没放对位置或STATIC_ROOT路径和 IIS 物理路径不一致如果/admin/50080% 是WSGI_HANDLER路径写错比如写成myproject.wsgi:application多了冒号。5. 常见问题与排查技巧实录那些文档不会写的坑5.1 问题速查表症状、原因、解法症状可能原因解决方案浏览器显示“Service Unavailable” (503)应用程序池停止或崩溃IIS 管理器 → 应用池 → 右键启动查看“事件查看器” → Windows 日志 → 应用程序找FastCGI相关错误/static/xxx.css返回 404web.config不在STATIC_ROOT目录下或STATIC_ROOT路径和 IIS 物理路径不匹配用资源管理器确认C:\myproject\staticfiles\web.config存在检查 IIS 网站“基本设置”里的物理路径页面加载但样式全无空白页web.config中staticContent缺少.woff2或.svgMIME 类型用浏览器 Network 标签看哪个文件 404对应添加mimeMap/admin/返回 500错误日志说ModuleNotFoundError: No module named myprojectPYTHONPATH指向错误或DJANGO_SETTINGS_MODULE拼写错误PYTHONPATH必须是C:\myproject项目根目录不是C:\myproject\myprojectDJANGO_SETTINGS_MODULE是myproject.settings不是myproject.settings.py图片上传后无法访问/media/404MEDIA_ROOT和MEDIA_URL未配置或web.config未为/media/开放静态处理在settings.py加MEDIA_URL /media/、MEDIA_ROOT os.path.join(BASE_DIR, media)在web.configlocation块里复制一份pathmedia的配置5.2 独家避坑技巧来自 12 个真实项目的血泪经验技巧 1用wfastcgi.py的调试模式抓 Python 错误默认wfastcgi静默失败。在web.config的appSettings里加一行add keyWSGI_LOG valueC:\myproject\logs\wfastcgi.log /然后创建C:\myproject\logs目录给IIS_IUSRS写入权限。重启网站访问触发错误的页面wfastcgi.log里会有完整的 Python traceback比 IIS 事件日志详细十倍。技巧 2解决collectstatic后 CSS 背景图路径失效Django 的collectstatic会把static/css/app.css里的url(../images/logo.png)改成url(../../static/images/logo.png)但 IIS 的web.config把/static/当根目录导致路径错位。解决方案在settings.py加STATICFILES_STORAGE django.contrib.staticfiles.storage.StaticFilesStorage # 强制不修改 CSS 中的 url() 路径或者用django-compressor替代原生collectstatic它能自动重写路径。技巧 3IIS 应用程序池“意外退出”的终极解法现象网站运行几小时后自动停止事件日志报Application pool MyDjangoAppPool is being automatically disabled。根源是 IIS 默认“空闲超时”设为 20 分钟Python 进程空闲就杀。解决IIS 管理器 → 应用池 → 右键“高级设置” → “空闲超时分钟”改为0永不超时→ “禁用重叠回收”设为True。技巧 4让DEBUGFalse时静态文件仍能加载生产环境DEBUGFalseDjango 默认不提供静态文件服务。但我们的web.config已接管/static/所以只要STATIC_ROOT正确DEBUG设为False完全不影响。唯一要注意的是ALLOWED_HOSTS必须包含localhost和你的域名否则 Django 会直接返回 400。技巧 5快速验证 FastCGI 是否生效不用等页面加载直接用curl测试curl -v http://localhost:8000/admin/login/如果返回HTTP/1.1 200 OK和 HTML 内容说明 FastCGI 通了如果返回HTTP/1.1 500 Internal Server Error看wfastcgi.log如果返回HTTP/1.1 404 Not Found说明请求没进 FastCGI检查web.config的handlers是否生效。最后分享个小技巧每次改完web.config不用重启 IIS只需在 IIS 管理器里右键网站 → “重新启动”。因为web.config是实时加载的重启网站比重启整个 IIS 服务快 10 秒且不影响其他网站。我在某银行项目里用这个技巧把部署验证时间从 5 分钟压到 40 秒——毕竟运维同事等着下班没人想陪你等 IIS 重启。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →