- proxy: asyncio TCP proxy with handshake parser, domain whitelist, transparent backend tunneling, SQLite logging, mtime hot reload - api: FastAPI routes for config/domains/logs/status + restart trigger - frontend: React + Vite NPM-style dashboard (dashboard/domains/logs/settings) - nginx: reverse proxy for /api -> api:8000 and / -> frontend:3000 - docker-compose: full stack with shared data volume - replace spec mc-domain-filter.md with README.md
176 lines
6.5 KiB
Markdown
176 lines
6.5 KiB
Markdown
# MC Domain Filter Proxy
|
|
|
|
마인크래프트 서버 앞단에 두는 **도메인 화이트리스트 프록시 + 웹 관리 대시보드**.
|
|
|
|
클라이언트가 마인크래프트 서버 주소창에 입력한 도메인이 허용 목록과 일치할 때만 백엔드 MC 서버로 연결을 통과시킵니다. 외부에서 공유기의 공인 IP를 직접 입력해서 접속하는 경로를 차단할 수 있습니다.
|
|
|
|
## 기능
|
|
|
|
- 마인크래프트 핸드셰이크 패킷에서 클라이언트가 입력한 server address 파싱
|
|
- 허용 도메인 화이트리스트 매칭, 불일치 시 즉시 연결 종료
|
|
- 통과한 연결은 백엔드 MC 서버로 투명 TCP 중계
|
|
(Fabric / Paper / Spigot / NeoForge 등 서버 종류 무관)
|
|
- 설정 파일(`data/config.json`) 변경을 프록시가 자동 감지해 hot reload (재시작 불필요)
|
|
- 모든 연결 시도(허용 / 차단 / 에러)를 SQLite 에 기록
|
|
- 웹 대시보드 (NPM 스타일): 도메인 관리, 실시간 로그, 통계 카드, 백엔드/포트 설정
|
|
|
|
## 네트워크 구조
|
|
|
|
```
|
|
외부 인터넷
|
|
↓
|
|
공유기 (포트포워딩 25565 → Proxmox)
|
|
↓
|
|
mc-filter-proxy 컨테이너 (25565)
|
|
↓
|
|
게임PC 내부IP:25565 (실제 마인크래프트 서버)
|
|
```
|
|
|
|
## 빠른 시작
|
|
|
|
1. 저장소 클론
|
|
|
|
```bash
|
|
git clone https://git.tkrmagid.kr/tkrmagid/mc_domain_proxy.git
|
|
cd mc_domain_proxy
|
|
```
|
|
|
|
2. (선택) 초기 설정 파일을 미리 생성. 생략하면 프록시 첫 기동 시 기본값으로 자동 생성됩니다.
|
|
|
|
```bash
|
|
mkdir -p data
|
|
cat > data/config.json <<'EOF'
|
|
{
|
|
"proxy": { "listen_port": 25565, "enabled": true },
|
|
"backend": { "host": "192.168.0.20", "port": 25565 },
|
|
"allowed_domains": [
|
|
{ "domain": "mc.tkrmagid.kr", "enabled": true, "note": "메인 도메인" }
|
|
]
|
|
}
|
|
EOF
|
|
```
|
|
|
|
3. 전체 스택 빌드 & 실행
|
|
|
|
```bash
|
|
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 폴링, 변경 감지 시 메모리 캐시 재로드
|
|
- `listen_port` 나 `proxy.enabled` 가 바뀌면 리스너 자체를 재시작, 그 외(도메인/백엔드)는 다음 연결부터 즉시 적용
|
|
|
|
## 보안 권장
|
|
|
|
- **대시보드 포트(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 없이)
|
|
|
|
각 서비스는 독립적으로 실행 가능합니다.
|
|
|
|
```bash
|
|
# 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).
|