Created
January 3, 2026 04:31
-
-
Save lijunle/1e8db8d6f9eecc09e05c618ec1c62495 to your computer and use it in GitHub Desktop.
Xray script to show and add user config
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| CONFIG_FILE="/usr/local/etc/xray/config.json" | |
| SERVICE_NAME="xray" | |
| # STRING MANIPULATION for HOST/REMARKS | |
| RAW_HOSTNAME=$(hostname) | |
| HOST="$RAW_HOSTNAME" # Change this to host's public domain | |
| REMARKS="$RAW_HOSTNAME" | |
| usage() { | |
| echo "Usage:" | |
| echo " $0 <email> # Show existing user info + QR" | |
| echo " $0 <email> --add # Add new user" | |
| echo " $0 <email> --add --force # Force add (overwrite existing)" | |
| exit 1 | |
| } | |
| if (( EUID != 0 )); then | |
| echo "ERROR: Must run as root." >&2 | |
| exit 1 | |
| fi | |
| if [[ $# -lt 1 ]]; then | |
| usage | |
| fi | |
| EMAIL="$1" | |
| ADD_MODE=false | |
| FORCE=false | |
| # Parse flags | |
| shift | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| --add) ADD_MODE=true ;; | |
| --force) FORCE=true ;; | |
| --help) usage ;; | |
| *) echo "Unknown option: $1" >&2; usage ;; | |
| esac | |
| shift | |
| done | |
| if ! command -v jq >/dev/null 2>&1 || ! command -v xray >/dev/null 2>&1 || ! command -v qrencode >/dev/null 2>&1; then | |
| echo "ERROR: jq, xray, qrencode must be installed." >&2 | |
| exit 1 | |
| fi | |
| # FUNCTION: Update config (handles permissions, temp file, chmod/chown) | |
| update_config() { | |
| local email="$1" remove_existing="$2" | |
| local uuid | |
| uuid=$(xray uuid) | |
| ORIGINAL_MODE=$(stat -c %a "$CONFIG_FILE") | |
| ORIGINAL_OWNER=$(stat -c %U:%G "$CONFIG_FILE") | |
| tmp=$(mktemp) | |
| # Read config file once into variable | |
| local config_content | |
| config_content=$(cat "$CONFIG_FILE") | |
| if [[ "$remove_existing" == true ]]; then | |
| # Remove existing first | |
| config_content=$(echo "$config_content" | jq --arg email "$email" ' | |
| .inbounds[0].settings.clients |= map(select(.email != $email)) | |
| ') | |
| fi | |
| # Add new user | |
| echo "$config_content" | jq --arg email "$email" --arg uuid "$uuid" ' | |
| .inbounds[0].settings.clients += [{ | |
| "email": $email, | |
| "id": $uuid, | |
| "flow": "xtls-rprx-vision", | |
| "level": 0 | |
| }] | |
| ' > "$tmp" | |
| mv "$tmp" "$CONFIG_FILE" | |
| chmod $ORIGINAL_MODE "$CONFIG_FILE" | |
| chown $ORIGINAL_OWNER "$CONFIG_FILE" | |
| # Return the generated UUID | |
| echo "$uuid" | |
| } | |
| # FUNCTION: Show user info + QR | |
| show_user_info() { | |
| local uuid="$1" email="$2" | |
| local port params link | |
| local config_content | |
| config_content=$(cat "$CONFIG_FILE") | |
| port=$(echo "$config_content" | jq -r '.inbounds[0].port') | |
| params="tls=1&tfo=1&xtls=2&remarks=${REMARKS}" | |
| link="vless://auto:${uuid}@${HOST}:${port}?${params}#${email}" | |
| echo "==================================================" | |
| echo " VLESS User: $email" | |
| echo " UUID: $uuid" | |
| echo " HOST: $HOST" | |
| echo " REMARKS: $REMARKS" | |
| echo "==================================================" | |
| echo " Link:" | |
| echo " $link" | |
| echo "==================================================" | |
| echo " QR:" | |
| qrencode -t UTF8 "$link" | |
| } | |
| # CHECK EXISTING USER | |
| config_content=$(cat "$CONFIG_FILE") | |
| EXISTING_UUID=$(echo "$config_content" | jq -r --arg email "$EMAIL" ' | |
| .inbounds[0].settings.clients[]? | |
| | select(.email == $email) | |
| | .id | |
| ') | |
| if [[ "$EXISTING_UUID" != "null" && -n "$EXISTING_UUID" ]]; then | |
| # User exists | |
| show_user_info "$EXISTING_UUID" "$EMAIL" | |
| echo | |
| if [[ "$ADD_MODE" == true ]]; then | |
| if [[ "$FORCE" == true ]]; then | |
| echo "FORCE ADDING (overwriting existing)..." | |
| UUID=$(update_config "$EMAIL" true) | |
| systemctl restart "$SERVICE_NAME" | |
| show_user_info "$UUID" "$EMAIL" | |
| else | |
| echo "ERROR: User exists. Use --force to overwrite." | |
| exit 1 | |
| fi | |
| else | |
| exit 0 | |
| fi | |
| elif [[ "$ADD_MODE" == true ]]; then | |
| # User doesn't exist and add mode is on | |
| echo "Creating new user: $EMAIL" | |
| UUID=$(update_config "$EMAIL" false) | |
| systemctl restart "$SERVICE_NAME" | |
| show_user_info "$UUID" "$EMAIL" | |
| else | |
| # User doesn't exist and add mode is off | |
| echo "ERROR: User '$EMAIL' does not exist." | |
| echo "Use: $0 $EMAIL --add" | |
| exit 1 | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment