commit fae4daeebe0cbf0c4efd153137bcaf379e67d441 Author: kappa Date: Mon Jan 12 11:57:32 2026 +0900 Initial commit: Xray 프록시 가이드 (XHTTP & Reality) - XHTTP 설정 가이드 - Reality 설정 가이드 - TLS 검열 우회 원리 - 트러블슈팅 가이드 diff --git a/README.md b/README.md new file mode 100644 index 0000000..837f81c --- /dev/null +++ b/README.md @@ -0,0 +1,808 @@ +# Xray 프록시 완벽 가이드: XHTTP & Reality + +> 검열 우회를 위한 스텔스 프록시 구축 가이드 +> +> 참고 영상: [How to Hide a Proxy Inside a Real Website (Xray + XHTTP)](https://www.youtube.com/watch?v=NziF6Srh-08) - LinuxCloudHacks + +--- + +## 목차 + +1. [핵심 개념](#핵심-개념) +2. [프로토콜 스택 이해](#프로토콜-스택-이해) +3. [XHTTP 설정](#xhttp-설정) +4. [Reality 설정](#reality-설정) +5. [XHTTP vs Reality 비교](#xhttp-vs-reality-비교) +6. [TLS와 검열 우회 원리](#tls와-검열-우회-원리) +7. [트러블슈팅](#트러블슈팅) +8. [참고 자료](#참고-자료) + +--- + +## 핵심 개념 + +### 현대 검열의 문제점 + +기존 VPN/프록시가 차단되는 이유: + +| 방식 | 탐지 방법 | +|------|----------| +| 일반 VPN | VPN 프로토콜 시그니처 탐지 | +| Shadowsocks | 랜덤 노이즈 패턴 → DPI가 "비정상" 판단 | +| 단순 프록시 | 특이한 포트, 서버 프로빙 시 프록시 응답 | + +### 해결책: 섞여들기 (Blending In) + +> "현대 검열은 숨김으로 이기는 게 아니라, **섞여들어감**으로 이긴다" + +- 일반 HTTPS 트래픽처럼 보이게 위장 +- 실제 웹사이트 또는 대형 사이트의 TLS를 활용 +- 클라이언트와 서버 양쪽 모두 위장 필요 + +--- + +## 프로토콜 스택 이해 + +### 3계층 구조 + +``` +┌─────────────────────────────────────────┐ +│ TLS (누구처럼) │ +│ - 암호화 │ +│ - 핑거프린트 위장 (UTLS → Chrome 흉내) │ +├─────────────────────────────────────────┤ +│ XHTTP (어떻게) │ +│ - HTTP POST/GET으로 데이터 전송 │ +│ - 일반 API 트래픽처럼 보임 │ +├─────────────────────────────────────────┤ +│ VLESS (무엇을) │ +│ - 프록시 프로토콜 │ +│ - 경량, 상태 비저장 │ +│ - UUID 기반 인증 │ +└─────────────────────────────────────────┘ +``` + +### VLESS 프레임 구조 + +``` +[버전][클라이언트ID][명령][포트][주소타입][주소][페이로드...] + 1B 16B 1B 2B 1B 가변 가변 +``` + +- **명령**: 1=TCP, 2=UDP +- **주소타입**: 1=IPv4, 2=도메인, 3=IPv6 +- **암호화 없음** → 전송 계층(TLS)에서 처리 + +### XHTTP 동작 방식 + +``` +클라이언트 → 서버: HTTP POST (세션ID + VLESS 프레임) +서버 → 클라이언트: HTTP GET (스트리밍 응답) +``` + +- 세션 ID로 다중 연결 관리 +- 병렬 POST 요청 가능 (Head-of-line blocking 회피) +- 일반 REST API 호출처럼 보임 + +--- + +## XHTTP 설정 + +### 아키텍처 + +``` +[클라이언트] + ↓ HTTPS (일반 브라우저처럼 보임) +[Nginx - Port 443] + ├── / (루트) → 실제 게임 웹사이트 + └── /api/stream (비밀 경로) → Xray (Port 8080) + ↓ + [인터넷] +``` + +### 준비물 + +- Linux 서버 (VPS/클라우드) +- **도메인** (필수) +- DNS 제공자 (Cloudflare 등) +- 포트 80, 443 오픈 + +### 서버 설정 + +#### 1. Nginx + Certbot 설치 + +```bash +apt update && apt install -y nginx certbot python3-certbot-nginx +``` + +#### 2. 위장용 웹사이트 배포 + +```bash +# 기본 페이지 삭제 후 게임 템플릿 다운로드 +rm /var/www/html/index.html +wget -O /var/www/html/index.html https://example.com/game-template.html +``` + +#### 3. SSL 인증서 발급 + +```bash +certbot certonly --webroot -w /var/www/html -d yourdomain.com +``` + +#### 4. Xray 설치 + +```bash +bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install +``` + +#### 5. UUID 생성 + +```bash +xray uuid +# 출력 예: a3482e88-686a-4a58-8126-99c9df64b060 +``` + +#### 6. Xray 서버 설정 + +`/usr/local/etc/xray/config.json`: + +```json +{ + "log": { + "loglevel": "warning" + }, + "inbounds": [ + { + "port": 8080, + "listen": "127.0.0.1", + "protocol": "vless", + "settings": { + "clients": [ + { + "id": "여기에-UUID-입력" + } + ], + "decryption": "none" + }, + "streamSettings": { + "network": "xhttp", + "xhttpSettings": { + "path": "/api/stream" + } + } + } + ], + "outbounds": [ + { + "protocol": "freedom" + } + ] +} +``` + +#### 7. Nginx 설정 + +`/etc/nginx/sites-available/xray`: + +```nginx +server { + listen 80; + server_name yourdomain.com; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + server_name yourdomain.com; + + ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; + + # 루트: 실제 웹사이트 (위장용) + location / { + root /var/www/html; + index index.html; + } + + # 비밀 경로: Xray로 프록시 + location /api/stream { + proxy_pass http://127.0.0.1:8080; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Connection ""; + proxy_buffering off; + proxy_read_timeout 300s; + } +} +``` + +```bash +ln -sf /etc/nginx/sites-available/xray /etc/nginx/sites-enabled/ +rm -f /etc/nginx/sites-enabled/default +nginx -t && systemctl reload nginx +systemctl restart xray +``` + +### 클라이언트 설정 + +#### CLI (config.json) + +```json +{ + "log": { + "loglevel": "warning" + }, + "inbounds": [ + { + "port": 1080, + "listen": "127.0.0.1", + "protocol": "socks" + } + ], + "outbounds": [ + { + "protocol": "vless", + "settings": { + "vnext": [ + { + "address": "yourdomain.com", + "port": 443, + "users": [ + { + "id": "서버와-동일한-UUID", + "encryption": "none" + } + ] + } + ] + }, + "streamSettings": { + "network": "xhttp", + "security": "tls", + "tlsSettings": { + "serverName": "yourdomain.com", + "fingerprint": "chrome" + }, + "xhttpSettings": { + "path": "/api/stream" + } + } + } + ] +} +``` + +#### V2rayN GUI 설정 + +| 항목 | 값 | +|------|-----| +| Address | yourdomain.com | +| Port | 443 | +| UUID | 서버와 동일 | +| Network | xhttp | +| Path | /api/stream | +| TLS | 활성화 | +| SNI | yourdomain.com | +| Fingerprint | chrome | + +--- + +## Reality 설정 + +### Reality란? + +> **도메인/인증서 없이, 대형 사이트의 TLS를 빌려 쓰는 기술** + +``` +[클라이언트] --TLS(SNI: www.microsoft.com)--> [내 서버:443] + ↓ + Reality가 TLS 처리 + (microsoft.com 인증서 흉내) + ↓ + [인터넷] +``` + +외부에서 보이는 것: `www.microsoft.com`에 접속 +실제: 내 VPS를 통해 터널링 + +### 준비물 + +- Linux 서버 (VPS/클라우드) +- 포트 443 오픈 +- **도메인 불필요!** + +### 서버 설정 + +#### 1. Xray 설치 + +```bash +bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install +``` + +#### 2. 키 생성 + +```bash +# UUID 생성 +xray uuid +# 출력 예: a3482e88-686a-4a58-8126-99c9df64b060 + +# X25519 키쌍 생성 +xray x25519 +# 출력 예: +# Private key: 2KZ4uouMKgI8nR-LDJNP1_MHisCJOmKGj9jUjZLncVU +# Public key: Z84J2IelR9ch3k8VtlVhhs5ycBUlXA7wHBWcBrjqnAw + +# Short ID 생성 +openssl rand -hex 8 +# 출력 예: 6ba85179e30d4fc2 +``` + +#### 3. 위장 사이트 선택 + +**선택 기준**: + +| 조건 | 설명 | +|------|------| +| 외국 사이트 | 검열 대상이 아닌 사이트 | +| TLSv1.3 지원 | 필수 | +| H2 지원 | HTTP/2 지원 필요 | +| 리다이렉트 없음 | URL이 다른 곳으로 이동하지 않음 | +| 서버와 가까운 지역 | 보너스 (속도 향상) | + +**추천 사이트**: +- `www.microsoft.com` +- `www.apple.com` +- `www.amazon.com` +- `www.cloudflare.com` +- `www.yahoo.com` + +#### 4. 서버 설정 파일 + +`/usr/local/etc/xray/config.json`: + +```json +{ + "log": { + "loglevel": "warning" + }, + "inbounds": [ + { + "listen": "0.0.0.0", + "port": 443, + "protocol": "vless", + "settings": { + "clients": [ + { + "id": "여기에-UUID-입력", + "flow": "xtls-rprx-vision" + } + ], + "decryption": "none" + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "dest": "www.microsoft.com:443", + "serverNames": [ + "www.microsoft.com", + "microsoft.com" + ], + "privateKey": "여기에-Private-Key-입력", + "shortIds": [ + "여기에-Short-ID-입력" + ] + } + }, + "sniffing": { + "enabled": true, + "destOverride": ["http", "tls"] + } + } + ], + "outbounds": [ + { + "protocol": "freedom", + "tag": "direct" + } + ] +} +``` + +```bash +systemctl restart xray +systemctl status xray +``` + +### 클라이언트 설정 + +#### CLI (config.json) + +```json +{ + "log": { + "loglevel": "warning" + }, + "inbounds": [ + { + "listen": "127.0.0.1", + "port": 1080, + "protocol": "socks" + } + ], + "outbounds": [ + { + "protocol": "vless", + "settings": { + "vnext": [ + { + "address": "서버-IP-주소", + "port": 443, + "users": [ + { + "id": "서버와-동일한-UUID", + "encryption": "none", + "flow": "xtls-rprx-vision" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "fingerprint": "chrome", + "serverName": "www.microsoft.com", + "publicKey": "서버의-Public-Key", + "shortId": "서버와-동일한-Short-ID" + } + }, + "tag": "proxy" + }, + { + "protocol": "freedom", + "tag": "direct" + } + ] +} +``` + +#### V2rayN GUI 설정 + +| 항목 | 값 | +|------|-----| +| Address | 서버 IP | +| Port | 443 | +| UUID | 생성한 UUID | +| Flow | xtls-rprx-vision | +| Network | tcp | +| TLS | reality | +| SNI | www.microsoft.com | +| Fingerprint | chrome | +| Public Key | 서버에서 생성한 공개키 | +| Short ID | 서버와 동일 | + +### Docker로 설정 (간편) + +#### docker-compose.yml + +```yaml +services: + xray: + image: ghcr.io/xtls/xray-core:latest + container_name: xray-reality + restart: unless-stopped + volumes: + - ./config.json:/usr/local/etc/xray/config.json:ro + ports: + - "443:443/tcp" +``` + +#### 키 생성 (Docker) + +```bash +docker run --rm ghcr.io/xtls/xray-core x25519 +docker run --rm ghcr.io/xtls/xray-core uuid +``` + +#### 실행 + +```bash +docker compose up -d +``` + +--- + +## XHTTP vs Reality 비교 + +### 기능 비교 + +| 구분 | XHTTP | Reality | +|------|-------|---------| +| 도메인 | 필요 | **불필요** | +| SSL 인증서 | 필요 (Let's Encrypt) | **불필요** | +| Nginx | 필요 | **불필요** | +| 설정 시간 | 30분+ | **5분** | +| CDN 통과 | **가능** | 불가 | +| 위장 방식 | 실제 웹사이트 운영 | 대형 사이트 TLS 흉내 | +| SNI 노출 | 내 도메인 | 대형 사이트 (microsoft.com 등) | + +### 사용 시나리오 + +#### Reality 사용 + +| 상황 | 이유 | +|------|------| +| 도메인 없음 | 도메인 구매/관리 불필요 | +| 빠른 설정 | 키 생성만으로 완료 | +| VPS만 있음 | IP 하나로 바로 시작 | +| 단순 우회 목적 | 복잡한 구성 불필요 | +| SNI 노출 걱정 | 대형 사이트로 위장 | + +#### XHTTP 사용 + +| 상황 | 이유 | +|------|------| +| CDN 필요 | Cloudflare 등 CDN 뒤에 숨기기 | +| IP 차단 환경 | VPS IP가 이미 차단된 경우 | +| 실제 서비스 운영 | 웹사이트 + 프록시 동시 운영 | +| 다수 사용자 | 여러 명에게 서비스 제공 | +| 서버 프로빙 대응 | 443 접속 시 실제 웹사이트 표시 | + +### 결정 가이드 + +``` +도메인이 없다 ──────────────────→ Reality + │ + ↓ 있다 +VPS IP가 차단됐다 ─────────────→ XHTTP + CDN + │ + ↓ 아니다 +SNI 노출이 걱정된다 ───────────→ Reality + │ + ↓ 괜찮다 +실제 웹사이트도 운영할 것이다 ──→ XHTTP + │ + ↓ 아니다 +빠른 설정을 원한다 ────────────→ Reality +``` + +--- + +## TLS와 검열 우회 원리 + +### TLS 핸드셰이크 구조 + +``` +[클라이언트] [서버] + │ │ + │─── Client Hello ──────────→│ 평문! (SNI 노출) + │ │ + │←── Server Hello ───────────│ + │←── Certificate ────────────│ + │←── Server Key Exchange ────│ + │ │ + │─── Client Key Exchange ───→│ + │─── Finished ──────────────→│ + │ │ + │←── Finished ───────────────│ + │ │ + [암호화 통신 시작] +``` + +### Client Hello 구조 + +``` +TLS Record Layer +├── Content Type: 0x16 (Handshake) +├── Version: 0x0301 +└── Handshake Protocol + ├── Type: 0x01 (Client Hello) + └── Client Hello Data + ├── Version: 0x0303 (TLS 1.2) + ├── Random: 32바이트 + ├── Session ID + ├── Cipher Suites (암호화 목록) + ├── Compression Methods + └── Extensions + ├── SNI (server_name) ← 평문 노출! + ├── Supported Versions + ├── Signature Algorithms + └── ... +``` + +### SNI 노출 문제 + +**SNI(Server Name Indication)**는 TLS 암호화 **전**에 평문으로 전송됨: + +``` +Extension: server_name +├── Type: 0x0000 (SNI) +└── Server Name + └── Name: "www.microsoft.com" ← ISP가 볼 수 있음 +``` + +| 방식 | SNI에 보이는 것 | 위험도 | +|------|----------------|--------| +| XHTTP | `myproxy.com` (내 도메인) | 도메인 차단 가능 | +| Reality | `www.microsoft.com` | 차단 어려움 | + +### DPI 핑거프린팅 + +검열 시스템이 Client Hello를 분석하는 방식: + +``` +Client Hello 수신 + ↓ +특징 추출: +- Cipher Suite 개수 및 순서 +- Extension 목록 및 순서 +- Supported Groups +- 전체 패킷 길이 + ↓ +데이터베이스 비교: +- Chrome: 일치 ✓ +- Firefox: 불일치 +- Python requests: 불일치 + ↓ +결과: "Chrome 브라우저로 판단" +``` + +### UTLS를 통한 위장 + +Xray는 **UTLS** 라이브러리를 사용하여 실제 브라우저의 Client Hello를 **바이트 단위로** 복제: + +```json +{ + "tlsSettings": { + "fingerprint": "chrome" // Chrome의 정확한 핑거프린트 사용 + } +} +``` + +복제하는 요소: +- Cipher Suites (암호화 알고리즘 목록 + 순서) +- Extensions (확장 목록 + 순서) +- Supported Groups (지원 곡선) +- Signature Algorithms (서명 알고리즘) +- ALPN (프로토콜 협상) +- Key Share (키 교환 데이터) + +### 서버 측 위장의 필요성 + +**양방향 모두 위장 필요**: + +| 방향 | 검사 대상 | 위장 주체 | +|------|----------|----------| +| Client → Server | Client Hello, SNI | 클라이언트 (UTLS) | +| Server → Client | 인증서, Server Hello | 서버 설정 | + +#### Reality 서버의 프로빙 대응 + +``` +정상 클라이언트 (올바른 shortId/publicKey): + ↓ +서버: "인증된 클라이언트" + ↓ +Reality 터널 연결 ✓ + +프로빙/스캐너 (shortId 없음): + ↓ +서버: "모르는 요청" + ↓ +실제 microsoft.com으로 포워딩 + ↓ +스캐너: "그냥 microsoft.com이네" → 의심 없음 +``` + +#### XHTTP 서버의 프로빙 대응 + +``` +일반 접속 (루트 경로): + ↓ +Nginx: 게임 웹사이트 표시 ✓ + +프록시 클라이언트 (비밀 경로): + ↓ +Nginx: Xray로 프록시 ✓ +``` + +--- + +## 트러블슈팅 + +### 공통 문제 + +| 문제 | 원인 | 해결 | +|------|------|------| +| 연결 안됨 | 방화벽 | 443 포트 오픈 확인 | +| 인증 실패 | UUID 불일치 | 서버/클라이언트 UUID 동일한지 확인 | +| 느린 속도 | 서버 위치 | 더 가까운 VPS 선택 | + +### XHTTP 문제 + +| 문제 | 원인 | 해결 | +|------|------|------| +| 502 Bad Gateway | Xray 미실행 | `systemctl status xray` 확인 | +| SSL 에러 | 인증서 만료 | `certbot renew` 실행 | +| 경로 불일치 | path 설정 | Nginx와 Xray의 path 동일한지 확인 | + +### Reality 문제 + +| 문제 | 원인 | 해결 | +|------|------|------| +| TLS 에러 | 위장 사이트 문제 | TLSv1.3 지원 사이트로 변경 | +| shortId 에러 | ID 불일치 | 서버/클라이언트 shortId 확인 | +| 키 에러 | 공개키/개인키 혼동 | 서버=개인키, 클라이언트=공개키 | + +### 연결 테스트 + +```bash +# 서버에서 Xray 상태 확인 +systemctl status xray +journalctl -u xray -f + +# 클라이언트에서 연결 테스트 +curl -x socks5h://127.0.0.1:1080 https://ipinfo.io +``` + +--- + +## 참고 자료 + +### 공식 문서 + +- [Project X 공식 문서](https://xtls.github.io/en/config/) +- [XTLS/Xray-core GitHub](https://github.com/XTLS/Xray-core) + +### 튜토리얼 + +- [Xray REALITY Tutorial - cscot](https://cscot.pages.dev/2023/03/02/Xray-REALITY-tutorial/) +- [XRAY XTLS Reality in Docker](https://linuxguidance.net/xray-xtls-reality-in-docker/) +- [XRAY XHTTP Behind Cloudflare CDN](https://linuxguidance.net/xray-xhttp-server-behind-cloudflares-cdn-in-docker/) +- [Coexisting Xray VLESS with XHTTP-Reality](https://henrywithu.com/coexisting-xray-vless-tcp-xtls-vision-and-vless-xhttp-reality-on-a-single-port/) + +### GitHub Discussions + +- [VLESS + TCP + REALITY + VISION 설정](https://github.com/XTLS/Xray-core/discussions/3518) +- [Xray + VLESS + Reality + Caddy](https://github.com/XTLS/Xray-core/discussions/4542) + +### 클라이언트 앱 + +- **Windows**: [v2rayN](https://github.com/2dust/v2rayN) +- **macOS**: [V2rayU](https://github.com/yanue/V2rayU) +- **Android**: [v2rayNG](https://github.com/2dust/v2rayNG) +- **iOS**: Shadowrocket (유료), Quantumult X + +--- + +## 부록: 빠른 설정 체크리스트 + +### Reality 설정 (5분) + +- [ ] VPS 준비 (포트 443 오픈) +- [ ] Xray 설치 +- [ ] UUID 생성 +- [ ] X25519 키쌍 생성 +- [ ] Short ID 생성 +- [ ] 서버 config.json 작성 +- [ ] 클라이언트 설정 + +### XHTTP 설정 (30분) + +- [ ] VPS 준비 (포트 80, 443 오픈) +- [ ] 도메인 준비 + DNS 설정 +- [ ] Nginx 설치 +- [ ] 위장용 웹사이트 배포 +- [ ] Certbot으로 SSL 인증서 발급 +- [ ] Xray 설치 +- [ ] UUID 생성 +- [ ] Xray config.json 작성 +- [ ] Nginx 설정 (루트 + 비밀 경로) +- [ ] 클라이언트 설정 + +--- + +*마지막 업데이트: 2025-01*