add xray-lists role

This commit is contained in:
2026-08-28 11:10:47 +00:00
parent 98873cb5eb
commit abeb2e0eb9
7 changed files with 215 additions and 84 deletions
+62
View File
@@ -0,0 +1,62 @@
---
#- name: collect xray policy hosts
# ansible.builtin.set_fact:
# _xray_hosts_with_policy: >-
# {{
# (_xray_hosts_with_policy | default([]))
# + [{'inventory_hostname': item, 'xray_policy': hostvars[item].xray_policy}]
# }}
# loop: "{{ groups[xray_managed_group] }}"
# when: hostvars[item].xray_policy is defined
#- name: validate xray policy sets
# ansible.builtin.assert:
# that:
# - (item.1.bypass | default(item.1.proxy)) == 'all' or
# (item.1.bypass | default(item.1.proxy)) in xray_ip_sets or
# (item.1.bypass | default(item.1.proxy)) in xray_domain_sets or
# (item.1.bypass | default(item.1.proxy)) in (xray_static_sets | default([]))
# fail_msg: "host {{ item.0.inventory_hostname }}: unknown xray set '{{ item.1.bypass | default(item.1.proxy) }}'"
# quiet: true
# loop: "{{ query('ansible.builtin.subelements', _xray_hosts_with_policy | default([]), 'xray_policy', {'skip_missing': True}) }}"
# loop_control:
# label: "{{ item.0.inventory_hostname }} -> {{ item.1.bypass | default(item.1.proxy) }}"
- name: render xray-lists config
ansible.builtin.template:
src: xray-config.yaml.j2
dest: /var/lib/xray-lists/config.yaml
mode: "0640"
notify: restart xray-lists timer
- name: bootstrap empty config files
ansible.builtin.copy:
dest: "/etc/nftables.d/{{ item }}"
content: ""
force: false
mode: "0644"
loop:
- 90-sets.nft
- 90-proxy-prerouting.nft
- 90-proxy-output.nft
- name: render nft sets
ansible.builtin.template:
src: 90-sets.nft.j2
dest: /etc/nftables.d/90-sets.nft
mode: "0644"
notify: reload nftables
- name: render proxy prerouting
ansible.builtin.template:
src: 90-proxy-prerouting.nft.j2
dest: /etc/nftables.d/90-proxy-prerouting.nft
mode: "0644"
notify: reload nftables
- name: render proxy output
ansible.builtin.template:
src: 90-proxy-output.nft.j2
dest: /etc/nftables.d/90-proxy-output.nft
mode: "0644"
notify: reload nftables
+108
View File
@@ -0,0 +1,108 @@
---
- name: install required system packages
apt:
name:
- python3-venv
- git
state: present
update_cache: yes
- name: ensure base directories exist
file:
path: "{{ item }}"
state: directory
owner: root
group: root
mode: '0755'
loop:
- /opt/xray-lists
- /var/lib/xray-lists
- name: clone xray-lists repository
git:
repo: 'https://gitea.oyacoi.ru/pyrschtjag/xray-lists'
dest: /opt/xray-lists-src
version: main
force: yes
- name: check if xray-lists is installed
command: /opt/xray-lists/venv/bin/pip show xray-lists
register: pip_check
changed_when: false
failed_when: false
- name: install xray-lists package into venv
command: /opt/xray-lists/venv/bin/pip install -e /opt/xray-lists-src[socks]
when: pip_check.rc != 0
- name: deploy update helper script
copy:
dest: /var/lib/xray-lists/update.sh
owner: root
group: root
mode: '0755'
content: |
#!/bin/sh
set -e
out=$(/opt/xray-lists/venv/bin/xray-lists)
echo "$out"
dns_changed=0
elements_changed=0
if echo "$out" | grep -A 10 "changed:" | grep -q "nftsets.conf"; then dns_changed=1; fi
if echo "$out" | grep -A 10 "changed:" | grep -q "\.elements\.nft"; then elements_changed=1; fi
if [ "$dns_changed" -eq 1 ] && [ "$elements_changed" -eq 1 ]; then exit 12;
elif [ "$dns_changed" -eq 1 ]; then exit 10;
elif [ "$elements_changed" -eq 1 ]; then exit 11;
fi
exit 0
- name: deploy systemd service unit
copy:
dest: /etc/systemd/system/xray-lists.service
owner: root
group: root
mode: '0644'
content: |
[Unit]
Description=Update Xray lists
[Service]
Type=oneshot
ExecStart=/bin/sh -c '\
/var/lib/xray-lists/update.sh; \
rc=$$?; \
case "$$rc" in \
10) systemctl restart dnsmasq ;; \
11) nft -f /etc/nftables.conf ;; \
12) nft -f /etc/nftables.conf && systemctl restart dnsmasq ;; \
esac'
- name: deploy systemd timer unit
copy:
dest: /etc/systemd/system/xray-lists.timer
owner: root
group: root
mode: '0644'
content: |
[Unit]
Description=Run xray-lists update daily and on boot
[Timer]
OnBootSec=5min
OnUnitActiveSec=12h
Persistent=true
[Install]
WantedBy=timers.target
- name: enable and start xray-lists
ansible.builtin.systemd:
name: xray-lists.timer
enabled: true
state: started
+4 -53
View File
@@ -1,55 +1,6 @@
---
- name: collect xray policy hosts
ansible.builtin.set_fact:
_xray_hosts_with_policy: >-
{{
(_xray_hosts_with_policy | default([]))
+ [{'inventory_hostname': item, 'xray_policy': hostvars[item].xray_policy}]
}}
loop: "{{ groups[xray_managed_group] }}"
when: hostvars[item].xray_policy is defined
- name: include xray-lists install
ansible.builtin.include_tasks: install.yml
- name: validate xray policy sets
ansible.builtin.assert:
that: >-
(item.1.bypass | default(item.1.proxy)) == 'all'
or (item.1.bypass | default(item.1.proxy)) in xray_ip_sets
or (item.1.bypass | default(item.1.proxy)) in xray_domain_sets
or (item.1.bypass | default(item.1.proxy)) in (xray_static_sets | default([]))
fail_msg: >-
host {{ item.0.inventory_hostname }}: unknown xray set
'{{ item.1.bypass | default(item.1.proxy) }}' in xray_policy
loop: "{{ query('ansible.builtin.subelements', _xray_hosts_with_policy | default([]), 'xray_policy', {'skip_missing': True}) }}"
loop_control:
label: "{{ item.0.inventory_hostname }} -> {{ item.1 }}"
- name: render xray-lists config
ansible.builtin.template:
src: xray-config.yaml.j2
dest: /etc/xray-lists/config.yaml
mode: "0640"
notify: restart xray-lists timer
- name: bootstrap empty config files
ansible.builtin.copy:
dest: "/etc/nftables.d/{{ item }}"
content: ""
force: false
mode: "0644"
loop:
- 90-sets.nft
- 90-proxy.nft
- name: render nft sets
ansible.builtin.template:
src: 90-sets.nft.j2
dest: /etc/nftables.d/90-sets.nft
mode: "0644"
notify: reload nftables
- name: render proxy prerouting
ansible.builtin.template:
src: 90-proxy.nft.j2
dest: /etc/nftables.d/90-proxy.nft
mode: "0644"
notify: reload nftables
- name: include xray-lists configure
ansible.builtin.include_tasks: configure.yml
@@ -0,0 +1,11 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% macro set_daddr(rule) %}
{%- if rule in (xray_ip_sets | default([])) or rule in (xray_static_sets | default([])) -%}
{{ rule }}_ip
{%- elif rule in (xray_domain_sets | default([])) -%}
{{ rule }}_dom
{%- endif -%}
{% endmacro %}
{% for rule in output_rules | default([]) | sort %}
ip daddr @{{ set_daddr(rule) }} meta mark set {{ xray_fwmark }} accept
{% endfor %}
@@ -0,0 +1,26 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{% macro set_daddr(name) %}
{%- if name == 'all' %}
0.0.0.0/0
{%- elif name in (xray_ip_sets | default([])) or name in (xray_static_sets | default([])) %}
@{{ name }}_ip
{%- elif name in (xray_domain_sets | default([])) %}
@{{ name }}_dom
{%- else %}
invalid_xray_set_{{ name }}
{% endif %}
{% endmacro %}
{% for item in groups[xray_managed_group] | default([]) | sort %}
{% set client = hostvars[item] %}
{% if client.xray_policy is defined %}
{% set src_ip = client.container_ip %}
{% for rule in client.xray_policy %}
{% set target_set = rule.bypass | default(rule.proxy) %}
{% if rule.bypass is defined %}
meta l4proto { tcp, udp } ip saddr {{ src_ip }} ip daddr {{ set_daddr(target_set) }} accept
{% elif rule.proxy is defined %}
meta l4proto { tcp, udp } ip saddr {{ src_ip }} ip daddr {{ set_daddr(target_set) }} tproxy ip to :{{ xray_tproxy_port }} meta mark set {{ xray_fwmark }} accept
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
@@ -1,31 +0,0 @@
#jinja2: trim_blocks: True, lstrip_blocks: True
{%- macro set_ref(name) -%}
{%- if name == 'all' -%}
0.0.0.0/0
{%- elif name in xray_ip_sets or name in (xray_static_sets | default([])) -%}
@{{ name }}_ip
{%- elif name in xray_domain_sets -%}
@{{ name }}_dom
{%- else -%}
INVALID_XRAY_SET_{{ name }}
{%- endif -%}
{%- endmacro -%}
{%- set rules_list = [] -%}
{%- for item in groups[xray_managed_group] | default([]) | sort -%}
{%- set client = hostvars[item] -%}
{%- if client.xray_policy is defined -%}
{%- set src_ip = client.container_ip | default(client.ansible_host | default(item)) -%}
{%- for rule in client.xray_policy -%}
{%- if rule.bypass is defined -%}
{%- set _ = rules_list.append("meta l4proto { tcp, udp } ip saddr " ~ src_ip ~ " ip daddr " ~ set_ref(rule.bypass) ~ " accept") -%}
{%- elif rule.proxy is defined -%}
{%- set _ = rules_list.append("meta l4proto { tcp, udp } ip saddr " ~ src_ip ~ " ip daddr " ~ set_ref(rule.proxy) ~ " tproxy ip to :" ~ (xray_tproxy_port | default(61219) | string) ~ " meta mark set " ~ (xray_fwmark | default('0x00000001')) ~ " accept") -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{%- endfor -%}
{%- if rules_list | length > 0 -%}
{{- rules_list | join('\n') -}}
{%- endif -%}
@@ -45,3 +45,7 @@ domain_sets:
{% endfor %}
{% endif %}
{% endfor %}
output_rules:
{% for rule in output_rules %}
- {{ rule }}
{% endfor %}