Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

URL Rewrite and ARR on IIS

By Kokil Thapa | Last reviewed: September 2026

URL Rewrite and ARR on IIS turn a Windows web server into a capable reverse proxy and load balancer. Most teams reach for Nginx or Apache on Linux first. Corporate networks, legacy .NET estates, and mixed Windows/Linux shops often keep IIS at the edge instead. If you need clean URLs, HTTPS enforcement, or traffic split across PHP and Laravel backends, the combination of the IIS URL Rewrite Module and Application Request Routing (ARR) is the standard path on Windows Server.

What is URL Rewrite and ARR on IIS, and when do you need both?

URL Rewrite is an IIS extension that rewrites, redirects, or blocks requests based on patterns you define. ARR sits one layer above the backend and handles reverse proxying, health checks, and load balancing across a server farm.

You need both when IIS terminates TLS and forwards traffic to Linux or Windows app servers behind it. A single URL Rewrite rule can redirect HTTP to HTTPS. ARR handles the actual proxy hop to http://10.0.1.20 or a three-node farm.

Common scenarios I see on migration and hybrid-hosting projects:

  • Reverse proxy from IIS to a Laravel application running on Ubuntu with Apache or Nginx.
  • Load balancing two or more identical PHP-FPM nodes during a website migration.
  • Canonical host redirects (www to bare domain, or the reverse).
  • Path-based routing: /api to one backend, everything else to another.
  • Staging environments where IIS fronts production-like traffic without exposing internal IPs.
ClientHTTPSIIS EdgeURL Rewrite+ ARR ProxyBackend ALaravelBackend BPHP-FPMRequest FlowTLS terminates at IISRewrite rules match URL, ARR forwards to farm
URL Rewrite and ARR on IIS: the edge server terminates HTTPS and proxies to internal application servers.

URL Rewrite alone handles redirects and internal rewrites within the same site. ARR alone cannot match complex URL patterns without Rewrite. Together they replace much of what Nginx proxy_pass and rewrite directives do on Linux.

How do you install URL Rewrite and ARR on IIS?

Install both modules before writing any rules. Missing ARR is the most common reason a rewrite rule silently fails to proxy.

Step 1: Install URL Rewrite Module 2

Download the URL Rewrite Module from Microsoft or use Web Platform Installer. After installation, open IIS Manager. You should see a URL Rewrite icon on every site and at the server level.

Step 2: Install Application Request Routing 3.0

ARR 3.0 depends on URL Rewrite and the Web Farm Framework. Install ARR, then confirm the Application Request Routing Cache icon appears at the server node in IIS Manager.

Step 3: Enable the proxy at server level

ARR ships with the proxy disabled. Enable it once at the server root:

  1. Open IIS Manager and click the server name, not a site.
  2. Double-click Application Request Routing Cache.
  3. Click Server Proxy Settings in the Actions pane.
  4. Check Enable proxy and apply.

Without this step, inbound rewrite actions of type Rewrite pointing to an external URL return HTTP 502 or do nothing useful. I have seen teams debug web.config for hours while the proxy toggle stayed off.

Step 4: Verify modules loaded

Run this in an elevated PowerShell session:

Get-WebGlobalModule | Where-Object { $_.Name -match 'Rewrite|ARR|Proxy' }

You should see RewriteModule and ARR-related modules listed. If either is missing, restart IIS with iisreset after reinstalling.

For a full IIS baseline, see the companion guide on hosting PHP on IIS. That walkthrough covers FastCGI and handler mappings this article assumes you can reach from a proxied backend.

How do you configure a reverse proxy with URL Rewrite and ARR on IIS?

The typical pattern is an inbound rule that matches all traffic and rewrites to a backend URL. ARR forwards the request and returns the response to the client.

Basic reverse proxy web.config

Place this in the site root web.config when IIS fronts a single Laravel or PHP backend:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="ReverseProxyToBackend" stopProcessing="true">
          <match url="(.*)" />
          <action type="Rewrite" url="http://10.0.1.20/{R:1}" />
          <serverVariables>
            <set name="HTTP_X_FORWARDED_PROTO" value="https" />
            <set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" />
            <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
            <set name="HTTP_ACCEPT_ENCODING" value="" />
          </serverVariables>
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Several details matter here. Clearing Accept-Encoding prevents double-compression bugs when ARR decompresses an upstream gzip response and IIS compresses again. Setting X-Forwarded-Proto lets Laravel generate correct HTTPS URLs when TLS stops at IIS.

Allow server variables

IIS blocks custom server variables until you whitelist them. At the server level in URL Rewrite, open View Server Variables and add:

  • HTTP_X_FORWARDED_PROTO
  • HTTP_X_FORWARDED_HOST
  • HTTP_X_ORIGINAL_ACCEPT_ENCODING
  • HTTP_ACCEPT_ENCODING

Skip this step and IIS returns HTTP 500.12 with a server-variable error in the failed-request trace.

Trust proxies in Laravel

On the Laravel backend, configure trusted proxies so Request::secure() and signed URLs work:

/* bootstrap/app.php or TrustProxies middleware */
->withMiddleware(function (Middleware $middleware) {
    $middleware->trustProxies(at: '*', headers: Request::HEADER_X_FORWARDED_ALL);
})

Signed and temporary links break without this. See Laravel signed URLs for temporary access for how proxy misconfiguration surfaces in production.

Inbound Rule PipelineRequest InMatch URLConditionsSet HeadersARR ProxyResponseRules run top to bottom; stopProcessing="true" halts further rules
How URL Rewrite evaluates inbound rules before ARR forwards the request to a backend server.

HTTPS redirect rule

Add a separate inbound rule above the proxy rule. It redirects plain HTTP to HTTPS:

<rule name="Force HTTPS" stopProcessing="true">
  <match url="(.*)" />
  <conditions>
    <add input="{HTTPS}" pattern="off" ignoreCase="true" />
  </conditions>
  <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>

Order matters. Put redirect rules first, then proxy rules. Test patterns with a regex tester before deploying to production.

How do you set up ARR server farms and load balancing on IIS?

When you have more than one backend, create an ARR server farm instead of hard-coding an IP in web.config. IIS handles health probes and distributes requests.

Create a server farm

  1. In IIS Manager, click the server node.
  2. Open Server Farms and click Create Server Farm.
  3. Name the farm (for example laravel-backend).
  4. Add server addresses and ports. Use internal IPs, not public DNS names.
  5. Choose a load-balancing algorithm. Round Robin is the default.
  6. Enable health checks against a probe URL like /health.

Point your rewrite rule at the farm using the special syntax:

<action type="Rewrite" url="http://laravel-backend/{R:1}" />

ARR resolves laravel-backend to the farm members you defined. Unhealthy nodes drop out automatically when probes fail.

FeatureURL Rewrite aloneURL Rewrite + ARR
HTTP to HTTPS redirectYesYes
Reverse proxy to one backendYes (with ARR proxy enabled)Yes
Load balancingNoYes (server farms)
Health-based failoverNoYes
Response caching at edgeNoYes (ARR cache)
Sticky sessions (affinity)NoYes

For high-traffic Laravel apps, pair ARR with Redis session storage on the backend. Sticky sessions at the IIS layer are a fallback, not a substitute for shared session state. See API rate limiting and abuse prevention for edge-layer throttling patterns that complement ARR.

ARR Server FarmRound RobinNode 1HealthyNode 2HealthyNode 3UnhealthyHealth Probe: GET /healthFailed nodes removed from rotation
ARR server farm distributes requests and removes unhealthy backends based on probe results.

What are the common URL Rewrite and ARR on IIS mistakes in production?

Most failures are configuration order, missing headers, or proxy settings — not ARR itself.

Lost client IP addresses

Backend logs show every request from the IIS server IP. Fix it by preserving the original IP in ARR:

  1. Server node → Application Request Routing Cache → Server Proxy Settings.
  2. Check Preserve client IP in the following header.
  3. Set the header name to X-Forwarded-For.

Configure your Laravel or Apache backend to read X-Forwarded-For for logging and rate limiting.

Infinite redirect loops

Loops happen when the backend also redirects HTTP to HTTPS, but IIS already terminated TLS. The backend sees HTTP, redirects to HTTPS, and the cycle repeats.

Fix: set X-Forwarded-Proto: https in the rewrite rule and trust it on the backend. Do not run a second HTTPS redirect behind the proxy unless you intentionally terminate TLS twice.

502 Bad Gateway after deploy

Check these in order:

  • ARR proxy enabled at server level.
  • Backend firewall allows inbound from the IIS server IP.
  • Backend binding listens on the correct port.
  • Server variables whitelisted.
  • No stale DNS if the farm uses hostnames.

Enable Failed Request Tracing in IIS for status code 502. The trace pinpoints whether Rewrite or ARR failed. For ongoing monitoring, support and maintenance contracts often include IIS and Linux edge debugging together.

WebSocket and long-polling failures

ARR supports WebSockets, but you must enable the protocol on the site. In IIS Manager, open the site → Configuration Editorsystem.webServer/webSocket → set enabled to True.

Livewire and Laravel Echo websocket connections fail silently when this setting is off. Increase ARR timeout values for long-running requests on reporting or export endpoints.

Production GotchasRedirect LoopMissing X-Forwarded-ProtoDouble GzipClear Accept-Encoding502 GatewayProxy not enabledWrong Client IPSet X-Forwarded-ForWS FailuresEnable webSocketFix PatternTrust proxy + headersValidate with curl -I and IIS Failed Request Tracing
Typical URL Rewrite and ARR on IIS production issues and the header or setting that resolves each one.

Outbound rewrite rules

Outbound rules transform response HTML — useful when a legacy app emits absolute http:// links. Define them in the same web.config under <outboundRules>. Test carefully; aggressive outbound rewriting breaks JSON API responses.

Validate outbound patterns with sample response bodies using a JSON formatter when APIs are in the path.

How does URL Rewrite and ARR on IIS compare to Nginx and Apache on Linux?

My daily production work runs on Ubuntu with Apache or Nginx and PHP-FPM 8.3/8.4. IIS with URL Rewrite and ARR is the right tool when Windows Server is already mandated or when a .NET and PHP hybrid must share one edge.

Nginx reverse proxy config is shorter:

location / {
    proxy_pass http://10.0.1.20;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
}

ARR plus URL Rewrite reaches the same outcome with more GUI surface area and XML in web.config. The operational model differs, not the HTTP semantics.

For greenfield Laravel 13 on PHP 8.3+, Linux with Nginx or Apache remains my default recommendation. IIS plus ARR wins when compliance, licensing, or existing Windows ops teams block a Linux edge. On a legal-tech portal project, the app ran on Laravel while the corporate edge stayed on IIS — ARR bridged the gap without rewriting either layer.

Projects like Adventure Third Pole Trek and Mijar Law Associates run on Linux stacks in production. The IIS patterns here apply when those same apps sit behind a Windows corporate reverse proxy during migration or hybrid hosting.

Reference documentation: Microsoft URL Rewrite Module docs and ARR planning guide. For Apache equivalents, see the Apache mod_proxy documentation.

Additional internal resources: building a URL shortener system design, Linux system administration, domain and hosting setup, testing and optimization, speed optimization, Ansible playbooks for PHP provisioning, and technical SEO for canonical URL rules at the edge.

Key Takeaways

  • Install URL Rewrite and ARR, then enable the ARR proxy at the server level before any rewrite rules will forward traffic.
  • Whitelist server variables (X-Forwarded-Proto, X-Forwarded-For) and trust proxies on Laravel backends.
  • Place HTTPS redirect rules above proxy rules; clear Accept-Encoding to prevent double compression.
  • Use ARR server farms with health probes for load balancing instead of hard-coded single IPs in production.
  • Enable WebSockets on the IIS site when proxying Livewire, Echo, or other persistent connections.
  • Validate with Failed Request Tracing and curl -I before cutover during a migration window.

People Also Ask

Can URL Rewrite on IIS work without ARR?

Yes, for redirects and internal rewrites within the same IIS site. Reverse proxying to external backends requires ARR with the server-level proxy enabled. URL Rewrite alone cannot forward requests to another server.

Does ARR support SSL offloading to Laravel backends?

Yes. Terminate TLS on IIS with a certificate bound to the site. Forward plain HTTP to internal backends on a private network. Set X-Forwarded-Proto: https so Laravel generates correct URLs and cookies.

How do you debug a 502 Bad Gateway from ARR?

Enable Failed Request Tracing for 502 on the IIS site. Confirm ARR proxy is enabled, the backend is reachable from the IIS server, firewall rules allow the hop, and server variables are whitelisted. Test the backend directly with curl from the IIS machine.

Is ARR suitable for high-traffic production load balancing?

ARR handles moderate to high traffic for many enterprise deployments. Very high-scale scenarios often move to dedicated load balancers or Nginx/HAProxy on Linux. ARR fits well when Windows infrastructure is fixed and backend pools are modest.

Deploy URL Rewrite and ARR on IIS with confidence

URL Rewrite and ARR on IIS give you a production-grade reverse proxy on Windows Server when Linux at the edge is not an option. Install both modules, enable the proxy, whitelist forwarded headers, and point inbound rules at a server farm with health checks. Match what your Laravel or PHP backend expects — trusted proxies, correct scheme headers, and WebSocket support — and the setup behaves like Nginx behind the scenes.

If you are migrating from IIS to Linux or need a hybrid edge configured and tested, contact us or review our website migration service. For greenfield apps, explore custom software development on the stack that fits your ops team.

Frequently Asked Questions

URL Rewrite is an IIS extension that rewrites, redirects, or blocks requests by pattern. ARR handles reverse proxying, health checks, and load balancing across a server farm. Together they replace much of what Nginx proxy_pass and rewrite directives do on Linux.

Yes, for redirects and internal rewrites within the same IIS site. Reverse proxying to external backends requires ARR with the server-level proxy enabled.

You need both when IIS terminates TLS and forwards traffic to Linux or Windows app servers behind it. URL Rewrite alone handles redirects like HTTP to HTTPS. ARR handles the actual proxy hop to an internal IP or a multi-node server farm. Common cases include reverse proxying to a Laravel app on Ubuntu, load balancing PHP-FPM nodes during migration, path-based routing, and staging environments where IIS fronts traffic without exposing internal IPs.

Install URL Rewrite Module 2 first, then Application Request Routing 3.0, which depends on URL Rewrite and Web Farm Framework. After installation, confirm the URL Rewrite icon appears on sites and Application Request Routing Cache appears at the server node. Enable the proxy at server level under Server Proxy Settings before writing rules. Verify modules with Get-WebGlobalModule filtering for Rewrite, ARR, and Proxy. Restart IIS with iisreset if modules are missing after reinstall.

ARR ships with the proxy disabled by default. Without checking Enable proxy under Application Request Routing Cache at the server root, inbound rewrite actions of type Rewrite pointing to an external URL return HTTP 502 or do nothing useful. This is the most common reason rewrite rules silently fail to proxy. Teams often debug web.config for hours while the proxy toggle stays off. Enable it once at the server node, not per site.

Add an inbound rule matching all traffic that rewrites to http://backend-ip/{R:1}. Set server variables HTTP_X_FORWARDED_PROTO to https, HTTP_X_FORWARDED_HOST to {HTTP_HOST}, clear HTTP_ACCEPT_ENCODING to prevent double compression, and store the original encoding in HTTP_X_ORIGINAL_ACCEPT_ENCODING. Whitelist those variables at server level in URL Rewrite. On Laravel, configure trusted proxies so Request::secure() and signed URLs work. Place HTTPS redirect rules above the proxy rule.

Yes. Terminate TLS on IIS with a certificate bound to the site and forward plain HTTP to internal backends on a private network. Set X-Forwarded-Proto to https in the rewrite rule so Laravel generates correct URLs and cookies.

In IIS Manager at the server node, open Server Farms and create a farm with a name like laravel-backend. Add internal IP addresses and ports, choose a load-balancing algorithm such as Round Robin, and enable health checks against a probe URL like /health. Point your rewrite rule at the farm using http://laravel-backend/{R:1}. ARR resolves the farm name to members and drops unhealthy nodes when probes fail. Use farms instead of hard-coded single IPs in production.

At server level in URL Rewrite, open View Server Variables and add HTTP_X_FORWARDED_PROTO, HTTP_X_FORWARDED_HOST, HTTP_X_ORIGINAL_ACCEPT_ENCODING, and HTTP_ACCEPT_ENCODING. IIS blocks custom server variables until whitelisted. Skipping this step returns HTTP 500.12 with a server-variable error in failed-request traces. These headers let Laravel detect HTTPS correctly and prevent double-compression bugs when ARR decompresses upstream gzip and IIS compresses again.

Loops happen when the backend also redirects HTTP to HTTPS but IIS already terminated TLS, so the backend sees plain HTTP and redirects again. Fix by setting X-Forwarded-Proto to https in the rewrite rule and trusting it on the Laravel backend. Do not run a second HTTPS redirect behind the proxy unless you intentionally terminate TLS twice. Put IIS HTTPS redirect rules first in web.config, then proxy rules below them.

ARR replaces the client IP with the IIS server address unless you preserve it. At the server node, open Application Request Routing Cache, then Server Proxy Settings. Check Preserve client IP in the following header and set the header name to X-Forwarded-For. Configure your Laravel or Apache backend to read X-Forwarded-For for logging and rate limiting. Without this, every request appears to originate from the edge server.

Enable Failed Request Tracing for status code 502 on the IIS site. Confirm ARR proxy is enabled at server level, the backend firewall allows inbound from the IIS server IP, the backend binding listens on the correct port, server variables are whitelisted, and farm hostnames are not stale. Test the backend directly with curl from the IIS machine. The trace pinpoints whether Rewrite or ARR failed.

ARR supports WebSockets but the protocol must be enabled on the IIS site. In IIS Manager, open the site, go to Configuration Editor, navigate to system.webServer/webSocket, and set enabled to True. Connections fail silently when this is off. For long-running reporting or export endpoints, increase ARR timeout values. Pair ARR with Redis session storage on high-traffic Laravel apps rather than relying on sticky sessions alone.

Nginx config is shorter with proxy_pass and proxy_set_header directives, but ARR plus URL Rewrite reaches the same HTTP outcome with more GUI surface area and web.config XML. For greenfield Laravel 13 on PHP 8.3 or higher, Linux with Nginx or Apache remains the default. IIS plus ARR wins when compliance, licensing, or existing Windows ops teams block a Linux edge. The operational model differs, not the HTTP semantics.

ARR handles moderate to high traffic for many enterprise deployments where Windows infrastructure is fixed and backend pools are modest. Very high-scale scenarios often move to dedicated load balancers or Nginx or HAProxy on Linux. Pair ARR server farms with health probes and Redis session storage on Laravel backends. Validate with Failed Request Tracing and curl -I before cutover during a migration window.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: