> For the complete documentation index, see [llms.txt](https://docs.appstrategy.com/apprules-r-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.appstrategy.com/apprules-r-documentation/platform/self-hosting/software-installation/iis-setting.md).

# IIS Settings

#### appRulesPortal — IIS Setup Guide

**.NET 10 / Wisej / Windows Server**

> **appRulesPortal does not require IIS.** By default it runs as a self-hosted Kestrel Windows Service and serves requests directly on its configured port. If you are deploying that way, skip this guide and see [Self-Hosted Server Settings](/apprules-r-documentation/platform/self-hosting/software-installation/hostservice.md) instead.

IIS is only needed when the portal must share a port with other sites, or when TLS is terminated at IIS. There are **two different ways** to involve IIS, and they are mutually exclusive — read section 1 and choose before configuring anything.

***

**1. Choose a hosting model**

|                                 | **Option A — Reverse proxy**         | **Option B — IIS-hosted (ANCM)**  |
| ------------------------------- | ------------------------------------ | --------------------------------- |
| Who runs the application        | The `appRulesPortal` Windows Service | The IIS worker process            |
| Windows Service required        | Yes — stays installed and running    | No — must be stopped and disabled |
| .NET 10 Hosting Bundle          | Not required                         | **Required**                      |
| ARR + URL Rewrite               | **Required**                         | Not required                      |
| `web.config` in the application | None                                 | **Required**, with `<aspNetCore>` |
| App Pool recycling settings     | Not applicable                       | Critical — see 4.3                |
| Components to install           | 3                                    | 1                                 |

**Option A is recommended.** It keeps the service model used everywhere else, and the portal behaves identically whether or not IIS is in front of it.

> ⚠️ **Never run both.** If the Windows Service is running *and* an IIS site hosts the application, you will have two instances of appRulesPortal on one machine — two Wisej session pools, two licence activations, and unpredictable behaviour depending on which one a user reaches.

***

**2. Prerequisites (both options)**

**.NET 10 runtimes**

appRulesPortal and the companion services require `Microsoft.WindowsDesktop.App` in addition to the web runtime, because the Wisej.NET UI framework depends on it.

| Option            | Install                                                                 |
| ----------------- | ----------------------------------------------------------------------- |
| A — Reverse proxy | **ASP.NET Core Runtime 10 (x64)** and **.NET 10 Desktop Runtime (x64)** |
| B — IIS-hosted    | **.NET 10 Hosting Bundle** and **.NET 10 Desktop Runtime (x64)**        |

Both are available from <https://dotnet.microsoft.com/en-us/download/dotnet/10.0>.

Verify:

```bat
dotnet --list-runtimes
```

`Microsoft.NETCore.App`, `Microsoft.AspNetCore.App` and `Microsoft.WindowsDesktop.App` must each show a 10.x version.

**IIS features**

Open **Server Manager → Add Roles and Features → Web Server (IIS)**:

| Feature            | Path                    | Required for             |
| ------------------ | ----------------------- | ------------------------ |
| Web Server         | Web Server (IIS)        | Base IIS                 |
| Static Content     | Common HTTP Features    | Serving JS, CSS, fonts   |
| Default Document   | Common HTTP Features    | Serving Default.html     |
| HTTP Errors        | Common HTTP Features    | Error pass-through       |
| Request Filtering  | Security                | Request size limits      |
| WebSocket Protocol | Application Development | **Wisej real-time sync** |

> ⚠️ **WebSocket Protocol is mandatory for Wisej.** Without it, Wisej falls back to long-polling — all users experience significantly degraded performance and higher server CPU.

```powershell
Install-WindowsFeature Web-WebSockets
# or on Windows 10/11:
Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebSockets
```

***

**3. Option A — IIS as a reverse proxy**

The `appRulesPortal` Windows Service continues to run and serve the application. IIS accepts requests on port 80/443 and forwards them to Kestrel.

**3.1 Install URL Rewrite and ARR**

| Component                        | Source                                                                |
| -------------------------------- | --------------------------------------------------------------------- |
| URL Rewrite Module               | <https://www.iis.net/downloads/microsoft/url-rewrite>                 |
| Application Request Routing 3.0+ | <https://www.iis.net/downloads/microsoft/application-request-routing> |

ARR 3.0 supports WebSockets, but only when the WebSocket Protocol feature from section 2 is installed.

**3.2 Enable the ARR proxy**

In IIS Manager, select the **server** node (not a site):

1. Open **Application Request Routing Cache**
2. Actions pane → **Server Proxy Settings**
3. Tick **Enable proxy** → Apply

Without this, URL Rewrite can only alter the path of a URL — it cannot forward a request to another process.

**3.3 Create the proxy site**

Create an empty folder — it holds only the `web.config` below:

```bat
mkdir C:\inetpub\appRulesProxy
```

Add a site bound to port 80 pointing at that folder, with its application pool set to **No Managed Code**. The proxy runs no .NET of its own.

**3.4 Proxy web.config**

Place in `C:\inetpub\appRulesProxy`. Adjust the port if the portal does not use 8080.

```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <webSocket enabled="true" />
    <rewrite>
      <rules>
        <rule name="appRulesPortal" stopProcessing="true">
          <match url="(.*)" />
          <action type="Rewrite" url="http://127.0.0.1:8080/{R:1}" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>
```

This file belongs to the proxy site. **The appRulesPortal application itself has no `web.config` and does not need one.**

**3.5 Allow the WebSocket extension header**

Rewrite rules cannot set IIS server variables unless those variables are allow-listed.

IIS Manager → proxy site → **URL Rewrite** → Actions pane → **View Server Variables** → **Add**:

```
HTTP_SEC_WEBSOCKET_EXTENSIONS
```

Skipping this produces a page that loads but does not respond to clicks.

***

**4. Option B — IIS-hosted with ANCM**

IIS starts and manages the application process. The Windows Service must not also be running.

**4.1 Stop and disable the Windows Service**

```bat
sc stop appRulesPortal
sc config appRulesPortal start= disabled
```

**4.2 Create the application directory**

```bat
mkdir C:\inetpub\appRulesPortal
mkdir C:\inetpub\appRulesPortal\logs
```

Copy the full Release build output here. The physical path is the site root — one level above `bin\`, not `bin\` itself.

**4.3 Create the application pool**

IIS Manager → **Application Pools → Add Application Pool**

| Setting               | Value               |
| --------------------- | ------------------- |
| Name                  | `appRulesPortal`    |
| .NET CLR Version      | **No Managed Code** |
| Managed Pipeline Mode | Integrated          |

> **"No Managed Code" is correct and unrelated to the .NET version.** It tells IIS not to load the legacy .NET Framework CLR into the worker process. The application runs on .NET 10 in the process that ANCM starts.

Then select the pool → **Advanced Settings**:

| Setting                         | Value                                       | Reason                                           |
| ------------------------------- | ------------------------------------------- | ------------------------------------------------ |
| Start Mode                      | `AlwaysRunning`                             | Wisej must always be running — do not lazy-start |
| Idle Time-out (minutes)         | `0`                                         | Idle shutdown kills active user sessions         |
| Regular Time Interval (minutes) | `0`                                         | Disable periodic recycling during business hours |
| Identity                        | `ApplicationPoolIdentity` or domain account | See 4.4                                          |

> ⚠️ **Never enable idle timeout or periodic recycling for a Wisej application.** Recycling the App Pool disconnects all active browser sessions immediately. If recycling is needed for memory management, schedule a Specific Time recycle outside business hours.

**4.4 Folder permissions**

```bat
REM Replace "IIS AppPool\appRulesPortal" with your domain account if applicable
icacls "C:\inetpub\appRulesPortal"      /grant "IIS AppPool\appRulesPortal:(OI)(CI)R"
icacls "C:\inetpub\appRulesPortal\logs" /grant "IIS AppPool\appRulesPortal:(OI)(CI)M"
```

| Folder          | Permission | Reason                                 |
| --------------- | ---------- | -------------------------------------- |
| Site root (`\`) | Read       | Serve static files, load configuration |
| `bin\`          | Read       | Load assemblies                        |
| `logs\`         | Modify     | ANCM writes stdout logs                |

**4.5 Create the site**

| Field            | Value                           |
| ---------------- | ------------------------------- |
| Site name        | `appRulesPortal`                |
| Application pool | `appRulesPortal`                |
| Physical path    | `C:\inetpub\appRulesPortal`     |
| Binding type     | `http` (add `https` separately) |
| Port             | `80`                            |
| Host name        | `yourserver.yourdomain.com`     |

```powershell
Import-Module WebAdministration

New-WebAppPool -Name "appRulesPortal"
Set-ItemProperty IIS:\AppPools\appRulesPortal managedRuntimeVersion ""
Set-ItemProperty IIS:\AppPools\appRulesPortal startMode "AlwaysRunning"
Set-ItemProperty IIS:\AppPools\appRulesPortal processModel.idleTimeout "00:00:00"

New-Website -Name "appRulesPortal" `
            -PhysicalPath "C:\inetpub\appRulesPortal" `
            -ApplicationPool "appRulesPortal" `
            -Port 80 `
            -HostHeader "yourserver.yourdomain.com"
```

**4.6 Verify ANCM is registered**

```bat
%windir%\system32\inetsrv\appcmd list modules | findstr AspNetCore
```

Expected:

```
MODULE "AspNetCoreModuleV2" (image:...aspnetcorev2.dll)
```

If IIS was running before the Hosting Bundle was installed:

```bat
iisreset /restart
```

***

**5. HTTPS (both options)**

**Bind a certificate**

1. IIS Manager → server node → **Server Certificates**
2. Import your certificate (PFX) or request one
3. Site → **Bindings → Add**: type `https`, port `443`, host name, certificate

**Force HTTPS**

Add inside `<system.webServer>` of the site's `web.config` — the proxy site for Option A, the application for Option B:

```xml
<rewrite>
  <rules>
    <rule name="HTTP to 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>
  </rules>
</rewrite>
```

Requires the URL Rewrite Module.

***

**6. Verify the deployment**

| Test                          | Expected result                                |
| ----------------------------- | ---------------------------------------------- |
| `GET /`                       | Wisej login page loads                         |
| `GET /Default.html`           | Same login page                                |
| `GET /appsettings.json`       | HTTP 403 Forbidden                             |
| `GET /Default.json`           | HTTP 200 (Wisej config — intentionally public) |
| Login with valid credentials  | Main portal opens                              |
| Click any control after login | Responds immediately                           |

**Confirm WebSocket is working**

Browser DevTools (F12) → Network → filter **WS**:

* A connection to `ws://yourserver/...`
* Status `101 Switching Protocols`
* Repeated XHR polling instead means WebSocket is not working

A page that renders but does not respond to clicks is the classic symptom of WebSocket traffic not reaching the application.

***

**7. Troubleshooting**

**Option A — reverse proxy**

| Symptom                            | Cause                                                       | Fix                                                                                     |
| ---------------------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `502.3` or connection refused      | Kestrel service not running                                 | `sc query appRulesPortal`                                                               |
| Page loads, interface unresponsive | WebSockets not proxied                                      | Check 2 (feature), 3.5 (server variable)                                                |
| `500.31`                           | An IIS site is trying to *host* the app instead of proxying | This is Option B configuration on an Option A setup — remove the `<aspNetCore>` element |
| Links point at `127.0.0.1:8080`    | Forwarded headers not applied                               | See below                                                                               |

**Option B — IIS-hosted**

| Error                      | Cause                                | Fix                                                        |
| -------------------------- | ------------------------------------ | ---------------------------------------------------------- |
| `500.19`                   | Malformed `web.config`               | Validate XML syntax                                        |
| `500.30`                   | Application failed to start          | Check stdout log (7.1)                                     |
| `500.31`                   | Required framework not found         | Install the .NET 10 Hosting Bundle **and** Desktop Runtime |
| `500.35`                   | ANCM in-process handler load failure | Reinstall the Hosting Bundle                               |
| `403.14`                   | Directory browsing                   | Set default document to `Default.html`                     |
| Blank page, no Wisej       | Wrong `arguments` path               | Confirm `.\bin\appRulesPortal.dll` exists                  |
| Sessions drop unexpectedly | App Pool idle timeout or recycling   | See 4.3                                                    |

**Both options**

| Symptom                                   | Cause                                                                                                                       |
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Licence warning banner on first page load | The Wisej licence key is not being applied at startup, or `wisej-server.lic` is missing on a server without internet access |

**7.1 stdout logging (Option B only)**

1. Set `stdoutLogEnabled="true"` in `web.config`
2. Ensure `.\logs\` exists and is writable by the App Pool identity
3. `%windir%\system32\inetsrv\appcmd recycle apppool /apppool.name:"appRulesPortal"`
4. Browse to the site to trigger the failure
5. Read `.\logs\stdout_*.log`
6. **Set `stdoutLogEnabled="false"` immediately after** — stdout logging is unbounded and will fill the disk

**7.2 Forwarded headers (Option A only)**

Behind a proxy the application needs the externally visible host and scheme. If generated links or redirects expose the internal address, confirm the application calls `app.UseForwardedHeaders()` with `XForwardedFor` and `XForwardedProto` enabled.

***

**8. Maintenance**

**After upgrading appRules**

| Option            | Action                                                  |
| ----------------- | ------------------------------------------------------- |
| A — Reverse proxy | `sc stop appRulesPortal` then `sc start appRulesPortal` |
| B — IIS-hosted    | `iisreset /restart` **before** browsing to the site     |

A worker process or service started before the upgrade still references the previous runtime.

**Upgrading the .NET runtime**

When a servicing update is installed (for example 10.0.12 → 10.0.13), restart the service or IIS so the new runtime is picked up. Do **not** uninstall older .NET runtimes that other applications may require — .NET runtimes install side by side.

***

**Reference**

| Item                                | Value                                                                       |
| ----------------------------------- | --------------------------------------------------------------------------- |
| .NET 10 runtimes and Hosting Bundle | <https://dotnet.microsoft.com/en-us/download/dotnet/10.0>                   |
| IIS URL Rewrite Module              | <https://www.iis.net/downloads/microsoft/url-rewrite>                       |
| IIS Application Request Routing     | <https://www.iis.net/downloads/microsoft/application-request-routing>       |
| Wisej deployment docs               | <https://docs.wisej.com/deployment/targets/iis>                             |
| Wisej self-hosting docs             | <https://docs.wisej.com/deployment/targets/self-hosting>                    |
| ANCM troubleshooting                | <https://learn.microsoft.com/en-us/aspnet/core/test/troubleshoot-azure-iis> |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.appstrategy.com/apprules-r-documentation/platform/self-hosting/software-installation/iis-setting.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
