−25%

en Windows con pago anual, hasta el 31/10. Ver planes

EQVPS
Empezar

Cómo ejecutar un script 24/7 en Windows Server: sobrevive al cierre de sesión, caídas y reinicios

Mantén un bot o script funcionando día y noche en un VPS con Windows Server 2022 solo con el Programador de tareas: arranca con el sistema sin nadie conectado, se reinicia en menos de un minuto tras una caída y nunca corre dos copias. Matamos el proceso y reiniciamos para comprobarlo.

Lo habitual para tener un bot en un VPS Windows es lanzarlo en una sesión de RDP y cerrar la ventana. Funciona hasta que una actualización reinicia el servidor a las 3 de la madrugada y nadie lo vuelve a lanzar. El Programador de tareas, presente en cualquier Windows Server, lo arregla sin software extra. La configuración de abajo:

  • arranca el script con el sistema, antes de que nadie inicie sesión;
  • lo reinicia en menos de un minuto si se cae o lo matan;
  • nunca corre dos copias a la vez.

Probamos las tres cosas en nuestra imagen de Windows Server 2022: matamos el proceso, reiniciamos el servidor y contamos las instancias.

El script de ejemplo

Un sustituto de tu bot: escribe una línea cada 10 segundos, así es fácil ver si sigue vivo.

New-Item -ItemType Directory -Force C:\bots | Out-Null
Set-Content C:\bots\heartbeat.ps1 -Encoding ascii -Value @'
while ($true) {
    Add-Content -Path C:\bots\heartbeat.log -Value ("{0:u} pid {1}" -f (Get-Date), $PID)
    Start-Sleep -Seconds 10
}
'@

Registra la tarea

Ejecuta en un PowerShell con permisos de administrador:

$action   = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-NoProfile -ExecutionPolicy Bypass -File C:\bots\heartbeat.ps1' -WorkingDirectory 'C:\bots'
$atBoot   = New-ScheduledTaskTrigger -AtStartup
$everyMin = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 1)
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit ([TimeSpan]::Zero) -MultipleInstances IgnoreNew -StartWhenAvailable
Register-ScheduledTask -TaskName 'mybot' -Action $action -Trigger $atBoot, $everyMin -Settings $settings -User 'SYSTEM' -RunLevel Highest
Start-ScheduledTask -TaskName 'mybot'

Qué hace cada parte:

  • -AtStartup lanza el bot al arrancar Windows, sin ningún usuario conectado.
  • La repetición cada minuto vuelve a ejecutar la tarea cada minuto. Si el bot está vivo, no pasa nada; si murió, arranca de nuevo.
  • -MultipleInstances IgnoreNew hace segura la repetición: una ejecución que encuentra el bot ya en marcha se omite.
  • -ExecutionTimeLimit 0 desactiva el límite predeterminado de 72 horas, tras el cual el Programador detendría el bot.
  • -User 'SYSTEM' lo ejecuta sin contraseña ni sesión. SYSTEM tiene todos los permisos en el servidor, así que ejecuta así solo tu propio código.

Para Python, cambia la acción:

$action = New-ScheduledTaskAction -Execute 'C:\Program Files\Python312\python.exe' -Argument 'C:\bots\bot.py' -WorkingDirectory 'C:\bots'

Lo que comprobamos

Caída. Matamos el proceso del bot con Stop-Process -Force. 46 segundos después el desencadenador de cada minuto había lanzado uno nuevo, y había exactamente una copia.

Reinicio. Reiniciamos el servidor y no iniciamos sesión. 40 segundos después del arranque el bot ya escribía en su registro, sin sesiones de usuario en el servidor.

Lo que no funcionó. Dos cosas parecen correctas y no lo son:

  1. «Si la tarea no se ejecuta, reiniciarla cada…» La activamos, matamos el proceso y la tarea se quedó varios minutos en Lista. Reacciona a que la tarea no logre arrancar, no a que tu programa muera después.
  2. Un bucle envoltorio (while ($true) { & bot; sleep 5 }). Reinicia un bot caído, pero si muere el propio envoltorio, su hijo sigue funcionando y el siguiente arranque lanza un segundo bot. Terminamos con dos copias, lo que en un bot de Telegram significa dos procesos peleándose por las mismas actualizaciones.

Cómo revisarlo

Get-ScheduledTask -TaskName mybot | Select-Object TaskName, State
Get-ScheduledTaskInfo -TaskName mybot | Select-Object LastRunTime, NextRunTime
Get-Content C:\bots\heartbeat.log -Tail 5

Para pararlo por mantenimiento, primero Disable-ScheduledTask mybot (si no, el desencadenador de cada minuto lo vuelve a arrancar) y luego detén el proceso. Enable-ScheduledTask mybot lo devuelve.

Registros

La tarea no captura la salida. Haz que el bot escriba su propio registro, como el ejemplo, o redirige la salida en un pequeño lanzador .cmd y apunta -Execute a ese archivo.

Qué plan elegir

Un bot en PowerShell o Python usa poca CPU, pero Windows en sí ocupa de 1 a 1,3 GB de RAM en reposo en nuestra imagen. Windows-Small (4 vCPU, 4 GB de RAM, 50 GB, $11/mes) es el tamaño adecuado para uno o dos bots. En un plan NAT, las conexiones salientes (Telegram, APIs de exchanges, webhooks a los que llamas) funcionan con normalidad. Si el bot necesita recibir webhooks u otro tráfico entrante, elige Windows Small-IP ($28/mes) con IPv4 propia.

Siguientes pasos: protege RDP y, si prefieres gestionar el bot por SSH, instala OpenSSH. El pago es en USDT, USDC o ETH, y Windows es Server 2022 con tu propia licencia (BYOL). Todos los planes: Windows VPS.

Preguntas frecuentes

¿Por qué no dejar el script corriendo en mi sesión de RDP?

Funciona hasta que algo cierra la sesión: cerrar sesión, un reinicio por actualizaciones o una caída. Cerrar la ventana de RDP (desconectar) mantiene la sesión viva, pero cerrar sesión mata todo lo que hay dentro, y tras un reinicio nadie ha iniciado sesión para volver a lanzarlo. Una tarea programada no depende de ninguna sesión.

¿El Programador de tareas no tiene la opción «reiniciar si se produce un error»?

La tiene, pero en nuestra prueba no sirvió. Cuando matamos el proceso del script, la tarea pasó a «Lista» y se quedó ahí. Esa opción reacciona cuando la tarea no logra arrancar, no cuando tu programa muere después. Lo que la devuelve a la vida es el desencadenador repetitivo de esta guía.

¿Pueden acabar corriendo dos copias de mi bot?

Con esta configuración, no. La tarea ejecuta el propio bot (sin script envoltorio) y usa MultipleInstances IgnoreNew, así que el desencadenador de cada minuto no hace nada mientras el bot esté vivo. Lo que crea duplicados es un bucle envoltorio: mata el envoltorio, su proceso hijo sigue funcionando y el nuevo envoltorio lanza otro. Vimos exactamente eso.

¿Funciona con Python o Node.js?

Sí. Pon el intérprete en -Execute y el script en -Argument, con rutas completas, por ejemplo -Execute 'C:\Program Files\Python312\python.exe' -Argument 'C:\bots\bot.py'. Instala el intérprete para todos los usuarios para que la cuenta SYSTEM lo encuentre.

Comentarios

Aún no hay comentarios. Sé el primero.

Deja un comentario

Los comentarios se moderan antes de aparecer.