SSD Nodes Learn Hosting plans →
가이드 Matt Connor작성자 Matt Connor · 업데이트됨 2026-08-07

트레이딩 봇용 VPS 선택 기준: 가동 시간과 systemd 설정

트레이딩 봇 운영 시 VPS의 가동 시간은 판매자의 광고 수치가 아닌 systemd의 재시작 규율에 달려 있습니다. OOM 킬러로 인한 프로세스 종료를 방지하는 설정과 정확한 시스템 시간 유지, 그리고 API 보안을 위한 필수 엔지니어링 가이드를 확인하십시오.

트레이딩 봇을 위한 VPS의 필수 요건

트레이딩 봇용 VPS는 다음 네 가지 기준으로 평가합니다. 프로세스 종료 시 자동 재시작 여부, 시스템 시간의 정확성, API(application programming interface) 키의 탈취 방지, 그리고 서비스 중단 시 알림 기능입니다. 개인 투자자용 봇의 경우, 주문 경로에서 가장 느린 구간은 호스트의 Python 실행 속도가 아니라 브로커와의 통신 및 물리적 거리이므로, 서버의 단순 연산 속도는 우선순위가 낮습니다.

본 문서는 엔지니어링 가이드입니다. 이 문서에는 어떠한 투자 조언도 포함되어 있지 않으며, 전략에 대해서도 다루지 않습니다.

가동 시간은 재시작 규율이며, 판매 페이지의 숫자가 아닙니다

지구상의 모든 호스트는 99.9 퍼센트의 가동 시간을 광고합니다. 그 수치는 하이퍼바이저를 의미할 뿐, 귀하의 봇을 의미하지는 않습니다. 봇은 처리되지 않은 예외, 재연결되지 않는 웹소켓, 또는 OOM (out of memory) 킬러로 인해 죽을 수 있으며, 이때 서버는 계속 가동 상태를 유지합니다. 따라서 유용한 질문은 프로세스가 종료된 후 10초 동안 무슨 일이 일어나는가입니다.

봇을 systemd 서비스로 실행하고 init 시스템이 재시작을 관리하도록 하십시오. 유닛 파일은 6줄로 이를 수행합니다.

[Unit]
Description=Trading bot
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=0

[Service]
Type=simple
User=bot
WorkingDirectory=/opt/tradingbot
EnvironmentFile=/etc/tradingbot/api.env
ExecStart=/opt/tradingbot/venv/bin/python -m tradingbot
Restart=always
RestartSec=10
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/tradingbot

[Install]
WantedBy=multi-user.target

StartLimitIntervalSec=0는 사람들이 놓치는 줄입니다. 기본적으로 systemd는 10초 동안 5번 재시작하면 포기하고 유닛을 영원히 failed 상태로 둡니다. 이는 새벽 3시에 절대 원하지 않는 동작입니다. 이 값을 0으로 설정하면 속도 제한이 비활성화되므로, 크래시 루프에 빠진 봇이 조용해지는 대신 계속 시도하게 됩니다. RestartSec=10은 해당 루프가 거래소에 재연결 요청을 퍼붓는 것을 방지합니다.

파일을 신뢰하기 전에 확인한 다음 시작하십시오:

sudo systemd-analyze verify /etc/systemd/system/tradingbot.service
sudo systemctl daemon-reload
sudo systemctl enable --now tradingbot
systemctl status tradingbot

enable는 재부팅 후에도 유지되는 절반의 설정입니다. 커널 업데이트는 곧 재부팅을 의미합니다. 봇이 조용히 죽어가고 있었는지 확인하려면 systemd에 재시작 카운터를 요청하십시오:

systemctl show tradingbot -p NRestarts
journalctl -u tradingbot --since "24 hours ago" | tail -50

일주일 후의 NRestarts=0은 건강한 봇을 의미합니다. NRestarts=812는 밤새 재연결을 반복하는 프로세스로 거래하고 있었음을 의미합니다. 일일 보고서와 같은 예약된 작업을 위한 타이머를 포함한 전체 유닛 파일 구조는 systemd 서비스로 프로그램 실행하기에서 다룹니다.

시스템 시간을 UTC로 설정하고 동기화 상태 확인하기

거래소 API는 요청에 타임스탬프를 포함하여 서명하며, 특정 시간(보통 5초 이내)을 벗어난 요청은 거부합니다. 시스템 시간이 맞지 않으면 인증 실패와 유사한 오류가 발생하므로, 많은 사용자가 시간을 확인하기 전에 몇 시간 동안 키를 교체하며 시간을 낭비합니다. Binance 방식의 API는 Timestamp for this request was 1000ms ahead of the server's time와 같은 명확한 메시지를 반환합니다.

서버 시간을 UTC로 설정하십시오. 로컬 시간대를 사용하면 서머타임(Daylight Saving Time) 전환 시점에 거래 세션이 중단될 수 있습니다.

sudo timedatectl set-timezone UTC
timedatectl

Ubuntu는 기본적으로 SNTP(Simple Network Time Protocol) 클라이언트인 systemd-timesyncd을 제공합니다. 이는 로그 기록에는 적합하지만, 수 밀리초 이내의 정밀도가 필요한 작업에는 부족합니다. 단일 서버만 폴링하며 지속적으로 클록을 보정하지 않기 때문입니다. 대신 chrony을 사용하십시오.

sudo apt update && sudo apt install -y chrony
sudo systemctl enable --now chrony
chronyc tracking
chronyc sources -v

chronyc tracking에서 확인해야 할 항목은 System time이며, 예시는 System time : 0.000031415 seconds fast of NTP time과 같습니다. 수 밀리초 이내라면 정상입니다. 만약 Leap status : Not synchronised로 표시된다면, 보통 아웃바운드 UDP 123 포트가 차단되어 chrony가 서버에 도달하지 못한 상태입니다. 방화벽 규칙을 수정하기 전에 1분 정도 기다린 후 다시 확인하십시오.

API 키를 복사하는 곳에 두지 마십시오

유출된 거래소 키는 유출된 SSH 키보다 더 위험합니다. 출금 권한이 있으면 즉시 금전적 피해로 이어지기 때문입니다. 두 가지 습관으로 대부분의 위험을 방지할 수 있습니다.

첫째, 봇 키에 출금 권한을 절대 부여하지 마십시오. 거래소에서 지원한다면 해당 키를 서버의 IP 주소로 바인딩하십시오. 이는 키를 도난당하더라도 무용지물로 만드는 가장 확실한 통제 수단입니다.

둘째, 비밀 값을 코드 디렉터리 내부에 두지 마십시오. /opt/tradingbot 내부의 모든 것은 머지않아 git 저장소나 백업 아카이브에 포함됩니다. systemd만 읽을 수 있도록 root 소유의 파일에 저장하십시오:

sudo install -d -m 750 -o root -g bot /etc/tradingbot
sudo install -m 640 -o root -g bot /dev/null /etc/tradingbot/api.env
sudo nano /etc/tradingbot/api.env

이 파일에는 따옴표나 export 없이 일반적인 KEY=value 줄만 포함됩니다. 모드를 640으로 설정하고 그룹을 bot로 지정하면 서비스 사용자만 읽을 수 있고 다른 사용자는 접근할 수 없습니다. sudo -u bot cat /etc/tradingbot/api.env으로 확인한 다음 다른 사용자로 접근하여 Permission denied 오류가 발생하는지 확인하십시오.

봇 자체는 root나 로그인 사용자로 실행해서는 안 됩니다. 셸과 홈 디렉터리가 없는 시스템 계정을 생성하십시오:

sudo useradd --system --shell /usr/sbin/nologin --home-dir /var/lib/tradingbot --create-home bot

각 플래그의 이유와 ProtectSystem=strict의 실제 적용 범위는 권한 없는 사용자로 서비스 실행하기에서 확인할 수 있습니다. 서버 기본 설정인 SSH 키와 방화벽에 관한 내용은 새 VPS에서의 첫 10분을 참조하십시오.

브로커가 알기 전에 서비스 중단 확인하기

systemctl status는 프로세스가 실행 중임을 나타낼 뿐, 봇이 정상적으로 작동하고 있다는 의미는 아닙니다. 데드 웹소켓에 대해 재시도 루프에 빠진 프로세스는 systemd가 수행하는 모든 검사를 통과합니다.

대신 하트비트를 사용하십시오. Uptime Kuma는 푸시 모니터를 지원합니다. 봇이 정해진 주기에 따라 URL을 호출하도록 설정하고, 호출이 중단되면 알림을 보냅니다. 메인 루프의 마지막 부분, 즉 시장 데이터 읽기 성공과 같이 봇이 살아있음을 증명하는 작업 뒤에 이 호출을 배치하십시오.

curl -fsS "http://monitor.example.com:3001/api/push/YOUR_TOKEN?status=up&msg=loop_ok"

모니터링 간격은 루프 시간의 약 2배로 설정하여 일반적인 지터(jitter)로 인해 호출이 오지 않는 상황을 방지하십시오. 모니터링 도구는 봇과 다른 서버에서 실행해야 합니다. 감시 대상과 함께 죽어버린 모니터는 아무런 정보도 보고할 수 없기 때문입니다. 설정 방법은 Uptime Kuma를 이용한 자체 호스팅 상태 모니터링에서 다룹니다.

디스크 알림도 추가하십시오. 상세 로그를 기록하는 봇은 몇 주 안에 루트 파일 시스템을 가득 채울 수 있습니다. 디스크가 가득 차면 네트워크 호출이 아닌 데이터베이스 쓰기가 먼저 중단되므로 증상이 모호해집니다. journalctl --vacuum-time=14d/etc/systemd/journald.conf 파일의 SystemMaxUse= 설정을 통해 저널 크기를 제한하십시오.

솔직한 이야기: 지연 시간의 대부분은 호스트의 문제가 아닙니다

트레이딩 VPS 제품 시장이 기술적 영역을 벗어나는 지점이 바로 여기입니다. 마케팅 페이지는 1밀리초 미만의 수치를 내세우며 호스트가 주문 체결의 성패를 좌우하는 것처럼 암시합니다. 하지만 거의 모든 개인용 봇에게 이는 사실이 아닙니다.

사용자의 주문은 봇에서 공용 인터넷을 거쳐 거래소나 브로커의 엔드포인트로 전달됩니다. 이 경로의 지연 시간은 물리적 거리와 사용자의 호스팅 제공업체와 브로커 간의 피어링(peering) 상태에 의해 결정됩니다. 프랑크푸르트의 서버에서 도쿄의 엔드포인트로 통신할 경우, CPU 속도와 관계없이 왕복 지연 시간은 약 250밀리초가 발생합니다. 여기에 브로커 시스템 자체의 대기열, 위험 관리 검사, 속도 제한이 추가되는데, 개인 계정의 경우 보통 수십에서 수백 밀리초가 소요됩니다.

추측하지 말고 직접 측정하십시오. curl은 실제 엔드포인트에 대한 연결 시간과 첫 바이트 도달 시간을 보고합니다.

curl -s -o /dev/null -w 'dns=%{time_namelookup}s connect=%{time_connect}s ttfb=%{time_starttransfer}s\n' \
  https://api.kraken.com/0/public/Time
mtr -rwzc 100 api.kraken.com

서버를 결정하기 전에 해당 서버에서 위 명령을 실행해 보십시오. 만약 connect가 0.180초라면 대륙이 잘못 선택된 것이며, 이는 반드시 수정해야 합니다. 만약 connect가 0.004초이고 ttfb이 0.140초라면, 나머지 지연 시간은 브로커의 처리 과정에서 발생하는 것이므로 호스트를 변경해도 해결되지 않습니다.

그렇다면 호스트가 중요한 경우는 언제일까요? 거래소와 같은 공간에 서버를 배치(colocation)하거나 직접 연결(cross-connect)하여 대기열 우선순위를 두고 경쟁할 때입니다. 이는 완전히 다른 비즈니스 영역이며 예산 규모도 다릅니다. 또한 사용자의 코드 자체가 병목 현상을 일으키는 경우도 있습니다. 틱이 발생할 때마다 전체 기록을 바탕으로 지표를 다시 계산하는 봇은 루프당 200밀리초의 CPU 시간을 소모할 수 있는데, 이는 사용자가 직접 제어할 수 있는 실질적인 지연 시간입니다. 더 빠른 서버를 찾기 전에 루프를 프로파일링하십시오.

호스트 선택에서 실제로 중요한 것은 지리적 위치, 안정적인 네트워크, 그리고 OOM killer가 개입하지 않을 만큼 충분한 메모리입니다. 2026년 7월 기준으로, 수백 개의 심볼을 메모리에 올리는 단일 전략 Python 봇은 2 GB RAM과 2 vCPU 환경에서 충분히 원활하게 작동합니다. 로컬 데이터베이스에 틱 기록을 저장한다면 메모리를 추가하십시오.

라이브 전환 전 간단한 체크리스트

  1. systemctl is-enabled tradingbot 명령이 enabled을 출력하며, 서비스가 sudo reboot 이후에도 정상적으로 유지됩니다.
  2. chronyc tracking 명령이 시스템 시간 오차를 수 밀리초 이내로 보고합니다.
  3. API 키에 거래 권한은 부여되어 있으나 출금 권한은 없으며, 거래소에서 제공하는 경우 IP 허용 목록이 설정되어 있습니다.
  4. sudo systemctl kill -s SIGKILL tradingbot 명령으로 프로세스를 종료해도 RestartSec 이내에 다시 시작됩니다.
  5. 봇을 의도적으로 중단했을 때 하트비트 모니터가 한 간격 내에 알림을 보냅니다.
  6. 로그 크기가 제한되어 있으며 df -h의 루트 파일 시스템에 여유 공간이 있습니다.

실제 자금을 투입하기 전에 일주일 동안 거래소의 샌드박스나 모의 투자 모드에서 전체 과정을 실행하십시오. 위 항목들은 해당 기간 동안 최소 한 번은 실패하게 되며, 그것이 바로 일주일간의 테스트를 진행하는 이유입니다.

FAQ

트레이딩 봇은 저지연 서버나 베어메탈 서버가 필요한가요?

같은 거래소에서 다른 자동화 참여자들과 실행 속도를 경쟁하는 경우에만 필요하며, 이 경우 일반적인 VPS보다는 코로케이션이 적합합니다. 개인용 봇의 경우 왕복 시간은 지리적 위치와 브로커 자체의 처리 속도에 의해 결정되므로, API 엔드포인트와 가까운 서버를 선택하고 더 빠른 사양을 구매하기 전에 curlmtr로 측정하십시오.

트레이딩 봇은 어느 정도의 RAM과 CPU가 필요한가요?

대부분의 단일 전략 봇은 네트워크 제한적이며 이벤트 사이에는 유휴 상태입니다. 2026년 7월 기준으로, 2 vCPU와 2 GB RAM이면 수백 개의 종목을 추적하는 Python 봇을 운영하기에 충분합니다. 프로세스 내에 틱 히스토리를 유지하거나 로컬 데이터베이스를 실행할 때 메모리가 제약 조건이 되므로, 추측하기보다는 free -h과 저널의 OOM kill 메시지를 모니터링하십시오.

거래소 API가 왜 타임스탬프 오류로 요청을 거부하나요?

서버 시계가 거래소의 서명 허용 범위(보통 수 초)를 벗어났기 때문입니다. chrony를 설치하고 chronyc tracking에서 System time 오프셋이 작고 동기화된 leap 상태인지 확인하십시오. 또한 서머타임 변경으로 인한 시간 변화가 없도록 시스템 시간을 UTC로 설정하십시오. API 키를 교체하는 것으로는 시계 문제를 해결할 수 없습니다.

밤사이에 봇이 죽는 것을 어떻게 방지할 수 있나요?

systemd에서 Restart=alwaysStartLimitIntervalSec=0을 사용하여 봇을 실행하면 프로세스가 완전히 종료되지 않고 충돌 루프가 재시도를 반복합니다. 여기에 봇이 각 성공적인 루프 끝에 보내는 하트비트를 추가하십시오. 재시작 설정은 프로세스 중단을 처리하고, 하트비트는 프로세스는 살아있지만 멈춘 상태를 감지합니다.

봇과 모니터링 도구를 같은 VPS에서 실행해도 되나요?

실행할 수는 있지만, 정작 중요한 순간에 모니터링 도구가 거짓 정보를 줄 수 있습니다. 봇을 중단시킨 장애가 모니터링 도구까지 함께 중단시키기 때문입니다. 알림 시스템은 다른 제공업체나 다른 리전의 별도 장비에서 운영하고, 봇 서버는 봇과 로그 기록만을 위해 사용하십시오.