¿Qué P#%&2$ pasó?
Hace algún tiempo publicamos en BaleadaGeek cómo instalar certificados gratuitos de Let’s Encrypt en IIS utilizando win-acme.
Todo quedó bonito:
- HTTPS funcionando.
- Candadito seguro en el navegador.
- Certificados instalados en IIS.
- Renovación automática configurada.
- Una tarea programada encargada de que nunca más tuviéramos que preocuparnos por el asunto.
La promesa era básicamente:
Configuralo una vez y olvidate del certificado.
Pues resulta que el servidor se tomó demasiado en serio la parte de “olvidate”.
En julio de 2026 descubrimos que el certificado de apps.zelvait.com había vencido, el de n8n.zelvait.com estaba a pocos días de correr la misma suerte y win-acme había decidido comunicarse con nosotros mediante jeroglíficos como estos:
Unable to read renewal:
missing TargetPluginOptions
Binding null not yet found in IIS
Target plugin did not generate a target
O sea: el candadito verde se había ido de vacaciones y nos había dejado pagando el hotel.
Lo que parecía una renovación rápida terminó convertido en una pequeña odisea entre IIS, PowerShell, bindings, archivos JSON, almacenes de certificados, tareas programadas y dos versiones distintas de win-acme.
La buena noticia es que logramos reparar los tres certificados sin incendiar producción.
Y como toda tragedia informática debe dejar al menos una buena documentación, aquí va el procedimiento completo.
📍 Entorno de batalla
Este era nuestro escenario:
- Sistema operativo: Windows Server 2022
- Servidor web: IIS 10
- Cliente ACME original: win-acme
2.0.10.444 - Cliente ACME actualizado: win-acme
2.2.9.1701 - Autoridad certificadora: Let’s Encrypt
- Almacén de certificados:
LocalMachine\WebHosting - Dominios involucrados:
apps.zelvait.comn8n.zelvait.comcieloschipe.zelvait.com
win-acme es un cliente ACMEv2 para Windows que permite crear, instalar y renovar automáticamente certificados, con integración específica para IIS. La versión recomendada por el proyecto al momento de esta reparación era la rama 2.2.9.1.
🚨 El primer síntoma: la renovación automática dejó de hacer su chamba
Ejecutamos manualmente la renovación desde la instalación existente:
C:\inetpub\win-acme.v2.0.10.444\wacs.exe `
--renew `
--baseuri "https://acme-v02.api.letsencrypt.org/"
Y recibimos esta alegre colección de errores:
Unable to read renewal:
missing TargetPluginOptions
Binding null not yet found in IIS,
create it or use the Manual target plugin instead
Target plugin did not generate a target
Renewal for [IIS] n8n,
n8n.zelvait.com failed
La primera sospecha era bastante lógica:
Seguramente alguien eliminó o cambió los bindings en IIS.
Entramos al Administrador de IIS y revisamos.
Los bindings sí existían.
Default Web Site
http *:80:apps.zelvait.com
https *:443:apps.zelvait.com
n8n
http *:80:n8n.zelvait.com
https *:443:n8n.zelvait.com
Entonces el mensaje:
Binding null not yet found in IIS
no significaba necesariamente que el binding visible hubiera desaparecido.
El problema podía estar en la configuración interna guardada por win-acme: la renovación ya no podía relacionar correctamente su fuente original con el binding actual.
Ahí comenzó la investigación de verdad.
🔎 Paso 1: confirmar qué certificados estaban vencidos
Primero consultamos los bindings HTTPS y sus certificados asociados:
Import-Module WebAdministration
Get-WebBinding -Protocol "https" |
Where-Object {
$_.bindingInformation -match `
"apps\.zelvait\.com|n8n\.zelvait\.com|cieloschipe\.zelvait\.com"
} |
Select-Object bindingInformation,
sslFlags,
certificateStoreName,
certificateHash
Los resultados mostraron que los certificados estaban almacenados en:
Cert:\LocalMachine\WebHosting
No en:
Cert:\LocalMachine\My
Este detalle importa porque buscar únicamente en LocalMachine\My puede hacerte creer que IIS no tiene ningún certificado instalado, aunque realmente esté utilizando el almacén WebHosting.
Después consultamos las fechas de expiración.
| Dominio | Expiración | Estado |
|---|---|---|
apps.zelvait.com | 25 de julio de 2026 | Vencido |
n8n.zelvait.com | 14 de agosto de 2026 | 15 días restantes |
cieloschipe.zelvait.com | 21 de octubre de 2026 | 83 días restantes |
¡Ajá!
Ya teníamos:
- un muerto;
- uno tosiendo;
- y otro todavía comiendo baleada tranquilo.
🗃️ Paso 2: revisar las renovaciones registradas por win-acme
win-acme guarda la configuración de sus renovaciones en archivos con extensión:
*.renewal.json
En nuestro servidor estaban en:
C:\ProgramData\win-acme\
acme-v02.api.letsencrypt.org\
Encontramos tres archivos:
0WGIJ7MsK0C4WCHqB1OeIg.renewal.json
A-2OJtiIBU6uITBOU5iLKw.renewal.json
CM6OnGtZk0eAUK7rbv_3kA.renewal.json
Para identificar a qué dominio correspondía cada renovación, buscamos los nombres de host dentro de los archivos:
$RenewalPath = `
"C:\ProgramData\win-acme\acme-v02.api.letsencrypt.org"
Get-ChildItem $RenewalPath -Filter "*.renewal.json" |
ForEach-Object {
$Raw = Get-Content $_.FullName -Raw
[PSCustomObject]@{
File = $_.Name
Apps = $Raw -match "apps\.zelvait\.com"
N8N = $Raw -match "n8n\.zelvait\.com"
CielosChipe = $Raw -match "cieloschipe\.zelvait\.com"
}
}
El mapa terminó así:
| Renovación | Sitio o dominio |
|---|---|
0WGIJ7... | Default Web Site, configurado como (any host) |
A-2OJti... | n8n.zelvait.com |
CM6OnG... | cieloschipe.zelvait.com |
El primer archivo no mencionaba literalmente apps.zelvait.com, por lo que al inicio parecía una renovación desconocida.
Pero su historial contenía este thumbprint:
6EF361BFD6C75CC351577810B379B34E89A0572A
Ese era exactamente el thumbprint asociado en IIS a:
apps.zelvait.com
Misterio resuelto.
El archivo supuestamente desconocido sí era la renovación de apps.zelvait.com.
Solo que estaba configurado de una forma demasiado genérica.
🧟 El verdadero problema
Encontramos tres debilidades principales.
1. Se seguía utilizando una versión vieja de win-acme
La tarea programada ejecutaba:
C:\inetpub\win-acme.v2.0.10.444\wacs.exe
En el servidor también existía otra versión descargada, pero no era la que utilizaba la tarea automática.
Tener una herramienta nueva guardada en una carpeta no significa que el servidor la esté usando.
La actualización desde cualquier versión 2.x.x hacia 2.2.x está documentada por win-acme como una actualización tipo xcopy: se puede extraer la versión nueva en otra ubicación y conservar la configuración existente en ProgramData.
2. La renovación de apps estaba configurada como “any host”
La renovación aparecía así:
[IIS] Default Web Site, (any host)
Y su fuente incluía el sitio completo:
IncludeSiteIds : 1
IncludeTypes : http
Eso era demasiado amplio.
Si se agregaba otro binding HTTP al Default Web Site, la renovación podía comenzar a considerar también ese hostname.
Cuando un certificado corresponde a un único dominio, es más seguro seleccionar expresamente ese binding. La documentación del plugin IIS permite filtrar y elegir bindings específicos en lugar de incluir todos los bindings de un sitio.
3. La renovación de n8n había perdido la relación correcta con IIS
El binding visible existía, pero win-acme respondía:
Binding null not yet found in IIS
La solución más limpia era volver a configurar la fuente de la renovación y seleccionar otra vez:
Sitio: n8n
Binding: n8n.zelvait.com
💾 Paso 3: hacer respaldo antes de tocar producción
Antes de modificar certificados, bindings o tareas programadas, respaldamos la configuración de win-acme:
$BackupRoot = "C:\Backup\win-acme-20260729"
New-Item `
-ItemType Directory `
-Path $BackupRoot `
-Force
Copy-Item `
-Path "C:\ProgramData\win-acme" `
-Destination "$BackupRoot\ProgramData-win-acme" `
-Recurse `
-Force
También respaldamos IIS:
& "$env:windir\System32\inetsrv\appcmd.exe" `
add backup BeforeWinAcmeRepair_20260729
El servidor respondió:
BACKUP object "BeforeWinAcmeRepair_20260729" added
📌 Regla BaleadaGeek:
Si no tenés respaldo, no estás reparando. Estás apostando.
⬆️ Paso 4: instalar la versión nueva sin borrar la anterior
Descargamos win-acme 2.2.9.1, compilación 2.2.9.1701, y lo extrajimos en:
C:\inetpub\win-acme.v2.2.9.1
Conservamos temporalmente la instalación anterior:
C:\inetpub\win-acme.v2.0.10.444
win-acme recomienda extraer el programa en una ubicación permanente, no en una carpeta temporal, para que la tarea programada pueda encontrar el ejecutable posteriormente.
Desde PowerShell intentamos ejecutar:
wacs.exe
Y PowerShell respondió:
The term 'wacs.exe' is not recognized...
Pero el archivo estaba allí.
No era otro misterio de IIS.
PowerShell no ejecuta automáticamente programas desde el directorio actual. Hay que anteponer:
.\wacs.exe
También funciona la ruta completa:
C:\inetpub\win-acme.v2.2.9.1\wacs.exe
La versión nueva inició correctamente:
Software version 2.2.9.1701
Connecting to Let's Encrypt...
Connection OK!
R: Run renewals (2 currently due)
A: Manage renewals (3 total)
La buena noticia era que la versión nueva podía leer las tres renovaciones.
🛠️ Paso 5: reparar apps.zelvait.com
Desde el menú principal seleccionamos:
A: Manage renewals
La lista mostraba:
1: [IIS] Default Web Site, (any host)
2: [IIS] n8n, n8n.zelvait.com
3: [IISBinding] cieloschipe.zelvait.com
Seleccionamos únicamente la primera renovación y entramos a:
E: Edit renewal
2: Source
1: Read bindings from IIS
Luego seleccionamos:
Site 1: Default Web Site
Binding 1: apps.zelvait.com
Confirmamos la selección y aceptamos el nuevo nombre:
[IIS] Default Web Site, apps.zelvait.com
win-acme sobrescribió la configuración anterior y comenzó la emisión:
Plugin IIS generated source apps.zelvait.com
Force renewing [IIS] Default Web Site, apps.zelvait.com
[apps.zelvait.com] Authorizing...
Authorization result: valid
Downloading certificate
Installing certificate in WebHosting
Updating existing https binding apps.zelvait.com:443
Finalmente eliminó el certificado vencido:
Removing certificate
[IIS] Default Web Site, (any host)
¡Primer paciente resucitado!
⚙️ Paso 6: reparar n8n.zelvait.com
Repetimos el procedimiento con la renovación de n8n:
A: Manage renewals
Seleccionar renovación n8n
E: Edit renewal
2: Source
1: Read bindings from IIS
Seleccionamos:
Site 2: n8n
Binding 1: n8n.zelvait.com
La renovación quedó registrada como:
[IIS] n8n, n8n.zelvait.com
Y win-acme emitió el certificado:
[n8n.zelvait.com] Authorizing...
Authorization result: valid
Installing certificate in WebHosting
Updating existing https binding n8n.zelvait.com:443
En este caso el binding conservó:
flags: 1
Ese valor representa el uso de SNI en el binding HTTPS, útil cuando varios sitios comparten la misma dirección IP y el puerto 443.
🕒 Paso 7: actualizar la tarea programada
La versión nueva detectó que la tarea existente apuntaba a otra ubicación:
Scheduled task points to different location
Scheduled task does not look healthy
Durante la instalación de los nuevos certificados, win-acme eliminó la tarea anterior y creó otra:
Name:
win-acme renew (acme-v02.api.letsencrypt.org)
Path:
C:\inetpub\win-acme.v2.2.9.1
Command:
wacs.exe --renew
La dejamos ejecutándose con la cuenta predeterminada del sistema, sin asignarle un usuario particular.
win-acme administra las configuraciones de renovación como unidades independientes y utiliza una tarea programada para comprobar cuándo corresponde reemplazar cada certificado.
🧪 Paso 8: ejecutar una prueba final
Después de reparar apps y n8n, el menú mostraba:
R: Run renewals (0 currently due)
Ejecutamos R para verificar el ciclo completo.
Curiosamente, win-acme decidió renovar también:
cieloschipe.zelvait.com
La operación terminó correctamente:
Updating existing https binding
cieloschipe.zelvait.com:443
Renewal for [IIS] cieloschipe,
cieloschipe.zelvait.com succeeded
Las otras dos renovaciones informaron:
apps.zelvait.com is due after 2026/9/23
n8n.zelvait.com is due after 2026/9/23
Y finalmente:
R: Run renewals (0 currently due)
A: Manage renewals (3 total)
Ahora sí:
- cero certificados vencidos;
- cero renovaciones pendientes;
- cero pacientes en cuidados intensivos.
✅ Estado final
| Dominio | Resultado |
|---|---|
apps.zelvait.com | Certificado nuevo instalado |
n8n.zelvait.com | Certificado nuevo instalado |
cieloschipe.zelvait.com | Certificado nuevo instalado |
| Renovaciones registradas | 3 |
| Renovaciones pendientes | 0 |
| Tarea programada | Actualizada |
| Ejecutable activo | win-acme 2.2.9.1701 |
| Próxima renovación | Después del 23 de septiembre de 2026 |
🧠 Lo que aprendimos de esta odisea
1. Que un binding exista no significa que la renovación esté sana
IIS puede mostrar correctamente el dominio y aun así win-acme conservar una referencia interna vieja, incompleta o demasiado genérica.
2. --force no repara una mala configuración
Ejecutar:
.\wacs.exe --renew --force
solo obliga a win-acme a ejecutar las configuraciones existentes.
Si la configuración está dañada, vas a forzar el mismo error, pero con más entusiasmo.
Además, Let’s Encrypt limita normalmente a cinco certificados nuevos para el mismo conjunto exacto de identificadores dentro de siete días. No conviene emitir certificados repetidamente mientras todavía estás diagnosticando.
3. Evitá “any host” cuando solo necesitás un hostname
Si la renovación corresponde únicamente a:
apps.zelvait.com
seleccioná expresamente ese binding.
Menos automatización indiscriminada significa menos sorpresas a las nueve de la noche.
4. Revisá qué ejecutable utiliza realmente la tarea programada
Podés tener la versión más nueva descargada y seguir operando durante meses con la anterior porque la tarea apunta a otra carpeta.
5. Revisá el almacén correcto de certificados
En IIS, los certificados pueden encontrarse en:
LocalMachine\WebHosting
Buscar únicamente en:
LocalMachine\My
puede darte un falso negativo.
6. El respaldo se hace antes del susto
Respaldá:
%ProgramData%\win-acme;- la configuración de IIS;
- y, cuando sea posible, la máquina virtual o el servidor.
📋 Checklist rápido
[ ] Confirmar bindings HTTP y HTTPS en IIS
[ ] Revisar fechas de expiración
[ ] Identificar los archivos *.renewal.json
[ ] Verificar el thumbprint de cada binding
[ ] Buscar certificados en WebHosting y My
[ ] Respaldar ProgramData\win-acme
[ ] Respaldar IIS con appcmd
[ ] Instalar la versión recomendada de win-acme
[ ] Revisar qué ejecutable usa la tarea programada
[ ] Editar la fuente de cada renovación dañada
[ ] Seleccionar un hostname específico
[ ] Emitir e instalar el certificado
[ ] Confirmar el binding HTTPS
[ ] Ejecutar una prueba normal de renovaciones
[ ] Verificar que existan cero renovaciones pendientes
🔥 Conclusión
El certificado vencido era solamente el síntoma.
El problema real era una combinación de:
- una versión vieja de win-acme;
- renovaciones almacenadas con referencias problemáticas;
- una fuente configurada como
(any host); - y una tarea programada que seguía apuntando al ejecutable anterior.
La solución no fue darle --force a todo y rezar.
Fue diagnosticar cada capa:
Dominio
→ Binding
→ Certificado
→ Renovación
→ Ejecutable
→ Tarea programada
Esa es probablemente la lección más importante de esta historia:
Cuando la automatización deja de funcionar, no forcés más automatización. Revisá primero qué demonios está automatizando.
Ahora los tres sitios tienen certificados vigentes, las renovaciones quedaron correctamente asociadas y el servidor puede volver a dormir tranquilo.
El administrador no.
Ese ya quedó traumado.

Average Rating