From cb9c1f032da392a4133ed5844490910555b39b08 Mon Sep 17 00:00:00 2001 From: Jacob Savel'ev Date: Wed, 30 Jul 2025 19:03:45 +0500 Subject: [PATCH] Added docs (small version) --- docs/docs.md | 366 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 docs/docs.md diff --git a/docs/docs.md b/docs/docs.md new file mode 100644 index 00000000..72a7718f --- /dev/null +++ b/docs/docs.md @@ -0,0 +1,366 @@ +# X-UI API Documentation + +## Overview + +This document provides instructions for interacting with the X-UI panel API. The API allows for programmatic management of inbounds (connections), users, and server settings. + +### Authentication + +The API uses a **cookie-based session** for authentication. + +1. You must first send a `POST` request to the `/login` endpoint with your credentials. +2. If successful, the server will respond with a `Set-Cookie` header containing a session cookie (e.g., `session=...`). +3. Your HTTP client **must** store this cookie and include it in the `Cookie` header for all subsequent API requests. + +While many headers sent by a browser are not strictly required, including a `User-Agent` and `Referer` is good practice to better emulate a real client. + +## Endpoints + +### 1. Login + +Authenticates the user and initiates a session by returning a session cookie. + +* **Endpoint:** `POST {base_url}/login` +* **Body:** `application/x-www-form-urlencoded` + +| Parameter | Type | Description | +| :--------- | :----- | :--------------------- | +| `username` | string | Your panel username. | +| `password` | string | Your panel password. | + +* **Success Response (200 OK):** + * The response will include a `Set-Cookie` header in the HTTP response. + ```json + { + "success": true, + "msg": "Login successful", + "obj": null + } + ``` + +### 2. Get All Inbounds + +Fetches a list of all configured inbound connections. + +* **Endpoint:** `POST {base_url}/panel/inbound/list` +* **Body:** None +* **Success Response (200 OK):** + + ```json + { + "success": true, + "msg": "", + "obj": [ + { + "id": 1, + "up": 40912424334, + "down": 537061968966, + "total": 0, + "remark": "My-First-Inbound", + "enable": true, + "expiryTime": 0, + "listen": "YOUR_SERVER_IP", + "port": 19271, + "protocol": "vless", + "settings": "{\"clients\":[{\"id\":\"user-uuid-goes-here\",\"email\":\"user-email-goes-here\",...}]}", + "streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"realitySettings\":{\"privateKey\":\"REALITY_PRIVATE_KEY\",\"settings\":{\"publicKey\":\"REALITY_PUBLIC_KEY\"},...}}", + "tag": "inbound-YOUR_SERVER_IP:19271", + "sniffing": "{\"enabled\":false,...}" + } + ] + } + ``` + +### 3. Get Online Clients + +Fetches a list of emails corresponding to currently online clients. + +* **Endpoint:** `POST {base_url}/panel/inbound/onlines` +* **Body:** None +* **Success Response (200 OK):** + ```json + { + "success": true, + "msg": "", + "obj": [ + "client1-email", + "online-user@example.com" + ] + } + ``` + +### 4. Get New Reality Certificate + +Generates a new X25519 key pair for use with VLESS Reality. + +* **Endpoint:** `POST {base_url}/server/getNewX25519Cert` +* **Body:** None +* **Success Response (200 OK):** + ```json + { + "success": true, + "msg": "", + "obj": { + "privateKey": "a_very_long_private_key_string", + "publicKey": "a_shorter_public_key_string" + } + } + ``` + +### 5. Add VLESS Reality Inbound + +Creates a new VLESS Reality inbound connection. + +* **Endpoint:** `POST {base_url}/panel/inbound/add` +* **Body:** `application/x-www-form-urlencoded` + +This endpoint requires a complex body where several parameters are URL-encoded JSON strings. + +| Parameter | Description | Example Value | +| :--------------- | :------------------------------------------------------------------------------ | :--------------------------------------------- | +| `remark` | A name or comment for the inbound. | `My-Test-Key` | +| `listen` | The server IP address to listen on. Leave empty for all IPs. | `YOUR_SERVER_IP` | +| `port` | The port to listen on. `0` for a random port. | `48673` | +| `protocol` | The protocol type. | `vless` | +| `expiryTime` | Expiration timestamp in milliseconds. `0` for no expiration. | `1753969593148` | +| `total` | Data limit in bytes. `0` for unlimited. | `0` | +| `settings` | URL-encoded JSON string with client details (UUID, email, etc.). | (See structure below) | +| `streamSettings` | URL-encoded JSON string with transport and security settings (e.g., Reality). | (See structure below) | +| `sniffing` | URL-encoded JSON string for traffic sniffing settings. | `{"enabled":false,...}` | + +* **Decoded `settings` Structure:** + ```json + { + "clients": [ + { + "id": "a-generated-uuid", + "email": "a-generated-email", + "enable": true, + "flow": "", + "limitIp": 0, + "totalGB": 0, + "expiryTime": 0, + "subId": "a-generated-sub-id" + } + ], + "decryption": "none", + "fallbacks": [] + } + ``` +* **Decoded `streamSettings` Structure:** + ```json + { + "network": "tcp", + "security": "reality", + "realitySettings": { + "dest": "example.com:443", + "serverNames": ["example.com", "www.example.com"], + "privateKey": "THE_PRIVATE_KEY_FROM_STEP_4", + "publicKey": "THE_PUBLIC_KEY_FROM_STEP_4", + "shortIds": ["generated_id1", "generated_id2"], + "fingerprint": "chrome", + "spiderX": "/" + } + } + ``` + +* **Success Response (200 OK):** The response object contains the full configuration of the newly created inbound. + ```json + { + "success": true, + "msg": "Create Successfully", + "obj": { + "id": 16, + "remark": "Test test", + "port": 48673, + "listen": "YOUR_SERVER_IP", + "settings": "{\"clients\":[{\"id\":\"60f3a042-7f0c-43a5-a9e6-de76f66703dd\",...}]}", + "streamSettings": "{\"network\":\"tcp\",\"security\":\"reality\",\"realitySettings\":{...}}", + // ... and other fields + } + } + ``` + +## Code Examples + +### Python (`requests`) + +The `requests.Session` object is perfect for this task as it automatically handles cookies across requests. + +```python +import requests + +# --- Configuration --- +BASE_URL = "http://127.0.0.1:PORT/YOUR_SECRET_PATH" +USERNAME = "your_username" +PASSWORD = "your_password" + +# 1. Create a session that will store cookies +session = requests.Session() + +# 2. Login to establish the session +try: + login_url = f"{BASE_URL}/login" + login_data = {"username": USERNAME, "password": PASSWORD} + response = session.post(login_url, data=login_data) + response.raise_for_status() + + if response.json().get("success"): + print("Login successful!") + + # 3. Now you can make other API calls with the same session + inbounds_url = f"{BASE_URL}/panel/inbound/list" + inbounds_response = session.post(inbounds_url) + inbounds_data = inbounds_response.json() + + print(f"Successfully fetched {len(inbounds_data.get('obj', []))} inbounds.") + else: + print(f"Login failed: {response.json().get('msg')}") + +except requests.exceptions.RequestException as e: + print(f"An error occurred: {e}") +``` + +### Node.js (`axios`) + +In Node.js, `axios` does not handle cookies by default. You need to use a cookie jar helper library like `axios-cookiejar-support` and `tough-cookie`. + +First, install the dependencies: +`npm install axios axios-cookiejar-support tough-cookie` + +```javascript +const axios = require('axios'); +const { HttpsCookieAgent } = require('http-cookie-agent/http'); +const tough = require('tough-cookie'); + +// --- Configuration --- +const BASE_URL = 'http://127.0.0.1:PORT/YOUR_SECRET_PATH'; +const USERNAME = 'your_username'; +const PASSWORD = 'your_password'; + +async function main() { + // 1. Create a cookie jar to store session cookies + const cookieJar = new tough.CookieJar(); + + // 2. Create an axios instance that uses the cookie jar + const apiClient = axios.create({ + httpAgent: new HttpsCookieAgent({ cookies: { jar: cookieJar } }), + httpsAgent: new HttpsCookieAgent({ cookies: { jar: cookieJar } }), + }); + + try { + // 3. Login + console.log('Attempting to log in...'); + const loginUrl = `${BASE_URL}/login`; + // For x-www-form-urlencoded, use a URLSearchParams object + const loginData = new URLSearchParams({ + username: USERNAME, + password: PASSWORD + }); + + const loginResponse = await apiClient.post(loginUrl, loginData); + + if (loginResponse.data.success) { + console.log('Login successful!'); + + // 4. Make another request. The cookie is sent automatically. + const inboundsUrl = `${BASE_URL}/panel/inbound/list`; + const inboundsResponse = await apiClient.post(inboundsUrl); + + if (inboundsResponse.data.success) { + console.log(`Successfully fetched ${inboundsResponse.data.obj.length} inbounds.`); + } else { + console.error('Failed to fetch inbounds:', inboundsResponse.data.msg); + } + } else { + console.error('Login failed:', loginResponse.data.msg); + } + } catch (error) { + console.error('An API error occurred:', error.message); + } +} + +main(); +``` + +### Browser JavaScript (`fetch`) + +In a web browser context, `fetch` can automatically handle cookies if the request is to the same origin, or if you specify `credentials: 'include'` for cross-origin requests. + +```javascript +// --- Configuration --- +const BASE_URL = 'http://127.0.0.1:PORT/YOUR_SECRET_PATH'; +const USERNAME = 'your_username'; +const PASSWORD = 'your_password'; + +async function runApiFlow() { + try { + // 1. Login + console.log('Logging in...'); + const loginResponse = await fetch(`${BASE_URL}/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + username: USERNAME, + password: PASSWORD + }), + // This is crucial for the browser to store and send cookies + credentials: 'include' + }); + + const loginResult = await loginResponse.json(); + if (!loginResult.success) { + throw new Error(`Login failed: ${loginResult.msg}`); + } + console.log('Login successful!'); + + // 2. Fetch inbounds. The browser automatically includes the cookie. + const inboundsResponse = await fetch(`${BASE_URL}/panel/inbound/list`, { + method: 'POST', + credentials: 'include' + }); + + const inboundsResult = await inboundsResponse.json(); + if (inboundsResult.success) { + console.log(`Found ${inboundsResult.obj.length} inbounds.`); + } else { + throw new Error(`Failed to fetch inbounds: ${inboundsResult.msg}`); + } + + } catch (error) { + console.error('API Flow Error:', error); + } +} + +runApiFlow(); +``` + +## Generating the VLESS URL + +After creating an inbound using the `/panel/inbound/add` endpoint, you can construct a standard `vless://` URL from the `obj` field in the JSON response. + +The URL format is: +`vless://{UUID}@{ADDRESS}:{PORT}?{PARAMETERS}#{REMARK}` + +Here is how to map the JSON response fields to the URL components: + +| URL Part | JSON Path from `obj` | Example | +| :---------- | :-------------------------------------------------------------- | :---------------------------------------------- | +| `UUID` | `settings.clients[0].id` (after JSON parsing) | `60f3a042-7f0c-43a5-a9e6-de76f66703dd` | +| `ADDRESS` | `listen` (or your server's domain name) | `YOUR_SERVER_IP` | +| `PORT` | `port` | `48673` | +| `REMARK` | `remark` (URL-encoded) | `Test%20test` | + +**Parameters (in the query string):** + +| Parameter | JSON Path from `obj` | Description | +| :-------- | :-------------------------------------------------------------- | :---------------------------------------------- | +| `type` | `streamSettings.network` | Transport protocol, e.g., `tcp`. | +| `security` | `streamSettings.security` | Security layer, e.g., `reality`. | +| `pbk` | `streamSettings.realitySettings.settings.publicKey` | The public key for Reality. | +| `fp` | `streamSettings.realitySettings.settings.fingerprint` | The browser fingerprint, e.g., `chrome`. | +| `sni` | `streamSettings.realitySettings.serverNames[0]` | The Server Name Indication to use. | +| `sid` | `streamSettings.realitySettings.shortIds[0]` | The first short ID from the list. | +| `spx` | `streamSettings.realitySettings.settings.spiderX` | The SpiderX path. | \ No newline at end of file