# DisHost 전체 문서 > Discord 봇 무료 호스팅 플랫폼의 전체 문서 통합본입니다. > 이 파일은 빌드 시 content/docs/ 의 MDX 파일들로부터 자동 생성됩니다. > 원본 문서: https://dishost.kr/docs --- ## 시작하기 ### 디스호스트 시작하기 > 디스호스트를 통해 평생 무료로 나만의 초고속 디스코드 봇을 배포하고 24시간 가동하는 방법을 알아봅니다. 디스호스트는 개발자와 커뮤니티 리더를 위한 평생 100% 무료 디스코드 봇 호스팅 플랫폼입니다. 복잡한 리눅스 서버 터미널 설정이나 요금 결제 없이, 웹 대시보드에서 단 몇 번의 클릭만으로 봇을 생성하고 24시간 안정적으로 구동할 수 있습니다. --- ## 플랫폼 아키텍처 디스호스트는 고성능 클라우드 인프라와 컨테이너 가상화 기술을 기반으로 운영됩니다. 1. **컨테이너 격리**: 각 디스코드 봇은 완벽히 독립된 샌드박스 환경(Docker Container) 내에서 실행되므로, 다른 사용자의 프로그램이나 외부 위협으로부터 보안이 철저히 보호됩니다. 2. **고성능 하드웨어**: 초고속 PCIe NVMe SSD 스토리지와 고성능 멀티코어 CPU 프로세서를 탑재하여 지연 시간(Latency) 없는 봇 이벤트 수신과 명령어 처리를 보장합니다. 3. **Pterodactyl 기반 컨트롤**: 검증된 게임/응용프로그램 호스팅 패널 시스템을 커스텀 빌드하여 직관적이고 안정적인 터미널 환경을 제공합니다. 4. **글로벌 네트워크 백본**: 고가용성 네트워크 및 저지연 CDN 프록시 라우팅을 채택하여 디스코드 API 게이트웨이와의 웹소켓 연결이 예기치 않게 단절되거나 지연되지 않도록 보장합니다. --- ## 리소스 사양 가이드 (기본 슬롯) 모든 가입자에게 기본 제공되는 봇 슬롯의 사양은 아래와 같습니다: | 리소스 항목 | 기본 할당량 | 설명 | | :--- | :--- | :--- | | **CPU** | 25% | Node.js/Python 봇 처리에 충분한 연산 능력 | | **RAM** | 128 MB | 핑퐁 봇 및 소규모 기능성 봇 구동에 최적화된 용량 | | **용량 (Disk)** | 512 MB | 로컬 캐시, 이미지 데이터, 로그 및 패키지 파일 보관을 위한 디스크 공간 | | **백업 슬롯** | 1개 | 수동 또는 스케줄링을 통한 시스템 스냅샷 1회 백업 보관 가능 | > [!TIP] > **더 많은 리소스가 필요하신가요?** > 대시보드 내 포인트 상점에서 커뮤니티 포인트로 추가 메모리 업그레이드권이나 추가 슬롯 연장권을 즉시 교환하여 확장할 수 있습니다. --- ## 공정 사용 정책 (Fair Use Policy) 디스호스트는 모든 개발자에게 쾌적한 호스팅 환경을 제공하기 위해 공정 사용 정책을 엄격히 시행하고 있습니다. * **금지 사항**: * 암호화폐 채굴기(Cryptocurrency Miners) 구동 * 디스코드 TOS를 위반하는 셀프봇(Self-bots) 또는 스패밍 목적의 봇 구동 * 대역폭을 과도하게 점유하는 무차별적 웹 스크래핑 및 디도스(DDoS) 공격 툴 * 대규모 파일 공유 및 토렌트 다운로더 등의 보관소 활용 * **제재 안내**: 본 정책을 위반하는 정황이 감지될 시 시스템 보안 엔진에 의해 컨테이너가 즉시 차단되며, 누적 적발 시 슬롯 회수 및 계정이 영구 정지될 수 있습니다. --- ## 문서 안내서 원하는 내용을 쉽고 빠르게 탐색할 수 있도록 분류된 카테고리를 활용해 보세요. * [**언어별 퀵스타트**](quickstarts/nodejs): Node.js(discord.js) 또는 Python(discord.py)을 이용한 최초 핑퐁 봇 배포 가이드. * [**대시보드 상세 기능**](features/console): 실시간 콘솔, 파일 매니저, 예약 재부팅(스케줄) 및 백업 활용법. * [**데이터베이스 연동**](database/sqlite-persistence): 로컬 SQLite 파일 보존 방법 및 Supabase, MongoDB Atlas 등 외부 클라우드 DB 연결. * [**디스코드 설정**](discord/gateway-intents): 특수 인텐트(Intents) 활성화 및 안전한 초대 링크 디자인 가이드. * [**트러블슈팅 및 FAQ**](troubleshooting/oom-crash): OOM(메모리 부족) 코드 137 오류 자가진단 및 자주 묻는 질문 해결. --- ## AI/LLM을 위한 문서 Cursor, Claude, ChatGPT 같은 AI 도구에서 DisHost 문서를 참고할 수 있도록 **llms.txt**를 제공합니다: | 파일 | 용도 | 링크 | | :--- | :--- | :--- | | **llms.txt** | 간결한 개요 + 각 문서 페이지 링크 | [/llms.txt](/llms.txt) | | **llms-full.txt** | 전체 문서 30개 이상을 하나로 통합한 100KB+ 풀버전 | [/llms-full.txt](/llms-full.txt) | - **llms.txt**: AI가 DisHost 서비스를 빠르게 파악하고 원하는 문서 페이지 링크를 찾을 수 있도록 구성된 인덱스 파일입니다. - **llms-full.txt**: DisHost의 모든 문서(CLI, API, GitHub 연동, 기능 가이드, 트러블슈팅 FAQ 등)를 하나의 파일에 담았습니다. AI 도구에 통째로 컨텍스트로 넣어 질문하면 더 정확한 답변을 받을 수 있습니다. > [!NOTE] > 이 파일들은 [llms.txt 표준](https://llmstxt.org/)에 따라 빌드 시 자동 생성됩니다. AI 코딩 도구에서 DisHost 관련 질문을 할 때 이 파일을 컨텍스트로 추가해 보세요. --- ## 봇 생성 ### 봇 생성 및 배포하기 > 디스코드 개발자 센터에서 봇 애플리케이션 등록, 토큰 발급, 그리고 디스호스트에서 컨테이너를 가동하기까지의 전체 과정을 상세히 다룹니다. 디스호스트에서 나만의 봇을 배포하기 위해서는 먼저 디스코드 공식 개발자 포털(Developer Portal)에서 봇 애플리케이션을 생성하고, 서버 접속 인증 정보인 **봇 토큰(Token)**을 발급받아야 합니다. --- ## 1단계: 디스코드 개발자 포털에서 봇 등록 1. **포털 접속**: 디스코드 개발자 포털(Discord Developer Portal)에 접속하여 디스코드 계정으로 로그인합니다. 2. **애플리케이션 생성**: 우측 상단의 New Application 버튼을 클릭합니다. - 팝업창이 뜨면 봇의 서비스명을 기입하고, 디스코드 개발자 약관 동의 체크박스에 체크한 뒤 Create를 누릅니다. 3. **Bot 설정 활성화**: 왼쪽 메뉴 목록에서 Bot 탭으로 이동합니다. 4. **토큰 발급 (Reset Token)**: - Reset Token 버튼을 누른 후 보안 문자 인증을 완료합니다. - 화면에 표시되는 알파벳과 기호의 긴 조합 문자열이 바로 봇 토큰입니다. - 복사하여 메모장 등 안전한 로컬 저장소에 기입해 둡니다. > [!CAUTION] > **토큰은 봇의 비밀번호입니다!** > 토큰이 외부(GitHub 공개 리포지토리 등)에 단 1초라도 유출되면 해커가 봇 계정을 탈취하여 불법 웹훅 발송이나 스팸 메시지 유포에 악용할 수 있습니다. 노출 즉시 포털에서 Reset Token을 수행하여 재생성해야 합니다. 5. **인텐트(Intents) 필수 설정**: - 동일한 Bot 페이지에서 스크롤을 아래로 내리면 Privileged Gateway Intents 섹션이 있습니다. - 봇이 메시지를 수신하거나 멤버들의 접속 상태 변화를 감지하기 위해서는 해당하는 토글 스위치(특히 Message Content Intent)를 활성화해야 합니다. - 변경 사항을 적용한 뒤 하단의 Save Changes 버튼을 눌러 저장합니다. --- ## 2단계: 디스호스트 대시보드 연동 1. **대시보드 접속**: 디스호스트 공식 대시보드 콘솔(/dashboard)로 이동합니다. 2. **봇 생성 위저드**: 우측 상단에 위치한 봇 생성 버튼을 클릭합니다. 3. **프로젝트 설정 기입**: - **프로젝트 이름**: 본인이 관리하기 편한 영문/한글 이름을 적습니다. (예: 나의-안내봇) - **디스코드 봇 토큰**: 위 1단계에서 발급받아 복사한 토큰 문자열을 그대로 붙여넣습니다. - **런타임 엔진 (플랫폼)**: - NodeJS: JavaScript 또는 TypeScript로 개발할 때 선택합니다. - Python: Python(discord.py, nextcord)으로 개발할 때 선택합니다. 4. **연동 완료**: 생성하기를 클릭하면 컨테이너 격리 볼륨이 자동 생성되며 가상 서버가 즉시 셋업됩니다. --- ## 3단계: 소스코드 구성 및 파일 매니징 1. **봇 관리 패널 진입**: 대시보드 리스트에서 방금 만든 봇 카드를 클릭합니다. 2. **필수 파일 업로드**: - 파일 매니저 탭으로 이동합니다. - **Node.js 개발 시**: 프로젝트의 핵심 소스 파일(index.js)과 설치할 패키지 정보가 명시된 package.json 파일을 드래그 앤 드롭으로 업로드합니다. - **Python 개발 시**: 진입점 소스 파일(main.py 또는 bot.py)과 requirements.txt 파일을 드래그 앤 드롭으로 업로드합니다. 3. **런타임 진입점 체크**: - 스타트업 설정 탭에서 실행될 진입 파일 이름이 본인이 올린 파일 이름(예: index.js)과 일치하는지 확인합니다. --- ## 4단계: 무중단 구동 개시 1. **가동 시작**: 화면 최상단의 제어 도구바에서 시작 (Start) 버튼을 누릅니다. 2. **실시간 로그 모니터링**: - 중앙의 실시간 콘솔 창에 부팅 프로세스 로그가 흘러가는지 봅니다. - 시스템이 종속 패키지(node_modules 또는 python 라이브러리)를 감지하고 누락된 패키지가 있다면 자동으로 백업 서버에서 fetch해와 설치를 시작합니다. 3. **구동 완료**: 로그 콘솔에 Client is ready! 또는 본인이 코드에 작성한 로그인 준비 메시지가 출력되면 성공입니다. 서버 목록에서 봇이 온라인으로 나타나는 것을 확인할 수 있습니다. --- ## 언어별 퀵스타트 ### Node.js 봇 시작하기 > discord.js v14 라이브러리를 활용해 1분 만에 핑퐁 봇을 구축하고 디스호스트 컨테이너에 완벽 배포하는 전체 코스입니다. 본 가이드는 Node.js 런타임 환경에서 가장 널리 사용되는 `discord.js` v14 버전을 이용해 기본적인 봇 스크립트를 빌드하고 실행하는 프로토콜을 설명합니다. --- ## 1단계: 로컬 개발 환경 정의 1. **프로젝트 폴더 생성**: 로컬 컴퓨터에 새로운 디렉토리를 생성하고 터미널로 진입합니다. ```bash mkdir my-discord-bot cd my-discord-bot ``` 2. **패키지 명세 초기화**: npm 도구를 사용해 패키지 설정 파일을 초기화합니다. ```bash npm init -y ``` 3. **discord.js 및 dotenv 설치**: 디스코드 API 연동 라이브러리와 로컬 환경 변수 관리 라이브러리를 추가합니다. ```bash npm install discord.js dotenv ``` --- ## 2단계: 핑퐁(Ping-Pong) 핵심 코드 작성 프로젝트 폴더 루트에 `index.js` 파일을 새로 생성하고 아래의 예제 코드를 붙여넣습니다: ```javascript // index.js require('dotenv').config(); const { Client, GatewayIntentBits } = require('discord.js'); // 봇이 수신하고자 하는 게이트웨이 이벤트 권한을 선언합니다. const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent ] }); // 봇이 디스코드 API 서버와 통신 준비를 마쳤을 때 실행됩니다. client.once('ready', () => { console.log(`Log: 로그인 완료! - 계정명: ${client.user.tag}`); }); // 사용자가 텍스트 메시지를 보냈을 때 작동하는 리스너입니다. client.on('messageCreate', async (message) => { // 봇이 보낸 메시지나 시스템 알림은 무시합니다. if (message.author.bot) return; // '!ping' 명령어가 도달하면 'pong'으로 답신합니다. if (message.content === '!ping') { await message.reply('pong! 🏓'); } }); // 디스코드 토큰 환경변수를 파싱해 게이트웨이에 로그인을 시도합니다. client.login(process.env.DISCORD_TOKEN); ``` --- ## 3단계: 디스호스트에 배포 및 실행 1. **프로젝트 압축**: - `index.js`와 `package.json`, 그리고 `package-lock.json` 파일만 묶어 하나의 `.zip` 파일로 만듭니다. 2. **대시보드 업로드**: - 디스호스트 파일 매니저 탭으로 진입합니다. - 드래그 앤 드롭으로 `.zip` 압축파일을 올립니다. - 파일 우클릭 후 **압축 풀기 (Unarchive)**를 실행합니다. 3. **진입점 및 종속성 검증**: - 스타트업 설정의 시작 명령(STARTUP_FILE) 필드에 `index.js`가 입력되어 있는지 확인합니다. 4. **구동**: - 콘솔 탭으로 이동하여 시작 (Start) 버튼을 클릭합니다. - 패키지 자동 설치가 끝나고 `Log: 로그인 완료!` 로그가 화면에 노출되면 성공입니다. ### Python 봇 시작하기 > discord.py v2 라이브러리를 활용해 1분 만에 핑퐁 봇을 빌드하고 디스호스트 환경에서 오류 없이 올바르게 구동하는 코스입니다. 본 가이드는 Python 런타임 환경에서 가장 대표적인 `discord.py` v2 버전을 이용해 기본적인 봇 스크립트를 작성하고 호스팅 인프라에 배포하는 방법을 소개합니다. --- ## 1단계: 로컬 개발 환경 정의 1. **프로젝트 디렉토리 생성**: 로컬 터미널을 열고 새 폴더를 지정해 진입합니다. ```bash mkdir my-python-bot cd my-python-bot ``` 2. **가상환경 구성 및 패키지 설치**: 로컬 실행 충돌 방지를 위해 가상환경을 만들고 `discord.py` 라이브러리를 다운로드합니다. ```bash python3 -m venv venv source venv/bin/activate pip install discord.py python-dotenv ``` 3. **의존성 명세 생성**: 디스호스트 컨테이너가 라이브러리 목록을 감지하도록 텍스트 문서를 출력해 둡니다. ```bash pip freeze > requirements.txt ``` --- ## 2단계: 핑퐁(Ping-Pong) 핵심 코드 작성 프로젝트 루트 폴더에 `bot.py` 파일을 생성하고 다음 예제 소스코드를 작성합니다: ```python # bot.py import os import discord from discord.ext import commands from dotenv import load_dotenv # 로컬 개발 시 .env 파일을 파싱합니다. (디스호스트에서는 대시보드 환경변수 우선 적용) load_dotenv() # 메시지 읽기 권한을 포함한 기본 인텐트를 지정합니다. intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix='!', intents=intents) @bot.event async def on_ready(): print(f'Log: 로그인 완료! - 계정명: {bot.user.name}') @bot.command(name='ping') async def ping(ctx): await ctx.reply('pong! 🏓') # DISCORD_TOKEN 환경변수로부터 키 값을 획득해 게이트웨이에 접속합니다. token = os.getenv("DISCORD_TOKEN") if token: bot.run(token) else: print("Error: DISCORD_TOKEN 환경변수가 감지되지 않았습니다.") ``` --- ## 3단계: 디스호스트에 배포 및 실행 1. **프로젝트 압축**: - 로컬 가상환경 폴더인 `venv`는 업로드 시 속도가 매우 저하되며 호스팅 컨테이너의 아키텍처와 충돌하므로 **절대 포함해서 압축하지 마십시오.** - `bot.py`와 `requirements.txt` 파일만 선택해 하나의 `.zip` 압축 파일로 패키징합니다. 2. **대시보드 업로드 및 세팅**: - 디스호스트 파일 매니저 탭으로 진입하여 압축 파일을 올리고 **압축 풀기 (Unarchive)**를 수행합니다. - **스타트업 설정** 탭으로 반드시 이동하여 `STARTUP_FILE` 항목에 메인 파이썬 진입 파일명인 `bot.py`를 정확히 기입하여 저장합니다. - `PY_PACKAGES` 필드에 필요한 외부 라이브러리 목록인 `discord.py python-dotenv`를 스페이스 간격으로 기입해 줍니다. 3. **가동**: - 콘솔 탭으로 이동해 시작 (Start) 버튼을 클릭합니다. - 시스템이 종속 라이브러리를 감지하고 가상 환경 가동 준비를 마친 뒤 `Log: 로그인 완료!` 메시지가 콘솔에 기록되면 모든 배포가 완료된 것입니다. --- ## CLI ### CLI 설치 > 터미널에서 DisHost를 사용하는 방법을 처음부터 알려드립니다 `dishost`는 터미널 하나로 봇을 배포하고 관리하는 CLI 도구입니다. ## 따라 하기 ### 1. 설치하기 터미널을 열고 아래 명령어를 입력하세요: ```bash npm install -g dishost ``` > `npm`이 설치되어 있어야 합니다. 없다면 [Node.js](https://nodejs.org)를 먼저 설치하세요. ### 2. 로그인하기 ```bash dishost login ``` 명령어를 실행하면 아래와 같은 안내가 나옵니다: ``` ┌──────────────────────────────────────────┐ │ 1. Open: https://dishost.kr/dashboard/settings │ 2. Create a new API key │ 3. Paste it below └──────────────────────────────────────────┘ ``` > **API Key가 뭔가요?** > CLI가 DisHost 서버와 통신할 때 쓰는 비밀번호 같은 겁니다. 대시보드에서 만들 수 있어요. 이제 대시보드로 이동해서: - **왼쪽 사이드바** → **"설정"** 클릭 - 아래로 스크롤 → **"API Keys"** 섹션 - 이름에 `CLI` 입력 → **"Create"** 버튼 - 생성된 긴 문자열을 **복사** - 터미널에 **붙여넣기**하고 Enter ``` ✓ Logged in! ``` 끝! 이제 모든 명령어를 사용할 수 있습니다. ### 3. 프로젝트 배포해보기 봇 코드가 있는 폴더로 이동해서: ```bash cd my-discord-bot dishost deploy ``` CLI가 자동으로 다음을 확인합니다: - 어떤 언어인지 (`package.json` → JavaScript, `requirements.txt` → Python) - Git 저장소 주소 - 필요한 환경변수 (`.env.example` 파일) - 봇 이름 확인 질문에 답하면 배포가 시작됩니다. ### 4. 수정한 파일 업로드하기 (Local File Push) Git push 단계를 거치지 않고 로컬의 소스 변경 사항을 즉시 서버에 실시간으로 업로드 및 배포하고 싶다면 `push` 명령을 사용합니다: ```bash # 로컬 코드를 서버에 즉시 덮어쓰기 배포 dishost push # 안 쓰는 구 버전 파일들을 서버에서 지우고 안전하게 배포 dishost push --clean ``` ### 로그아웃 ```bash dishost logout ``` ### 업데이트 ```bash npm install -g dishost@latest ``` ### CLI 명령어 Reference > DisHost CLI의 모든 명령어 사용법과 실제 활용 시나리오를 가이드합니다. DisHost CLI를 사용하면 터미널 하나로 봇의 생성부터 실시간 로그 추적, 소스 코드 동기화까지 신속하게 처리할 수 있습니다. --- ## 실제 시나리오별 활용 가이드 (Real-world Workflows) ### 1. Git 저장소를 연동하여 새로운 봇 만들기 (deploy) GitHub 저장소에 있는 소스 코드를 가져와 DisHost 서버에 새로운 봇 인스턴스를 구축하고 연동합니다. ```bash # 1. 봇 코드가 포함된 로컬 폴더로 이동 cd my-discord-bot # 2. 배포 명령 실행 dishost deploy ``` * **동작 흐름**: CLI가 현재 폴더의 언어(JavaScript/Python)와 Git 원격지 주소를 자동 진단합니다. 이후 봇의 이름과 `.env.example`에 기재된 환경 변수를 프롬프트로 입력받아 서버에 생성합니다. **생성이 완료되면 현재 폴더가 새 봇의 ID와 자동으로 링크됩니다.** --- ### 2. 로컬 코드 실시간 덮어쓰기 배포 (push) Git 커밋 및 Push를 거치지 않고, 로컬의 소스 변경 사항을 즉시 원격 서버에 반영(핫 디플로이)합니다. ```bash # 1. 변경된 로컬 파일들이 올바른지 확인 후 실행 dishost push ``` * **동작 흐름**: `node_modules`, `.git`, `.env` 등 불필요한 대용량 파일/설정은 생략하고 압축하여 서버에 업로드한 후, 프터로닥틸 컨테이너 내부에서 압축을 풀어 기존 코드를 덮어씌웁니다. --- ### 3. 미사용 파일 삭제 및 안전한 클린 배포 (push --clean) 로컬에서 필요 없어진 레거시 파일들을 삭제했을 때, 원격 서버에서도 깔끔하게 소스 폴더를 비우고 다시 맞춤 배포합니다. ```bash # 1. 원격을 깨끗이 정리하고 배포 dishost push --clean # 또는 dishost push -c ``` * **보호 규칙**: `.env`(환경 설정)와 `node_modules`(패키지 폴더)는 **안전하게 보존**된 상태에서 소스 코드만 청소한 후 동기화됩니다. 데이터 손실이나 패키지 전체 재설치 대기 시간 없이 안전하게 배포할 수 있습니다. --- ## 명령어 명세 ### `dishost login` DisHost 계정에 로그인하여 터미널 세션 인증을 완료합니다. ```bash dishost login ``` ### `dishost logout` 로컬 세션 및 저장된 API 키를 안전하게 초기화합니다. ```bash dishost logout ``` ### `dishost list` 계정에 연결된 모든 봇 목록과 실시간 구동 상태 및 메모리 사용량(`현재 점유 / 한도`)을 확인합니다. ```bash dishost list ``` * **출력 예시**: ``` ┌──────────┬────────────────────────┬─────────────┬──────┬───────────────┬────────┬──────┐ │ ID │ Name │ Status │ Lang │ Mem │ Renew │ Auto │ ├──────────┼────────────────────────┼─────────────┼──────┼───────────────┼────────┼──────┤ │ cmrag6pg…│ ticket-bot │ ● running │ js │ 18MB / 128MB │ 3d │ - │ └──────────┴────────────────────────┴─────────────┴──────┴───────────────┴────────┴──────┘ ``` * **상태 아이콘**: * `● running` (초록색): 봇이 실행 중이거나 부팅 중(Starting)인 상태 * `⟳ stopping` (노란색): 봇이 중지 과정을 거치고 있는 상태 * `○ stopped` (노란색): 정상 중지(오프라인) 상태 * `○ expired` (빨간색): 연장 기간이 만료되어 정지된 상태 ### `dishost status <봇이름>` 컨테이너의 CPU, 메모리, 디스크의 정확한 실시간 자원 상태 수치를 출력합니다. ```bash dishost status my-bot ``` ### `dishost logs <봇이름> [--follow]` 서버 콘솔의 표준 출력(logs) 데이터를 읽어옵니다. `-f` 또는 `--follow` 옵션을 통해 WebSocket에 직접 연결하여 실시간 감시 대기(Tail)를 할 수 있습니다. ```bash # 단발성 최근 콘솔 로그 확인 dishost logs my-bot # 실시간 감시 (종료: Ctrl + C) dishost logs my-bot --follow ``` ### `dishost env list <봇이름>` 서버에 설정된 가동용 환경변수 리스트를 나열합니다. 보안 상 노출되면 안 되는 민감 정보는 자동 블라인드(`****`) 처리됩니다. ```bash dishost env list my-bot ``` ### `dishost pull [봇이름]` 원격 웹 패널이나 서버에 주입된 최종 환경변수 설정을 로컬 작업 디렉토리의 `.env` 파일로 덮어씌워 갱신(동기화)합니다. ```bash dishost pull my-bot ``` ### `dishost link [봇이름]` 현재 터미널 작업 디렉토리를 DisHost 상의 특정 봇 ID와 매핑시킵니다. 연결을 완료하면 명령어 실행 시 이름을 기입하지 않고 즉시 배포할 수 있습니다. ```bash dishost link my-bot ``` ### `dishost start <봇이름>` / `stop` / `restart` 봇 서버 인스턴스의 구동 전원을 터미널에서 즉시 제어합니다. ```bash dishost start my-bot dishost stop my-bot dishost restart my-bot ``` ### `dishost delete <봇이름>` 컨테이너 가동을 멈추고 서버 및 DB의 호스팅 등록을 제거하여 봇 슬롯을 반환합니다. ```bash dishost delete my-bot ``` ### `dishost doctor` 현재 작업 리포지토리의 패키지 구성 상태, 가동 스크립트 존재성, Git 원격 연결 현황 등을 진단하여 정상 배포 가능 상태인지 체크리스트로 보여줍니다. ```bash dishost doctor ``` ### `dishost init` 대화형 질의를 거쳐 디렉토리 내에 맞춤 배포 규칙 설정용 `dishost.yml`을 신속하게 생성해 줍니다. ```bash dishost init ``` ### dishost.yml > 배포 설정 파일 레퍼런스 프로젝트 루트에 `dishost.yml` 파일을 두면 CLI가 설정을 읽어 배포합니다. ## 기본 구조 ```yaml name: my-discord-bot # 봇 이름 (필수) language: javascript # javascript | python (필수, 런타임 자동 추론) startup: npm start # 시작 명령어 (기본값: npm start / python main.py) env: # 환경변수 DISCORD_TOKEN: "" CLIENT_ID: "" git: # Git 설정 autoDeploy: true # Push 시 자동 재배포 branch: main # 배포 브랜치 ``` ## 전체 옵션 | 필드 | 타입 | 기본값 | 설명 | |------|------|--------|------| | `name` | string | — | 봇 이름 (필수) | | `language` | `javascript` \| `python` | — | 프로젝트 언어 (필수, 런타임 자동 추론) | | `startup` | string | 언어별 자동 | 시작 명령어 | | `build` | string | — | 빌드 명령어 (예: `npm run build`) | | `workdir` | string | — | 모노레포 서브디렉토리 | | `memory` | number | `128` | 메모리 (MB) | | `cpu` | number | `25` | CPU (%) | | `disk` | number | `512` | 디스크 (MB) | | `env` | object | `{}` | 환경변수 | | `git.autoDeploy` | boolean | `false` | Push 시 자동 재배포 | | `git.branch` | string | `main` | 배포 브랜치 | ## 예제 ```yaml # Node.js + npm name: ticket-bot language: javascript startup: npm start build: npm run build env: DISCORD_TOKEN: "" CLIENT_ID: "" GUILD_ID: "" git: autoDeploy: true branch: main ``` ```yaml # Python + pip name: music-bot language: python env: DISCORD_TOKEN: "" git: autoDeploy: true ``` ```yaml # Monorepo (subdirectory) name: api-server language: javascript workdir: packages/api startup: node index.js env: PORT: "3000" DATABASE_URL: "" ``` --- ## GitHub 연동 ### GitHub 연결 > GitHub 계정을 DisHost에 연결하는 방법을 단계별로 설명합니다 GitHub를 연결하면 두 가지 기능을 사용할 수 있습니다: 1. **레포지토리 목록에서 선택 배포** — URL을 복사할 필요 없이 내 레포 목록에서 클릭 한 번 2. **Push 자동 배포** — 코드 Push만 하면 DisHost가 알아서 재시작 ## 사전 준비 - DisHost 계정 (Discord 로그인) - GitHub 계정 - 배포할 코드가 있는 GitHub 레포지토리 --- ## Step 1 — GitHub 계정 연결 **왜 필요한가요?** DisHost가 내 GitHub 프로필을 확인하고, 개발자 인증 배지를 표시합니다. 1. [대시보드](https://dishost.kr/dashboard) → 왼쪽 사이드바 → **"설정"** 2. 상단 **"Connect GitHub"** 버튼 클릭 3. GitHub 팝업 창이 열리면 → **"Authorize"** 클릭 4. 자동으로 창이 닫히고, 설정 페이지에 내 GitHub 계정이 표시됩니다 연결 성공하면: ``` @내아이디 ✓ Verified ``` > **연결 해제**: 언제든지 "연결 해제" 버튼으로 GitHub 연결을 끊을 수 있습니다. --- ## Step 2 — GitHub App 설치 **왜 필요한가요?** DisHost가 내 레포지토리를 읽고, Push 이벤트를 감지할 수 있게 합니다. 1. 같은 설정 페이지 아래쪽 → **"Install GitHub App"** 버튼 클릭 2. GitHub 페이지가 열리면 **접근을 허용할 레포지토리 선택** - 전체 레포: **"All repositories"** - 특정 레포만: **"Only select repositories"** → 내 봇 레포만 선택 3. **"Install"** 클릭 이제 DisHost가 선택한 레포지토리에 접근할 수 있습니다. > **보안**: GitHub App은 레포지토리 읽기 권한만 요청합니다. 코드를 수정하거나 다른 정보에 접근하지 않습니다. --- ## Step 3 — 레포지토리에서 배포 1. 대시보드 → **"Create Bot"** 2. **"Git으로 불러오기"** 선택 3. **레포지토리 목록**에서 내 레포 선택 - 검색창으로 빠르게 찾을 수 있습니다 - 공개/비공개 레포 모두 표시됩니다 4. ☑ **"Push 시 자동 재배포"** 체크 (선택) 5. 언어 선택 → 생성 완료 --- ## Step 4 — 자동 배포 설정 (선택) 봇 생성 시 **"Push 시 자동 재배포"**를 체크하면: ``` 내 컴퓨터에서: git add . git commit -m "버그 수정" git push origin main → 30초 후 DisHost가 자동으로 새 코드를 배포합니다 ``` **동작 방식**: 1. GitHub에 Push 2. GitHub → DisHost로 Webhook 알림 3. DisHost 서버에서 `git pull`로 최신 코드 가져오기 4. `npm install` (필요한 경우에만) 5. 봇 재시작 --- ## 문제 해결 ### "redirect_uri is not associated with this application" GitHub App의 Callback URL이 잘못 설정된 경우입니다. 이 오류는 DisHost 설정 문제이므로 관리자에게 문의하세요. ### 레포지토리 목록이 안 보여요 1. GitHub App이 올바르게 설치되었는지 확인: [GitHub Applications](https://github.com/settings/installations) 2. 대시보드에서 로그아웃 후 다시 로그인 3. 그래도 안 되면 설정 페이지에서 GitHub 연결을 해제했다가 다시 연결 ### 비공개 레포는 어떻게 하나요? GitHub App 설치 시 해당 비공개 레포를 선택하면 됩니다. DisHost는 Installation Token을 통해 안전하게 접근합니다. ### Auto Deploy > GitHub Push 시 자동 배포 설정 가이드 코드를 Push할 때마다 DisHost가 자동으로 봇을 재배포합니다. `git push` 한 번으로 코드 업데이트가 완료됩니다. ## 설정 방법 1. [GitHub App 설치](/docs/github/connect) (레포지토리 접근 권한 부여) 2. 봇 생성 시 **"Push 시 자동 재배포"** 체크박스 활성화 3. `git push origin main` → 자동 배포 시작 ## 동작 방식 ``` git push origin main ↓ GitHub → DisHost Webhook 수신 ↓ 연결된 봇 찾기 → Deploy Queue ↓ Pterodactyl 재시작 ↓ git stash → git fetch → git reset --hard → git stash pop ↓ npm install → npm run build → npm start ``` ## Queue 짧은 시간 내 여러 번 Push가 발생하면: - **30초 쿨다운**: 마지막 배포 후 30초 내 Push는 무시 - **Coalescing**: 배포 진행 중 Push가 들어오면, 현재 배포 완료 후 **가장 마지막 커밋**만 배포 ## 배포 이력 확인 대시보드 → 봇 상세 → "배포" 탭에서 모든 배포 내역을 확인할 수 있습니다. 커밋 SHA, 메시지, 브랜치, 소요 시간이 기록됩니다. ## 비활성화 봇 설정에서 Auto Deploy 체크박스를 해제하면 Push 시 자동 배포가 중지됩니다. --- ## API ### API 인증 > API Key 또는 JWT로 DisHost API에 접근하는 방법 DisHost API는 **웹 대시보드에서 할 수 있는 모든 기능**을 프로그램으로 호출할 수 있습니다. CLI, CI/CD, 커스텀 도구를 만들 때 사용하세요. ## 인증 방식 선택 | 방식 | 사용처 | 예시 | |------|--------|------| | **API Key** | CLI, GitHub Actions, 스크립트 | `curl -H "x-api-key: ..."` | | **JWT** | 웹 대시보드 (자동) | `Authorization: Bearer ...` | 둘 중 하나만 있으면 모든 API를 사용할 수 있습니다. --- ## API Key 사용하기 ### 1. 키 발급 1. [대시보드 설정](https://dishost.kr/dashboard/settings) → **"API Keys"** 섹션 2. 이름 입력 (예: `내 CLI`, `GitHub Actions`, `자동화 스크립트`) 3. **"Create"** 버튼 클릭 4. **생성된 키를 복사** — 이 창을 닫으면 다시 볼 수 없습니다 > 키는 `dsh_live_` 로 시작하는 긴 문자열입니다. ### 2. 요청 보내기 모든 요청에 `x-api-key` 헤더를 추가합니다: ```bash # 내 봇 목록 조회 curl -H "x-api-key: dsh_live_abc123..." \ https://api.dishost.kr/api/v1/bots # 새 봇 배포 curl -X POST https://api.dishost.kr/api/v1/deployments \ -H "x-api-key: dsh_live_abc123..." \ -H "Content-Type: application/json" \ -d '{"botId":"abc123"}' ``` ### 3. 키 관리 - **이름**: 용도 구분용 (검증에 영향 없음) - **폐기**: 더 이상 사용하지 않는 키는 삭제 버튼으로 폐기 - **보관**: `.env` 파일이나 시크릿 관리 도구에 보관하세요. GitHub에 올리지 마세요 --- ## JWT (Bearer Token) JWT는 Discord 로그인 시 자동으로 발급됩니다. 웹 대시보드에서만 사용하고, 7일 후 만료됩니다. 일반적으로는 API Key를 대신 사용하세요. ```bash curl -H "Authorization: Bearer eyJhbGciOi..." \ https://api.dishost.kr/api/v1/bots ``` --- ## Public API (인증 불필요) 일부 정보는 인증 없이 누구나 조회할 수 있습니다: ```bash # 서버 상태 확인 curl https://api.dishost.kr/api/v1/health # → { "status": "ok", "db": "connected", "uptime": 123456 } # API 버전 확인 curl https://api.dishost.kr/api/v1/version # → { "version": "2.0.0", "apiPrefix": "v1" } # 템플릿 목록 curl https://api.dishost.kr/api/v1/templates ``` Public API는 IP당 15분에 100회로 제한됩니다. --- ## 기본 URL ``` https://api.dishost.kr/api/v1 ``` 모든 API 요청은 이 URL로 시작합니다. ### API 레퍼런스 > DisHost API의 모든 엔드포인트를 용도별로 정리했습니다 > 전체 기술 명세는 [Swagger UI](https://api.dishost.kr/api/v1/docs)에서 확인할 수 있습니다. --- ## 🤖 봇 관리 ### 내 봇 목록 ```bash GET /bots ``` ```bash curl -H "x-api-key: dsh_live_xxx" \ https://api.dishost.kr/api/v1/bots ``` ### 봇 상세 정보 ```bash GET /bots/:id ``` ### 봇 생성 ```bash POST /bots ``` ```json { "name": "my-bot", "type": "git", "language": "javascript", "gitUrl": "https://github.com/user/repo.git", "gitBranch": "main", "autoDeployEnabled": true } ``` `type` 옵션: - `"custom"` — 빈 프로젝트로 시작 - `"git"` — GitHub에서 가져오기 - `"marketplace"` — 템플릿으로 시작 ### 봇 수정 ```bash PATCH /bots/:id ``` ```json { "name": "새 이름", "autoDeployEnabled": false } ``` ### 봇 삭제 ```bash DELETE /bots/:id ``` ### 갱신 (7일 연장) ```bash POST /bots/:id/renew ``` --- ## 🚀 배포 ### 배포 이력 ```bash GET /bots/:id/deployments?page=1&limit=20 ``` ### 배포 실행 ```bash POST /deployments ``` ```json { "botId": "abc123", "source": "cli" } ``` --- ## ⚡ 서버 관리 ```bash # 시작 / 정지 / 재시작 POST /servers/:identifier/power { "signal": "start" } // "start" | "stop" | "restart" # 리소스 사용량 GET /servers/:identifier/resources # 환경변수 조회 GET /servers/:identifier/startup # 환경변수 수정 PUT /servers/:identifier/startup/variable { "key": "DISCORD_TOKEN", "value": "..." } ``` --- ## 🔗 GitHub ```bash # 설치 목록 GET /github/installations # 설치된 레포지토리 목록 GET /github/installations/:id/repos # 레포-봇 연결 POST /github/connect-repo { "installationId": 123, "repoFullName": "user/repo", "repoId": 456, "botId": "abc" } ``` --- ## 🔐 GitHub OAuth ```bash # 연결 상태 GET /auth/github/status # 연결 해제 DELETE /auth/github/disconnect ``` --- ## 🔑 API Key 관리 ```bash # 생성 POST /auth/api-keys { "name": "my-token" } # 목록 GET /auth/api-keys # 폐기 DELETE /auth/api-keys/:id ``` --- ## 🪝 Webhook ```bash # 구독 POST /webhooks/subscriptions { "url": "https://my-app.com/webhook", "events": ["deploy.completed", "server.crashed"], "secret": "my-secret" } # 구독 목록 GET /webhooks/subscriptions # 구독 해제 DELETE /webhooks/subscriptions/:id ``` --- ## 📊 Public API (인증 불필요) ```bash # 서버 상태 GET /health # 버전 GET /version # 템플릿 목록 GET /templates ``` ### Webhooks > DisHost 이벤트를 웹훅으로 외부 서비스에 전달하는 방법 DisHost에서 발생하는 이벤트를 외부 서비스로 전달할 수 있습니다. Discord 알림, Slack 메시지, CI 트리거에 활용하세요. ## 지원 이벤트 | 이벤트 | 설명 | Payload | |--------|------|---------| | `deploy.completed` | 배포 완료 | `{ botId, botName, commitSha, commitMsg, branch, durationMs }` | | `server.crashed` | 서버 크래시 | `{ botId, botName, lastLog, timestamp }` | | `backup.completed` | 백업 완료 | `{ botId, botName, backupId, sizeBytes, timestamp }` | ## 구독 ### API ```bash curl -X POST https://api.dishost.kr/api/v1/webhooks/subscriptions \ -H "x-api-key: dsh_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "url": "https://my-server.com/webhook", "events": ["deploy.completed", "server.crashed"], "secret": "my-signature-secret" }' ``` ### 구독 목록 ```bash curl -H "x-api-key: dsh_live_xxx" \ https://api.dishost.kr/api/v1/webhooks/subscriptions ``` ### 구독 해제 ```bash curl -X DELETE \ -H "x-api-key: dsh_live_xxx" \ https://api.dishost.kr/api/v1/webhooks/subscriptions/{id} ``` ## 시그니처 검증 모든 Webhook 요청에는 `X-Dishost-Signature` 헤더가 포함됩니다. ```javascript const crypto = require("crypto"); function verifySignature(payload, signature, secret) { const hmac = crypto.createHmac("sha256", secret); const expected = "sha256=" + hmac.update(payload).digest("hex"); return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected)); } ``` ## 재시도 - 배달 실패 시 최대 3회 재시도 (1s → 5s → 25s) - 10회 연속 실패 시 Webhook 자동 비활성화 --- ## 대시보드 기능 ### 실시간 콘솔 및 모니터링 > 봇 컨테이너의 실시간 작동 상황 파악, 전원 제어, 그리고 메모리 및 CPU 자원 모니터링 시스템의 올바른 활용법을 다룹니다. 실시간 콘솔(Console)은 디스호스트에서 봇의 상태를 시각화하여 모니터링하고 제어할 수 있는 핵심 관제 센터입니다. --- ## 1. 실시간 로그 스트림 콘솔 화면 중앙의 검은색 뷰어 영역은 컨테이너 커널 시스템의 표준 출력(Stdout)과 표준 에러(Stderr) 스트림 데이터를 지연 없이 중계합니다. * **실시간 감시**: 봇이 구동되면서 `console.log()` 또는 `print()` 함수를 통해 내뱉는 모든 개발자 로그와 내부 익셉션 에러 트레이스가 실시간 출력됩니다. * **스크롤 잠금**: 로그 출력량이 많을 때 최하단 포커스를 유지하거나, 특정 시점 로그 분석을 위해 자동 스크롤을 끄고 화면을 멈출 수 있습니다. --- ## 2. 실시간 시스템 지표 모니터링 콘솔 상단 및 사이드 패널에는 컨테이너 가상 엔진이 물리 서버에서 소비 중인 시스템 리소스 정보가 1초 단위로 업데이트됩니다. 1. **CPU 사용량 (Usage)**: 컨테이너에 할당된 25% 코어 대비 실시간 스레드 로드율을 뜻합니다. 무한 루프나 과도한 동기식 연산이 지속될 경우 할당 한도(25%)에 도달하며 일시적 봇 지연이 유발됩니다. 2. **RAM (Memory) 소비량**: 봇이 사용 중인 실제 가상 램 용량입니다. 기본 제공량인 128MB를 넘어설 기미가 보인다면 가비지 컬렉션 세팅 조율 또는 포인트 상점을 통한 RAM 사양 업그레이드를 추천합니다. 3. **디스크 스토리지 용량**: 현재 격리 볼륨 내에 저장된 모든 소스파일 및 로컬 데이터베이스의 용량 점유 현황입니다. 만약 512MB 스토리지 임계값에 도달할 경우 새로운 파일 쓰기 작업이 거부되어 프로세스 오작동이 일어납니다. --- ## 3. 원클릭 물리 전원 제어 디렉터리 상단 우측의 전원 컨트롤 버튼 모음은 가상 컨테이너의 하드웨어 전원을 원격 지시합니다. * **시작 (Start)**: 정지된 컨테이너에 부팅 전원 시그널을 전송합니다. * **중지 (Stop)**: 프로세스에 안전한 정지 명령(SIGINT)을 보내 현재 진행 중인 내부 작업이나 데이터베이스 쓰기 작업을 깔끔하게 종료한 뒤 컨테이너를 안전하게 휴면 상태로 전환합니다. * **재시작 (Restart)**: 프로세스를 정지한 직후 즉시 리부팅합니다. 소스코드를 수정했거나 환경변수를 새로 주입했다면 **반드시 재시작을 눌러 런타임 메모리에 변경사항을 재로드**해 주어야 반영됩니다. * **강제 종료 (Kill)**: 봇이 비정상 루프에 빠져 안전한 중지(SIGINT) 호출에 응답하지 않을 때, 커널 단에서 프로세스를 강제 사살(SIGKILL) 처리합니다. 데이터 유실 예방을 위해 일반적인 상황에서의 강제 종료 사용은 권장하지 않습니다. ### 파일 매니저 및 웹 에디터 > 웹 브라우저 환경에서 직접 파일을 수정하고 폴더를 만들며, 대용량 소스 파일 압축을 전송 및 관리하는 전체 파일 탐색기 시스템을 설명합니다. 디스호스트 파일 매니저(File Manager)는 가상 컨테이너 내부의 격리 스토리지 볼륨에 직접 액세스하여 파일을 제어할 수 있는 브라우저 내장형 파일 시스템 브라우저입니다. --- ## 1. 드래그 앤 드롭 파일 업로드 로컬 PC에서 개발 완료한 여러 개의 소스코드 파일을 드래그하여 파일 매니저 빈 영역에 놓으면 업로드 큐(Queue)가 작동하여 대시보드 내부 저장소로 즉시 전송됩니다. * **대용량 및 폴더 전송 팁**: 브라우저 특성상 수백 개의 폴더 구조를 직접 쪼개어 업로드하면 전송 끊김 현상이 발생할 수 있습니다. 로컬 폴더 전체를 `.zip` 압축파일 하나로 압축하여 대시보드에 업로드한 후, 파일 매니저 우클릭 메뉴의 **압축 풀기 (Unarchive)** 기능을 이용하면 계층 폴더 구조가 0.1초 만에 깔끔히 풀려 반영됩니다. --- ## 2. 모나코(Monaco) 웹 코드 에디터 텍스트 형식의 파일(예: `.js`, `.py`, `.json`, `.txt`, `.md`)을 마우스로 더블 클릭하면 마이크로소프트 VS Code와 동일한 강력한 성능의 **Monaco 에디터** 프레임워크가 작동합니다. * **주요 제공 기능**: * 해당 코드 언어의 신택스 하이라이팅 및 문법 색상 강조 적용. * 가독성 높은 자동 들여쓰기(Format Document) 및 줄 번호 추적. * 찾기 및 바꾸기(Ctrl + F / Ctrl + H) 기능 지원. * **변경사항 저장**: 코드 수정 완료 후 우측 하단의 **저장 (Save)** 버튼을 누르면 즉시 가상 컨테이너 스토리지에 덮어씌워 쓰기가 마칩니다. 변경 후에는 메인 콘솔에서 봇 재시작을 수행해야 프로세스 스레드에 반영됩니다. --- ## 3. 우클릭 컨텍스트 메뉴 활용 각 파일 및 폴더 행 우측 끝의 점 세 개 아이콘을 클릭하거나 마우스 우클릭을 입력하면 시스템 제어 명령 리스트가 확장됩니다. * **이름 변경 (Rename)**: 파일이나 폴더의 물리 경로 이름을 바꿉니다. * **복사 (Copy)** 및 **이동 (Move)**: 파일 복제본 생성 또는 타 경로 폴더 하위로 요소를 이사시킵니다. * **다운로드 (Download)**: 웹서버 브라우저를 통해 해당 파일을 로컬 컴퓨터로 다운로드합니다. * **압축 (Archive)**: 선택한 여러 개의 파일들을 묶어 단일 압축본으로 패키징합니다. * **삭제 (Delete)**: 스토리지를 해제하고 불필요한 노드를 영구 제거합니다. ### 스케줄 및 자동 예약 관리 > 특정 주기마다 봇을 재기동하거나, 백업 스냅샷을 생성하고 명령을 실행하기 위한 크론(Cron) 스크립트 작성법을 학습합니다. 스케줄(Schedules) 매니저는 인간의 개입 없이 가상 호스팅 인프라가 지정된 특정 요일, 특정 시간 간격마다 봇을 자동으로 재시작하거나, 데이터를 백업하고, 특정 시작 시그널을 주입하도록 제어하는 완전 자동화 스케줄러 도구입니다. --- ## 1. 스케줄 등록 및 실행 시퀀스 1. 봇 상세 관리 페이지에서 **스케줄** 탭으로 진입한 뒤 우측 상단의 **스케줄 생성 (Create Schedule)**을 선택합니다. 2. 스케줄을 나타낼 명칭과 주기를 제어할 크론 표기식을 기입합니다. 3. 생성이 끝나면 스케줄 상세를 누르고 **태스크 추가 (Add Task)**를 연동합니다. - **태스크 종류**: - Power Action: 봇의 물리 상태를 변경합니다 (시작, 재시작, 중지). - Backup Action: 현재 봇의 모든 폴더 구조를 압축 백업본으로 새로 생성합니다. --- ## 2. 크론(Cron) 표기식 정밀 구성법 주기를 지정하는 문자열은 리눅스 표준 5필드 크론 표기식 구조를 빌려 적용합니다. ```text * * * * * │ │ │ │ │ │ │ │ │ └─ 요일 (0 - 7, 0과 7은 일요일) │ │ │ └────── 월 (1 - 12) │ │ └─────────── 일 (1 - 31) │ └──────────────── 시간 (0 - 23, KST 한국 표준시 반영) └─────────────────────── 분 (0 - 59) ``` ### 많이 쓰이는 주간 프리셋 예시 * **매일 새벽 4시 정각에 봇 강제 재시작**: ```text 0 4 * * * ``` - 봇 프로세스 내에 누적된 가비지 컬렉터 잔재와 누수 메모리를 매일 새벽마다 초기화해 주는 가장 추천하는 설정값입니다. * **매주 일요일 밤 12시 0분에 자동 백업 생성**: ```text 0 0 * * 0 ``` - 주기적으로 유저들의 데이터베이스 세이브포인트를 격리 보관할 때 유용합니다. * **매시간 0분마다 주기적 상태 새로고침 (정각 리부트)**: ```text 0 * * * * ``` --- ## 3. 스케줄 가동 안전 조건 스케줄 설정 시 아래 부가 제어 플래그를 설정하여 유연성을 도모할 수 있습니다: * **동작 조건 (Only when online)**: 이 토글 스위치를 활성화하면, 봇이 이미 꺼져 있는 잠금 상태일 때는 스케줄이 트리거되어도 강제 부팅을 수행하지 않고 통과합니다. 봇을 의도적으로 일시 휴면 중지시켰을 때 불필요한 작동을 차단할 수 있습니다. * **활성화 여부 (Is Active)**: 스케줄을 물리적으로 지우지 않고, 일시적으로 작동을 비활성화(Pause)할 때 토글합니다. ### 데이터 백업 및 복원 > 불의의 설정 사고나 DB 깨짐 현상을 예방하기 위해 컨테이너 상태 스냅샷을 보존하고 이전 상태로 빠르게 롤백하는 프로토콜을 제시합니다. 백업(Backups) 탭은 현재 내 봇 가상 컨테이너 스토리지에 존재하는 모든 코드, 의존 라이브러리, 환경 설정 파일, 로컬 데이터베이스 파일의 전체 상태를 단일 아카이브 파일로 고정 보존하는 시스템 스냅샷 솔루션입니다. --- ## 1. 백업 생성 및 복원 동작법 * **백업 생성**: 1. 대시보드의 **백업** 탭으로 진입합니다. 2. 우측 상단의 **백업 생성 (Create Backup)** 버튼을 클릭합니다. 3. 필요에 따라 백업을 구별하기 위한 메모 이름을 붙입니다. (예: 데이터베이스 마이그레이션 전 백업) 4. 생성이 시작되면 백업 압축 스택이 준비되며, 완료 즉시 리스트에 타임스탬프와 파일 크기가 노출됩니다. * **백업 복원 (Restore)**: - 백업 리스트 우측의 옵션 아이콘을 눌러 **복원 (Restore)**을 실행합니다. - **주의**: 복원이 트리거되면 현재 컨테이너에 작동 중인 모든 파일 구조가 말소되고 백업을 수행했던 과거 시점의 스냅샷 데이터로 완전히 대체됩니다. 중요한 최신 코드가 있다면 미리 로컬에 내려받은 뒤 복원을 개시해야 합니다. --- ## 2. 파일 제외 규칙 (.pignore) 스토리지 공간을 절약하고 백업 속도를 높이기 위해 불필요한 패키지 폴더나 캐시 파일들을 백업 범위에서 사전 여과할 수 있습니다. * 프로젝트 루트 디렉토리에 **`.pignore`** 파일을 생성하고 백업에서 빼낼 파일 경로들을 줄바꿈 단위로 작성합니다: ```text # 의존성 모듈은 패키지 파일 기반 자동 설치가 가능하므로 제외 node_modules/ .venv/ venv/ # 임시 빌드 아웃풋 및 캐시 제외 .next/ dist/ .cache/ ``` --- ## 3. 백업 슬롯 용량 제한 정책 * **슬롯 초과 대처**: 새 백업을 만들기 위해서는 기존에 등록되어 있는 과거 백업 리스트 우측의 삭제 버튼을 클릭하여 스페이스를 비워두거나, 포인트 상점에서 포인트를 지불하고 백업 슬롯 영구 확장권을 구입해야 합니다. * **백업 보호 잠금 (Lock)**: 목록 우측의 자물쇠 버튼을 누르면, 백업을 강제 해제(Unlock)하기 전까지 실수로 삭제 버튼을 누르는 사고를 방지할 수 있습니다. * **외부 아카이빙 다운로드**: 로컬 PC 백업 백업용으로 다운로드 버튼을 지원합니다. 브라우저로 백업본 압축 파일을 영구 다운로드해 안전하게 이중 보관하는 것이 가능합니다. ### 스타트업 환경 변수 설정 > 봇 컨테이너 구동 시 주입되는 런타임 환경변수(ENV)의 종류와 시작 실행 파일 이름, 파이썬 종속 패키지 리스트 선언 요령을 익힙니다. 스타트업 설정(Startup Settings) 탭은 가상 머신 컨테이너가 최초 부팅을 개시할 때 어떤 파일 실행 프레임워크를 가동할지, 어떤 컴파일러 옵션 파라미터를 인젝션할지 정의하는 핵심 브레인보드입니다. --- ## 1. 봇 토큰 및 환경 변수(Environment Variables) 설정 보안 유지를 위해 봇 토큰이나 외부 API 키(예: OpenAI API Key) 같은 민감 정보는 절대로 소스코드 내부에 하드코딩해서는 안 됩니다. * **설정 메커니즘**: 환경변수는 `dotenv` 라이브러리 등을 이용하여 런타임에 주입해주어야 합니다. 디스호스트 상세 패널의 **환경 변수** 탭에서 루트 디렉터리의 `.env` 파일을 웹 상에서 쉽게 수정할 수 있습니다. * **코드 내 파싱 예시**: * **Node.js (`dotenv` 라이브러리 사용)**: ```javascript require('dotenv').config(); const myToken = process.env.DISCORD_TOKEN; ``` * **Python (`python-dotenv` 라이브러리 사용)**: ```python import os from dotenv import load_dotenv load_dotenv() my_token = os.getenv("DISCORD_TOKEN") ``` --- ## 2. 런타임 실행 메인 파일 지정 (STARTUP_FILE) 가상 머신에 전원이 들어왔을 때 부팅 프로세스가 가장 먼저 컴파일하고 실행시킬 진입점 파일을 지정합니다. * **기본 세팅**: * **Node.js**: 보통 `index.js` 또는 `main.js`를 사용합니다. * **Python**: 보통 `bot.py` 또는 `main.py`를 사용합니다. * **경로 입력 주의**: 서브 디렉터리 안에 있는 파일을 가동하고 싶다면 `src/index.js`와 같은 루트 기준 계층 경로를 온전히 적어주어야 실행 오류를 회피할 수 있습니다. --- ## 3. 파이썬 종속 패키지 리스트 (PY_PACKAGES) 파이썬 런타임 슬롯을 활용하는 경우, 컨테이너 부팅 과정에서 가상환경에 자동 다운로드해 설치할 패키지 목록을 기입하는 필드입니다. * **작성 규칙**: 설치하고자 하는 pip 패키지 명칭을 공백(스페이스바) 한 칸 주기로 나열해 기입합니다: ```text discord.py python-dotenv aiohttp requests ``` * **자동 검증**: 부팅 셸이 해당 목록 데이터를 파싱해 `pip install` 루프를 한 단계씩 실행합니다. 버전을 한정하고 싶을 땐 `discord.py==2.3.2`와 같이 정확한 등호식을 첨부할 수 있습니다. ### 포트 포워딩 및 도메인 연동 > 봇 컨테이너 내부에 Express, FastAPI 웹 서버를 구동하고 외부 포트 바인딩 및 SSL 적용 서브도메인을 할당받아 웹훅을 처리하는 기법을 다룹니다. 디스호스트 컨테이너는 단순히 백그라운드 디스코드 봇 프로세스 가동에 머무르지 않고, 외부로부터 HTTP 웹 요청을 수신하는 포트 바인딩 및 서브도메인 역프록시(Reverse Proxy) 시스템을 지원합니다. 이를 통해 웹 대시보드 구축이나 외부 서비스 결제 웹훅(Webhook) 수신 채널을 가동할 수 있습니다. > [!WARNING] > **무료 플랜 미지원** > 기본 무료 슬롯에서는 외부 접속(포트 포워딩 및 도메인 연동) 기능을 지원하지 않습니다. 외부 웹 서버 연결이나 웹훅 수신을 위해 본 기능을 사용하려면 업그레이드가 필요합니다. --- ## 1. 포트 포워딩 동작 아키텍처 컨테이너 환경은 고유한 내부 사설 IP만을 가집니다. 따라서 외부 인터넷에서 직접 컨테이너의 특정 포트로 접근할 수 없으므로 디스호스트 라우터 프록시가 포트를 연동해 줍니다. * **할당 포트 확인**: 봇 관리 대시보드의 **네트워크/포트** 설정을 확인하면 외부 포트(External Port)와 내부 매핑 포트(Internal Port) 주소가 지정되어 있습니다. * **역프록시 SSL (HTTPS) 지원**: 외부에서 접속할 때는 안전한 암호화 채널인 `https://` 프로토콜로 주소가 자동 연결되며, 포트 프록시 서버 단에서 SSL 인증서를 자동 파싱해 주므로 코드 내에 별도로 SSL 인증서를 심을 필요가 없습니다. --- ## 2. Node.js (Express) 웹 서버 소스 구현 Node.js 환경에서 Express 패키지를 가동해 디스호스트에서 지정한 내부 바인딩 포트 번호(보통 환경변수 `SERVER_PORT` 또는 명시된 내부 포트)로 접속 대기하는 코드입니다. ```javascript const express = require('express'); const app = express(); // 디스호스트 컨테이너 시스템이 제공하는 내부 환경 변수 포트를 우선 감지합니다. const PORT = process.env.SERVER_PORT || 8080; app.use(express.json()); app.get('/', (req, res) => { res.send('DisHost Web Server is Running!'); }); // 외부 웹훅 수신 경로 정의 app.post('/webhook', (req, res) => { console.log('Log: 웹훅 수신 데이터:', req.body); res.status(200).json({ status: 'success' }); }); app.listen(PORT, '0.0.0.0', () => { console.log(`Log: 웹 서버가 포트 ${PORT}에서 성공적으로 시작되었습니다.`); }); ``` --- ## 3. Python (FastAPI) 웹 서버 소스 구현 파이썬의 uvicorn 웹 서버 엔진을 기반으로 FastAPI 스크립트를 연결하는 프로토콜입니다. ```python import os from fastapi import FastAPI import uvicorn app = FastAPI() @app.get("/") def read_root(): return {"message": "DisHost FastAPI Server is Running!"} if __name__ == "__main__": # 시스템 환경 변수 SERVER_PORT가 존재하면 사용하고 기본값은 8000으로 우회합니다. port = int(os.getenv("SERVER_PORT", 8000)) # 외부 접속 허용을 위해 host 주소는 반드시 '0.0.0.0'이어야 작동합니다. uvicorn.run(app, host="0.0.0.0", port=port) ``` --- ## 4. 접속 문제 해결 체크리스트 * **Host 바인딩 주소 누락**: 웹 서버를 띄울 때 호스트 주소를 `localhost`나 `127.0.0.1`로 묶어두면, 컨테이너 외부 프록시 라우터가 접속 신호를 밀어 넣지 못해 통신 차단 에러(502 Bad Gateway)가 납니다. 반드시 `0.0.0.0`으로 호스트 지정을 고정해야 외부 접속 바인딩이 체결됩니다. * **포트 일치**: 웹 엔진에 적은 포트 번호가 대시보드 **시작 설정** 또는 **네트워크**에 부여된 내부 포트와 한 자리도 틀리지 않고 정확히 일치하는지 두 번 검수하시기 바랍니다. ### 계정 이전 및 데이터 이관 > 디스코드 부계정을 사용하거나 계정을 변경해야 할 때, 기존 호스팅 봇과 모아둔 포인트를 새 계정으로 안전하게 자동 이관하는 방법을 알아봅니다. 디스호스트는 부득이한 사정으로 디스코드 계정을 변경해야 하는 사용자분들을 위해, 수동 데이터 백업이나 관리자 대행 요청 없이 스스로 안전하게 이전할 수 있는 **자동 계정 이전 기능**을 지원합니다. --- ## 1. 자동 계정 이전의 원리 디스호스트는 1인 1계정 원칙을 유지하고 남용을 방지하기 위해 가입 시 **휴대폰 본인 인증**을 필수로 요구합니다. 이 본인 인증 정보를 기준으로 계정 소유권을 식별합니다. * 새 디스코드 계정으로 새로 회원가입한 뒤, 기존 구계정에서 인증했던 동일한 전화번호로 인증을 시도하면 시스템이 이를 실시간으로 감지합니다. * 소유주가 동일함을 증명하고 승인할 시, 기존 구계정에 묶여 있던 모든 데이터가 신규 계정으로 합쳐지며 구계정은 보안상 자동으로 삭제 처리됩니다. --- ## 2. 이전되는 데이터 범위 계정 이전을 실행하면 구계정의 다음 데이터가 누락 없이 새 계정으로 완전히 누적 합산 및 소유권 이관 처리됩니다: > [!IMPORTANT] > **이관되는 주요 항목** > - **호스팅 중인 모든 봇 및 Pterodactyl 서버의 소유권** > - **보유 중인 봇 슬롯 및 남은 기간** > - **진행 중인 하드웨어 업그레이드(메모리/CPU/디스크 부스트) 상태** > - **그동안 획득한 포인트 잔액 누적 합산** > - **포인트 적립 이력 및 구매 이력** > - **백링크 제출 이력 및 파트너 자격 여부** > - **협업자로 추가된 봇의 권한 정보** --- ## 3. 계정 이전 실행 절차 자동 이전 시나리오는 다음과 같은 단계로 안전하게 처리됩니다. ### 1단계: 새 계정으로 가입 1. 디스호스트 웹사이트에 접속합니다. 2. 새로 사용할 디스코드 계정으로 **디스코드 로그인**을 통해 신규 회원가입을 완료합니다. ### 2단계: 휴대전화 본인인증 진행 1. 가입 온보딩 페이지 또는 대시보드 마이페이지로 이동합니다. 2. 본인인증 메뉴에서 **기존 계정에서 사용하던 동일한 전화번호**를 입력하고 인증번호를 전송합니다. 3. 수신된 인증번호를 입력해 인증을 완료합니다. ### 3단계: 이전 확인 팝업 승인 1. 인증을 완료하는 순간 화면에 **"이미 등록된 번호입니다. 기존 계정의 데이터를 이 계정으로 이전하시겠습니까?"** 라는 팝업 창이 나타납니다. 2. **이전 확인** 버튼을 클릭하여 소유권 이전을 최종 승인합니다. ### 4단계: 이전 완료 및 확인 1. 승인과 즉시 데이터 마이그레이션 백엔드 트랜잭션이 작동합니다. 2. 이관이 성공적으로 완료되면 봇 목록 페이지로 리다이렉트되며, 기존 봇이 그대로 노출되고 포인트와 등급이 합산된 것을 확인할 수 있습니다. 3. 구계정은 완전히 파기되어 더 이상 접근할 수 없게 됩니다. --- ## 4. 주의사항 및 제한 > [!WARNING] > - **계정 이전 빈도 제한**: 무분별한 계정 스와핑 및 어뷰징 방지를 위해 계정 이전은 **1년에 1회**로 엄격히 제한됩니다. 이전 신청 전에 반드시 신중히 결정해 주세요. > - **정지 계정 이전 불가**: 기존 구계정이 시스템 보안 규칙 위반 또는 불법 약관 위반으로 인해 정지된 상태라면 계정 이전을 진행할 수 없습니다. > - **Pterodactyl 패널 임시 비번 변경**: 계정이 정상 이전된 후 Pterodactyl 패널 계정도 신규 생성되므로, 필요한 경우 패널 비밀번호 재설정을 수행해 주시기 바랍니다. --- ## 데이터베이스 ### 로컬 SQLite 파일 저장 관리 > 디스호스트 컨테이너 내부 스토리지에 SQLite DB 파일을 배치해 서버 데이터를 보존하고, 쓰기 에러를 줄이는 디스크 저장법과 WAL 모드 활성화 옵션을 다룹니다. 서버 멤버의 포인트 정보나 가입 일자 등의 가벼운 관계형 데이터를 저장할 때 가장 편리하게 도입할 수 있는 데이터베이스는 파일 기반의 **SQLite**입니다. 디스호스트 기본 컨테이너 환경 내에서 데이터를 유실 걱정 없이 영구 기록하는 구성법을 안내합니다. --- ## 1. 스토리지 영구 경로 지정 (Root Path) 디스호스트는 컨테이너 재기동 시 컨테이너의 일부 임시 가상 영역(예: `/tmp`, `/var` 등)에 기록된 데이터를 초기화해 휘발시킵니다. 하지만 봇 프로젝트가 업로드되는 루트 작업 공간인 **`/home/container`** (또는 개발 프로젝트 상대 경로) 하위는 영구 스토리지 볼륨으로 완전히 보호됩니다. * **잘못된 선언 예시**: DB 파일 생성 경로를 시스템 절대 루트나 임시 폴더로 잡는 경우, 컨테이너를 재시작하는 순간 모든 가입 정보가 소실됩니다. * **올바른 선언 예시**: 반드시 소스코드 디렉토리 바로 아래의 로컬 상대 파일로 연결하거나 경로 설정을 기입해야 합니다. ### Node.js (better-sqlite3) 정의 예시 ```javascript const Database = require('better-sqlite3'); const path = require('path'); // 프로젝트 폴더 바로 밑에 data.db 파일을 생성하고 보존합니다. const dbPath = path.join(__dirname, 'data.db'); const db = new Database(dbPath, { verbose: console.log }); ``` ### Python (sqlite3) 정의 예시 ```python import sqlite3 import os # 현재 스크립트 실행 디렉터리를 감지해 절대 보존 경로를 확보합니다. base_dir = os.path.dirname(os.path.abspath(__file__)) db_path = os.path.join(base_dir, "data.db") conn = sqlite3.connect(db_path) ``` --- ## 2. WAL (Write-Ahead Logging) 모드 활성화 SQLite는 동시성 쓰기 트랜잭션이 집중될 경우 디스크 잠금(`SQLITE_BUSY: database is locked`) 현상이 빈번하게 일어납니다. 디스호스트 환경에서 이를 억제하기 위해 **WAL 모드**를 켤 것을 적극 권장합니다. * **WAL 장점**: 읽기 트랜잭션과 쓰기 트랜잭션이 서로를 차단하지 않고 병렬 처리되어 입출력 성능이 대폭 상승합니다. ### WAL 모드 설정 스크립트 주입 ```javascript // better-sqlite3 기준 선언 직후 프라그마 주입 db.pragma('journal_mode = WAL'); ``` ```python # python sqlite3 기준 커서 획득 후 주입 cursor = conn.cursor() cursor.execute("PRAGMA journal_mode=WAL;") ``` --- ## 3. 백업 시 주의 사항 SQLite는 파일 하나에 모든 데이터를 봉인 보관하므로 백업 탭을 통해 백업을 생성할 때 매우 안전하고 깨끗하게 복구 데이터를 보관할 수 있습니다. 단, 백업 생성 명령을 내릴 땐 봇 프로세스가 데이터베이스에 한창 대량의 값을 쓰는 중(Writing state)이 아닌 한산한 새벽 시간대에 트리거되도록 스케줄러를 세팅하는 것이 안전합니다. ### 외부 클라우드 DB 연동 가이드 > 봇 컨테이너 외부의 Supabase, MongoDB Atlas 등의 클라우드 DB 연동법과 디스호스트 IP 대역 차단 방지를 위한 방화벽 설정 요령을 안내합니다. 대규모 디스코드 서비스를 설계 중이거나, 여러 웹 대시보드와 데이터를 상호 공유해야 한다면, 컨테이너 내부에 DB를 두기보다 외부 전문 클라우드 데이터베이스 서비스(SaaS)로 연결을 돌리는 것이 관리와 백업 측면에서 훨씬 탁월합니다. --- ## 1. 외부 DB 사용의 이점 및 추천 서비스 * **스토리지 보존**: 봇 호스팅 컨테이너가 폭파되거나 초기화되어도 사용자의 모든 재화 데이터는 물리 데이터베이스 원격 서버에 격리 보관되어 완전히 안전합니다. * **쉬운 다중 인스턴스 연동**: 하나의 DB를 공유하는 로드밸런싱 클러스터 구조로 여러 대의 봇을 동시에 안전 가동할 수 있습니다. * **추천 플랫폼**: * **Supabase (PostgreSQL)**: 무료 티어로 관계형 DB 구축 가능. REST API 및 실시간 소켓 통신 모듈 지원. * **MongoDB Atlas (NoSQL)**: 스키마가 필요 없는 자유로운 문서 기반 데이터 수집에 용이하며 무료 샌드박스 제공. * **Firebase / Firestore**: 실시간 동기화가 필요한 소형 키-값 저장소에 유리. --- ## 2. 외부 방화벽 IP 허용 (Fact check: Allow All IPs) 대부분의 클라우드 데이터베이스 플랫폼은 비인가 접속자를 원천 차단하기 위해 방화벽(IP Whitelist) 시스템을 디폴트로 활성화해 둡니다. > [!IMPORTANT] > **모든 IP 대역 접속 허용 세팅이 필수적입니다.** > 디스호스트의 컨테이너 구동 머신 노드들은 로드밸런싱 라우터 가상화 기법을 사용하므로, 봇을 재기동하거나 다른 노드로 컨테이너가 마이그레이션될 때 컨테이너 외부 출력 IP 주소가 유동적으로 변합니다. > 따라서 특정 고정 IP 주소 하나만 DB 방화벽 화이트리스트에 올릴 경우, 봇이 재기동된 후 DB 커넥션 제한 에러를 발생시키게 됩니다. > 원활한 연결을 위해 DB 콘솔의 방화벽 설정 항목에서 아래와 같이 **모든 연결 허용 주소**를 추가해 주시기 바랍니다: > ```text > 0.0.0.0/0 > ``` --- ## 3. Node.js (MongoDB Atlas) 연동 코드 명세 환경 변수에 DB 주소 문자열(`DATABASE_URL`)을 등록하고 안전하게 커넥션을 맺는 코드입니다. ```javascript const mongoose = require('mongoose'); const connectDB = async () => { try { // 환경변수 주소로 안전 연동 시도 await mongoose.connect(process.env.DATABASE_URL); console.log('Log: 외부 MongoDB 데이터베이스 연결에 성공했습니다.'); } catch (err) { console.error('Error: 데이터베이스 접속 중 치명적 에러 발생:', err.message); process.exit(1); } }; connectDB(); ``` --- ## 4. Python (Supabase/PostgreSQL) 연동 코드 명세 파이썬의 `psycopg2-binary` 라이브러리를 가동해 연동하는 구조입니다. ```python import os import psycopg2 from dotenv import load_dotenv load_dotenv() def get_db_connection(): try: conn = psycopg2.connect(os.getenv("DATABASE_URL")) return conn except Exception as e: print(f"Error: PostgreSQL 원격 연결 실패: {e}") return None ``` --- ## 디스코드 봇 설정 ### 게이트웨이 인텐트 설정 > 봇이 접속 준비를 마치고 작동하는데도 이벤트 메시지를 수신하지 못하는 대표적인 현상과 인텐트 설정법을 제시합니다. 디스코드 봇은 실시간으로 사용자 액션을 수신하기 위해 게이트웨이 웹소켓(Gateway WebSocket) 연결을 활용합니다. 이때 디스코드 API 서버에 어떤 이벤트를 선별해 구독하겠다는 청원 신호인 인텐트(Intents)를 올바르게 정의하지 않으면, 봇이 온라인 상태임에도 어떠한 메시지에도 응답하지 않는 먹통 상태가 됩니다. --- ## 1단계: 디스코드 개발자 센터 승인 기본 보안 인텐트 외에 멤버 리스트나 채팅 내용 등을 수집하려면 개발자 센터 단의 사전 토글 스위치 활성화가 의무적입니다. 1. [디스코드 개발자 센터(Discord Developer Portal)](https://discord.com/developers/applications)의 본인 봇 애플리케이션으로 진입합니다. 2. 왼쪽 메뉴바에서 Bot 탭으로 이동합니다. 3. Privileged Gateway Intents 섹션까지 스크롤을 내립니다. 4. 필요로 하는 스위치를 ON으로 전환합니다: - **Presence Intent**: 서버 멤버들의 온라인/자리 비움/다른 게임 가동 여부 감지. - **Server Members Intent**: 서버 멤버 가입/탈퇴 이벤트 및 닉네임 목록 갱신 감지. - **Message Content Intent**: 사용자가 보낸 채팅 내용 문자열 읽기. (채팅 감지형 봇에 필수) 5. 변경 사항 적용을 위해 Save Changes를 클릭합니다. --- ## 2단계: 소스코드 내 Intents 선언 명시 개발자 포털에서 스위치를 켰다면, 실행 프로그램 코드 생성 옵션에서도 같은 범위의 인텐트를 명확히 명시하여 세션을 연결해야 합니다. ### Node.js (discord.js v14) ```javascript const { Client, GatewayIntentBits } = require('discord.js'); const client = new Client({ intents: [ GatewayIntentBits.Guilds, // 서버 기본 구성 이벤트 수신 GatewayIntentBits.GuildMessages, // 서버 메시지 발송 감지 GatewayIntentBits.MessageContent // 메시지 텍스트 파싱 허용 ] }); ``` ### Python (discord.py v2) ```python import discord from discord.ext import commands intents = discord.Intents.default() intents.message_content = True # 메시지 텍스트 파싱 허용 intents.members = True # 멤버 리스트 추적 허용 bot = commands.Bot(command_prefix='!', intents=intents) ``` --- ## 흔한 문제 및 자가 진단 FAQ ### Q. 봇이 켜졌는데 명령어 입력에 전혀 대답을 안 합니다. * **원인**: Message Content Intent 스위치가 디스코드 개발자 센터에서 꺼져 있거나 코드 내 intents 배열에 GatewayIntentBits.MessageContent 누락이 발생한 상태입니다. * **자가 진단 방법**: 봇의 로그 콘솔에 on_message 혹은 messageCreate 로그 리스너를 간단히 찍어 인풋 텍스트가 null 혹은 빈 문자열로 뭉개져 도달하는지 확인합니다. ### OAuth2 초대 링크 생성 > 보안 위협을 방지하고 일반 서버 소유자들이 안심하고 봇을 추가할 수 있도록 안전하고 구조적인 봇 초대 링크 생성 프로세스를 설명합니다. 봇 제작이 성공적으로 끝났다면, 다른 사람들의 디스코드 서버에 내 봇을 초대하여 서비스를 제공할 준비를 마쳐야 합니다. 디스코드 API는 권한 탈취 사고를 차단하기 위해 OAuth2 기술을 사용해 봇 추가 링크를 제어합니다. --- ## 안전한 초대 URL 빌딩 순서 1. 디스코드 개발자 센터의 봇 상세 페이지로 접속합니다. 2. 왼쪽 사이드 메뉴바에서 OAuth2 -> URL Generator 탭으로 이동합니다. 3. Scopes (권한 범위) 선택 바에서 필수 항목을 체크합니다: - bot: 일반 봇 계정을 서버에 투입하기 위해 필요합니다. - applications.commands: 최근 표준인 슬래시 명령어(/)를 사용자들이 입력할 수 있도록 봇에 명령 권한을 연동합니다. 4. Bot Permissions (봇 상세 동작 권한) 항목 선택: - 보안상 최우선 조치로 Administrator (관리자) 권한 체크는 가능한 지양합니다. - 봇이 구동하는 데 최소한으로 요구되는 권한만 선별해 선택하는 것이 보안성과 이용자 신뢰 확보에 크게 기여합니다. - **권장 체크 리스트**: - Read Messages/View Channels: 채널 글을 읽기 위해 기본 활성화. - Send Messages: 사용자의 호출에 대댓글을 달거나 공지를 작성. - Embed Links: 세련된 임베드(Card) 레이아웃 형태로 메시지를 전달할 때 필수. - Read Message History: 과거 명령이나 이력을 체크할 필요가 있을 때. 5. URL 복사 및 배포: 하단에 생성된 `https://discord.com/api/oauth2/authorize...` 형태의 주소를 복사하여 봇 소개 사이트나 백링크 포털에 게시합니다. --- ## 권한 남용(Administrator)의 위험성 안내 > [!WARNING] > **관리자 권한 부여는 매우 위험합니다.** > 편의를 위해 Administrator 권한을 체크해 배포하면, 봇 토큰이 단 한 번 유출되었을 때 공격자가 봇을 추가한 모든 서버의 채널을 폭파하거나, 역할을 조작하고 모든 멤버를 강퇴(Kick/Ban)할 수 있는 무제한의 재앙을 낳습니다. > 반드시 최소 기능 권한만 묶어서 초대장을 배포하는 습관을 들이시기 바랍니다. ### 슬래시 명령어 개발 및 등록 > 구식 접두사 문자 명령어에서 디스코드 공식 표준인 애플리케이션 슬래시 명령어(/) 등록법과 즉시 반영 팁을 안내합니다. 과거에 많이 사용하던 문장 감지형 명령어(예: `!도움말`)는 디스코드 보안 정책 및 API 최적화 정책에 의해 점차 사용이 제한되고 있으며, 현재는 시스템 통합 슬래시 명령어(예: `/도움말`) 사용이 필수화되었습니다. --- ## 글로벌 명령어 vs 특정 서버(Guild) 명령어 슬래시 명령어를 디스코드 서버에 대여 등록할 때, 등록 대상 범위에 따라 반영 속도의 큰 차이가 발생합니다: 1. **글로벌 명령어 (Global Commands)**: - 봇이 들어가 있는 전 세계 모든 서버에 일괄 적용되는 명령어입니다. - 디스코드 본사 서버의 전역 분산 캐싱 정책 때문에, 등록 스크립트 실행 후 실제 일반 사용자 클라이언트에 명령 아이콘이 활성화되기까지 **최대 1시간 내외의 지연 시간**이 발생합니다. 2. **길드 명령어 (Guild Commands)**: - 개발 중인 특정 디스코드 테스트 서버(Guild ID 지정) 한정으로만 배포하는 명령어입니다. - 스크립트 호출 즉시 **0.1초 만에 클라이언트에 즉시 갱신되어 반영**됩니다. - **추천**: 개발 단계나 로컬 테스트 중에는 무조건 특정 길드 명령어 배포 방식으로 개발하고, 최종 서비스 런칭 시 글로벌 등록으로 전환하는 것이 쾌적합니다. --- ## Node.js (discord.js v14) 등록 예시 스크립트 프로젝트 폴더 내에 별도의 배포용 파일(`deploy-commands.js`)을 두고 등록을 처리하는 구조입니다. ```javascript const { REST, Routes, SlashCommandBuilder } = require('discord.js'); require('dotenv').config(); // 등록할 명령어 목록 정의 const commands = [ new SlashCommandBuilder() .setName('핑') .setDescription('봇의 반응 속도를 테스트합니다.'), new SlashCommandBuilder() .setName('정보') .setDescription('디스호스트 컨테이너 정보 출력.') ].map(command => command.toJSON()); const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN); (async () => { try { console.log('Log: 슬래시 명령어 갱신 배포를 시작합니다...'); // 테스트 서버 Guild ID를 환경변수나 하드코딩으로 입력받아 즉각 등록합니다. await rest.put( Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID), { body: commands } ); console.log('Log: 특정 테스트 서버에 명령어가 즉시 배포되었습니다!'); } catch (error) { console.error(error); } })(); ``` --- ## Python (discord.py v2) 등록 예시 코드 `discord.py`에서는 봇 메인 루프 시퀀스 안에서 커맨드 트리 동기화(`sync()`) 명령을 주입하여 가동 단계에서 바로 등록할 수 있습니다. ```python import discord from discord.ext import commands class MyBot(commands.Bot): def __init__(self): intents = discord.Intents.default() super().__init__(command_prefix="!", intents=intents) async def setup_hook(self): # 봇 구동 시 특정 테스트 길드를 대상으로 트리거 동기화를 수행합니다. guild = discord.Object(id=123456789012345) # 본인의 테스트 서버 ID 기입 self.tree.copy_global_to(guild=guild) await self.tree.sync(guild=guild) print("Log: 테스트 서버 대상 슬래시 명령어 동기화 완료!") bot = MyBot() @bot.tree.command(name="ping", description="반응 속도 체크") async def ping(interaction: discord.Interaction): await interaction.response.send_message("pong!") bot.run("DISCORD_TOKEN") ``` ### 임베드 및 컴포넌트 V2 활용 > 디스코드 메시지 카드(Embed) 디자인 양식과 사용자 상호작용을 돕는 버튼, 선택 메뉴, 그리고 최신 컴포넌트 V2(Components V2) 레이아웃 코드 구현법을 익힙니다. 디스코드 일반 텍스트 문장을 넘어 시각적으로 정돈된 카드 정보 창을 출력할 수 있는 **임베드(Embed)** 기능과 사용자가 마우스로 직접 누를 수 있는 인터랙티브 UI 요소인 **컴포넌트(Components)** 적용 프로토콜을 설명합니다. --- ## 1. 리치 임베드(Rich Embed) 빌딩 규칙 임베드는 제목, 설명, 썸네일 이미지, 주요 필드 목록, 하단 꼬리말(Footer) 등으로 구성되는 풍부한 포맷의 안내 카드 영역입니다. ### Node.js (discord.js v14) 임베드 예제 ```javascript const { EmbedBuilder } = require('discord.js'); const welcomeEmbed = new EmbedBuilder() .setColor(0x0071E3) // 애플 블루 브랜드 색상 코드 .setTitle('디스호스트 서버 안내') .setDescription('무료 고성능 디스코드 봇 호스팅에 오신 것을 환영합니다.') .addFields( { name: '기본 메모리', value: '128MB', inline: true }, { name: '디스크 용량', value: '512MB', inline: true } ) .setTimestamp() .setFooter({ text: 'DisHost Docs Team' }); // 채널에 전송할 때 embeds 배열에 담아 송신합니다. message.channel.send({ embeds: [welcomeEmbed] }); ``` --- ## 2. 인터랙티브 컴포넌트 v2 (Components v2) 디스코드는 최근 봇 인터페이스 고도화를 위해 버튼과 메뉴의 레이아웃 배열을 세밀히 제어할 수 있는 차세대 **Components V2** 사양을 적용하기 시작했습니다. 그리드 형태의 배치나 모달(Modal) 응답을 유연하게 다룰 수 있습니다. ### Python (discord.py v2) 버튼 컴포넌트 구현 ```python import discord class InteractiveView(discord.ui.View): def __init__(self): super().__init__(timeout=60) # 60초 뒤 버튼 작동 비활성화 @discord.ui.button(label="서버 정보 조회", style=discord.ButtonStyle.primary) async def info_button(self, interaction: discord.Interaction, button: discord.ui.Button): # 버튼을 누른 멤버 본인에게만 보이는 메시지로 응답합니다. await interaction.response.send_message( content="본 봇은 디스호스트 컨테이너(128MB)에서 작동 중입니다.", ephemeral=True ) # 커맨드 함수 내에서 view 매개변수로 탑재하여 발송합니다. @bot.command(name='메뉴') async def menu(ctx): await ctx.send("원하는 작업을 선택해 주세요:", view=InteractiveView()) ``` --- ## 3. 컴포넌트 사용 가이드라인 * **Custom ID 충돌 주의**: 버튼이나 드롭다운 메뉴를 만들 때 선언하는 `custom_id` 값은 디스코드 이벤트 핸들러가 컴포넌트를 고유 식별하는 핵심 열쇠입니다. 여러 컴포넌트에 같은 custom_id를 사용하면 이벤트 충돌 및 오작동이 유발됩니다. * **응답 제한 타임아웃 (3초)**: 사용자가 버튼을 클릭한 시점부터 봇 소스코드가 디스코드 API 서버에 연동 응답(`interaction.deferReply()` 또는 `interaction.response.send_message()`)을 전달하기까지 **최대 3초**의 임계 한계 시간이 존재합니다. 무거운 연산이 실행되어야 할 땐 반드시 3초 내에 임시 응답 지연 처리(Defer)를 선포하여 타임아웃 오류를 차단해 주어야 합니다. --- ## 마켓플레이스 ### 템플릿 마켓플레이스 활용 및 공유 > 코딩 한 줄 없이 1초 만에 음악 봇, 티켓 봇, 관리 봇을 내 컨테이너에 복제 설치하고 내가 직접 제작한 보일러플레이트를 공유하는 방법을 안내합니다. 코딩에 익숙하지 않거나 빠르게 기성 완성형 서비스를 런칭하고 싶다면, 디스호스트 템플릿 마켓플레이스(Marketplace)를 통해 검증된 오픈소스 봇들을 원클릭으로 설치하여 가동할 수 있습니다. --- ## 1클릭 설치 동작법 마켓플레이스 메뉴에서는 전 세계 개발자들이 검증한 카테고리별 최고의 오픈소스 디스코드 봇 템플릿을 제공합니다: 1. **카테고리 탐색**: 음악(Music), 관리(Moderation), 유틸리티, 경제 등 원하는 카테고리를 찾습니다. 2. **템플릿 선택**: 각 템플릿 카드에는 원본 오픈소스 리포지토리 정보와 사용 방법이 연동되어 있습니다. 3. **프로젝트 연동 복제**: 내 봇 슬롯에 복제하기 버튼을 클릭하면, 빈 슬롯 컨테이너에 해당 봇의 전용 소스 파일 및 종속 패키지 정의서가 1초 만에 자동 주입 배포됩니다. 4. **환경 변수 세팅**: 복제가 완료된 봇의 상세 관리 대시보드로 이동해, 봇 발급 토큰(DISCORD_TOKEN)만 정상 등록해 주면 즉시 무중단 구동이 가능합니다. --- ## 내 프로젝트 템플릿화 및 공유 내가 직접 제작하여 완벽하게 커스텀 동작하도록 최적화된 봇 소스코드가 있다면, 타인이 사용할 수 있도록 템플릿 포털에 등록해 기여할 수 있습니다. * **등록 요건**: 소스코드 루트 디렉토리 내에 다른 이용자가 사용할 수 있도록 설정 가이드(README.md)와 메인 진입 소스파일, 그리고 라이브러리 명세(package.json 또는 requirements.txt)가 반드시 규격에 맞춰 포함되어 있어야 합니다. * **보안 검수**: 등록 제출 시, 본인의 개인용 봇 토큰이나 데이터베이스 암호 등의 기밀이 하드코딩되지 않았는지 점검받는 내부 보안 정밀 스캔 단계를 거칩니다. * **초대 권한 설정(botPermissions)**: 다른 사용자가 내 템플릿을 기반으로 봇을 생성한 후 즉시 서버에 초대할 때 요구할 권한 플래그 숫자(예: 8=관리자, 3072=채팅 읽기/보내기)를 지정하여 원터치 초대를 지원할 수 있습니다. * **배포 가이드(deployGuide)**: 봇 배포 성공 팝업창 내에 렌더링될 배포 후 필수 가이드를 작성합니다. 마크다운이 완벽 지원되며, 디스코드 개발자 포털의 필수 Intents 설정이나 초기 명령어 가동 방법 등을 체크리스트 형태로 친절히 제공하는 데 사용됩니다. --- ## 포인트 및 상점 ### 포인트 상점 및 무료 연장권 > 커뮤니티 개발 활동을 바탕으로 포인트를 모아 무료로 봇 호스팅의 하드웨어 리소스를 늘리거나 무료 구동을 연장하는 방법을 소개합니다. 디스호스트는 상업성 결제 유도를 최소화하고, 건강한 개발 커뮤니티 활성화를 유도하기 위해 자체 포인트 시스템(Point System)을 운영합니다. 개발 Q&A 해결이나 노하우 공유 글쓰기 등으로 포인트를 모으면, 봇의 램 성능을 확장하거나 무료 봇 구동 기한을 평생 연장할 수 있습니다. --- ## 포인트 적립 규칙 (Earning Points) 커뮤니티 게시판 및 디스코드 채널 등에서의 기여도에 따라 포인트가 차등 지급됩니다: * **일반 채팅**: 디스코드 채팅 발송 시 글자당 `1P` 적립 * **답장/댓글**: 게시글 및 답장 작성 시 글자당 `2P` 적립 * **서버 태그 착용**: 디스코드 프로필 상태메시지에 서버 태그 착용 시 시간당 `5P` 적립 (하루 최대 `120P`) * **주간 갱신 보상**: 매주 가동 인증 시 주차별 `200P ~ 500P` 지급 * **서버 부스팅**: 디스호스트 디스코드 서버 부스트 시 30일 주기마다 `4,500P` 적립 * **한디리 하트**: Koreanbots 하트 클릭 시 12시간 주기마다 `100P` 적립 * **일일 상한선**: 악성 매크로 및 도배 방지를 위해 커뮤니티 글쓰기로 획득 가능한 일일 최대 한계는 `1,000P`로 엄격히 제한됩니다. --- ## 포인트 상점 교환 아이템 품목 모은 포인트는 상점 탭에서 즉시 소모하여 가상 컨테이너 인프라 옵션을 변경하는 데에 사용할 수 있습니다. | 아이템 명칭 | 포인트 소모량 | 효과 | | :--- | :--- | :--- | | **봇 수동 갱신 (7일 연장)** | 500 P | 선택한 봇의 만료 시간을 7일 연장 | | **메모리 업그레이드 (+512MB)** | 2,500 P | 선택한 봇 컨테이너의 RAM을 30일간 512MB 추가 확장 | | **추가 봇 슬롯 (+1개)** | 5,000 P | 동시에 가동할 수 있는 총 봇 생성 한도를 30일간 +1개 증설 | --- ## 슬롯 만료 및 자동 알림 기본 무료 등급에서 연장하지 않은 봇은 기본 가동 한도 기간(7일)이 만료되면 대기열에서 해제되어 가동이 정지됩니다. 따라서 일주일마다 수동 갱신을 해주어야 지속해서 가동할 수 있습니다. * **알림 주기**: * **만료 3일 전**: 디스호스트 연동 디스코드 봇이 개인 DM 또는 대시보드 공지를 통해 만료 경고를 1차 발송합니다. * **만료 1일 전**: 만료 알림 2차 발송. * **만료 시점**: 봇의 컨테이너 상태가 강제로 정지(Stopped) 상태로 변경되고, 만약 7일(일주일) 이내에 갱신을 통해 슬롯 복원을 거치지 않으면 소스코드 볼륨 파일이 영구 삭제 처리(복구 불가)되므로 각별한 관리가 요망됩니다. --- ## 보안 ### 토큰 유출 방지 및 보안 수칙 > 봇 토큰과 기밀 설정 정보를 철저하게 비밀로 유지하고, 만약의 유출 사고 시 신속하게 대응하여 피해를 최소화하는 방법을 정리합니다. 디스코드 봇 개발 및 호스팅 과정에서 가장 치명적인 보안 허점은 봇 토큰(Token)의 노출입니다. 토큰이 악의적인 해커의 손에 들어갈 경우, 내 봇이 속한 모든 디스코드 채널에 피싱 메시지를 올리거나 권한을 훼손할 수 있습니다. 본 문서에서는 보안을 지키기 위한 필수 조치를 규정합니다. --- ## 1. 환경변수 필수 사용 및 소스코드 하드코딩 금지 개발 편의를 위해 소스코드 파일(예: `index.js`, `main.py`) 내부에 토큰 문자열을 직접 기입해두는 행동은 매우 위험합니다. * **대처 방법**: 대시보드의 환경 변수 메뉴를 이용해 `DISCORD_TOKEN` 키와 봇 토큰 값을 주입한 뒤, 코드 상에서는 `process.env.DISCORD_TOKEN` (Node.js) 또는 `os.getenv("DISCORD_TOKEN")` (Python)과 같은 런타임 바인딩 방식으로 토큰을 획득하게끔 설계하십시오. * 디스호스트는 대시보드 환경변수 스토리지 데이터를 외부로 노출하지 않으며 강력한 비대칭 암호화 기술로 봉인 보관하므로 가장 안전합니다. --- ## 2. Git .gitignore 설정 수칙 깃허브(GitHub) 등 공개 리포지토리에 소스코드를 푸시할 때 로컬 테스트용 설정 파일인 `.env`가 함께 업로드되어 전 세계에 노출되는 사고가 자주 발생합니다. 프로젝트 루트 폴더에 `.gitignore` 파일을 생성하고 아래의 설정 기밀 경로들을 반드시 등록하여 커밋 대상에서 필터 제외하십시오: ```text # 로컬 개발용 환경 변수 파일 제외 .env .env.local # Node.js 패키지 볼륨 폴더 및 시스템 로그 제외 node_modules/ npm-debug.log* # Python 가상환경 및 캐시 제외 .venv/ venv/ __pycache__/ *.pyc ``` --- ## 3. 토큰 유출 사고 시 응급 대처 행동 요령 만약 깃허브 공개 저장소에 코드가 커밋되어 디스코드 본사 또는 감시 봇으로부터 토큰 유출 경고를 수신했거나 유출이 의심된다면, 지체 없이 아래 시퀀스를 밟아야 합니다: 1. **토큰 리셋 (1순위)**: - 디스코드 개발자 센터로 즉시 이동합니다. - 본인 봇 설정의 Bot 탭으로 진입하여 Reset Token 버튼을 강제 실행합니다. - 이 동작을 밟는 즉시 기존에 유출되었던 과거 토큰의 권한은 무효화되므로 해커가 더 이상 봇을 움직일 수 없습니다. 2. **대시보드 환경변수 수정**: - 새로 발급받은 봇 토큰을 복사합니다. - 디스호스트 상세 패널의 환경 변수 탭으로 이동하여 기존 `DISCORD_TOKEN` 항목에 새 토큰을 덮어쓰고 저장합니다. 3. **봇 재시작**: - 대시보드 상단 제어바에서 재시작 (Restart)을 눌러 새 토큰이 프로세스 메모리에 연동되도록 재부팅합니다. ### API 속도 제한 및 보안 필터링 > 디스코드 본사로부터 요청 거부(429 Too Many Requests) 차단을 당하지 않기 위한 봇 단위 요청 한도 제한 및 사용자 입력 검증 필터를 소개합니다. 봇을 안정적으로 운영하기 위해서는 외부 사용자들의 악의적인 도배 공격이나 부적절한 특수 문자 유입을 안전하게 차단할 수 있는 **API 레이트 리밋(Rate Limit) 제어**와 **입력 필터링** 코드 작성이 필수입니다. --- ## 1. 디스코드 API 속도 제한 (Rate Limit) 우회 디스코드 API 게이트웨이는 단일 IP 및 봇 토큰 단위로 초당 요청 처리 한계치가 엄격히 정해져 있습니다. 이 규칙을 어기고 메시지 발송 루프를 고속 가동하면 `429 Too Many Requests` 상태 코드가 보고되며 봇 IP가 일시적으로 블랙리스트 격리됩니다. * **메시지 전송 일괄 결합(Batching)**: 수십 명의 전적을 동시에 뿌려야 한다면, 한 통씩 개별 메시지로 보내지 말고 하나의 임베드 필드 목록에 병합하여 1회에 발송하십시오. * **슬립 타임아웃 주입**: 반복 루프를 구동할 땐 최소 0.5초에서 1초 이상의 인위적인 스레드 대기(Sleep/Await) 구문을 주입해 지연을 걸어주어야 안전합니다. --- ## 2. 사용자 입력 문자열 검증 및 SQL 인젝션 예방 사용자가 입력 창이나 명령어 파라미터로 넘겨주는 데이터는 항상 오염되어 있다고 가정하고 철저히 검증 필터를 적용해야 합니다. * **SQL prepared statement 의무화**: SQLite 등 DB에 사용자 닉네임이나 메모 내용을 저장할 때 문자열 더하기(`+`) 방식을 사용하면 악의적 쿼리가 삽입되어 데이터가 파괴될 수 있습니다. 반드시 바인딩 변수 파라미터(`?` 또는 플레이스홀더)를 적용하십시오. * **특수 코드 이스케이프**: 사용자 문자열을 터미널 명령어 인자로 직접 주입하여 `child_process.exec()`로 실행시키는 구성은 백도어 노출을 의미하므로 절대 금지해야 합니다. --- ## 3. 이벤트 리스너 중첩 등록 금지 (메모리 누수 원인) 디스코드 개발 입문자들의 흔한 오류 중 하나는 이벤트 리스너 내부에 또 다른 리스너 함수를 네스팅 정의하는 구조입니다. ### 잘못된 설계 예시 (안 좋은 예) ```javascript client.on('messageCreate', (message) => { if (message.content === '!인증') { // 메시지 수신 함수 안에서 또 다른 리스너를 계속해서 대여 등록합니다. // 사용자가 !인증을 입력할 때마다 리스너가 메모리에 중복 등록되어 심각한 메모리 누수와 중복 응답 현상이 촉발됩니다. client.on('messageCreate', (reply) => { if (reply.content === '동의') { message.reply('인증이 끝났습니다.'); } }); } }); ``` ### 올바른 설계 예시 (좋은 예) 이러한 후속 대기 상태는 임시 이벤트 리스너 누적 방지를 지원하는 **Collector** 모듈을 이용해 설계해야 합니다. ```javascript client.on('messageCreate', async (message) => { if (message.content === '!인증') { message.reply('동의 여부를 입력해 주세요. (제한시간 10초)'); // 특정 멤버의 후속 답변 1개만 수집하는 콜렉터를 정의합니다. const filter = m => m.author.id === message.author.id; const collector = message.channel.createMessageCollector({ filter, time: 10000, max: 1 }); collector.on('collect', m => { if (m.content === '동의') { m.reply('인증이 정상 완료되었습니다.'); } }); } }); ``` --- ## 문제 해결 ### 메모리 부족 (OOM) 크래시 해결 > 봇 프로세스가 불규칙적으로 멈추며 종료 코드 137(Exit Code 137)이 발생하는 원인을 짚어보고, 코드 최적화 및 힙 메모리 조절법을 다룹니다. 디스호스트에서 봇을 가동하는 중 로그 콘솔에 `Process exited with code 137` 혹은 `Out of Memory (OOM)` 경고 메시지가 기록되며 봇이 강제 정지되는 경우가 발생할 수 있습니다. 이는 시스템 하이퍼바이저가 할당된 메모리 한계치를 침범한 컨테이너 프로세스를 강제로 물리적 차단 및 격리하면서 나타나는 대표적인 증상입니다. --- ## OOM 크래시의 원인 진단 디스호스트 기본 슬롯에는 128MB의 메모리가 할당됩니다. 이는 핑퐁 봇이나 가벼운 데이터 파싱 봇에는 충분하지만, 아래 케이스에 해당될 경우 RAM 공급 한계를 초과하여 크래시가 유발될 수 있습니다: 1. **대형 외부 라이브러리 탑재**: 대규모 이미지 가공 모듈(`canvas`, `sharp`) 또는 브라우저 자동화 라이브러리(`puppeteer`) 등을 불러와 가동하는 경우. 2. **메모리 누수 (Memory Leak)**: 이벤트 리스너가 누적되거나 전역 배열 변수에 사용자 데이터를 가비지 컬렉션(GC) 회수 없이 지속적으로 적재만 시키는 오작동 코드 구현. 3. **디스코드 서버 캐시 적재**: 봇이 참여 중인 수백 개 서버의 전체 멤버 오브젝트와 메시지 히스토리를 메모리에 실시간 캐싱할 경우. --- ## 해결 방안 1: Node.js 힙(Heap) 메모리 제한 조율 Node.js는 기본 설정 상 머신의 물리 램 용량에 비례해 과도하게 큰 규모의 가상 힙 메모리 공간을 선점하려고 시도합니다. 128MB 가상 머신 환경 내에서 과도한 힙 선점을 억제하기 위해 시작 파라미터를 강제 규제할 필요가 있습니다. ### 스타트업 매개변수 적용법 대시보드의 스타트업 설정 내 시작 명령 인수 필드에 아래 변수를 기입해 자바 가상머신(V8) 엔진의 가용 크기를 수동 제약해 줍니다: ```text --max-old-space-size=90 ``` - 본 옵션을 적용하면 Node.js 런타임이 힙 메모리 크기가 90MB를 넘기 전 스스로 가비지 컬렉션(GC)을 강력하게 소집 작동시켜 128MB 하드웨어 장벽을 뚫고 올라가는 상황을 예방합니다. --- ## 해결 방안 2: 디스코드 클라이언트 캐시 제한 개발 라이브러리 선언 옵션에서 불필요한 오브젝트 캐싱을 원천 배제합니다. ### Node.js (discord.js v14) 캐시 제한 예시 ```javascript const { Client, GatewayIntentBits, Options } = require('discord.js'); const client = new Client({ intents: [GatewayIntentBits.Guilds], makeCache: Options.cacheWithLimits({ MessageManager: 0, // 과거 메시지 캐싱 억제 (OOM 방지 핵심) PresenceManager: 0, UserManager: 0 }) }); ``` --- ## 해결 방안 3: 포인트 상점을 통한 메모리 증설 코드를 극도로 쥐어짜도 봇의 핵심 비즈니스 크기 때문에 메모리가 절대적으로 부족한 상황이라면, 대시보드 내 포인트 상점을 활용하는 것이 근본적인 해결책입니다. 포인트 상점에서 메모리 업그레이드 연장 아이템을 구매하면 즉시 RAM 스펙이 확장되어 넉넉한 공간에서 봇을 운용할 수 있습니다. ### 패키지 설치 오류 및 해결 > npm install 또는 pip install 중 발생하는 빌드 오류와 네이티브 C++ 라이브러리 모듈 빌드 실패에 대한 원인 분석 및 해결 팁을 알아봅니다. 디스호스트는 봇 컨테이너 구동 시 package.json 또는 requirements.txt 파일을 자동 탐색해 패키지 설치를 중재합니다. 하지만 패키지 자체의 컴파일 요건 충돌이나 파일 결함으로 인해 부팅 단계에서 멈추거나 중단 오류가 보고될 수 있습니다. --- ## 1. 대표적인 C++ 네이티브 모듈 컴파일 실패 오류 (node-gyp 등) 디스코드 봇 중 오디오(음악) 스트리밍 연동 모듈(`@discordjs/opus`, `sodium`, `canvas` 등)은 구동 속도 극대화를 위해 내부적으로 C/C++ 소스코드를 로컬에서 빌드하는 컴파일러 의존성을 띱니다. * **증상**: gyp ERR! build error 또는 make: *** [Release/obj.target/...] Error 스택 트레이스 출력과 함께 부팅 실패. * **원인**: 격리 컨테이너의 가벼운 볼륨 환경 내에 무거운 C++ 컴파일 툴체인(gcc, g++, python-dev 등) 컴파일 환경 라이브러리가 존재하지 않아 로컬 컴파일에 실패하는 상황입니다. * **해결 방법**: - **오디오 오푸스 코덱의 경우**: C++ 네이티브 빌드가 필요한 `@discordjs/opus` 대신, 순수 JS(JavaScript)로 짜여 컴파일 단계가 필요 없는 **`@discordjs/voice` + `opusscript`** 조합 라이브러리로 종속성을 선언 및 변경해 줍니다. - **이미지 가공 모듈의 경우**: 로컬 C 컴파일이 강제되는 `canvas` 패키지 대신, 사전 컴파일된 런타임 바이너리를 공급해 컴파일 요건이 없는 **`sharp`** 라이브러리로 우회 마이그레이션하는 것을 적극 추천합니다. --- ## 2. 캐시 오염 및 패키지 강제 초기화 방법 패키지 설치 도중 네트워크 지연이나 불의의 취소 동작을 수행해 `node_modules` 폴더가 일부 누락 훼손되었을 때, 다음 부팅 시 시스템이 정상 설치된 것으로 오해하고 구동하다가 `Cannot find module` 에러를 연쇄 유포할 수 있습니다. 이 경우 캐시 볼륨을 깨끗하게 정리하고 신규 상태로 패키지를 처음부터 다시 내려받아야 합니다. ### 패키지 초기화 순서 1. 대시보드 상세 보기 화면으로 이동합니다. 2. 제어 도구바 우측의 동작 제어 드롭다운 버튼을 누릅니다. 3. 의존성 캐시 초기화 및 재설치 메뉴를 클릭합니다. 4. 컨테이너가 볼륨 내부의 node_modules (또는 python 가상 라이브러리 캐시)를 즉시 물리적으로 일괄 제거한 뒤, 빌드 시퀀스에 다시 진입해 패키지를 첫 단계부터 복구 갱신합니다. --- ## 3. 종속성 파일 문법 결함 검증 패키지 명세 파일의 포맷 결함 유무를 최종 점검하십시오. * **Node.js**: `package.json`은 철저한 JSON 문법 표준을 따릅니다. 괄호 누락이나 콤마(`,`) 기호 오용이 없는지 로컬 JSON Validator 등을 활용해 정합성을 체크해 보시기 바랍니다. * **Python**: `requirements.txt` 작성 시 버전을 특정하기 위한 더블 등호(`==`)를 단일 등호(`=`)로 기재하거나 오타가 섞이면 PIP 배포 도구가 패키지를 추적해오지 못하므로 확인이 필요합니다. ### 흔히 발생하는 터미널 경고 및 대처 > 봇 실행 중 실시간 로그 콘솔에 기록되는 비동기 프로미스 예외, 디스크립터 경고, 그리고 파이썬 이벤트 루프 중단 오류의 조치법을 소개합니다. 봇이 완전히 뻗지는 않으나 실시간 콘솔 창에 다량의 경고 메세지(Warning) 또는 거절 스택 로그가 기록되는 경우, 미래의 치명적인 중단 사고로 이어질 수 있으므로 선제적인 예방 조치 조율이 요구됩니다. --- ## 1. Node.js 비동기 미처리 거부 (Unhandled Promise Rejection) 비동기 함수(`async/await` 또는 `.then()`)를 활용하는 과정에서 API 통신 단절이나 권한 부족으로 통신 실패 시 에러 예외 처리를 누락했을 때 기록되는 대표적인 경고입니다. * **증상**: `UnhandledPromiseRejectionWarning: Unhandled promise rejection...` 또는 `DeprecationWarning: Unhandled promise rejections are deprecated.` 출력. * **자가 해결책**: 비동기 API 명령 실행 단에 반드시 `try-catch` 스크립트 블록이나 예외 캐싱 콜백인 `.catch()` 구문을 결합하십시오: ```javascript // 올바른 비동기 예외 캐싱 예시 try { await message.reply('명령 처리 중...'); } catch (error) { console.error('Log: 메시지 발송 실패:', error.message); } ``` --- ## 2. Python 이벤트 루프 차단 및 Closed Loop 에러 파이썬의 비동기 비즈니스 프레임워크(asyncio) 기반인 `discord.py` 라이브러리 구동 도중 프로세스 정지 단계에서 비동기 소켓 세션이 미처 수거되지 못하고 끊겼을 때 발생하는 현상입니다. * **증상**: `RuntimeError: Event loop is closed` 경고 출력. * **원인**: 파이썬 3.8 이상 윈도우/리눅스 환경의 기본 루프 핸들러 정책 호환성 때문에 가동 종료 단계에서 잔여 태스크를 회수하는 도중 프로세스가 루프를 강제로 닫으면서 터집니다. * **해결 방법**: 봇 가동 종료 단계에서 유발되는 단순 세션 마감 오류로, 실제 봇 서비스 실시간 가동 중에는 성능상 악영향을 유도하지 않는 경미한 경고이므로 안심하고 넘어가셔도 안전합니다. --- ## 3. 디프리케이션 경고 (DeprecationWarning) * **원인**: 라이브러리가 최신 스펙으로 갱신되면서 더 이상 미래 버전에서 지원하지 않는 구식 메소드를 실행하고 있음을 알리는 시그널입니다. * **대처 가이드**: * Node.js: 구식 `new MessageEmbed()` 양식은 v14 기준 제거되었으므로 최신 규격인 `new EmbedBuilder()` 형식으로 모두 전환하여 코드를 보강해야 합니다. * Python: `bot.logout()` 명령이 완전히 제거되었으므로 대신 `await bot.close()` 비동기 마감 자원 회수 함수를 적용해 종료 로직을 디자인해야 합니다. ### 자주 묻는 질문 FAQ > 디스호스트 커뮤니티 자유게시판 및 개발 Q&A 포털에서 개발자분들이 가장 빈번하게 올리시는 단골 질문들을 선별해 답변을 수록했습니다. 디스호스트 사용 중에 발생할 수 있는 일반적인 질문과 핵심 궁금증에 대한 답변입니다. 원하는 질문을 찾지 못했다면 커뮤니티 Q&A 포털에 자유롭게 질문글을 남겨주시면 고수 개발자들이 빠르게 도와드립니다. --- ## 자주 묻는 질문 모음 ### Q. 봇이 대시보드에서는 시작(Started) 상태인데 디스코드 서버에서는 오프라인(Offline)으로 보입니다. * **A**: 디스코드 포털에서의 게이트웨이 인텐트(Gateway Intents) 누락이 원인일 가능성이 99%입니다. - 디스코드 개발자 센터 -> Bot 탭으로 가셔서 Privileged Gateway Intents 섹션 하단의 세 가지 권한(특히 Message Content Intent) 스위치를 모두 활성화한 뒤 저장해 주세요. - 코드가 다시 실행되도록 봇을 재기동해 주셔야 온전하게 온라인 마킹이 들어옵니다. 자세한 세부 조치는 [게이트웨이 인텐트 설정 가이드](/docs/discord/gateway-intents)를 참조하세요. --- ### Q. 평생 무료로 가동할 수 있는 봇 슬롯은 최대 몇 개까지인가요? * **A**: 디스호스트는 최초 가입 시 1개의 무료 기본 봇 슬롯을 제공합니다. - 만약 더 많은 봇을 동시에 독립 가동하고 싶다면, 커뮤니티 활동으로 포인트를 획득해 추가 봇 슬롯 (+1개) 확장권을 포인트 상점에서 구매하여 늘리실 수 있습니다. --- ### Q. 봇이 음성(보이스) 채널에 입장하여 노래를 재생(Streaming)할 수 있나요? * **A**: 음악 재생은 가능하지만 권장하지 않으며, 추가 의존성 세팅이 필요합니다. - 음악 봇 구동 시 오디오 변환을 위해 필수 도구인 ffmpeg 엔진이 컨테이너 내부 런타임 상에 사전 포함되어 있어야 합니다. - 디스호스트는 오디오 연동을 위해 경량화된 빌드 환경을 구축해두었으나, 다량의 음원 디코딩 및 보이스 스트리밍 연산은 CPU(25%) 및 128MB 램 메모리 한계를 순식간에 침범하여 OOM(메모리 부족) 137 크래시를 촉발합니다. - 되도록 소규모 서버용 핑퐁/안내봇 용도로 활용하시는 것을 권장합니다. --- ### Q. 봇에서 외부 웹 서버(Express, FastAPI)를 띄워 포트 연결을 수신할 수 있나요? * **A**: 기본 무료 플랜에서는 지원하지 않습니다. - 기본 무료 슬롯에서는 외부 접속(포트 포워딩 및 서브도메인 연동) 기능이 제한됩니다. 이 기능을 활용하여 외부 웹훅이나 대시보드 웹 서버 접속을 수신하시려면 업그레이드가 필요합니다.