Skip to content
호스팅 · 서버 구성

봇용 서버 API

Millida Hosting 클라이언트 API를 알아보세요: 키 발급, 권한, 자체 봇이나 스크립트에서의 서버 관리와 콘솔 스트리밍.

업데이트 2026년 10월 13일

제어판에서 할 수 있는 모든 작업을 직접 작성한 코드로도 할 수 있어요. 일정에 따라 서버를 시작하고, Discord에 상태를 표시하고, 봇에서 명령을 보낼 수 있죠.

키

API는 유료 요금제라면 어디서든 사용할 수 있어요. 파일, SFTP, 팀 액세스가 있는 바로 그곳이에요. 무료 요금제에서는 키가 발급되지 않아요. 키는 동일한 공유 액세스를 봇용으로 제공하는 것뿐이거든요.

"플레이어 및 액세스" 섹션 → "API 키" → "발급"을 선택하세요. 키로 무엇을 할 수 있는지 확인하세요. 권한은 공유 액세스와 동일해요.

키는 한 번만 표시돼요. 저희는 지문만 저장하거든요. 분실했다면 새로 발급하고 이전 키는 폐기하세요.

키는 Authorization: Bearer mhk_live_... 헤더로 전달해요.

메서드

기본 URL — https://millida.net/v2/hosting/api.

메서드하는 일필요한 권한
GET /server서버 카드console
GET /status상태 및 온라인console
POST /start시작start
POST /stop중지start
POST /restart재시작start
POST /command콘솔에 명령 전송console
GET /console실시간 로그 (SSE)console
GET /files?path=파일 목록files
GET /files/configs폼에서 읽는 구성 파일files
GET /files/config?path=타입이 포함된 파일 설정files
POST /files/config파일 설정 변경files
GET /backups백업 목록backups
POST /backups백업 생성backups
GET /antibot안티봇 설정, 백엔드, 방화벽 규칙protection
PUT /antibot보호 설정 변경protection
GET /antibot/overview?range=hour, day, week 기준 연결 및 차단protection
POST /antibot/backends백엔드 추가 {"address":"host:port","label":"..."}protection
DELETE /antibot/backends/{id}백엔드 제거protection
POST /antibot/rules방화벽 규칙 {"kind":"allow"|"deny","cidr":"1.2.3.0/24"}protection
DELETE /antibot/rules/{id}규칙 제거protection
POST /antibot/verify-domain/check인증 페이지 도메인의 DNS 확인protection

예시: 서버를 시작하고 온라인이 될 때까지 기다리기

KEY="mhk_live_xxx"
API="https://millida.net/v2/hosting/api"

curl -sX POST "$API/start" -H "Authorization: Bearer $KEY"

until curl -s "$API/status" -H "Authorization: Bearer $KEY" | grep -q RUNNING; do
  sleep 5
done
echo "server online"

백업은 백그라운드에서 생성돼요

POST /backups는 즉시 {"id":"..."}를 반환하지만, 아카이브 자체는 노드에서 조립돼요. 몇 기가바이트짜리 월드는 몇 분이 걸리죠. GET /backups에서 status 필드로 준비 상태를 확인하세요. pending — 아직 조립 중, ready — 스토리지에 저장됨(이때 실제 sizeMb가 나타나요), failed — 조립 실패.

ID=$(curl -sX POST "$API/backups" -H "Authorization: Bearer $KEY" | jq -r .id)

until curl -s "$API/backups" -H "Authorization: Bearer $KEY" \
  | jq -e --arg id "$ID" '.[] | select(.id==$id) | select(.status=="ready")' >/dev/null; do
  sleep 15
done
echo "backup ready"

백업이 진행 중인 동안에는 같은 서버에서 두 번째 백업을 만들 수 없어요. 노드는 한 번에 하나씩 처리하거든요.

실시간 콘솔

GET /console은 Server-Sent Events 스트림을 반환해요. 각 줄은 data: 접두사와 함께 도착하죠. WebSocket은 필요 없어요. SSE는 어떤 프록시든 통과하니까요.

알아두면 좋은 점

  • 모든 키 작업은 서버 로그에 "API 키 N"이라는 작성자와 함께 기록돼요. 사람과 봇이 모두 서버를 운영할 때 바로 이게 필요하죠.
  • 속도 제한은 주소가 아니라 키 단위로 계산돼요. IP를 바꿔도 제한을 우회할 수 없고, 사무실 네트워크의 옆자리 사람이 제한을 소모하지도 않아요. 일반적인 자동화에는 넉넉하지만, 1초마다 상태를 폴링하면 제한에 걸려요. 10~15초에 한 번이면 충분해요. 콘솔 스트림은 분당 최대 열 번까지 열 수 있어요. 메시지마다 새로 여는 대신 연결 하나를 유지하세요.
  • 서버가 정지되거나 요금제가 더 이상 유료가 아니면 키는 즉시 작동을 멈춰요. 그 경우 수동으로 폐기할 필요는 없어요.
  • 서버당 최대 다섯 개의 키. 필요 없는 키는 폐기하세요.

안티봇 보호

GET /antibot은 두 필드로 설정을 반환해요. config — 서버 자체 설정이고, 아직 존재하지 않으면 null이며 서버는 기본값(default 필드)으로 보호돼요. effective는 항상 존재해요. 현재 적용 중이거나 첫 수정 후 서버가 사용하게 될 설정이죠. 여기서 값을 읽으세요.

PUT /antibot은 변경하려는 필드만 받아요.

curl -sX PUT "$API/antibot" -H "Authorization: Bearer $KEY"   -H 'Content-Type: application/json'   -d '{"preset":"balanced"}'

레벨(preset): off, under_attack, balanced, aggressive, custom. 레벨은 검사 값을 스스로 확장하므로, 수동 구성에는 custom을 선택하고 검사를 보내세요. checkCaptcha, checkPhysics, checkKeepAlive, checkTeleport, checkBrand, checkPing, checkTransfer, checkClientSettings — 각각 off, under_attack, always 중 하나예요. 주소 목록(vpnMode, datacenterMode, torMode) — off, log, block. 지역 필터 — geoMode(off, allow, deny)와 geoCountries(국가 코드, 예: ["RU","BY"]).

포워딩 시크릿은 API로 발급하거나 변경하지 않아요. 소유자에게만 제어판에 표시돼요.

구성 설정

GET /files/config?path=server.properties는 파싱된 파일을 반환해요. 각 항목에 타입, 현재 값, "재시작 필요" 플래그가 함께 나오죠.

{
  "path": "server.properties",
  "format": "properties",
  "options": [
    { "key": "pvp", "type": "boolean", "value": "true", "owner": "sync", "requiresRestart": false },
    { "key": "difficulty", "type": "select", "value": "normal", "values": ["peaceful", "easy", "normal", "hard"], "owner": "sync", "requiresRestart": false },
    { "key": "server-port", "type": "integer", "value": "25565", "owner": "platform", "requiresRestart": true }
  ]
}

owner는 해당 항목으로 무엇을 할 수 있는지 알려줘요. platform — 값이 호스팅에서 설정되며 수정은 거부돼요. sync — 항목이 제어판과 파일 양쪽에 존재해요. file — 파일만 알고 있는 항목이죠.

쓰기는 보내는 키만 변경하고, 파일의 나머지는 그대로 유지돼요.

curl -sX POST "$API/files/config" -H "Authorization: Bearer $KEY"   -H 'Content-Type: application/json'   -d '{"path":"server.properties","values":{"pvp":"false","difficulty":"hard"}}'

폼은 .properties, .yml/.yaml, .toml을 읽어요. 제어판이 전혀 모르는 플러그인 구성 파일도 포함되죠. 필드 타입은 값에서 추론해요. 중첩 키는 점으로 구분해요. settings.bungeecord, advanced.compression-threshold.

전체 파일은 여전히 GET/PUT /files/content?path=로 사용할 수 있어요. 두 경로 모두 같은 곳에 쓰거든요.

Node.js와 Python으로 만든 바로 사용 가능한 클라이언트

아래는 최소한의 클라이언트예요. 상태를 확인하고, 서버를 시작하고, 채팅에 메시지를 보내요. 키는 MILLIDA_KEY 환경 변수에서 가져와요. git에 올라가는 코드에 키를 붙여 넣지 마세요. 오류 응답은 message 필드가 있는 JSON이에요. 봇이 기록해야 하는 값이 바로 이것이에요.

Node.js 18+ (내장 fetch):

const API = 'https://millida.net/v2/hosting/api';
const KEY = process.env.MILLIDA_KEY;

async function call(method, path, body) {
  const res = await fetch(`${API}${path}`, {
    method,
    headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
    body: body ? JSON.stringify(body) : undefined,
  });
  if (!res.ok) throw new Error(`${method} ${path}: ${res.status} ${await res.text()}`);
  return res.status === 204 ? null : res.json();
}

const status = await call('GET', '/status');
if (status.status !== 'RUNNING') await call('POST', '/start');
await call('POST', '/command', { command: 'say Hello from the bot' });

requests 라이브러리를 사용하는 Python 3, 그리고 실시간 콘솔 읽기:

import os
import requests

API = "https://millida.net/v2/hosting/api"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['MILLIDA_KEY']}"

def call(method, path, body=None):
    res = session.request(method, API + path, json=body, timeout=15)
    res.raise_for_status()
    return res.json() if res.content else None

status = call("GET", "/status")
if status["status"] != "RUNNING":
    call("POST", "/start")
call("POST", "/command", {"command": "say Hello from the bot"})

with session.get(API + "/console", stream=True, timeout=None) as stream:
    for line in stream.iter_lines(decode_unicode=True):
        if line and line.startswith("data:"):
            print(line[5:].strip())
Minecraft 호스팅오프라인일 때도 서버가 실행돼요서버 만들기