deploying-xray-nodes

Deploys TCP Trojan proxy nodes on Xray-core with certbot Let's Encrypt or self-signed EC P-256 + SHA-256 certificate fingerprint pinning, TCP Fast Open kernel tuning with BBR, nginx-compatible fallback site, gRPC user sync (not HTTP auth callback), and systemd hardening with strict filesystem isolation. Use when deploying a Trojan node on Xray, pinning a self-signed cert fingerprint, configuring TCP Fast Open, or setting up the Xray gRPC stats API. Not for Hysteria2 — see deploying-hy2-nodes.

11 stars

Best use case

deploying-xray-nodes is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Deploys TCP Trojan proxy nodes on Xray-core with certbot Let's Encrypt or self-signed EC P-256 + SHA-256 certificate fingerprint pinning, TCP Fast Open kernel tuning with BBR, nginx-compatible fallback site, gRPC user sync (not HTTP auth callback), and systemd hardening with strict filesystem isolation. Use when deploying a Trojan node on Xray, pinning a self-signed cert fingerprint, configuring TCP Fast Open, or setting up the Xray gRPC stats API. Not for Hysteria2 — see deploying-hy2-nodes.

Teams using deploying-xray-nodes should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/deploying-xray-nodes/SKILL.md --create-dirs "https://raw.githubusercontent.com/Buywatermelon/tunpilot/main/plugin/skills/deploying-xray-nodes/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/deploying-xray-nodes/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How deploying-xray-nodes Compares

Feature / Agentdeploying-xray-nodesStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Deploys TCP Trojan proxy nodes on Xray-core with certbot Let's Encrypt or self-signed EC P-256 + SHA-256 certificate fingerprint pinning, TCP Fast Open kernel tuning with BBR, nginx-compatible fallback site, gRPC user sync (not HTTP auth callback), and systemd hardening with strict filesystem isolation. Use when deploying a Trojan node on Xray, pinning a self-signed cert fingerprint, configuring TCP Fast Open, or setting up the Xray gRPC stats API. Not for Hysteria2 — see deploying-hy2-nodes.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# TunPilot Xray-core Trojan Node Deployment

Deploy a production-grade Xray-core Trojan proxy node with automatic performance tuning, security hardening, and certificate fingerprint pinning.

**Prerequisite:** TunPilot server running and `tunpilot` CLI configured (use `getting-started` skill if not). All TunPilot operations below go through the CLI.

**Auxiliary files (read when referenced below):**

- [xray-template.md](xray-template.md) — config templates (ACME / self-signed variants)
- [../_shared/DIAG_SETUP.md](../_shared/DIAG_SETUP.md) — diagnostic tooling install
- [../_shared/SYSTEMD_HARDENING.md](../_shared/SYSTEMD_HARDENING.md) — hardening drop-in template
- [../_shared/SSH_TROUBLESHOOTING.md](../_shared/SSH_TROUBLESHOOTING.md) — generic SSH/systemd issues

---

## Phase 1: Gather Information & Probe Server

### 1.1 Ask the User

- **SSH destination** — e.g. `root@node1.example.com` or SSH config alias
- **Domain name** (optional) — if none, self-signed + fingerprint pinning will be used
- **Node name** — human-readable label (e.g. `tokyo-trojan`)

### 1.2 Test SSH

```bash
ssh <server> "echo ok"
```

### 1.3 Probe Server (single SSH round trip)

```bash
ssh <server> bash <<'PROBE'
echo "=== OS/ARCH ==="
uname -s -m
cat /etc/os-release 2>/dev/null | grep -E '^(ID|VERSION_ID)='
echo "=== CPU ==="
nproc
echo "=== MEMORY ==="
free -b | awk '/Mem/{print $2}'
echo "=== PORT CONFLICTS ==="
ss -tulnp | grep -E ':443|:80' || echo "no conflicts"
echo "=== FIREWALL ==="
if command -v ufw &>/dev/null; then echo "ufw"; ufw status 2>/dev/null
elif command -v firewall-cmd &>/dev/null; then echo "firewalld"; firewall-cmd --state 2>/dev/null
elif command -v nft &>/dev/null; then echo "nftables"
else echo "none"
fi
echo "=== EXISTING XRAY ==="
xray version 2>/dev/null || echo "not installed"
echo "=== NETWORK ==="
ip -4 addr show scope global 2>/dev/null
ip -6 addr show scope global 2>/dev/null
echo "=== SYSCTL ==="
sysctl -n net.core.rmem_max net.core.wmem_max net.core.somaxconn \
  net.ipv4.tcp_congestion_control net.core.default_qdisc net.ipv4.tcp_fastopen 2>/dev/null
echo "=== DISK ==="
df -h / 2>/dev/null
PROBE
```

### 1.4 Build Server Profile

| Parameter | Source | Derived Setting |
|-----------|--------|-----------------|
| Memory | `free -b` | TCP buffer sizes (rmem/wmem) |
| CPU cores | `nproc` | Connection capacity |
| Port conflicts | `ss -tulnp` | Whether TCP/443 and TCP/80 are available |
| Firewall type | probe | ufw / firewall-cmd / manual |
| Kernel tuning | sysctl | Skip 2.1 if BBR + somaxconn + TFO already set |
| Existing Xray | version check | Fresh install vs upgrade |

### 1.5 Confirm With User

- **TLS strategy** — ACME (requires domain) vs self-signed + SHA-256 fingerprint pinning
- **Fallback site** — what to serve on port 80 for non-Trojan traffic (default: skip; nginx can be added later)
- **gRPC API port** — default `10085`

---

## Phase 2: Deploy

### 2.1 Kernel Tuning

Skip if probe showed values already tuned.

```bash
ssh <server> bash <<'SYSCTL'
cat > /etc/sysctl.d/99-xray.conf << 'EOF'
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.somaxconn = 4096
net.ipv4.tcp_fastopen = 3
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
sysctl -p /etc/sysctl.d/99-xray.conf
SYSCTL
```

### 2.2 Install Xray-core

```bash
ssh <server> 'apt-get update -qq && apt-get install -y -qq unzip curl && bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install'
ssh <server> "xray version"
```

### 2.3 Install Diagnostic Tooling

Read [../_shared/DIAG_SETUP.md](../_shared/DIAG_SETUP.md) and run both steps on this server.

### 2.4 TLS Certificate

**Config A — Domain + certbot standalone:**

Keep cert management separate from Xray via certbot. Auto-reload Xray on renewal via a post-hook:

```bash
ssh <server> bash <<'ACME'
command -v certbot &>/dev/null || apt-get install -y certbot
ss -tlnp | grep ':80 ' && echo "WARNING: port 80 in use — stop it first" || echo "port 80 available"

certbot certonly --standalone -d {{DOMAIN}} --non-interactive --agree-tos --email admin@{{DOMAIN}}

mkdir -p /etc/xray
ln -sf /etc/letsencrypt/live/{{DOMAIN}}/fullchain.pem /etc/xray/cert.pem
ln -sf /etc/letsencrypt/live/{{DOMAIN}}/privkey.pem  /etc/xray/key.pem

cat > /etc/letsencrypt/renewal-hooks/post/restart-xray.sh << 'HOOK'
#!/bin/bash
systemctl restart xray
HOOK
chmod +x /etc/letsencrypt/renewal-hooks/post/restart-xray.sh
ACME
```

**Config B — Self-signed EC P-256 + SHA-256 fingerprint pinning:**

```bash
ssh <server> bash <<'SELFSIGN'
mkdir -p /etc/xray
openssl req -x509 -newkey ec \
  -pkeyopt ec_paramgen_curve:prime256v1 \
  -keyout /etc/xray/key.pem \
  -out /etc/xray/cert.pem \
  -days 3650 -nodes \
  -subj '/CN=bing.com'

echo "=== Certificate SHA-256 Fingerprint ==="
openssl x509 -in /etc/xray/cert.pem -noout -fingerprint -sha256 | sed 's/://g' | cut -d= -f2
SELFSIGN
```

**Save the fingerprint** — used in `add_node` (2.5) and embedded in subscription configs so clients can verify the cert despite self-signed status.

### 2.5 Register Node in TunPilot

Run `tunpilot node add`. Note: **Trojan/Xray uses gRPC sync** rather than HTTP auth callback, so the returned `auth_callback_url` is not consumed by the client.

```bash
tunpilot node add \
  --name <node-name> \
  --host <server-ip-or-domain> \
  --port 443 \
  --protocol trojan \
  --stats-port 10085 \
  --sni <domain-or-omit> \
  --cert-path /etc/xray/cert.pem \
  --ssh-user root --ssh-port 22 \
  --insecure <0-if-acme-or-1-if-selfsigned> \
  --cert-fingerprint <hex-sha256-without-colons>  # Config B only
```

### 2.6 Write Xray Config

Read [xray-template.md](xray-template.md) and pick:

- **Config A (ACME)** — cert paths point to Let's Encrypt symlinks
- **Config B (Self-signed)** — cert paths point to `/etc/xray/*.pem` directly

Fill placeholders, then:

```bash
ssh <server> "cat > /usr/local/etc/xray/config.json << 'CONF'
<filled config from template>
CONF"
```

### 2.7 Systemd Hardening

Read [../_shared/SYSTEMD_HARDENING.md](../_shared/SYSTEMD_HARDENING.md) and apply with:

- `{{SERVICE}}` = `xray`
- `{{READ_WRITE_PATHS}}` = `/usr/local/etc/xray /etc/xray /var/log/xray`
- `{{CAPABILITIES}}` — omit both `AmbientCapabilities` and `CapabilityBoundingSet` lines; Xray runs as root and does not need them.

### 2.8 Firewall

Trojan is TCP-only (unlike Hysteria2 which is UDP):

```bash
ssh <server> bash <<'FIREWALL'
if command -v ufw &>/dev/null; then
  ufw allow 443/tcp && ufw allow 80/tcp && ufw reload
elif command -v firewall-cmd &>/dev/null; then
  firewall-cmd --permanent --add-port=443/tcp
  firewall-cmd --permanent --add-port=80/tcp
  firewall-cmd --reload
else
  echo "No firewall manager — ensure TCP/443 and TCP/80 are open at provider level"
fi
FIREWALL
```

### 2.9 Start Service & Sync Users

```bash
ssh <server> "systemctl enable --now xray && sleep 2 && systemctl is-active xray"
```

If inactive:

```bash
ssh <server> "journalctl -u xray --no-pager -n 50"
```

Once running, run `tunpilot node sync` to push all assigned users to the node via gRPC. Unlike Hysteria2, Xray needs an explicit sync because it does not authenticate via HTTP callback.

---

## Phase 3: Verify

### 3.1 Health Check

```bash
tunpilot health <node-id>
```

### 3.2 gRPC API

```bash
ssh <server> "xray api statsquery --server=127.0.0.1:10085"
```

Returns stats (possibly empty if no traffic yet). If the command errors, verify the `api` block in the Xray config and that `10085` is listening.

### 3.3 Deployment Summary

Report to user: node name and ID, server IP/domain, protocol (Trojan) and port, TLS type, certificate fingerprint (if self-signed), gRPC API port, kernel tuning status, health check result, and subscription instructions (`tunpilot user update <user-id> --nodes <node-id>,…` to grant access, then `tunpilot node sync` to push users).

---

## Troubleshooting

| Symptom | Diagnosis | Fix |
|---------|-----------|-----|
| `tunpilot health` shows unreachable | gRPC API not accessible | Verify `stats_port` matches Xray `api.listen`; check SSH connectivity |
| Service won't start | Config syntax error | `xray run -test -c /usr/local/etc/xray/config.json` validates JSON; then `journalctl -u xray --no-pager -n 50` |
| ACME cert fails | DNS misconfig or port 80 occupied | `dig <domain>`; `ss -tlnp \| grep ':80 '` |
| Clients can't connect | Firewall blocking TCP/443 | `ss -tlnp \| grep 443`; test with `nc -z <ip> 443` |
| gRPC sync fails | Xray API not listening | Verify `api` block; `ss -tlnp \| grep 10085` |
| Users authenticate but get no quota | Users not synced after assign | Run `tunpilot node sync` |
| Certificate pinning errors | Fingerprint mismatch | Re-extract: `openssl x509 -in /etc/xray/cert.pem -noout -fingerprint -sha256` and update via `tunpilot node update <id> --cert-fingerprint <hex>` |

For generic SSH / systemd issues, see [../_shared/SSH_TROUBLESHOOTING.md](../_shared/SSH_TROUBLESHOOTING.md).

---

## CLI Reference

| Command | Use When |
|---------|----------|
| `tunpilot node list` | See all registered nodes |
| `tunpilot node add --protocol trojan …` | Register a new node (Phase 2.5) |
| `tunpilot node update <id> …` | Change node config (port, SNI, fingerprint, enable/disable) |
| `tunpilot node remove <id>` | Delete a node (cascades user assignments) |
| `tunpilot health [<id>]` | Verify node reachability |
| `tunpilot node sync` | Push users to Trojan nodes via gRPC (Phase 2.9) |
| `tunpilot traffic --node <id>` | Query traffic usage |
| `tunpilot user update <id> --nodes <node-id>,…` | Grant a user access to specific nodes |
| `tunpilot sub create --user <id> --format <format>` | Generate a subscription link |

Related Skills

testing-nodes

11
from Buywatermelon/tunpilot

Runs IP reputation checks (risk scores, streaming unlock, blacklists via 9 providers) and network performance tests (BGP, latency, speed, routing to 31 Chinese provinces) on proxy nodes via SSH. Generates structured health reports with actionable recommendations. Use when testing proxy node quality, checking IP risk scores, verifying streaming unlock status, running speed tests, diagnosing latency, or comparing multiple nodes side-by-side.

deploying-hy2-nodes

11
from Buywatermelon/tunpilot

Deploys UDP/QUIC Hysteria2 proxy nodes with Brutal or BBR congestion control, inline ACME (or self-signed EC P-256), HTTP masquerade, QUIC receive/send window tuning based on server memory, systemd hardening with CAP_NET_ADMIN, and HTTP auth callback registration in TunPilot. Use when deploying a new Hysteria2 node, choosing Brutal vs BBR, tuning QUIC windows, setting up masquerade, or switching between ACME and self-signed TLS. Not for Xray/Trojan — see deploying-xray-nodes.

getting-started

11
from Buywatermelon/tunpilot

Deploys TunPilot server via SSH, wires up the local `tunpilot` CLI or web admin, and verifies end-to-end connectivity. Use when installing TunPilot, deploying the server, configuring remote access, updating an existing installation, or setting up TunPilot for the first time.

deploying-tailscale-for-zero-trust-vpn

16
from plurigrid/asi

Deploy and configure Tailscale as a WireGuard-based zero trust mesh VPN with identity-aware access controls, ACLs, and exit nodes for secure peer-to-peer connectivity.

deploying-software-defined-perimeter

16
from plurigrid/asi

Deploy a Software-Defined Perimeter using the CSA v2.0 specification with Single Packet Authorization, mutual TLS, and SDP controller/gateway configuration to enforce zero trust network access.

deploying-ransomware-canary-files

16
from plurigrid/asi

Deploys and monitors ransomware canary files across critical directories using Python's watchdog library for real-time filesystem event detection. Places strategically named decoy files that mimic high-value targets (financial records, credentials, database exports) in locations ransomware typically enumerates first. Monitors for any read, modify, rename, or delete operations on canary files and triggers immediate alerts via email, Slack webhook, or syslog when interaction is detected, providing early warning before full encryption begins.

deploying-palo-alto-prisma-access-zero-trust

16
from plurigrid/asi

Deploying Palo Alto Networks Prisma Access for SASE-based zero trust network access using GlobalProtect agents, ZTNA Connectors, security policy enforcement, and integration with Strata Cloud Manager for unified security management.

deploying-osquery-for-endpoint-monitoring

16
from plurigrid/asi

Deploys and configures osquery for real-time endpoint monitoring using SQL-based queries to inspect running processes, open ports, installed software, and system configuration. Use when building visibility into endpoint state, threat hunting across fleet, or implementing compliance monitoring. Activates for requests involving osquery deployment, endpoint visibility, fleet management, or SQL-based endpoint querying.

deploying-edr-agent-with-crowdstrike

16
from plurigrid/asi

Deploys and configures CrowdStrike Falcon EDR agents across enterprise endpoints to enable real-time threat detection, behavioral analysis, and automated response. Use when onboarding endpoints to EDR coverage, configuring detection policies, or integrating Falcon telemetry with SIEM platforms. Activates for requests involving CrowdStrike deployment, Falcon sensor installation, EDR policy configuration, or endpoint detection and response.

deploying-decoy-files-for-ransomware-detection

16
from plurigrid/asi

Deploys canary files (honeytokens) across file systems to detect ransomware encryption activity in real time. Uses strategically placed decoy documents monitored via file integrity monitoring or OS-level watchdogs to trigger alerts when ransomware modifies or encrypts them. Activates for requests involving ransomware canary deployment, honeyfile setup, deception-based ransomware detection, or file integrity monitoring for encryption.

deploying-cloudflare-access-for-zero-trust

16
from plurigrid/asi

Deploying Cloudflare Access with Cloudflare Tunnel to provide zero trust access to self-hosted and private applications, configuring identity-aware access policies, device posture checks, and WARP client enrollment for VPN replacement.

deploying-active-directory-honeytokens

16
from plurigrid/asi

Deploys deception-based honeytokens in Active Directory including fake privileged accounts with AdminCount=1, fake SPNs for Kerberoasting detection (honeyroasting), decoy GPOs with cpassword traps, and fake BloodHound paths. Monitors Windows Security Event IDs 4769, 4625, 4662, 5136 for honeytoken interaction. Use when implementing AD deception defenses for detecting lateral movement, credential theft, and reconnaissance.