Files
common-skills/skills/xui-deploy/references/xray-inbound-config.md
T
Team 881fbf6dbb fix: xui inbound client must have enable:true, fix WS nginx headers
- lessons-learned: add two critical issues from first real deployment
  1. client enable:false causes auto-removal by x-ui scheduler
  2. CF proxy strips Connection header, nginx must hardcode WS headers
- xray-inbound-config.md: fix API path, add enable:true to client,
  hardcode Upgrade/Connection headers in nginx WS location
2026-04-25 20:20:03 +08:00

165 lines
5.3 KiB
Markdown

# Recommended Xray Inbound Configuration
This reference covers the best protocol/transport combinations for security and performance,
and the API payloads to create them via the x-ui REST API.
## Protocol Recommendation (ranked)
| Rank | Protocol | Transport | TLS | Why |
|------|----------|-----------|-----|-----|
| ✅ Best | VLESS | WebSocket | TLS (via Nginx) | CDN-friendly, low overhead, widely supported |
| ✅ Best | VLESS | gRPC | TLS (via Nginx) | Multiplexed, low latency, CDN-friendly |
| Good | VLESS | TCP | XTLS/Reality | No CDN needed, excellent performance, anti-detection |
| Good | VMess | WebSocket | TLS (via Nginx) | Broad client support |
| Avoid | VMess | TCP | none | Detectable, no forward secrecy |
| Avoid | Shadowsocks | — | — | Blocked in many regions |
**Default recommendation**: VLESS + WebSocket + TLS, proxied through Nginx.
- Panel port stays on `127.0.0.1` (localhost-only)
- Nginx terminates TLS on 443 and forwards to the inbound port on `127.0.0.1`
- Inbound port also stays localhost-only (e.g. `127.0.0.1:10000`)
---
## Step-by-Step: Create VLESS + WS + TLS Inbound
### 1. Collect inbound parameters
Ask the user (or use defaults):
| Field | Default |
|-------|---------|
| Inbound port | `10000` |
| WS path | `/ws/` (use a random string for security) |
| Remark | `vless-ws` |
### 2. Create inbound via x-ui API
The x-ui panel exposes a REST API at `http://127.0.0.1:<panel_port><base_path>`.
Authenticate with a session cookie first, then POST the inbound.
```bash
# 1. Login and save session cookie
PANEL_USER=$(bash /repo/common-skills/tools/kp-get.sh "<entry_title>" UserName)
PANEL_PASS=$(bash /repo/common-skills/tools/kp-get.sh "<entry_title>" Password)
ssh -i <key_path> -p <ssh_port> <user>@<host> "
curl -sc /tmp/xui-cookie.txt \
-X POST http://127.0.0.1:<panel_port><base_path>login \
-H 'Content-Type: application/json' \
-d '{\"username\":\"'\"$PANEL_USER\"'\",\"password\":\"'\"$PANEL_PASS\"'\"}'
"
# 2. Generate a UUID for the client
UUID=$(ssh -i <key_path> -p <ssh_port> <user>@<host> "cat /proc/sys/kernel/random/uuid")
# 3. Create VLESS + WebSocket inbound
ssh -i <key_path> -p <ssh_port> <user>@<host> "
curl -sb /tmp/xui-cookie.txt \
-X POST http://127.0.0.1:<panel_port><base_path>panel/api/inbounds/add \
-H 'Content-Type: application/json' \
-d '{
\"remark\": \"vless-ws\",
\"enable\": true,
\"protocol\": \"vless\",
\"listen\": \"127.0.0.1\",
\"port\": 10000,
\"settings\": \"{\\\"clients\\\":[{\\\"id\\\":\\\"'\"$UUID\"'\\\",\\\"flow\\\":\\\"\\\"}],\\\"decryption\\\":\\\"none\\\"}\",
\"streamSettings\": \"{\\\"network\\\":\\\"ws\\\",\\\"wsSettings\\\":{\\\"path\\\":\\\"/ws/\\\"}}\",
\"sniffing\": \"{\\\"enabled\\\":true,\\\"destOverride\\\":[\\\"http\\\",\\\"tls\\\"]}\"
}'
"
```
### 3. Add Nginx location for the WS path
Append to the existing Nginx config (`/etc/nginx/conf.d/x-ui.conf`):
```nginx
location /ws/ {
proxy_pass http://127.0.0.1:10000;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
proxy_set_header Connection upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400s;
}
```
Reload Nginx: `systemctl reload nginx`
### 4. Report client config
Output the connection info for the user to import into their client (v2rayN, Clash, etc.):
```
Protocol : VLESS
Address : <domain>
Port : 443
UUID : <uuid>
Transport: WebSocket
Path : /ws/
TLS : TLS
SNI : <domain>
```
Or generate a VLESS share link:
```
vless://<uuid>@<domain>:443?encryption=none&security=tls&type=ws&path=%2Fws%2F&sni=<domain>#vless-ws
```
---
## Alternative: VLESS + Reality (no CDN, no domain needed)
Reality is the best option when no domain is available. It mimics a real TLS handshake against a target site.
```bash
# Generate Reality key pair inside the container/host
ssh -i <key_path> -p <ssh_port> <user>@<host> \
"docker exec x-ui xray x25519" # Docker
# or: xray x25519 # native
```
Save the `Private key` and `Public key` output.
Create inbound via API (replace keys and port):
```json
{
"remark": "vless-reality",
"enable": true,
"protocol": "vless",
"listen": "",
"port": 443,
"settings": "{\"clients\":[{\"id\":\"<uuid>\",\"flow\":\"xtls-rprx-vision\"}],\"decryption\":\"none\"}",
"streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"realitySettings\":{\"show\":false,\"dest\":\"www.microsoft.com:443\",\"serverNames\":[\"www.microsoft.com\"],\"privateKey\":\"<private_key>\",\"shortIds\":[\"\"]}}"
}
```
Client connection info:
```
Protocol : VLESS
Address : <vps_ip>
Port : 443
UUID : <uuid>
Flow : xtls-rprx-vision
Transport : TCP
Security : Reality
PublicKey : <public_key>
SNI : www.microsoft.com
```
> Note: Reality listens on `0.0.0.0:443` (must be public). This is intentional — it's the proxy traffic port, not the panel.
---
## Security Hardening for Inbounds
- Always set `"listen": "127.0.0.1"` for WS/gRPC inbounds (Nginx handles public exposure).
- Use a random UUID per client; rotate periodically.
- Use a non-obvious WS path (e.g. `/a3f9k2/` not `/ws/`).
- Enable sniffing (`destOverride: ["http","tls"]`) to block DNS leaks.
- For Reality, use a high-traffic legitimate domain as `dest` (e.g. `www.microsoft.com`, `www.apple.com`).