# IIS and Nginx security baseline on Windows Server

> A practical baseline: remove unused features, lock request surface, separate identities, enable logging and patch the host, without claiming CIS compliance.

**Tested on**

- Build: 26100.33650
- Edition: Standard / Datacenter
- Architecture: x64
- Evidence: E1
- Verified: 2026-10-29

## The short answer

A baseline is not a 300-line script. It is a repeatable set of decisions:

1. Install only the roles/modules you use.
2. Remove the default site and sample content.
3. Give each site an app pool and least-privilege identity.
4. Limit request surface (methods, size, extensions, directory browsing).
5. Terminate TLS correctly; no plaintext admin.
6. Log access/errors and ship them off-box.
7. Patch Windows, IIS/Nginx, runtimes and dependencies.
8. Restrict management (RDP/WinRM/WAC) to a management network.

## Host

- Windows Update/patches on a schedule; reboot plan.
- Defender/EDR enabled and exclusions reviewed (not “exclude everything for performance”).
- Firewall: only 80/443 public; 3389/5985/5986 management-only.
- No IIS FTP/WebDAV/IIS 6 compatibility unless required.
- Dedicated service accounts; no LocalSystem for web apps.
- Local admin group small; use LAPS/just-in-time where possible.

## IIS

```powershell
Get-WindowsFeature Web-Server,Web-Ftp-Server,Web-DAV-Publishing,Web-Windows-Auth
Get-WebSite | Select-Object Name,State,PhysicalPath,ApplicationPool
Get-WebVirtualDirectory | Select-Object Site,Path,PhysicalPath
```

Checklist:

- Default Web Site stopped/removed.
- Directory browsing off.
- Request filtering on; only required extensions/methods.
- App pool = No Managed Code for static/PHP/Node, dedicated identity.
- `web.config` not writable by the app pool.
- Custom errors on; detailed errors local only.
- Logging on, retention set, logs off the system drive.
- Unused handlers/modules removed (careful with static content).

## Nginx

```nginx
server_tokens off;
autoindex off;
client_max_body_size 50m;
```

- One `server` block per host; explicit `server_name`.
- TLS only; redirect 80 → 443.
- Deny dotfiles and backup paths.
- Keep `error_log`/`access_log` and rotate them.
- Run as a dedicated account, not LocalSystem.

## Baseline vs compliance

CIS/Microsoft security baselines are useful references, but “we applied a baseline” is not compliance. Record:

- OS build and patch level;
- IIS/Nginx version;
- runtime versions;
- exceptions and owners;
- last test date.

> **Caution: Do not copy a hardening script blind**
>
> A script that disables “unused” services can break WMI, backup, monitoring or the app. Apply one change at a time, snapshot/back up, and test.

## Verify

```powershell
Get-Service W3SVC,WAS
Get-NetFirewallProfile | Select-Object Name,Enabled
Get-Website | Where-Object State -eq 'Started'
```

Then scan from another host: only intended ports should answer. A local `localhost` test does not prove the firewall.

## Lab boundary

E1. The lab applied a minimal IIS install and no production hardening; this checklist is the baseline to verify on Server 2025.

## Sources

- [Microsoft Learn — IIS security](https://learn.microsoft.com/en-us/iis/configuration/system.webserver/security/)
- [Microsoft Learn — Windows security baselines](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/windows-security-baselines)
- [nginx — Security controls](https://nginx.org/en/docs/http/ngx_http_core_module.html)

---

Source: https://windows.homes/en/server/security/baseline/
