# 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*