Files
mypointvpn/src/serverus/playbooks/xui_inbound.yml
T

137 lines
5.8 KiB
YAML

# extravars: remark, short_ids, xhttp_path, target (optional)
#
# Создает в 3x-ui подключение vless + xhttp + reality на 443 порту с ежемесячным сбросом трафика.
# Цель reality подбирает сканер панели: TLS 1.3, h2, X25519 и валидный сертификат, из подходящих - с наименьшей задержкой.
# Без target сканируются кандидаты из настроек панели. Ключи x25519 генерирует панель.
# Если подключение с таким remark уже есть, оно не меняется: плейбук только возвращает его параметры.
- name: Create reality inbound
hosts: target
gather_facts: false
vars:
xui_bin: /usr/local/x-ui/x-ui
inbound_port: 443
fingerprint: firefox
tasks:
- ansible.builtin.import_tasks: tasks/xui_api.yml
- name: List inbounds
ansible.builtin.uri:
url: "{{ xui_api_url }}/inbounds/list"
headers: "{{ xui_api_headers }}"
validate_certs: false
register: inbounds
failed_when: not inbounds.json.success | default(false)
no_log: true
- name: Find inbound
ansible.builtin.set_fact:
inbound: "{{ inbounds.json.obj | default([], true) | selectattr('remark', 'equalto', remark) | first | default(none) }}"
no_log: true
- name: Create inbound
when: inbound is none
block:
- name: Scan reality targets
ansible.builtin.uri:
url: "{{ xui_api_url }}/server/scanRealityTargets"
method: POST
headers: "{{ xui_api_headers }}"
body_format: form-urlencoded
body:
targets: "{{ target | default('') }}"
validate_certs: false
timeout: 120
register: scan
failed_when: not scan.json.success | default(false)
- name: Choose reality target
ansible.builtin.set_fact:
reality_target: >-
{{ scan.json.obj
| selectattr('feasible') | rejectattr('privateTarget')
| selectattr('tls13') | selectattr('h2') | selectattr('x25519') | selectattr('certValid')
| sort(attribute='latencyMs') | first | default(none) }}
- name: Require reality target
ansible.builtin.assert:
that: reality_target is not none
fail_msg: "No suitable reality target: {{ scan.json.obj | map(attribute='target') | join(', ') }}"
- name: Generate x25519 keys
ansible.builtin.uri:
url: "{{ xui_api_url }}/server/getNewX25519Cert"
headers: "{{ xui_api_headers }}"
validate_certs: false
register: x25519
failed_when: not x25519.json.success | default(false)
no_log: true
- name: Add inbound
ansible.builtin.uri:
url: "{{ xui_api_url }}/inbounds/add"
method: POST
headers: "{{ xui_api_headers }}"
body_format: json
body:
remark: "{{ remark }}"
enable: true
listen: ""
port: "{{ inbound_port }}"
protocol: vless
total: 0
expiryTime: 0
trafficReset: monthly
trafficResetDay: 1
settings: "{{ {'clients': [], 'decryption': 'none', 'fallbacks': []} | to_json }}"
streamSettings: >-
{{ {
'network': 'xhttp',
'security': 'reality',
'externalProxy': [],
'xhttpSettings': {'path': xhttp_path, 'host': '', 'mode': 'auto', 'xPaddingBytes': '100-1000'},
'realitySettings': {
'show': false,
'xver': 0,
'target': reality_target.host ~ ':' ~ reality_target.port,
'serverNames': [reality_target.host],
'privateKey': x25519.json.obj.privateKey,
'minClientVer': '',
'maxClientVer': '',
'maxTimediff': 0,
'shortIds': short_ids,
'mldsa65Seed': '',
'settings': {
'publicKey': x25519.json.obj.publicKey,
'fingerprint': fingerprint,
'serverName': '',
'spiderX': '/',
'mldsa65Verify': '',
},
},
} | to_json }}
sniffing: "{{ {'enabled': true, 'destOverride': ['http', 'tls', 'quic', 'fakedns'], 'metadataOnly': false, 'routeOnly': false} | to_json }}"
validate_certs: false
register: added
failed_when: not added.json.success | default(false)
no_log: true
- name: Remember created inbound
ansible.builtin.set_fact:
inbound: "{{ added.json.obj }}"
no_log: true
- name: Return inbound
vars:
# список отдает строку JSON, а ответ на добавление - уже объект
stream: "{{ inbound.streamSettings if inbound.streamSettings is mapping else inbound.streamSettings | from_json }}"
ansible.builtin.set_stats:
aggregate: false
data:
inbound_id: "{{ inbound.id }}"
port: "{{ inbound.port }}"
target: "{{ stream.realitySettings.target | default(stream.realitySettings.dest | default('')) }}"
server_name: "{{ stream.realitySettings.serverNames | first }}"
public_key: "{{ stream.realitySettings.settings.publicKey }}"
short_ids: "{{ stream.realitySettings.shortIds }}"
path: "{{ stream.xhttpSettings.path }}"