−25%

Windows 연간 결제, 10월 31일까지. 요금제 보기

EQVPS
시작하기

Windows Server에서 스크립트 24시간 실행하기: 로그아웃, 충돌, 재부팅에도 살아남기

Windows Server 2022 VPS에서 작업 스케줄러만으로 봇이나 스크립트를 밤낮없이 돌리는 방법: 아무도 로그인하지 않아도 부팅 시 시작하고, 충돌 후 1분 안에 다시 살아나며, 절대 두 개가 동시에 돌지 않습니다. 프로세스를 강제로 종료하고 재부팅해서 확인했습니다.

Windows VPS에서 봇을 돌리는 흔한 방법은 RDP 세션에서 실행하고 창을 닫는 것입니다. 이 방법은 업데이트가 새벽 3시에 서버를 재부팅하고 아무도 봇을 다시 켜지 않을 때까지만 통합니다. 모든 Windows Server에 있는 작업 스케줄러로 추가 소프트웨어 없이 해결할 수 있습니다. 아래 구성은:

  • 누군가 로그인하기 전에 부팅 시 스크립트를 시작하고,
  • 충돌하거나 종료되면 1분 안에 다시 시작하며,
  • 절대 두 개를 동시에 돌리지 않습니다.

세 가지 모두 저희 Windows Server 2022 이미지에서 확인했습니다. 프로세스를 종료하고, 서버를 재부팅하고, 인스턴스 수를 셌습니다.

예제 스크립트

봇을 대신하는 예제입니다. 10초마다 한 줄을 써서 살아 있는지 쉽게 알 수 있습니다.

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
}
'@

작업 등록

관리자 권한 PowerShell에서 실행합니다.

$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'

각 부분의 역할:

  • **-AtStartup**은 로그인한 사용자가 없어도 Windows 부팅 시 봇을 시작합니다.
  • 1분마다 반복은 매분 작업을 다시 실행합니다. 봇이 살아 있으면 아무 일도 일어나지 않고, 죽었다면 다시 시작합니다.
  • **-MultipleInstances IgnoreNew**가 반복을 안전하게 만듭니다. 봇이 이미 실행 중일 때의 실행은 건너뜁니다.
  • **-ExecutionTimeLimit 0**은 기본 72시간 제한을 끕니다. 이 제한이 있으면 작업 스케줄러가 봇을 멈춥니다.
  • **-User 'SYSTEM'**은 비밀번호와 세션 없이 실행합니다. SYSTEM은 서버의 모든 권한을 가지므로 이 방식으로는 내 코드만 실행하세요.

Python이라면 동작을 바꿉니다.

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

확인한 내용

충돌. Stop-Process -Force로 봇 프로세스를 종료했습니다. 46초 뒤 1분마다 오는 트리거가 새 프로세스를 띄웠고, 정확히 하나만 돌고 있었습니다.

재부팅. 서버를 재부팅하고 로그인하지 않았습니다. 부팅 40초 뒤 봇이 이미 로그를 쓰고 있었고, 서버에 사용자 세션은 없었습니다.

효과가 없었던 것. 맞아 보이지만 그렇지 않은 두 가지가 있습니다.

  1. '작업이 실패하면 다시 시작 간격…'. 켜고 프로세스를 종료했더니 작업이 몇 분 동안 준비 상태에 머물렀습니다. 작업이 시작하지 못할 때 반응하는 설정이지, 프로그램이 나중에 죽을 때가 아닙니다.
  2. 래퍼 루프(while ($true) { & bot; sleep 5 }). 충돌한 봇은 다시 띄우지만, 래퍼 자체가 죽으면 자식 프로세스가 계속 돌고 다음 실행에서 두 번째 봇이 뜹니다. 저희도 결국 두 개가 됐는데, Telegram 봇이라면 같은 업데이트를 두 프로세스가 서로 가져가려 다투게 됩니다.

상태 확인

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

유지 보수를 위해 멈추려면 먼저 Disable-ScheduledTask mybot을 실행하고(그러지 않으면 1분마다 오는 트리거가 다시 켭니다) 그다음 프로세스를 멈추세요. Enable-ScheduledTask mybot으로 되돌립니다.

로그

작업은 출력을 저장하지 않습니다. 예제처럼 봇이 직접 로그를 쓰게 하거나, 작은 .cmd 실행 파일에서 출력을 리디렉션하고 -Execute가 그 파일을 가리키게 하세요.

어떤 플랜을 고를까

PowerShell이나 Python 봇은 CPU를 거의 쓰지 않지만, 저희 이미지에서 Windows 자체가 유휴 상태에서 RAM을 1~1.3 GB 사용합니다. Windows-Small(4 vCPU, RAM 4 GB, 50 GB, 월 $11)이 봇 한두 개에 알맞은 크기입니다. NAT 플랜에서도 나가는 연결(Telegram, 거래소 API, 호출하는 웹훅)은 평소처럼 동작합니다. 봇이 웹훅 같은 들어오는 트래픽을 받아야 한다면 전용 IPv4가 있는 Windows Small-IP(월 $28)를 고르세요.

다음 단계: RDP 보호하기, 그리고 SSH로 봇을 관리하고 싶다면 OpenSSH 설치하기. 결제는 USDT, USDC, ETH로 하며, Windows는 직접 보유한 라이선스로 쓰는 Server 2022입니다(BYOL). 전체 플랜: Windows VPS.

자주 묻는 질문

RDP 세션에서 스크립트를 그냥 돌려 두면 안 되나요?

무언가가 세션을 끝낼 때까지만 동작합니다. 로그아웃, 업데이트 후 재부팅, 충돌 같은 경우입니다. RDP 창을 닫으면(연결 끊기) 세션은 살아 있지만, 로그아웃하면 그 안의 모든 것이 종료되고, 재부팅 후에는 다시 실행해 줄 사람이 로그인해 있지 않습니다. 예약된 작업은 어떤 세션에도 의존하지 않습니다.

작업 스케줄러에 '실패하면 다시 시작' 설정이 있지 않나요?

있지만 저희 테스트에서는 도움이 되지 않았습니다. 스크립트 프로세스를 종료하자 작업은 '준비' 상태가 되어 그대로 멈춰 있었습니다. 이 설정은 작업이 시작에 실패할 때 반응하며, 프로그램이 나중에 죽을 때는 반응하지 않습니다. 다시 살려내는 것은 이 가이드의 반복 트리거입니다.

봇이 두 개 동시에 돌 수도 있나요?

이 구성에서는 그렇지 않습니다. 작업이 봇 자체를 직접 실행하고(래퍼 스크립트 없음) MultipleInstances IgnoreNew를 쓰므로, 봇이 살아 있는 동안 1분마다 오는 트리거는 아무것도 하지 않습니다. 오히려 중복을 만드는 것은 래퍼 루프입니다. 래퍼를 종료해도 자식 프로세스는 계속 돌고, 새 래퍼가 또 하나를 띄웁니다. 저희가 실제로 그렇게 됐습니다.

Python이나 Node.js에서도 되나요?

됩니다. -Execute에 인터프리터를, -Argument에 스크립트를 전체 경로로 지정하세요. 예: -Execute 'C:\Program Files\Python312\python.exe' -Argument 'C:\bots\bot.py'. SYSTEM 계정이 찾을 수 있도록 인터프리터는 모든 사용자용으로 설치하세요.

댓글

아직 댓글이 없습니다. 첫 번째가 되세요.

댓글 남기기

댓글은 표시되기 전에 검토됩니다.