Files
runbooks/xray-proxy-guide.md
kappa 53a655d4d5 Initial commit: Add runbooks collection
- anvil-load-test-report.md
- claude_communication_flow.md
- incus-crowdsec-architecture.md
- incus-meilisearch-manual.md
- kitty-setup-guide.md
- OpenAppSec_WAF_Operations_Guide.md
- openappsec-setup-20250817.md
- xray-proxy-guide.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 00:31:54 +09:00

19 KiB

Xray 프록시 완벽 가이드: XHTTP & Reality

검열 우회를 위한 스텔스 프록시 구축 가이드

참고 영상: How to Hide a Proxy Inside a Real Website (Xray + XHTTP) - LinuxCloudHacks


목차

  1. 핵심 개념
  2. 프로토콜 스택 이해
  3. XHTTP 설정
  4. Reality 설정
  5. XHTTP vs Reality 비교
  6. 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 설치

apt update && apt install -y nginx certbot python3-certbot-nginx

2. 위장용 웹사이트 배포

# 기본 페이지 삭제 후 게임 템플릿 다운로드
rm /var/www/html/index.html
wget -O /var/www/html/index.html https://example.com/game-template.html

3. SSL 인증서 발급

certbot certonly --webroot -w /var/www/html -d yourdomain.com

4. Xray 설치

bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install

5. UUID 생성

xray uuid
# 출력 예: a3482e88-686a-4a58-8126-99c9df64b060

6. Xray 서버 설정

/usr/local/etc/xray/config.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:

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;
    }
}
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)

{
  "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 -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install

2. 키 생성

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

{
  "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"
    }
  ]
}
systemctl restart xray
systemctl status xray

클라이언트 설정

CLI (config.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

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)

docker run --rm ghcr.io/xtls/xray-core x25519
docker run --rm ghcr.io/xtls/xray-core uuid

실행

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를 바이트 단위로 복제:

{
  "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 확인
키 에러 공개키/개인키 혼동 서버=개인키, 클라이언트=공개키

연결 테스트

# 서버에서 Xray 상태 확인
systemctl status xray
journalctl -u xray -f

# 클라이언트에서 연결 테스트
curl -x socks5h://127.0.0.1:1080 https://ipinfo.io

참고 자료

공식 문서

튜토리얼

GitHub Discussions

클라이언트 앱


부록: 빠른 설정 체크리스트

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