Streamlit Host in IIS server

Streamlit on IIS — Step by Step Guide

A complete guide to hosting a Streamlit Python app on Windows Server using IIS as a reverse proxy with full WebSocket support.


What You Need Before Starting

  • Windows Server with IIS installed

  • Python installed (3.9+ recommended)

  • Streamlit app ready (app.py)

  • Domain name (optional but recommended)

  • NSSM downloaded from https://nssm.cc


Step 1 — Install IIS Modules

Download and install both modules from Microsoft:

After installing, restart IIS:

iisreset


Step 2 — Enable ARR Proxy

  1. Open IIS Manager

  2. Click the server name (root node)

  3. Double-click Application Request Routing Cache

  4. Click Server Proxy Settings on the right panel

  5. Check :white_check_mark: Enable proxy

  6. Click Apply

  7. :white_check_mark: Enable WebSocket support(WebSocket | Microsoft Learn)


Step 3 — Run Streamlit as a Windows Service

Using NSSM to run Streamlit as a background Windows Service ensures it starts automatically and stays alive after reboots.

Open PowerShell as Administrator:

cd C:\nssm\win64

.\nssm.exe install StreamlitApp "C:\Python312\python.exe" "-m streamlit run C:\sites\myapp\app.py"

.\nssm.exe set StreamlitApp AppDirectory "C:\sites\myapp"

net start StreamlitApp

Verify it is running:

# Check service status
sc query StreamlitApp

# Check port is listening
netstat -an | findstr 8501

You should see port 8501 in LISTENING state.

:warning: Make sure you point NSSM to your Streamlit file (app.py), not a FastAPI or other backend entry point.


Step 4 — Configure Streamlit

Create the file .streamlit/config.toml inside your app folder:

C:\sites\myapp\.streamlit\config.toml

[server]
headless = true
port = 8501
enableCORS = false
enableXsrfProtection = false

[browser]
gatherUsageStats = false

Setting Value Reason
headless true Prevents Streamlit opening a browser on the server
port 8501 Explicit port so IIS and NSSM configs match
enableCORS false IIS handles CORS — Streamlit’s check blocks proxy requests
enableXsrfProtection false XSRF tokens break when accessed through a proxy domain

Restart the service after saving:

net stop StreamlitApp
net start StreamlitApp


Step 5 — Create IIS Site

  1. Open IIS Manager

  2. Right-click SitesAdd Website

  3. Fill in:

    • Site name: myapp

    • Physical path: C:\sites\myapp

    • Binding: HTTPS, port 443

    • Hostname: myapp.yourdomain.com

    • SSL certificate: select your certificate

  4. Click OK


Step 6 — Create web.config

Create web.config inside your site’s physical path folder C:\sites\myapp\:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>

    <!-- Enable WebSocket at IIS level -->
    <webSocket enabled="true" />

    <rewrite>
      <rules>

        <!-- Rule 1: WebSocket upgrade requests — MUST come first -->
        <rule name="StreamlitWebSocket" stopProcessing="true">
          <match url="(.*)" />
          <conditions logicalGrouping="MatchAll">
            <add input="{HTTP_CONNECTION}" pattern="Upgrade" ignoreCase="true" />
            <add input="{HTTP_UPGRADE}" pattern="websocket" ignoreCase="true" />
          </conditions>
          <action type="Rewrite" url="ws://127.0.0.1:8501/{R:1}" />
        </rule>

        <!-- Rule 2: All regular HTTP requests -->
        <rule name="StreamlitHTTP" stopProcessing="true">
          <match url="(.*)" />
          <action type="Rewrite" url="http://127.0.0.1:8501/{R:1}" />
        </rule>

      </rules>
    </rewrite>

  </system.webServer>
</configuration>

:warning: Rule order matters. The WebSocket rule MUST come before the HTTP rule. IIS processes rules top to bottom and stops at the first match.


Step 7 — DNS Setup

In your DNS provider (Namecheap, Cloudflare, GoDaddy, etc.):

Type Host Value
A Record myapp YOUR_SERVER_IP

:warning: Critical: If your DNS provider shows a CDN, Proxy, or HTTPS toggle next to the record — turn it OFF.

CDN/proxy layers intercept WebSocket upgrade headers and silently block them. Your Streamlit app will load but freeze immediately. Always point DNS directly to your server IP.

Verify DNS is resolving correctly:

# Via Google DNS
nslookup myapp.yourdomain.com 8.8.8.8

# Via Cloudflare DNS (faster propagation)
nslookup myapp.yourdomain.com 1.1.1.1

Both should return your server’s IP. DNS propagation can take 5–30 minutes after making changes.


Step 8 — Verify Everything Works

Run these checks one by one:

# 1. Is the Streamlit service running?
sc query StreamlitApp

# 2. Is port 8501 listening?
netstat -an | findstr 8501

# 3. Does Streamlit respond locally?
Invoke-WebRequest -Uri "http://127.0.0.1:8501" -UseBasicParsing

# 4. Is DNS pointing to your server?
nslookup myapp.yourdomain.com 8.8.8.8

Then open your browser and navigate to https://myapp.yourdomain.com.

Press F12 → go to the Console tab → you should see no WebSocket errors.

A working connection looks like:

WebSocket connection to 'wss://myapp.yourdomain.com/_stcore/stream' established


Common Problems & Fixes

Problem Cause Fix
Page loads but immediately freezes WebSocket rule missing in web.config Add the WebSocket rule above the HTTP rule
wss:// connection keeps failing CDN/proxy toggle is ON in DNS settings Turn OFF the CDN toggle — use plain A Record
Streamlit service won’t start Wrong file in NSSM (e.g. main.py) Make sure NSSM points to app.py
enableCORS or XSRF errors in logs Default Streamlit settings Set both to false in config.toml
After iisreset WebSocket breaks IIS drops the proxy connection pool Use Restart-WebAppPool instead of iisreset
DNS showing wrong IP after update DNS propagation delay Wait 5–30 min, run ipconfig /flushdns as Admin

Quick Reference Commands

# --- Streamlit Service ---
sc query StreamlitApp                     # Check status
net start StreamlitApp                    # Start
net stop StreamlitApp                     # Stop
net stop StreamlitApp && net start StreamlitApp  # Restart

# --- IIS Management ---
iisreset                                  # Full restart (avoid for routine use)
Restart-WebAppPool "myapp"               # Restart one app pool only
Stop-Website "myapp"                     # Stop one site
Start-Website "myapp"                    # Start one site

# --- DNS Checks ---
nslookup myapp.yourdomain.com 8.8.8.8   # Check via Google DNS
nslookup myapp.yourdomain.com 1.1.1.1   # Check via Cloudflare DNS

# --- Network ---
ipconfig /flushdns                        # Clear DNS cache (run as Admin)
netstat -an | findstr 8501               # Check Streamlit port

# --- Test Locally ---
Invoke-WebRequest -Uri "http://127.0.0.1:8501" -UseBasicParsing


Summary Checklist

  • [ ] URL Rewrite module installed

  • [ ] ARR module installed

  • [ ] ARR proxy + WebSocket enabled in IIS Manager

  • [ ] Streamlit running as NSSM Windows Service on port 8501

  • [ ] .streamlit/config.toml created with CORS and XSRF disabled

  • [ ] IIS site created with HTTPS binding and SSL certificate

  • [ ] web.config placed in site root with WebSocket rule first

  • [ ] DNS A record pointing directly to server IP (CDN toggle OFF)

  • [ ] nslookup confirms correct IP

  • [ ] Browser console shows no WebSocket errors


All problems listed in this guide were encountered and resolved in a real production deployment on Windows Server with IIS 10.

Welcome to the Streamlit community, and thanks for sharing such a thorough step-by-step guide! :tada: Your instructions for deploying Streamlit on Windows Server with IIS as a reverse proxy (including full WebSocket support) are well-aligned with best practices and community recommendations. The key steps—installing URL Rewrite and ARR, enabling proxy and WebSocket support, running Streamlit as a Windows service (NSSM), configuring Streamlit for headless/proxy use, setting up IIS site bindings, and writing the correct web.config rules—are all essential for a robust deployment.

Your approach to disabling CORS and XSRF in Streamlit’s config.toml is necessary when using IIS as a reverse proxy, as IIS will handle those protections. The web.config rules, especially the order (WebSocket rule before HTTP), are critical for proper WebSocket upgrades, which Streamlit relies on for client-server communication. Community threads confirm that missing or misordered WebSocket rules, or leaving CDN/proxy toggles ON in DNS, are common causes of apps freezing or failing to load. For troubleshooting, your checklist and command references are spot-on—these match the advice given in official docs and forum posts for resolving blank pages, connection errors, and WebSocket issues when deploying behind IIS or other reverse proxies. For more details, see the official Streamlit remote deployment troubleshooting guide and community IIS deployment threads.

If you’d like a more detailed breakdown of any step, or want to see sample config files or troubleshooting logs, just let us know! And if you run into any issues, please share your config, error messages, and minimum reproducible example so the community can jump in and help. :rocket:

Sources: