컴퓨터 원격 제어 2편 텔레그램으로 외부에서 집 컴퓨터 켜는 법 (WOL & 원격 종료 )

컴퓨터 원격 제어 2편 텔레그램으로 외부에서 집 컴퓨터 켜는 법 (WOL & 원격 종료 )

회사나 카페 등 외부에서 급하게 집에 있는 컴퓨터 자료가 필요할 때, 혹은 외출 후 깜빡하고 켜두고 나온 모니터가 신경 쓰여 발을 동동 구른 적 있으신가요?

단순히 PC 본체만 깨우는 WOL(Wake on LAN) 기능을 넘어, 이제는 스마트폰 텔레그램 버튼 하나로 PC 전원 온/오프(ON/OFF)는 물론 실시간 모니터 절전까지 완벽하게 제어하는 스마트 홈 오피스 환경을 구축해 보세요.

이번 포스팅에서는 오라클 클라우드와 같은 리눅스(우분투) 서버를 활용해 24시간 중단 없이 작동하는 텔레그램 WOL 봇 만들기 전체 과정을 소개합니다. 특히 초보자분들이 PC 원격 부팅 설정 중 가장 애를 먹는 ‘라이브러리 버전 충돌’과 ‘공유기 포트포워딩 신호 차단’ 문제를 한 방에 해결해 드립니다.

가장 직관적이고 안정적인 python-telegram-bot v13.15 버전을 기반으로, 코딩을 몰라도 복사 붙여넣기만 하면 완성되는 윈도우 원격 제어를 상세히 담았습니다. 지금 바로 내 컴퓨터를 언제 어디서든 깨울 수 있는 만능 리모컨을 만들어보세요!

  • 밖에서 스마트폰 클릭 한 번으로 집 PC를 켜고 싶으신 분
  • PC 전원뿐만 아니라 모니터만 따로 끄는 정교한 제어가 필요하신 분
  • 서버가 재부팅되어도 자동으로 살아나는 안정적인 시스템을 원하시는 분
  • 포트 충돌이나 방화벽 문제로 원격 제어에 실패했던 분

1. 리눅스 서버에 설치하기

텔레그램으로 내 컴퓨터 전원관리

1-1. 필수 라이브러리 설치

가장 먼저 파이썬 환경을 준비해야 합니다. 최신 v20+ 버전은 코드가 비동기 방식으로 바뀌어 초보자가 다루기 매우 복잡하므로, 훨씬 직관적이고 자료가 많은 v13.15 버전을 사용합니다.

아래 명령어를 한 줄씩 복사해서 터미널에 입력해 주세요

# 1. 목록 업데이트
sudo apt update

# 2. 기존 라이브러리 제거 (깔끔하게)
pip3 uninstall -y python-telegram-bot

# 3. 호환 버전 및 도구 설치
pip3 install python-telegram-bot==13.15 wakeonlan
  • v13.15: “버튼 누르면 이거 해”라고 직관적으로 짜기 좋습니다. 자료도 엄청나게 많습니다.
  • v20: 비동기(Async/Await)라는 어려운 개념이 들어가서 코드가 복잡해지고, 초보자가 수정하다가 에러가 나면 잡기가 매우 힘듭니다

1-2. 오라클 서버 코드 최종 업데이트

이제 터미널에서 아래 과정을 그대로 따라 해서 코드를 완성해 보세요. 먼저 터미널 창에 아래 명령어를 입력하여 편집기를 엽니다.

nano wol_bot.py

열린 편집기에 아래 내용을 통째로 복사해서 붙여넣으세요. 주의: 본인의 텔레그램 토큰, PC의 MAC 주소, 그리고 연결된 도메인(또는 공인 IP)을 반드시 자신의 정보로 수정해야 정상 작동합니다.

import logging
import os
import socket
from telegram import Update, ReplyKeyboardMarkup
from telegram.ext import Updater, CommandHandler, CallbackContext

# 로그 설정: 봇이 실행되면서 발생하는 상황을 터미널에 기록합니다.
logging.basicConfig(format='%(asctime)s - %(message)s', level=logging.INFO)

# --- 사용자 설정 정보] 이 부분을 본인의 정보로 수정해야 합니다 ---
# 텔레그램 BotFather에게 받은 봇 토큰
API_TOKEN = 'YOUR_BOT_TOKEN_HERE' 

# 제어할 PC의 랜카드 물리 주소 (MAC Address)
MAC_ADDR = '00:00:00:00:00:00' 

# 외부에서 접속 가능한 도메인 또는 고정 IP (클라우드플레어 사용 시 회색 구름 필수)
TARGET_IP = 'your.domain.com' 
# -----------------------------------------------------------

def get_keyboard():
 """텔레그램 채팅창 하단에 표시될 커스텀 버튼 메뉴를 생성합니다."""
 # /on: 켜기, /moff: 모니터 끄기, /off: 전원 종료
 return ReplyKeyboardMarkup('/on'], '/moff'], '/off']], resize_keyboard=True)

def pc_on(update: Update, context: CallbackContext):
 """PC 켜기] wakeonlan 패키지를 사용하여 매직 패킷을 전송합니다."""
 # -i: 타겟 주소, -p: 포트 번호 (보통 7777 또는 9번 사용)
 os.system(f"wakeonlan -i {TARGET_IP} -p 7777 {MAC_ADDR}")
 update.message.reply_text('PC ON 신호(WOL)를 전송했습니다.', reply_markup=get_keyboard())

def monitor_off(update: Update, context: CallbackContext):
 """모니터 끄기] 99번 포트로 'MONITOR_OFF'라는 문자열 신호를 보냅니다."""
 try:
 # UDP 통신을 사용하여 데이터 전송
 with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
 s.sendto(b"MONITOR_OFF", (TARGET_IP, 99))
 
 logging.info(f"SENT: MONITOR_OFF to {TARGET_IP}:99")
 update.message.reply_text('모니터 끄기 신호(99번 포트)를 보냈습니다.', reply_markup=get_keyboard())
 except Exception as e:
 logging.error(f"FAIL: {e}")
 update.message.reply_text(f'모니터 제어 에러: {e}')

def pc_off(update: Update, context: CallbackContext):
 """PC 종료] 9번 포트로 'SHUTDOWN' 신호를 보내 PC를 종료시킵니다."""
 try:
 # 9번 포트는 공유기 WOL 기능과 겹칠 수 있으므로 별도 데이터로 전송
 with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
 s.sendto(b"SHUTDOWN", (TARGET_IP, 9))
 
 logging.info(f"SENT: SHUTDOWN to {TARGET_IP}:9")
 update.message.reply_text('PC 종료 신호(9번 포트)를 보냈습니다.', reply_markup=get_keyboard())
 except Exception as e:
 logging.error(f"FAIL: {e}")
 update.message.reply_text(f'종료 제어 에러: {e}')

def main():
 """봇을 실행하고 사용자의 명령을 대기합니다."""
 # 봇 토큰을 사용하여 업데이터 생성
 updater = Updater(API_TOKEN)
 dp = updater.dispatcher

 # 각 명령어(/on, /moff, /off)가 들어왔을 때 실행할 함수 연결
 dp.add_handler(CommandHandler("on", pc_on))
 dp.add_handler(CommandHandler("moff", monitor_off))
 dp.add_handler(CommandHandler("off", pc_off))

 print(f"--- 원격 제어 봇 가동 중 (Target: {TARGET_IP}) ---")
 
 # 봇 실행 시작 (기존에 쌓여있던 메시지는 무시)
 updater.start_polling(drop_pending_updates=True)
 updater.idle()

if __name__ == '__main__':
 main()

(저장: Ctrl+O – Enter – Ctrl+X)

1-3. 봇 실행 및 로그 확인

기존 프로세스를 죽이고 새 코드를 백그라운드에서 실행합니다.

# 기존 봇 프로세스 종료
pkill -f wol_bot.py

# 새 봇 실행 (로그 파일 생성)
nohup python3 wol_bot.py > wol.log 2>&1 &

서버가 재부팅되거나 예상치 못한 오류로 프로세스가 죽으면 다시 켜줘야 하는 번거로움이 있습니다. 우분투의 systemd(서비스) 기능을 사용하면 서버가 켜질 때 자동으로 실행되고, 죽어도 알아서 다시 살아나게 만들 수 있습니다.

1-4. 서비스 파일 만들기

우분투 시스템 서비스로 등록하는 과정입니다. 아래 명령어를 터미널에 복사해서 입력하세요. 이 코드는 작성하신 wol_bot.py 파일을 우분투 서버가 켜질 때마다 자동으로 실행하게 해주고, 혹시라도 봇이 죽으면 다시 살려주는 “자동 관리 명세서”입니다.

리눅스에서는 이런 설정을 systemd 서비스(Service)라고 부릅니다. 이 코드가 있어야 우리가 일일이 터미널에서 실행하지 않아도 봇이 24시간 내내 텔레그램 신호를 기다릴 수 있습니다

sudo nano /etc/systemd/system/wol_bot.service

열린 창에 아래 내용을 그대로 붙여넣으세요. (ubuntu 계정 기준입니다.)

Unit]
Description=Telegram WOL Bot Service
After=network.target

Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu
ExecStart=/usr/bin/python3 /home/ubuntu/wol_bot.py
Restart=always
RestartSec=5

Install]
WantedBy=multi-user.target

(저장: Ctrl+O – Enter – Ctrl+X)

1-5. 서비스 활성화 및 실행

이제 만든 서비스를 시스템에 등록하고 바로 가동합니다.

# 1. 기존에 nohup으로 돌던 봇은 확실히 죽입니다.
pkill -f wol_bot.py

# 2. 시스템 설정 새로고침
sudo systemctl daemon-reload

# 3. 부팅 시 자동 실행 설정
sudo systemctl enable wol_bot.service

# 4. 지금 바로 실행
sudo systemctl start wol_bot.service

1-6. 상태 확인하기

서비스가 에러 없이 잘 돌아가고 있는지 확인해 보세요.

sudo systemctl status wol_bot.service

화면에 active (running)이라는 초록색 글자가 보이면 완벽합니다! 이제 오라클 서버를 껐다 켜도 봇은 항상 텔레그램 뒤에서 대기하게 됩니다.

1-7. 관리 팁 (나중에 수정할 때)

나중에 코드를 수정(IP 변경 등)했다면 아래 명령어만 기억하세요.

  • sudo systemctl restart wol_bot.service (봇 재시작)
  • sudo systemctl stop wol_bot.service (봇 정지)

이제 핸드폰으로 언제 어디서든 /on만 치면 집 컴퓨터가 반갑게 깨어날 겁니다.

2. 원격 제어 수신단: 윈도우 PC 설정 방법

우분투 서버(발신용)에서 보낸 신호를 윈도우 PC가 받아서 실제로 모니터를 끄거나 전원을 관리하게 만드는 과정입니다.

2-1. 필수 도구 준비

먼저 두 가지 도구가 필요합니다.

  • Python: 스크립트를 실행하기 위해 필요합니다. (python.org에서 설치)
  • NirCmd: 마우스나 모니터 전원 등을 명령어로 제어하게 해주는 가벼운 도구입니다.
    • NirSoft 공식 홈페이지 하단에서 다운로드 후, 압축을 풀어 nircmd.exe 파일을 예: C:\scripts\ 폴더에 넣어주세요.
랜으로 내컴퓨터 전원관리하기

2-2. 수신 스크립트 작성 (kill.py)

메모장을 열고 아래 코드를 복사해서 C:\scripts\kill.py로 저장하세요. 이 코드는 99번 포트(모니터)와 9번 포트(전원)를 동시에 감시합니다.

import socket
import os
import sys
import threading

# 1. 신호를 기다리는 함수
def start_listen(port, mode):
 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 try:
 sock.bind(('0.0.0.0', port))
 except Exception as e:
 print(f"포트 {port} 바인딩 실패: {e}")
 return

 print(f"--- {mode} 대기] {port}번 포트 감시 중 ---")

 while True:
 data, addr = sock.recvfrom(1024)
 msg = data.decode('utf-8', errors='ignore').strip().upper()
 print(f"\n!] {port}번 포트 신호 수신 (발신지: {addr0]})")
 
 # 99번 포트로 MONITOR가 포함된 신호가 오면 모니터 끄기
 if port == 99 and "MONITOR" in msg:
 print("명령 확인: 모니터 끄기 실행")
 os.system("C:\\scripts\\nircmd.exe monitor off")
 
 # 9번 포트로 신호가 오면 시스템 종료
 elif port == 9:
 print("명령 확인: 5초 후 시스템 종료")
 os.system("shutdown /s /t 5")
 sys.exit()

if __name__ == "__main__":
 # 두 개의 포트를 각각 별도의 스레드로 동시에 감시합니다.
 t1 = threading.Thread(target=start_listen, args=(9, "PC 종료"))
 t2 = threading.Thread(target=start_listen, args=(99, "모니터 끄기"))
 
 t1.start()
 t2.start()

2-3. 윈도우 방화벽 문 열기

외부(우분투 서버)에서 들어오는 접속이 방화벽에 차단되지 않도록 9번과 99번(임의 설정) 포트를 허용해야 합니다.해당 포트들은 공유기 설정에서 포트포워딩을 완료해 주세요. 자세한 설정 방법은 이 링크를 참고하시기 바랍니다.

  1. 시작 메뉴에서 PowerShell을 검색해 관리자 권한으로 실행합니다.
  2. 아래 명령어를 복사해서 붙여넣으세요.
# 99번(모니터) 및 9번(종료) UDP 포트 허용 규칙 추가
netsh advfirewall firewall add rule name="Remote_Control_99" dir=in action=allow protocol=UDP localport=99
netsh advfirewall firewall add rule name="Remote_Control_9" dir=in action=allow protocol=UDP localport=9

2-4. PC 켤 때마다 자동 실행하기 (작업 스케줄러)

매번 직접 실행하기 귀찮으므로, 윈도우가 켜질 때 자동으로 실행되게 설정합니다.

  1. Win + R 키를 누르고 taskschd.msc를 입력해 작업 스케줄러를 엽니다.
  2. 오른쪽 [기본 작업 만들기…] 클릭.
  3. 이름: RemoteControlBot -> 다음.
  4. 트리거: [컴퓨터 시작 시] 선택 -> 다음.
  5. 작업: [프로그램 시작] 선택 -> 다음.
  6. 프로그램/스크립트: pythonw.exe (검은 창 없이 실행하려면 pythonw를 사용하세요).
  7. 인수 추가: C:\scripts\kill.py.
  8. 마침을 누른 후, 생성된 작업의 [속성]에서 [가장 높은 수준의 권한으로 실행]에 체크하세요. (nircmd 제어를 위해 필요합니다)

2-5. 최종 체크리스트

  • 공유기: 외부 99번 포트가 내 PC(192.168.219.100)의 내부 99번으로 포워딩 되어 있나요?
  • 클라우드플레어: 내 도메인이 회색 구름(DNS 전용) 상태인가요?
  • 실행:kill.py를 실행했을 때 “99번 포트 감시 중”이라는 문구가 뜨나요?

댓글 남기기