Qué vas a conseguir
Dar soporte a las aplicaciones web que corren en IIS: saber qué sitio responde a qué nombre, en qué grupo de aplicaciones corre y con qué cuenta, qué certificado entrega, dónde está el log de cada petición y qué hacer cuando la página dice HTTP Error 503. The service is unavailable.
Antes de empezar
- Windows Server 2022 o 2025 con IIS 10 y permisos de administrador local.
- Las características que esta guía usa:
Install-WindowsFeature Web-Server, Web-Mgmt-Console, Web-Scripting-Tools, Web-Http-Tracing. - PowerShell como administrador, con WebAdministration (la unidad
IIS:\) o IISAdministration (Get-IISSite,Get-IISAppPool). Los dos sirven; no los mezcles en el mismo script.
1. Sitios, enlaces y encabezados de host
Un sitio es una carpeta con uno o varios enlaces (bindings): protocolo, IP, puerto y nombre de host. Varios sitios comparten la IP y el puerto 443 si cada uno tiene su nombre:
- Con HTTPS y varios sitios en el mismo puerto hace falta SNI (Require Server Name Indication): el navegador dice el nombre antes de recibir el certificado.
- Cada sitio tiene un ID: su carpeta de logs se llama
W3SVC<ID>. Apúntalo en la ficha de la aplicación.
Get-IISSite o appcmd list sites listan los sitios con su ID, su estado y sus enlaces.
2. Grupos de aplicaciones
El grupo de aplicaciones (application pool) es el proceso w3wp.exe que ejecuta el sitio. Un grupo por aplicación: si una se cuelga o se recicla, las demás siguen.
- Identidad: por defecto, ApplicationPoolIdentity, una cuenta virtual llamada
IIS AppPool\Reservasa la que se dan permisos NTFS sobre la carpeta. Si la aplicación necesita entrar en SQL Server o en un recurso compartido con autenticación de Windows, una cuenta de dominio; mejor una gMSA (CONTOSO\gmsa-reservas$, sin contraseña que caduque). - Versión de .NET CLR:
v4.0para ASP.NET 4.x; No Managed Code para ASP.NET Core, que lleva su propio runtime. Modo de canalización: Integrated. - Reciclado: por defecto, cada 1.740 minutos (29 horas), así que cada día a una hora distinta. Mejor una hora fija sin uso, como las 4:00. El Idle Time-out (20 minutos) apaga el proceso si nadie entra.
- Rapid-Fail Protection: si el proceso falla 5 veces en 5 minutos, IIS detiene el grupo. Es el origen del 503 más frecuente.
Get-IISAppPool muestra el estado, la versión de CLR y la identidad de cada grupo; appcmd list wp, el PID de cada w3wp.exe, el que buscas en el Administrador de tareas cuando un proceso consume CPU.
3. El certificado HTTPS
- El certificado va en el almacén del equipo, Local Machine › Personal, con su clave privada:
Import-PfxCertificate -FilePath .\reservas.pfx -CertStoreLocation Cert:\LocalMachine\My -Password $pwd. - El enlace guarda la huella (thumbprint) del certificado. Al renovarlo, el nuevo tiene otra huella y el enlace sigue con el viejo hasta que lo cambias.
$thumb = (Get-ChildItem Cert:\LocalMachine\My | Where-Object Subject -like "*reservas.corp.example*" | Sort-Object NotAfter -Descending | Select-Object -First 1).ThumbprintImport-Module WebAdministration(Get-WebBinding -Name "Reservas" -Protocol https).AddSslCertificate($thumb, "My")netsh http show sslcert hostnameport=reservas.corp.example:443netsh muestra lo que HTTP.sys tiene de verdad asociado a ese nombre y puerto.
4. Logs: W3C y HTTPERR
- Logs de IIS en
%SystemDrive%\inetpub\logs\LogFiles\W3SVC<ID>\, un ficherou_exAAMMDD.logpor día en formato W3C. Las horas están en UTC: en Madrid, una o dos horas menos que el reloj. - Los campos clave:
sc-status,sc-substatusytime-taken(milisegundos). - HTTPERR en
%SystemRoot%\System32\LogFiles\HTTPERR\: lo que HTTP.sys rechazó antes de pasarlo a IIS. Un 503 con el grupo detenido aparece aquí, no en el log del sitio. El último campo es el motivo:AppOffline(los errores de la aplicación la han dejado fuera de servicio),Disabled(un administrador la ha detenido) oQueueFull(la cola está llena).
5. Failed Request Tracing
Cuando el log dice 500 y no se sabe qué módulo lo produce, Failed Request Tracing (FREB) guarda el recorrido completo de la petición:
- En el sitio, Actions › Failed Request Tracing... y marcar Enable (por defecto guarda hasta 50 ficheros).
- En Failed Request Tracing Rules, una regla: All content, códigos
500-599o un tiempo mayor que 30 segundos. - Reproducir el error. Los ficheros quedan en
%SystemDrive%\inetpub\logs\FailedReqLogFiles\W3SVC<ID>\y se abren con el navegador. Desactívalo al acabar.
Un 503 de un grupo detenido no deja traza en FREB: la petición se queda en HTTP.sys y nunca entra en IIS. Para ese caso, HTTPERR y el registro de eventos.
6. El ticket: "la aplicación de reservas da 503 Service Unavailable"
Lunes, 8:30. Recepción no puede abrir la aplicación de reservas: HTTP Error 503. The service is unavailable.
- El grupo: en el Administrador de IIS, Application Pools,
Reservasaparece Stopped. HTTPERR lo confirma con503 ... AppOffline Reservas. - Por qué se detuvo: en el Visor de eventos › Registros de Windows › Sistema, origen WAS. Uno de estos dos eventos:
- 5021: The identity of application pool Reservas is invalid. La contraseña de la cuenta
CONTOSO\svc-reservasha caducado o alguien la ha cambiado en el directorio activo. Tras varios intentos fallidos, WAS deshabilita el grupo. - 5002: Application pool 'Reservas' is being automatically disabled due to a series of failures. Es la protección contra errores rápidos: el proceso arranca y se cae. En el registro Aplicación, el error de
w3wp.exe(evento 1000) o de .NET Runtime dice por qué, a menudo un despliegue del viernes.
Si es el 5021, la contraseña: comprobar la cuenta con Get-ADUser svc-reservas -Properties PasswordExpired, LockedOut, pedir el cambio de contraseña al responsable de la cuenta y ponerla en el grupo:
$cred = Get-Credential CONTOSO\svc-reservasImport-Module WebAdministrationSet-ItemProperty IIS:\AppPools\Reservas -Name processModel -Value @{userName=$cred.UserName; password=$cred.GetNetworkCredential().Password; identityType=3}Start-WebAppPool -Name "Reservas"(Invoke-WebRequest https://reservas.corp.example -UseBasicParsing).StatusCode200Si es el 5002, los errores rápidos: arrancar el grupo no basta: se volverá a parar a los cinco fallos, y desactivar la protección solo esconde el problema. Primero la causa (deshacer el despliegue, la dependencia que falta, el web.config roto) y después Start-WebAppPool. Para que no se repita, el grupo pasa a una gMSA.
En el ticket: grupo, evento de WAS, causa, cambio y la comprobación final (200 desde fuera del servidor).
Siguientes pasos
- La guía de Windows Server cubre los roles, los parches y los eventos del sistema que has usado aquí.
- La de Nginx y Apache del Nivel 3 es lo mismo en Linux: sitios por nombre, certificados, proxy inverso y el 502.
¿Falta algo o en tu entorno es distinto? Escríbeme y lo corrijo.
What you'll get
Supporting the web applications that run on IIS: knowing which site answers to which name, which application pool it runs in and under which account, which certificate it presents, where each request's log is and what to do when the page says HTTP Error 503. The service is unavailable.
Before you start
- Windows Server 2022 or 2025 with IIS 10 and local administrator rights.
- The features this guide uses:
Install-WindowsFeature Web-Server, Web-Mgmt-Console, Web-Scripting-Tools, Web-Http-Tracing. - PowerShell as administrator, with WebAdministration (the
IIS:\drive) or IISAdministration (Get-IISSite,Get-IISAppPool). Both work; do not mix them in the same script.
1. Sites, bindings and host headers
A site is a folder with one or more bindings: protocol, IP, port and host name. Several sites share the IP and port 443 if each has its own name:
- With HTTPS and several sites on the same port you need SNI (Require Server Name Indication): the browser states the name before it receives the certificate.
- Each site has an ID: its log folder is called
W3SVC<ID>. Note it on the application's record.
Get-IISSite or appcmd list sites lists the sites with their ID, state and bindings.
2. Application pools
The application pool is the w3wp.exe process that runs the site. One pool per application: if one hangs or recycles, the others carry on.
- Identity: by default, ApplicationPoolIdentity, a virtual account called
IIS AppPool\Reservasthat is given NTFS permissions on the folder. If the app needs to reach SQL Server or a share with Windows authentication, a domain account; better a gMSA (CONTOSO\gmsa-reservas$, with no password to expire). - .NET CLR version:
v4.0for ASP.NET 4.x; No Managed Code for ASP.NET Core, which brings its own runtime. Pipeline mode: Integrated. - Recycling: by default every 1,740 minutes (29 hours), so at a different time each day. Better a fixed quiet time, such as 4:00. The Idle Time-out (20 minutes) shuts the process down if nobody uses it.
- Rapid-Fail Protection: if the process fails 5 times in 5 minutes, IIS stops the pool. It is the source of the most common 503.
Get-IISAppPool shows each pool's state, CLR version and identity; appcmd list wp, the PID of each w3wp.exe, the one you look for in Task Manager when a process is eating CPU.
3. The HTTPS certificate
- The certificate goes in the computer store, Local Machine › Personal, with its private key:
Import-PfxCertificate -FilePath .\reservas.pfx -CertStoreLocation Cert:\LocalMachine\My -Password $pwd. - The binding stores the certificate's thumbprint. When it is renewed, the new one has a different thumbprint and the binding keeps the old one until you change it.
$thumb = (Get-ChildItem Cert:\LocalMachine\My | Where-Object Subject -like "*reservas.corp.example*" | Sort-Object NotAfter -Descending | Select-Object -First 1).ThumbprintImport-Module WebAdministration(Get-WebBinding -Name "Reservas" -Protocol https).AddSslCertificate($thumb, "My")netsh http show sslcert hostnameport=reservas.corp.example:443netsh shows what HTTP.sys really has associated with that name and port.
4. Logs: W3C and HTTPERR
- IIS logs in
%SystemDrive%\inetpub\logs\LogFiles\W3SVC<ID>\, oneu_exYYMMDD.logfile per day in W3C format. Times are in UTC: in Madrid, one or two hours behind the clock. - The key fields:
sc-status,sc-substatusandtime-taken(milliseconds). - HTTPERR in
%SystemRoot%\System32\LogFiles\HTTPERR\: what HTTP.sys rejected before passing it to IIS. A 503 with the pool stopped shows up here, not in the site log. The last field is the reason:AppOffline(application errors have taken it offline),Disabled(an administrator has stopped it) orQueueFull(the queue is full).
5. Failed Request Tracing
When the log says 500 and nobody knows which module produces it, Failed Request Tracing (FREB) records the request's full path:
- On the site, Actions › Failed Request Tracing... and tick Enable (by default it keeps up to 50 files).
- In Failed Request Tracing Rules, a rule: All content, status codes
500-599or time taken over 30 seconds. - Reproduce the error. The files land in
%SystemDrive%\inetpub\logs\FailedReqLogFiles\W3SVC<ID>\and open in the browser. Turn it off when you are done.
A 503 from a stopped pool leaves no FREB trace: the request stays in HTTP.sys and never enters IIS. For that case, HTTPERR and the event log.
6. The ticket: "the bookings app gives 503 Service Unavailable"
Monday, 8:30. Reception cannot open the bookings app: HTTP Error 503. The service is unavailable.
- The pool: in IIS Manager, Application Pools,
Reservasshows Stopped. HTTPERR confirms it with503 ... AppOffline Reservas. - Why it stopped: in Event Viewer › Windows Logs › System, source WAS. One of these two events:
- 5021: The identity of application pool Reservas is invalid. The password of the
CONTOSO\svc-reservasaccount has expired or someone changed it in Active Directory. After several failed attempts, WAS disables the pool. - 5002: Application pool 'Reservas' is being automatically disabled due to a series of failures. That is rapid-fail protection: the process starts and crashes. In the Application log, the
w3wp.exeerror (event 1000) or the .NET Runtime error says why, often a Friday deployment.
If it is 5021, the password: check the account with Get-ADUser svc-reservas -Properties PasswordExpired, LockedOut, ask the account owner for the password change and set it on the pool:
$cred = Get-Credential CONTOSO\svc-reservasImport-Module WebAdministrationSet-ItemProperty IIS:\AppPools\Reservas -Name processModel -Value @{userName=$cred.UserName; password=$cred.GetNetworkCredential().Password; identityType=3}Start-WebAppPool -Name "Reservas"(Invoke-WebRequest https://reservas.corp.example -UseBasicParsing).StatusCode200If it is 5002, rapid-fail: starting the pool is not enough: it will stop again after five failures, and turning off the protection only hides the problem. First the cause (roll back the deployment, the missing dependency, the broken web.config) and then Start-WebAppPool. So it does not happen again, the pool moves to a gMSA.
In the ticket: pool, WAS event, cause, change and the final check (200 from outside the server).
Next steps
- The Windows Server guide covers the roles, patching and system events you used here.
- The Level 3 Nginx and Apache guide is the same on Linux: sites by name, certificates, reverse proxy and the 502.
Is something missing, or different in your environment? Get in touch and I'll fix it.
Tech Career Lab · newsletter
¿Te ha servido? Cada dos semanas envío una idea práctica para perfiles IT: LinkedIn, proyectos, networking y procesos de selección.Found this useful? Every two weeks I send one practical idea for IT professionals: LinkedIn, projects, networking and hiring processes.
Apúntate y llévate las 33 ideasSign up and get the 33 ideas →