Files
mc_domain_proxy/README.md
claude-bot 58b112e449 feat: per-domain backend routing
Each allowed_domains entry can now carry its own backend {host, port}.
That lets one proxy on port 25565 serve multiple MC servers, picking
the upstream from the domain the client typed.

- proxy/main.py: ProxyState.backend_for(domain) → tuple|None,
  honors per-domain backend first, falls back to top-level backend.
  handle_client uses backend_for(); blocked / disabled domains
  return None (and still get a Login Disconnect on join attempts).
- api/routes/{config,domains}.py: DomainBackend model + optional
  backend field on create/patch. PATCH supports clear_backend=true
  to drop a per-domain override and revert to default.
- frontend/Domains.jsx: full rewrite — new-domain form has host/port
  inputs, table shows each row's effective backend, inline edit +
  reset button per row.
- frontend/Settings.jsx: backend section relabeled "기본 백엔드 (fallback)"
- README updated with multi-server example config.
2026-05-23 17:25:14 +09:00

7.6 KiB

MC Domain Filter Proxy

마인크래프트 서버 앞단에 두는 도메인 화이트리스트 프록시 + 웹 관리 대시보드.

클라이언트가 마인크래프트 서버 주소창에 입력한 도메인이 허용 목록과 일치할 때만 백엔드 MC 서버로 연결을 통과시킵니다. 외부에서 공유기의 공인 IP를 직접 입력해서 접속하는 경로를 차단할 수 있습니다.

기능

  • 마인크래프트 핸드셰이크 패킷에서 클라이언트가 입력한 server address 파싱
  • 허용 도메인 화이트리스트 매칭, 불일치 시 Login Disconnect 패킷으로 차단 사유(커스텀 가능) 표시 후 연결 종료
  • 통과한 연결은 백엔드 MC 서버로 투명 TCP 중계 (Fabric / Paper / Spigot / NeoForge 등 서버 종류 무관)
  • 도메인별 백엔드 라우팅: 도메인마다 다른 IP:포트로 보낼 수 있어 하나의 25565 포트로 여러 MC 서버를 동시에 운영 가능 (예: mc.tkrmagid.kr → 게임PC:25565, creative.tkrmagid.kr → NAS:25566)
  • 설정 파일(data/config.json) 변경을 프록시가 자동 감지해 hot reload (재시작 불필요)
  • 모든 연결 시도(허용 / 차단 / 에러)를 SQLite 에 기록
  • 웹 대시보드 (NPM 스타일): 도메인 관리, 실시간 로그, 통계 카드, 백엔드/포트 설정

네트워크 구조

외부 인터넷
    ↓
공유기 (포트포워딩 25565 → Proxmox)
    ↓
mc-filter-proxy 컨테이너 (25565)
    ↓
게임PC 내부IP:25565 (실제 마인크래프트 서버)

빠른 시작

  1. 저장소 클론

    git clone https://git.tkrmagid.kr/tkrmagid/mc_domain_proxy.git
    cd mc_domain_proxy
    
  2. (선택) 초기 설정 파일을 미리 생성. 생략하면 프록시 첫 기동 시 기본값으로 자동 생성됩니다.

    mkdir -p data
    cat > data/config.json <<'EOF'
    {
      "proxy":   { "listen_port": 25565, "enabled": true },
      "backend": { "host": "192.168.0.20", "port": 25565 },
      "block_message": "이 서버는 허용된 도메인에서만 접속 가능합니다.",
      "allowed_domains": [
        { "domain": "mc.tkrmagid.kr", "enabled": true, "note": "메인 서버" },
        { "domain": "creative.tkrmagid.kr", "enabled": true, "note": "크리에이티브",
          "backend": { "host": "192.168.0.21", "port": 25566 } }
      ]
    }
    EOF
    

    각 도메인 entry 에 backend 필드가 있으면 그 host:port 로, 없으면 top-level backend 로 라우팅됩니다.

  3. 전체 스택 빌드 & 실행

    docker compose up -d --build
    
  4. 접속

    • 마인크래프트 클라이언트: mc.tkrmagid.kr (또는 등록한 도메인)
    • 대시보드: http://<Proxmox-IP>:8080

구성 요소

서비스 포트 설명
proxy 25565 (외부) asyncio TCP 프록시, 핸드셰이크 파싱
api 8000 (내부) FastAPI, 설정/로그/통계 REST API
frontend 3000 (내부) React + Vite SPA
nginx 8080 (외부) 대시보드 리버스 프록시

data/ 디렉터리는 모든 서비스가 공유 볼륨으로 마운트해 config.json, logs.db 를 공용합니다.

API

메서드 경로 설명
GET /api/config 전체 설정 조회
PUT /api/config 전체 설정 저장
GET /api/domains 허용 도메인 목록
POST /api/domains 도메인 추가
PATCH /api/domains/{domain} 활성/메모 변경
DELETE /api/domains/{domain} 도메인 삭제
GET /api/logs?limit&offset&action 접속 로그 (페이지네이션)
GET /api/status 프록시 상태 + 통계
POST /api/proxy/restart config 파일 touch (프록시 재로드 트리거)

Hot reload 동작

  • API 가 data/config.json 을 atomic rename (tempfile + os.replace) 으로 갱신
  • 프록시가 2초 간격으로 mtime 폴링, 변경 감지 시 메모리 캐시 재로드
  • proxy.enabled 가 바뀌면 리스너를 재시작 (켜기/끄기), 그 외(도메인/백엔드)는 다음 연결부터 즉시 적용
  • POST /api/proxy/restart 는 별도 신호 파일(data/restart.signal)을 touch 해서 프록시가 listener 를 강제로 stop → start 한다 (config 변경이 없어도 동작)

리스닝 포트 변경: proxy.listen_port 는 docker-compose 의 ports 매핑과 짝이라 대시보드에서 편집할 수 없습니다. 바꾸려면 data/config.jsondocker-compose.yml25565:25565 매핑을 함께 수정한 뒤 docker compose up -d --force-recreate proxy 하세요.

보안 권장

  • 대시보드 포트(8080)는 외부 포트포워딩 금지. Proxmox 내부망 / VPN / SSH 터널을 통해서만 접근하세요.
  • API 에는 인증이 없으므로 외부에 노출해야 하는 경우 nginx 앞단에 basic auth 또는 OAuth proxy 를 추가하세요.
  • 프록시 컨테이너는 핸드셰이크 단계에서만 패킷을 검사하고, 그 외에는 단순 TCP 중계라서 MC 프로토콜 변경에 영향을 받지 않습니다.

디렉터리 구조

.
├── proxy/             # asyncio TCP 프록시
│   ├── main.py
│   ├── handshake.py
│   ├── config.py
│   ├── requirements.txt
│   └── Dockerfile
├── api/               # FastAPI 백엔드
│   ├── main.py
│   ├── config_io.py
│   ├── routes/
│   │   ├── config.py
│   │   ├── domains.py
│   │   ├── logs.py
│   │   └── status.py
│   ├── requirements.txt
│   └── Dockerfile
├── frontend/          # React + Vite 대시보드
│   ├── src/
│   │   ├── pages/
│   │   │   ├── Dashboard.jsx
│   │   │   ├── Domains.jsx
│   │   │   ├── Logs.jsx
│   │   │   └── Settings.jsx
│   │   ├── App.jsx
│   │   ├── api.js
│   │   ├── main.jsx
│   │   └── styles.css
│   ├── index.html
│   ├── vite.config.js
│   ├── package.json
│   └── Dockerfile
├── nginx/
│   └── nginx.conf
├── data/              # 런타임 데이터 (git 무시; config.json, logs.db)
└── docker-compose.yml

로컬 개발 (Docker 없이)

각 서비스는 독립적으로 실행 가능합니다.

# proxy
cd proxy
MC_CONFIG_PATH=$(pwd)/../data/config.json \
MC_LOG_DB=$(pwd)/../data/logs.db \
python main.py

# api (다른 터미널)
cd api
pip install -r requirements.txt
MC_CONFIG_PATH=$(pwd)/../data/config.json \
MC_LOG_DB=$(pwd)/../data/logs.db \
uvicorn main:app --reload --port 8000

# frontend (또 다른 터미널)
cd frontend
npm install
npm run dev   # http://localhost:3000, /api 는 8000 으로 자동 프록시

환경 변수

변수 기본값 적용 서비스
MC_CONFIG_PATH /data/config.json proxy, api
MC_LOG_DB /data/logs.db proxy, api

라이선스

내부 사용 (TkrMagid).