b6e3cef844
- SKILL.md v1.1: full deployment workflow for 3x-ui on VPS via SSH - Covers Docker/native install, Nginx+TLS, Xray inbound config - references/xray-inbound-config.md: VLESS+WS+TLS and Reality configs - references/lessons-learned.md: lessons from first real deployment - /app/x-ui binary vs shell wrapper in Docker - correct API path: panel/api/inbounds/add - subPath-only DB write (subURI causes blank settings page) - --network host port exposure workaround - Agent prompt and eval configs included
165 lines
5.3 KiB
Markdown
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>xui/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 $http_upgrade;
|
|
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`).
|