{"id":835,"date":"2026-10-05T03:42:06","date_gmt":"2026-10-05T03:42:06","guid":{"rendered":"https:\/\/windows-vps.org\/blog\/?p=835"},"modified":"2026-10-07T22:06:50","modified_gmt":"2026-10-07T22:06:50","slug":"iis-web-farm-arr-load-balancing-health-probes-windows","status":"publish","type":"post","link":"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/","title":{"rendered":"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State"},"content":{"rendered":"<div style=\"padding:20px\">\n\n\n<p class=\"wp-block-paragraph\">A single IIS server eventually hits a ceiling. The two ways past it are scale up (a larger VPS) or scale out (several nodes behind a load balancer). On Windows Server the native scale-out answer is an IIS Web Farm fronted by Application Request Routing (ARR) with URL Rewrite. This walkthrough stands up a two-node farm on separate Windows VPS instances, configures ARR as a reverse proxy, and adds health probes so a failed node drops out without manual intervention. Provisioning the nodes is the first step \u2014 the <a href=\"https:\/\/windows-vps.org\/#providers\">comparison of Windows VPS providers<\/a> lists plans with matching regions, which matters when nodes must share a low-latency network. When one box is no longer enough, that page is the starting point for choosing the front-end and backend hosts.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Architecture and Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Front end<\/strong> \u2014 one small Windows Server with IIS, ARR, and URL Rewrite. Terminates TLS, balances, and runs health checks.<\/li><li><strong>Backends<\/strong> \u2014 two or more IIS nodes serving identical content.<\/li><li><strong>Shared state<\/strong> \u2014 sessions and content must be shared or stateless, or users bounce between nodes and lose carts and logins.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Place all nodes in the same region so intra-farm latency stays under 2 ms. Cross-region backends introduce TLS renegotiation and session lag that health probes mask but users feel.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Install ARR and URL Rewrite<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Install the IIS role, then add <em>Application Request Routing 3.0<\/em> and <em>URL Rewrite 2.1<\/em> from Microsoft. Verify both modules loaded:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>Get-WebGlobalModule | Where-Object Name -like '*ARR*'<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The output should list <code>ApplicationRequestRouting<\/code> and its provider modules. If nothing returns, the install did not register \u2014 reinstall with the Web Platform Installer (WebPI) or the MSI directly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Create the Server Farm and Probes<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In IIS Manager, open <em>Server Farms &gt; Create Server Farm<\/em>. Add both backend addresses. On the Health Test tab, set a <strong>URL<\/strong> the app exposes cheaply (a static <code>\/health.txt<\/code> is ideal \u2014 do not probe a database-backed endpoint), an <strong>interval<\/strong> of 10 seconds, and a <strong>failure threshold of 3<\/strong>. That means a bad node is removed within 30 seconds.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Probe setting<\/th><th>Recommended value<\/th><th>Effect<\/th><\/tr><\/thead><tbody><tr><td>URL<\/td><td>\/health.txt (static)<\/td><td>Cheap, avoids DB load per probe<\/td><\/tr><tr><td>Interval<\/td><td>10 s<\/td><td>Detects failure within 30 s at threshold 3<\/td><\/tr><tr><td>Timeout<\/td><td>5 s<\/td><td>Rejects slow nodes before they cascade<\/td><\/tr><tr><td>Failure threshold<\/td><td>3<\/td><td>Prevents flapping on a single dropped packet<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">4. Load Balancing Algorithm and Affinity<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">ARR defaults to weighted round-robin. For stateless ASP.NET Core apps that is correct. For classic ASP.NET sessions backed by <code>InProc<\/code>, either move to <code>StateServer<\/code>\/<code>SQLServer<\/code> or enable client affinity \u2014 but affinity undermines the point of a farm, so fix session storage instead. Set a sticky cookie only for short-lived migration windows.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. X-Forwarded Headers<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Behind ARR, every request appears to originate from the proxy. Rewrite the client identity headers so logs and rate-limiting see the real IP:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Enable <code>X-Forwarded-For<\/code> and <code>X-Forwarded-Proto<\/code> in the farm&#8217;s proxy settings.<\/li><li>In ASP.NET Core, add ForwardedHeaders middleware and clear <code>KnownNetworks<\/code>\/<code>KnownProxies<\/code> defaults to trust only your front-end.<\/li><li>In classic ASP.NET, read the header in <code>Application_BeginRequest<\/code> and update <code>Request.UserHostAddress<\/code> carefully \u2014 do not trust it from arbitrary clients.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">6. Verifying Failover<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Test rather than trust. Stop the Application Pool on one backend, then poll the farm URL and watch which node answers. A correctly configured farm returns 200 throughout, with the dead node showing <em>Unhealthy<\/em> in the ARR farm view within the threshold window. If requests still land on the dead node, the probe URL is wrong or the failure threshold is too high.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">7. Handling Sessions on a Web Farm<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Round-robin balancing exposes any session state held in-process. Three options, in order of preference:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Stateless tokens<\/strong> \u2014 for ASP.NET Core, store state in a JWT or a signed cookie and skip server sessions entirely.<\/li><li><strong>Distributed cache<\/strong> \u2014 Redis or a SQL-backed session store shared by all nodes; adds a dependency but scales cleanly.<\/li><li><strong>Client affinity<\/strong> \u2014 sticky sessions via the ARR affinity cookie. Simplest, but a node failure logs out its users and uneven traffic follows.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For file uploads, do not write to local disk on one node \u2014 the next request may hit another. Use a shared SMB share, Azure Blob, or object storage consistent across nodes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Common Failure Modes<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Symptom<\/th><th>Likely cause<\/th><th>Check<\/th><\/tr><\/thead><tbody><tr><td>502 from the front end<\/td><td>Backend unreachable or probe says down<\/td><td>Farm health view, backend firewall<\/td><\/tr><tr><td>Node flapping<\/td><td>Probe timeout too tight<\/td><td>Raise timeout to 5 s, threshold to 3<\/td><\/tr><tr><td>Random logouts<\/td><td>InProc session state<\/td><td>Move to distributed cache<\/td><\/tr><tr><td>Wrong client IP in logs<\/td><td>Forwarded headers not enabled<\/td><td>X-Forwarded-For settings<\/td><\/tr><tr><td>Stale content on one node<\/td><td>Deploy missed a node<\/td><td>Deployment script targets all nodes<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Cost vs Complexity<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">An ARR farm reuses the IIS skills and licensing you already have, which makes it the cheapest scale-out route on Windows. The trade-off is that ARR itself is a single point of failure until you add a second front end or a DNS-level failover. Size the backends for peak-single-node load so a surviving node can carry the traffic during a failure \u2014 with the current pricing laid out on the <a href=\"https:\/\/windows-vps.org\/#providers\">Windows VPS plan comparison<\/a>, that headroom is a line-item decision, not a guess.<\/p>\n\n\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>A single IIS server eventually hits a ceiling. The two ways past it are scale up (a larger VPS) or scale out (several nodes behind a load balancer). On Windows Server the native scale-out answer is an IIS Web Farm fronted by Application Request Routing (ARR) with URL Rewrite. This walkthrough stands up a two-node &#8230; <a title=\"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State\" class=\"read-more\" href=\"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/\" aria-label=\"Read more about IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":7,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-835","post","type-post","status-publish","format-standard","hentry","category-reviews"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State - Windows VPS Blog<\/title>\n<meta name=\"description\" content=\"A single IIS server eventually hits a ceiling. The two ways past it are scale up (a larger VPS) or scale out (several nodes behind a load balancer). On\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State\" \/>\n<meta property=\"og:description\" content=\"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State\" \/>\n<meta property=\"og:url\" content=\"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/\" \/>\n<meta property=\"og:site_name\" content=\"Windows VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-05T03:42:06+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-07T22:06:50+00:00\" \/>\n<meta name=\"author\" content=\"windows-vps\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@myxiechengxuan\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"windows-vps\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/\",\"url\":\"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/\",\"name\":\"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State - Windows VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/#website\"},\"datePublished\":\"2026-10-05T03:42:06+00:00\",\"dateModified\":\"2026-10-07T22:06:50+00:00\",\"author\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58\"},\"description\":\"A single IIS server eventually hits a ceiling. The two ways past it are scale up (a larger VPS) or scale out (several nodes behind a load balancer). On\",\"breadcrumb\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/windows-vps.org\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#website\",\"url\":\"https:\/\/windows-vps.org\/blog\/\",\"name\":\"Windows VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/windows-vps.org\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58\",\"name\":\"windows-vps\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g\",\"caption\":\"windows-vps\"},\"sameAs\":[\"https:\/\/windows-vps.org\/blog\",\"https:\/\/x.com\/myxiechengxuan\"],\"url\":\"https:\/\/windows-vps.org\/blog\/author\/myxiechengxuan\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State - Windows VPS Blog","description":"A single IIS server eventually hits a ceiling. The two ways past it are scale up (a larger VPS) or scale out (several nodes behind a load balancer). On","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/","og_locale":"en_US","og_type":"article","og_title":"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State","og_description":"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State","og_url":"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/","og_site_name":"Windows VPS Blog","article_published_time":"2026-10-05T03:42:06+00:00","article_modified_time":"2026-10-07T22:06:50+00:00","author":"windows-vps","twitter_card":"summary_large_image","twitter_creator":"@myxiechengxuan","twitter_misc":{"Written by":"windows-vps","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/","url":"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/","name":"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State - Windows VPS Blog","isPartOf":{"@id":"https:\/\/windows-vps.org\/blog\/#website"},"datePublished":"2026-10-05T03:42:06+00:00","dateModified":"2026-10-07T22:06:50+00:00","author":{"@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58"},"description":"A single IIS server eventually hits a ceiling. The two ways past it are scale up (a larger VPS) or scale out (several nodes behind a load balancer). On","breadcrumb":{"@id":"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/windows-vps.org\/blog\/iis-web-farm-arr-load-balancing-health-probes-windows\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/windows-vps.org\/blog\/"},{"@type":"ListItem","position":2,"name":"IIS Web Farm with ARR: Load Balancing, Health Probes, and Session State"}]},{"@type":"WebSite","@id":"https:\/\/windows-vps.org\/blog\/#website","url":"https:\/\/windows-vps.org\/blog\/","name":"Windows VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/windows-vps.org\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58","name":"windows-vps","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g","caption":"windows-vps"},"sameAs":["https:\/\/windows-vps.org\/blog","https:\/\/x.com\/myxiechengxuan"],"url":"https:\/\/windows-vps.org\/blog\/author\/myxiechengxuan\/"}]}},"_links":{"self":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/835","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/comments?post=835"}],"version-history":[{"count":2,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/835\/revisions"}],"predecessor-version":[{"id":848,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/835\/revisions\/848"}],"wp:attachment":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/media?parent=835"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/categories?post=835"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/tags?post=835"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}