### Install Nginx
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/fallback-nginx.md
Installs Nginx on the server. This is a prerequisite for setting up the fallback site.
```bash
ssh {nickname} "sudo apt update && sudo apt install -y nginx"
```
--------------------------------
### Verify 3x-ui-setup Skill Installation
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Checks if the 3x-ui-setup skill has been installed correctly by verifying the presence of its main markdown file. Expected output is 'Verification: OK'.
```bash
# Expected output: "Verification: OK"
ls ~/.claude/skills/3x-ui-setup/SKILL.md
```
--------------------------------
### Manual Install 3x-ui Skill
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/README.md
Clone the repository and copy the skill to the Claude skills directory for manual installation.
```bash
git clone https://github.com/AndyShaman/3x-ui-skill.git
cp -r 3x-ui-skill/skill ~/.claude/skills/3x-ui-setup
rm -rf 3x-ui-skill
```
--------------------------------
### Install Base Packages and Enable Time Sync
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Installs essential packages like chrony for time synchronization, curl, wget, unzip, and net-tools. It also ensures chrony starts on boot.
```bash
sudo apt install -y chrony curl wget unzip net-tools
sudo systemctl enable chrony
```
--------------------------------
### Install 3x-ui Skill with curl
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/README.md
Use this command to quickly install the 3x-ui skill script from GitHub.
```bash
curl -fsSL https://raw.githubusercontent.com/AndyShaman/3x-ui-skill/main/install.sh | bash
```
--------------------------------
### Install 3x-ui Panel
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Downloads and installs the 3x-ui panel. Answers 'n' to port customization for auto-generated random port and credentials. Capture the output for panel username, password, port, and web base path.
```bash
ssh myserver "curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh \
-o /tmp/3x-ui-install.sh && echo 'n' | sudo bash /tmp/3x-ui-install.sh"
```
```bash
ssh myserver "sudo x-ui status"
```
--------------------------------
### Install and Configure Fail2ban
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Installs Fail2ban, configures it to protect SSH, and enables it to start on boot. It sets ban time, find time, and max retries for SSH.
```bash
ssh myserver 'sudo apt install -y fail2ban && sudo tee /etc/fail2ban/jail.local << JAILEOF
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h
JAILEOF
sudo systemctl enable fail2ban && sudo systemctl restart fail2ban'
```
--------------------------------
### Install and Configure UFW Firewall
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Installs the Uncomplicated Firewall (UFW), sets default policies to deny incoming and allow outgoing traffic, and explicitly allows SSH, HTTP, and HTTPS.
```bash
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
sudo ufw status
```
--------------------------------
### Install 3x-ui Panel
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Installs the 3x-ui panel script. The `echo 'n'` command bypasses the port customization prompt, generating random credentials and a port. Capture the output for access details. Do not use process substitution with sudo.
```bash
ssh {nickname} "curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh -o /tmp/3x-ui-install.sh && echo 'n' | sudo bash /tmp/3x-ui-install.sh"
```
--------------------------------
### Install SSH Key for New User
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Sets up the SSH authorized_keys file for the new user, ensuring secure key-based authentication. Permissions are set to restrict access.
```bash
mkdir -p /home/{username}/.ssh
echo "{PUBLIC_KEY_CONTENT}" > /home/{username}/.ssh/authorized_keys
chmod 700 /home/{username}/.ssh
chmod 600 /home/{username}/.ssh/authorized_keys
chown -R {username}:{username} /home/{username}/.ssh
```
--------------------------------
### Install SSH Public Key for New User
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Copies the generated SSH public key to the new user's authorized_keys file, enabling passwordless SSH login for that user.
```bash
mkdir -p /home/deploy/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... deploy@myserver" > /home/deploy/.ssh/authorized_keys
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
```
--------------------------------
### Test New User Login and Sudo Access
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Tests the newly created user's ability to log in via SSH using the installed key and execute commands with sudo privileges. This is a critical checkpoint before proceeding.
```bash
# Open a NEW terminal — keep root session alive
ssh -i ~/.ssh/myserver_key deploy@203.0.113.42
# Verify sudo works
sudo whoami
# Must output: root
# If test fails, debug as root:
ls -la /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
```
--------------------------------
### Install and Configure Fail2ban
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Installs the fail2ban service to protect against brute-force attacks, configures it to monitor SSH logs, and enables it to automatically restart. It also locks down SSH by disabling root login and password authentication.
```bash
ssh {nickname} 'sudo apt install -y fail2ban && sudo tee /etc/fail2ban/jail.local << JAILEOF
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h
JAILEOF
sudo systemctl enable fail2ban && sudo systemctl restart fail2ban'
```
```bash
ssh {nickname} 'sudo sed -i "s/^#\?PermitRootLogin.*/PermitRootLogin no/" /etc/ssh/sshd_config && sudo sed -i "s/^#\?PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config && sudo systemctl restart sshd'
```
--------------------------------
### Manage x-ui Panel Service
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Provides commands to start, stop, restart, check status, view logs, reset settings, update, and manage SSL certificates for the x-ui panel.
```bash
ssh myserver "sudo x-ui start"
```
```bash
ssh myserver "sudo x-ui stop"
```
```bash
ssh myserver "sudo x-ui restart"
```
```bash
ssh myserver "sudo x-ui status"
```
```bash
ssh myserver "sudo x-ui log"
```
```bash
ssh myserver "sudo x-ui setting -reset"
```
```bash
ssh myserver "sudo x-ui update"
```
```bash
ssh myserver "sudo x-ui cert"
```
--------------------------------
### Check 3x-ui Status
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Verifies if the 3x-ui service is running. If not, it provides a command to start it.
```bash
ssh {nickname} "sudo x-ui status"
```
```bash
ssh {nickname} "sudo x-ui start"
```
--------------------------------
### Deploy Nginx Camouflage Page
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Installs Nginx to serve a camouflage page. This is applicable for VLESS TLS with TCP transport.
```bash
ssh myserver "sudo apt update && sudo apt install -y nginx"
```
--------------------------------
### Configure UFW Firewall
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Installs and configures the Uncomplicated Firewall (UFW) to deny incoming traffic by default, allow outgoing traffic, and permit SSH, HTTP, and HTTPS.
```bash
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
sudo ufw status
# Output:
# Status: active
# To Action From
# 22/tcp ALLOW Anywhere
# 80/tcp ALLOW Anywhere
# 443/tcp ALLOW Anywhere
```
--------------------------------
### Get VLESS TLS Connection Link
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/vless-tls.md
Executes a command on a remote server to fetch VLESS TLS connection details. It queries the panel API, filters for VLESS protocol with TLS, and formats the output into a connection link. Ensure the panel port and nickname are correctly substituted.
```bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -b /tmp/3x-cookie "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/panel/api/inbounds/list" | python3 -c "
import json,sys
data = json.load(sys.stdin)
for inb in data.get(\"obj\", []):
if inb.get(\"protocol\") == \"vless\" and \"tls\" in inb.get(\"streamSettings\", \""):
settings = json.loads(inb[\"settings\"])
stream = json.loads(inb[\"streamSettings\"])
client = settings[\"clients\"][0]
uuid = client[\"id\"]
port = inb[\"port\"]
sni = stream.get(\"tlsSettings\", {{}}).get(\"serverName\", \"")
flow = client.get(\"flow\", \"")
link = f\"vless://{uuid}@{sni}:{port}?type=tcp&security=tls&sni={sni}&fp=chrome&flow={flow}#vless-tls\"
print(link)
break
"'
```
--------------------------------
### Obtain SSL Certificate using acme.sh
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/vless-tls.md
A non-interactive method to obtain an SSL certificate using acme.sh. Ensure socat is installed and the script is executed with appropriate permissions.
```bash
ssh {nickname} "sudo apt install -y socat && curl https://get.acme.sh | sh && sudo ~/.acme.sh/acme.sh --issue -d {domain} --standalone --httpport 80 && sudo ~/.acme.sh/acme.sh --install-cert -d {domain} --key-file /root/cert/{domain}/privkey.pem --fullchain-file /root/cert/{domain}/fullchain.pem --reloadcmd 'x-ui restart'"
```
--------------------------------
### Test New User SSH Login
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Connect to the server using the new user's credentials and SSH key. This is a critical step to verify access before proceeding.
```bash
ssh -i ~/.ssh/{nickname}_key {username}@{SERVER_IP}
```
--------------------------------
### Verify Sudo Access for New User
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
After logging in as the new user, run this command to confirm that sudo privileges are correctly configured.
```bash
sudo whoami
```
--------------------------------
### Update System Packages Non-interactively
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Updates package lists and upgrades installed packages on Debian/Ubuntu systems without user interaction, suitable for automation.
```bash
apt update && DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt upgrade -y
```
--------------------------------
### Final Verification Commands
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
After setting up the SSH shortcut, connect using 'ssh {nickname}' and then run these commands on the server to verify firewall status and kernel network filtering.
```bash
# Then on server:
sudo ufw status
sudo sysctl net.ipv4.conf.all.rp_filter
```
--------------------------------
### Create Stub HTML Page
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/fallback-nginx.md
Creates a realistic-looking fake cloud login page at /var/www/html/index.html to serve as the fallback content.
```bash
ssh {nickname} 'sudo tee /var/www/html/index.html << '"'"'HTML_EOF'"'"'
Cloud Storage
Cloud Storage
Sign in to access your files
HTML_EOF'
```
--------------------------------
### Run Reality Scanner in Local Mode (/24 subnet)
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Executes the RealiTLScanner directly on the VPS to scan the local /24 subnet. It determines the system architecture, downloads the correct scanner binary, makes it executable, and then runs the scan, limiting the output to the first 80 lines. This is useful when direct access to the VPS is available.
```bash
ARCH=$(dpkg --print-architecture); case "$ARCH" in amd64) SA="64";; arm64|aarch64) SA="arm64-v8a";; *) SA="$ARCH";; esac && curl -sL "https://github.com/XTLS/RealiTLScanner/releases/latest/download/RealiTLScanner-linux-${SA}" -o /tmp/scanner && chmod +x /tmp/scanner && file /tmp/scanner | grep -q ELF || { echo "ERROR: scanner binary not valid for this architecture"; exit 1; }; MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\[0-9]*\.0\/24/"); echo "Scanning subnet: $SUBNET"; timeout 120 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80
```
--------------------------------
### Create VLESS Reality Inbound via API
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Authenticates to the 3x-ui panel API, generates necessary keys (X25519, UUID, short ID), and creates a VLESS Reality inbound on port 443. Includes a pre-check for port 443 conflicts.
```bash
ssh myserver "ss -tlnp | grep ':443 '"
```
```bash
ssh myserver 'curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie \
-X POST "https://127.0.0.1:54321/panel/login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=x7kP2m&password=9vQr#Lx"'
```
```bash
ssh myserver "sudo /usr/local/x-ui/bin/xray-linux-* x25519"
```
```bash
ssh myserver "sudo /usr/local/x-ui/bin/xray-linux-* uuid"
```
```bash
ssh myserver "openssl rand -hex 8"
```
--------------------------------
### Create Non-root User with Sudo Privileges
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Creates a new user account, sets a password, and adds the user to the sudo group, granting administrative privileges.
```bash
useradd -m -s /bin/bash deploy
echo "deploy:G7#kP2$xQm9vL" | chpasswd
usermod -aG sudo deploy
# Verify group membership
groups deploy
# Output: deploy : deploy sudo
```
--------------------------------
### Add VLESS Reality Inbound via API
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Create a new VLESS Reality inbound configuration using the 3x-ui API. Ensure all placeholder values like {CLIENT_UUID}, {PRIVATE_KEY}, {PUBLIC_KEY}, {SHORT_ID}, {BEST_SNI}, and {web_base_path} are correctly substituted.
```bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie -X POST "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/panel/api/inbounds/add" -H "Content-Type: application/json" -d '"'"'{
"up": 0,
"down": 0,
"total": 0,
"remark": "vless-reality",
"enable": true,
"expiryTime": 0,
"listen": "",
"port": 443,
"protocol": "vless",
"settings": "{\"clients\":[{\"id\":\"{CLIENT_UUID}\",\"flow\":\"xtls-rprx-vision\",\"email\":\"user1\",\"limitIp\":0,\"totalGB\":0,\"expiryTime\":0,\"enable\":true}],\"decryption\":\"none\",\"fallbacks\":[]}",
"streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"externalProxy\":[],\"realitySettings\":{\"show\":false,\"xver\":0,\"dest\":\"{BEST_SNI}:443\",\"serverNames\":[\"{BEST_SNI}\"],\"privateKey\":\"{PRIVATE_KEY}\",\"minClient\":\"\",\"maxClient\":\"\",\"maxTimediff\":0,\"shortIds\":[\"{SHORT_ID}\"],\"settings\":{\"publicKey\":\"{PUBLIC_KEY}\",\"fingerprint\":\"chrome\",\"serverName\":\"\",\"spiderX\":\"/\"}},\"tcpSettings\":{\"acceptProxyProtocol\":false,\"header\":{\"type\":\"none\"}}}",
"sniffing": "{\"enabled\":true,\"destOverride\":[\"http\",\"tls\",\"quic\",\"fakedns\"],\"metadataOnly\":false,\"routeOnly\":false}",
"allocate": "{\"strategy\":\"always\",\"refresh\":5,\"concurrency\":3}"
}'"'"''
```
--------------------------------
### Run Reality Scanner in Local Mode (/23 subnet)
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Executes RealiTLScanner on the VPS to scan a broader /23 subnet (512 IPs). This is used when the default /24 scan is insufficient. The command downloads the scanner, sets permissions, and runs the scan with an extended 180-second timeout. It's suitable for sparse subnets.
```bash
MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\[0-9]*\.0\/23/"); timeout 180 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80
```
--------------------------------
### Create VLESS Reality Inbound via API
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
This snippet demonstrates how to create a VLESS Reality inbound using the 3x-ui API. It includes steps for obtaining a session cookie, generating necessary keys, and making the API call to add the inbound configuration.
```APIDOC
## POST /panel/api/inbounds/add
### Description
Creates a new VLESS Reality inbound configuration for the 3x-ui panel.
### Method
POST
### Endpoint
`https://127.0.0.1:{panel_port}/{web_base_path}/panel/api/inbounds/add`
### Parameters
#### Request Body
- **up** (integer) - Upload limit in bytes (0 for unlimited).
- **down** (integer) - Download limit in bytes (0 for unlimited).
- **total** (integer) - Total data limit in bytes (0 for unlimited).
- **remark** (string) - A descriptive remark for the inbound.
- **enable** (boolean) - Whether the inbound is enabled.
- **expiryTime** (integer) - Expiry time in Unix timestamp (0 for no expiry).
- **listen** (string) - Listen address (empty string for default).
- **port** (integer) - The port for the inbound (e.g., 443).
- **protocol** (string) - The protocol to use (e.g., "vless").
- **settings** (string) - JSON string containing client settings. Example: `{"clients":[{"id":"{CLIENT_UUID}","flow":"xtls-rprx-vision","email":"user1","limitIp":0,"totalGB":0,"expiryTime":0,"enable":true}],"decryption":"none","fallbacks":[]}`
- **streamSettings** (string) - JSON string containing stream settings. Example: `{"network":"tcp","security":"reality","externalProxy":[],"realitySettings":{"show":false,"xver":0,"dest":"{BEST_SNI}:443","serverNames":["{BEST_SNI}"],"privateKey":"{PRIVATE_KEY}","minClient":"","maxClient":"","maxTimediff":0,"shortIds":["{SHORT_ID}"],"settings":{"publicKey":"{PUBLIC_KEY}","fingerprint":"chrome","serverName":"","spiderX":"/"}},"tcpSettings":{"acceptProxyProtocol":false,"header":{"type":"none"}}}`
- **sniffing** (string) - JSON string for sniffing settings. Example: `{"enabled":true,"destOverride":["http","tls","quic","fakedns"],"metadataOnly":false,"routeOnly":false}`
- **allocate** (string) - JSON string for allocation strategy. Example: `{"strategy":"always","refresh":5,"concurrency":3}`
### Request Example
```bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie -X POST "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/panel/api/inbounds/add" -H "Content-Type: application/json" -d "'"'"'{
"up": 0,
"down": 0,
"total": 0,
"remark": "vless-reality",
"enable": true,
"expiryTime": 0,
"listen": "",
"port": 443,
"protocol": "vless",
"settings": "{\"clients\":[{\"id\":\"{CLIENT_UUID}\",\"flow\":\"xtls-rprx-vision\",\"email\":\"user1\",\"limitIp\":0,\"totalGB\":0,\"expiryTime\":0,\"enable\":true}],\"decryption\":\"none\",\"fallbacks\":[]}",
"streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"externalProxy\":[],\"realitySettings\":{\"show\":false,\"xver\":0,\"dest\":\"{BEST_SNI}:443\",\"serverNames\":[\"{BEST_SNI}\"],\"privateKey\":\"{PRIVATE_KEY}\",\"minClient\":\"\",\"maxClient\":\"\",\"maxTimediff\":0,\"shortIds\":[\"{SHORT_ID}\"],\"settings\":{\"publicKey\":\"{PUBLIC_KEY}\",\"fingerprint\":\"chrome\",\"serverName\":\"\",\"spiderX\":\"/\"}},\"tcpSettings\":{\"acceptProxyProtocol\":false,\"header\":{\"type\":\"none\"}}}",
"sniffing": "{\"enabled\":true,\"destOverride\":[\"http\",\"tls\",\"quic\",\"fakedns\"],\"metadataOnly\":false,\"routeOnly\":false}",
"allocate": "{\"strategy\":\"always\",\"refresh\":5,\"concurrency\":3}"
}'"'"''
```
### Response
#### Success Response (200)
- **msg** (string) - Success message.
- **obj** (object) - The created inbound object.
#### Response Example
```json
{
"msg": "add inbounds success",
"obj": {
"id": 1,
"up": 0,
"down": 0,
"total": 0,
"remark": "vless-reality",
"enable": true,
"expiryTime": 0,
"listen": "",
"port": 443,
"protocol": "vless",
"settings": "{\"clients\":[{\"id\":\"{CLIENT_UUID}\",\"flow\":\"xtls-rprx-vision\",\"email\":\"user1\",\"limitIp\":0,\"totalGB\":0,\"expiryTime\":0,\"enable\":true}],\"decryption\":\"none\",\"fallbacks\":[]}",
"streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"externalProxy\":[],\"realitySettings\":{\"show\":false,\"xver\":0,\"dest\":\"{BEST_SNI}:443\",\"serverNames\":[\"{BEST_SNI}\"],\"privateKey\":\"{PRIVATE_KEY}\",\"minClient\":\"\",\"maxClient\":\"\",\"maxTimediff\":0,\"shortIds\":[\"{SHORT_ID}\"],\"settings\":{\"publicKey\":\"{PUBLIC_KEY}\",\"fingerprint\":\"chrome\",\"serverName\":\"\",\"spiderX\":\"/\"}},\"tcpSettings\":{\"acceptProxyProtocol\":false,\"header\":{\"type\":\"none\"}}}",
"sniffing": "{\"enabled\":true,\"destOverride\":[\"http\",\"tls\",\"quic\",\"fakedns\"],\"metadataOnly\":false,\"routeOnly\":false}",
"allocate": "{\"strategy\":\"always\",\"refresh\":5,\"concurrency\":3}"
}
}
```
--------------------------------
### Generate Client Connection Link
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Fetches the client connection link from the 3x-ui API. This script parses the API response to find VLESS protocol configurations and constructs a shareable link, including REALITY settings. It requires SSH access to the server.
```bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -b /tmp/3x-cookie "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/panel/api/inbounds/list" | python3 -c "
import json,sys
data = json.load(sys.stdin)
for inb in data.get(\"obj\", []):
if inb.get(\"protocol\") == \"vless\":
settings = json.loads(inb[\"settings\"])
stream = json.loads(inb[\"streamSettings\"])
client = settings[\"clients\"][0]
uuid = client[\"id\"]
port = inb[\"port\"]
security = stream.get(\"security\", \"none\")
if security == \"reality\":
rs = stream[\"realitySettings\"]
sni = rs[\"serverNames\"][0]
pbk = rs[\"settings\"][\"publicKey\"]
sid = rs[\"shortIds\"][0]
fp = rs[\"settings\"].get(\"fingerprint\", \"chrome\")
flow = client.get(\"flow\", \"\")
link = f\"vless://{uuid}@$(curl -4 -s ifconfig.me):{port}?type=tcp&security=reality&pbk={pbk}&fp={fp}&sni={sni}&sid={sid}&spx=%2F&flow={flow}#vless-reality\"
print(link)
break
"'
```
--------------------------------
### Connect to Server as Root
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Initial SSH connection to the server as the root user. May require a password change on first login.
```bash
ssh root@203.0.113.42
# If provider forces password change on first login:
# Enter current password → set new temporary password → reconnect
ssh root@203.0.113.42 # reconnect with new password
```
--------------------------------
### Apply SSL Certificate to x-ui Panel
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/vless-tls.md
Configure the x-ui panel to use the obtained SSL certificate for HTTPS access. Restart the panel to apply changes.
```bash
ssh {nickname} "sudo /usr/local/x-ui/x-ui cert -webCert /root/cert/{domain}/fullchain.pem -webCertKey /root/cert/{domain}/privkey.pem"
```
```bash
ssh {nickname} "sudo x-ui restart"
```
--------------------------------
### Obtain SSL Certificate using x-ui
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/vless-tls.md
Use the x-ui built-in certificate management to obtain an SSL certificate for your domain. This process is interactive.
```bash
ssh {nickname} "sudo x-ui cert"
```
--------------------------------
### Configure Nginx Stub Server
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/fallback-nginx.md
Sets up Nginx to listen on localhost:8081 and serve static files from /var/www/html. This Nginx instance acts as the fallback server.
```bash
ssh {nickname} "sudo tee /etc/nginx/sites-available/stub << 'NGINX_EOF'
server {
listen 127.0.0.1:8081;
server_name _;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
NGINX_EOF
sudo ln -sf /etc/nginx/sites-available/stub /etc/nginx/sites-enabled/stub && sudo rm -f /etc/nginx/sites-enabled/default && sudo nginx -t && sudo systemctl reload nginx"
```
--------------------------------
### Debug SSH Permissions
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
If the new user's sudo access fails, use these commands to inspect SSH directory permissions and the authorized_keys file on the server.
```bash
# Check on server as root:
ls -la /home/{username}/.ssh/
cat /home/{username}/.ssh/authorized_keys
# Fix ownership:
chown -R {username}:{username} /home/{username}/.ssh
```
--------------------------------
### Generate Reality Keys (x25519)
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Generate the necessary private and public keys for Reality configuration using the xray binary. Note that 'Password' output from xray is the public key.
```bash
ssh {nickname} "sudo /usr/local/x-ui/bin/xray-linux-* x25519"
```
--------------------------------
### Create Non-Root User and Set Password
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Creates a new user with a bash shell, sets a strong temporary password, and adds them to the sudo group. Remember to save the generated password for the user.
```bash
useradd -m -s /bin/bash {username}
echo "{username}:{GENERATE_STRONG_PASSWORD}" | chpasswd
usermod -aG sudo {username}
```
--------------------------------
### Create VLESS Reality Inbound
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Adds a VLESS Reality inbound configuration to the panel API. Ensure the panel is running and accessible.
```bash
ssh myserver 'curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie \
-X POST "https://127.0.0.1:54321/panel/api/inbounds/add" \
-H "Content-Type: application/json" \
-d '"'"'{
"remark": "vless-reality",
"enable": true,
"port": 443,
"protocol": "vless",
"settings": "{\"clients\":[{\"id\":\"550e8400-e29b-41d4-a716-446655440000\",\"flow\":\"xtls-rprx-vision\",\"email\":\"user1\",\"limitIp\":0,\"totalGB\":0,\"expiryTime\":0,\"enable\":true}],\"decryption\":\"none\",\"fallbacks\":[]}",
"streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"realitySettings\":{\"dest\":\"shop.finn-auto.fi:443\",\"serverNames\":[\"shop.finn-auto.fi\"],\"privateKey\":\"eKmFk3...\",\"shortIds\":[\"a3f8c21d9e047b5c\"],\"settings\":{\"publicKey\":\"bNpQ7r...\",\"fingerprint\":\"chrome\",\"spiderX\":\"/\"}}}",
"sniffing": "{\"enabled\":true,\"destOverride\":[\"http\",\"tls\",\"quic\",\"fakedns\"]}"
}'"'"''
```
--------------------------------
### Configure Local SSH Shortcut
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Appends an entry to the local SSH config file, allowing connection to the server using a simple alias 'myserver'.
```bash
cat >> ~/.ssh/config << 'EOF'
Host myserver
HostName 203.0.113.42
User deploy
IdentityFile ~/.ssh/myserver_key
IdentitiesOnly yes
EOF
```
--------------------------------
### Configure Local SSH Client Config
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Adds an entry to the local SSH configuration file to create a shortcut for connecting to the server. This simplifies future connections by using a nickname instead of IP and username.
```bash
cat >> ~/.ssh/config << 'EOF'
Host {nickname}
HostName {SERVER_IP}
User {username}
IdentityFile ~/.ssh/{nickname}_key
IdentitiesOnly yes
EOF
```
--------------------------------
### Configure Nginx for Localhost Only
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Sets up Nginx to listen on localhost:8081, serving static files from /var/www/html. This configuration is useful for fallback pages.
```bash
ssh myserver "sudo tee /etc/nginx/sites-available/stub << 'EOF'
server {
listen 127.0.0.1:8081;
server_name _;
root /var/www/html;
index index.html;
location / { try_files $uri $uri/ =404; }
}
EOF
sudo ln -sf /etc/nginx/sites-available/stub /etc/nginx/sites-enabled/stub
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx"
```
--------------------------------
### Troubleshoot SSH Permission Denied
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/README.md
If you encounter 'Permission denied (publickey)', check and correct SSH key permissions on your client machine.
```bash
chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
```
--------------------------------
### Deploy Stub HTML Page
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Deploys a simple HTML file to serve as a stub page, typically for fallback or placeholder content.
```bash
ssh myserver 'sudo tee /var/www/html/index.html << "'"'"'HTML_EOF'"'"'"'"
Cloud Storage
Cloud Storage
Sign in to access your files
HTML_EOF'
```
--------------------------------
### Login to x-ui API
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/vless-tls.md
Authenticate with the x-ui panel's API using provided credentials to perform subsequent API operations. Cookies are stored in /tmp/3x-cookie.
```bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie -X POST "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/login" -H "Content-Type: application/x-www-form-urlencoded" -d "username={panel_username}&password={panel_password}"'
```
--------------------------------
### Create VLESS TLS Inbound
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Adds a VLESS TLS inbound configuration to the panel API using specified certificate files. Ensure the certificate files exist.
```bash
ssh myserver 'curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie \
-X POST "https://127.0.0.1:54321/panel/api/inbounds/add" \
-H "Content-Type: application/json" \
-d '"'"'{
"remark": "vless-tls",
"enable": true,
"port": 443,
"protocol": "vless",
"settings": "{\"clients\":[{\"id\":\"550e8400-e29b-41d4-a716-446655440000\",\"flow\":\"xtls-rprx-vision\",\"email\":\"user1\",\"limitIp\":0,\"totalGB\":0,\"expiryTime\":0,\"enable\":true}],\"decryption\":\"none\",\"fallbacks\":[]}",
"streamSettings": "{\"network\":\"tcp\",\"security\":\"tls\",\"tlsSettings\":{\"serverName\":\"vpn.example.com\",\"minVersion\":\"1.2\",\"maxVersion\":\"1.3\",\"certificates\":[{\"certificateFile\":\"/root/cert/vpn.example.com/fullchain.pem\",\"keyFile\":\"/root/cert/vpn.example.com/privkey.pem\",\"ocspStapling\":3600}],\"alpn\":[\"h2\",\"http/1.1\"]}}",
"sniffing": "{\"enabled\":true,\"destOverride\":[\"http\",\"tls\",\"quic\",\"fakedns\"]}"
}'"'"''
```
--------------------------------
### Troubleshoot Panel Not Accessible via SSH Tunnel
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/README.md
If the 3x-ui panel is not accessible in your browser, use an SSH tunnel to forward the panel's port.
```bash
ssh -L 2053:localhost:2053 user@server
```
--------------------------------
### Extract VLESS Connection Link
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Fetches the VLESS connection URL from the panel API and formats it as a vless:// link. Requires jq for JSON parsing.
```bash
ssh myserver 'curl -sk -b /tmp/3x-cookie \
"https://127.0.0.1:54321/panel/api/inbounds/list" | python3 -c "
import json, sys
data = json.load(sys.stdin)
for inb in data.get(\"obj\", []):
if inb.get(\"protocol\") == \"vless\":
settings = json.loads(inb[\"settings\"])
stream = json.loads(inb[\"streamSettings\"])
client = settings[\"clients\"][0]
uuid = client[\"id\"]
port = inb[\"port\"]
if stream.get(\"security\") == \"reality\":
rs = stream[\"realitySettings\"]
sni = rs[\"serverNames\"][0]
pbk = rs[\"settings\"][\"publicKey\"]
sid = rs[\"shortIds\"][0]
fp = rs[\"settings\"].get(\"fingerprint\", \"chrome\")
flow = client.get(\"flow\", \"\")$(curl -4 -s ifconfig.me):{port}?type=tcp&security=reality&pbk={pbk}&fp={fp}&sni={sni}&sid={sid}&spx=%2F&flow={flow}#vless-reality"
print(link)
break
"'
```
```bash
ssh myserver "echo 'vless://...' > ~/vpn-link.txt"
```
```bash
ssh myserver "rm -f /tmp/3x-cookie"
```
--------------------------------
### Create VLESS TLS Inbound via API
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/vless-tls.md
Add a VLESS TLS inbound configuration to the x-ui panel using its API. This requires a valid client UUID and domain, and configures port 443 with TLS settings.
```bash
ssh {nickname} 'PANEL_PORT={panel_port}; curl -sk -c /tmp/3x-cookie -b /tmp/3x-cookie -X POST "https://127.0.0.1:${PANEL_PORT}/{web_base_path}/panel/api/inbounds/add" -H "Content-Type: application/json" -d '"'"'{ "up": 0, "down": 0, "total": 0, "remark": "vless-tls", "enable": true, "expiryTime": 0, "listen": "", "port": 443, "protocol": "vless", "settings": "{\"clients\":[{\"id\":\"{CLIENT_UUID}\",\"flow\":\"xtls-rprx-vision\",\"email\":\"user1\",\"limitIp\":0,\"totalGB\":0,\"expiryTime\":0,\"enable\":true}],\"decryption\":\"none\",\"fallbacks\":[]}", "streamSettings": "{\"network\":\"tcp\",\"security\":\"tls\",\"externalProxy\":[],\"tlsSettings\":{\"serverName\":\"{domain}\",\"minVersion\":\"1.2\",\"maxVersion\":\"1.3\",\"cipherSuites\":\"\",\"rejectUnknownSni\":false,\"disableSystemRoot\":false,\"enableSessionResumption\":false,\"certificates\":[{\"certificateFile\":\"/root/cert/{domain}/fullchain.pem\",\"keyFile\":\"/root/cert/{domain}/privkey.pem\",\"ocspStapling\":3600,\"oneTimeLoading\":false,\"usage\":\"encipherment\",\"buildChain\":false}],\"alpn\":[\"h2\",\"http/1.1\"]},\"tcpSettings\":{\"acceptProxyProtocol\":false,\"header\":{\"type\":\"none\"}}}", "sniffing": "{\"enabled\":true,\"destOverride\":[\"http\",\"tls\",\"quic\",\"fakedns\"],\"metadataOnly\":false,\"routeOnly\":false}", "allocate": "{\"strategy\":\"always\",\"refresh\":5,\"concurrency\":3}" }'"'"''
```
--------------------------------
### Run Reality Scanner in Remote Mode (/24 subnet)
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Executes the RealiTLScanner on a remote server via SSH to scan the local /24 subnet. It automatically detects the architecture, downloads the appropriate scanner binary, and initiates the scan, outputting the first 80 lines of results. Ensure the SSH user has necessary permissions.
```bash
ssh {nickname} 'ARCH=$(dpkg --print-architecture); case "$ARCH" in amd64) SA="64";; arm64|aarch64) SA="arm64-v8a";; *) SA="$ARCH";; esac && curl -sL "https://github.com/XTLS/RealiTLScanner/releases/latest/download/RealiTLScanner-linux-${SA}" -o /tmp/scanner && chmod +x /tmp/scanner && file /tmp/scanner | grep -q ELF || { echo "ERROR: scanner binary not valid for this architecture"; exit 1; }; MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\[0-9]*\.0\/24/"); echo "Scanning subnet: $SUBNET"; timeout 120 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80'
```
--------------------------------
### Check Port 443 Availability
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Verify if port 443 is already in use before configuring the VLESS inbound. If it is, stop and disable the occupying service.
```bash
ssh {nickname} "ss -tlnp | grep ':443 '"
```
--------------------------------
### Configure Kernel Security Settings
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Applies various network security enhancements by configuring kernel parameters. These settings help protect against common network attacks.
```bash
sudo tee /etc/sysctl.d/99-security.conf << 'EOF'
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
EOF
sudo sysctl -p /etc/sysctl.d/99-security.conf
```
--------------------------------
### Verify Connection Status
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Checks the status of the x-ui service and lists active network connections on ports 443 and the specified panel port. This is used to verify that the VPN connection is active and the server is listening on the correct ports.
```bash
ssh {nickname} "sudo x-ui status && ss -tlnp | grep -E '443|{panel_port}'"
```
--------------------------------
### Troubleshoot SSH Host Key Verification Failed
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/README.md
To resolve 'Host key verification failed', remove the old host key entry for the server IP from your known_hosts file.
```bash
ssh-keygen -R
```
--------------------------------
### Verify SSH Key Access
Source: https://context7.com/andyshaman/3x-ui-skill/llms.txt
Confirms that SSH key-based authentication is working correctly before proceeding with further security configurations.
```bash
ssh myserver "echo 'SSH key access OK'"
```
--------------------------------
### Verify DNS Resolution
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/vless-tls.md
Check if the domain's A-record points to the server's IP address. This is crucial for SSL certificate issuance.
```bash
nslookup {domain}
```
```bash
ssh {nickname} "sudo apt install -y dnsutils > /dev/null 2>&1; nslookup {domain}"
```
--------------------------------
### Save Connection Link to File
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Saves the generated VLESS connection link to a file named 'vpn-link.txt' in the user's home directory on the remote server. This provides an easy way to access the link later.
```bash
ssh {nickname} "echo '{VLESS_LINK}' > ~/vpn-link.txt"
```
--------------------------------
### Change Panel Credentials
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/vless-tls.md
Update the x-ui panel's username and password for enhanced security. Restart the panel after changing credentials.
```bash
ssh {nickname} "sudo x-ui setting -username {new_username} -password {new_password}"
```
```bash
ssh {nickname} "sudo x-ui restart"
```
--------------------------------
### Access Panel via SSH Tunnel
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/vless-tls.md
Establish an SSH tunnel to securely access the x-ui panel over HTTPS. Note that the browser will show a certificate mismatch warning, which is expected.
```bash
ssh -L {panel_port}:127.0.0.1:{panel_port} {nickname}
```
--------------------------------
### Configure VLESS Inbound Fallback
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/references/fallback-nginx.md
Adds a fallback destination to the VLESS inbound settings, directing traffic to the Nginx stub server on 127.0.0.1:8081 when direct connections fail.
```json
"fallbacks": [{"dest": "127.0.0.1:8081"}]
```
--------------------------------
### Reset 3x-ui Panel Password
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/README.md
If you forget the 3x-ui panel password, you can reset it directly on the server using this command.
```bash
sudo x-ui setting -reset
```
--------------------------------
### Run Reality Scanner in Remote Mode (/23 subnet)
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Scans a wider /23 subnet (512 IPs) using RealiTLScanner via SSH. This is a fallback option when the /24 scan yields no results or times out, common with providers like OVH. The timeout is increased to 180 seconds to accommodate the larger scan range.
```bash
ssh {nickname} 'MY_IP=$(curl -4 -s ifconfig.me); SUBNET=$(echo $MY_IP | sed "s/\[0-9]*\.0\/23/"); timeout 180 /tmp/scanner --addr "$SUBNET" 2>&1 | head -80'
```
--------------------------------
### Verify SSH Lockdown
Source: https://github.com/andyshaman/3x-ui-skill/blob/main/skill/SKILL.md
Verifies that SSH lockdown configurations (disabling root login and password authentication) have been applied correctly and that the fail2ban service is running. It also confirms that SSH key access is still functional.
```bash
ssh {nickname} "grep -E 'PermitRootLogin|PasswordAuthentication' /etc/ssh/sshd_config && sudo systemctl status fail2ban --no-pager -l && echo 'Lockdown OK'"
```