diff --git a/.gitignore b/.gitignore index a783af6..b02fbf1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,18 @@ +# Secrets — never commit real credentials vault_password.txt +**/secrets.yml +**/vault_password.txt +**/*.secret +**/*.vault + .vscode .ansible roles/hosts.yml -roles/sing-box/defaults/secrets.yml -roles/sing-box-playbook/defaults/secrets.yml -roles/hosts.yml -roles/xray/defaults/secrets.yml -roles/xray/defaults/vic_secret.yml # Generated by tests/run.sh tests/.cache/ tests/.output/ tests/fixtures/test_secrets.yml + +CLAUDE.md \ No newline at end of file diff --git a/roles/sing-box-playbook/defaults/main.yml b/roles/sing-box-playbook/defaults/main.yml index bee8b0b..eb9b2f9 100644 --- a/roles/sing-box-playbook/defaults/main.yml +++ b/roles/sing-box-playbook/defaults/main.yml @@ -2,7 +2,7 @@ # Default variables for the sing-box role with Hysteria2 # --- Sing-box Download Variables --- -singbox_version: "1.12.21" +singbox_version: "1.13.3" singbox_auto_update: true singbox_repo: "SagerNet/sing-box" singbox_architecture: "amd64" # Options: amd64, arm64, armv7 @@ -12,16 +12,9 @@ singbox_config_dir: "/etc/sing-box" singbox_user: "nobody" # --- DNS Settings --- -singbox_dns_servers: - - tag: "google" - address: "tls://8.8.8.8" - strategy: "prefer_ipv4" - - tag: "cloudflare" - address: "tls://1.1.1.1" - strategy: "prefer_ipv4" - - tag: "local" - address: "local" - detour: "direct" +# sing-box 1.12+ format: type + server fields (address: prefix is legacy) +singbox_dns_strategy: "prefer_ipv4" # global: prefer_ipv4, prefer_ipv6, ipv4_only, ipv6_only +singbox_dns_final: "local" # default server tag when no rule matches # --- Log Settings --- singbox_log_disabled: false @@ -93,4 +86,15 @@ singbox_geosite_enabled: true singbox_geosite_url: "https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db" singbox_geosite_path: "/etc/sing-box/geosite.db" +# --- Raven-subscribe integration --- +# When enabled, Raven-subscribe will sync Hysteria2 users from sing-box config. +# This variable is consumed by the xray role's raven-subscribe/config.json.j2 template. +# Set raven_subscribe_singbox_config to point to sing-box config file. +# Set raven_subscribe_singbox_enabled: true to activate sync. +# +# These variables are only effective when both roles (xray + sing-box) are deployed together. +# If deploying sing-box standalone, configure Raven manually. +raven_subscribe_singbox_config: "{{ singbox_config_dir }}/config.json" +raven_subscribe_singbox_enabled: true + # --- System Packages --- diff --git a/roles/sing-box-playbook/defaults/secrets.yml.example b/roles/sing-box-playbook/defaults/secrets.yml.example new file mode 100644 index 0000000..84f3d9e --- /dev/null +++ b/roles/sing-box-playbook/defaults/secrets.yml.example @@ -0,0 +1,21 @@ +--- +# secrets.yml — encrypt with ansible-vault: +# ansible-vault encrypt roles/sing-box-playbook/defaults/secrets.yml + +# --- Hysteria2 users --- +# At least one user required. +singbox_hysteria2_users: + - name: "user@example.com" + password: "change-me-strong-password" + +# --- Obfuscation (required when singbox_hysteria2_obfs_enabled: true) --- +singbox_hysteria2_obfs_password: "change-me-obfs-password" + +# --- TLS / ACME --- +singbox: + tls_enabled: true + tls_server_name: "your-server.com" # Public domain pointing to this server + tls_acme_domain: "your-server.com" # Domain for Let's Encrypt certificate + tls_acme_email: "admin@your-server.com" # Email for Let's Encrypt notifications + tls_acme_provider: "letsencrypt" # letsencrypt or zerossl + tls_acme_data_directory: "/etc/sing-box/acme" diff --git a/roles/sing-box-playbook/handlers/main.yml b/roles/sing-box-playbook/handlers/main.yml index 3be70b2..a2d2939 100644 --- a/roles/sing-box-playbook/handlers/main.yml +++ b/roles/sing-box-playbook/handlers/main.yml @@ -1,5 +1,14 @@ # handlers/main.yml -# Handlers for the sing-box role +# IMPORTANT: Ansible executes handlers in definition order, not notification order. +# Validate must come BEFORE Restart so invalid configs are caught before reload. + +- name: Validate sing-box config + ansible.builtin.command: + cmd: "{{ singbox_install_dir }}/sing-box check -c {{ singbox_config_dir }}/config.json" + register: singbox_validate_result + changed_when: false + failed_when: singbox_validate_result.rc != 0 + when: ansible_facts['service_mgr'] in ['systemd', 'openrc'] - name: Reload systemd and restart sing-box ansible.builtin.systemd: @@ -7,16 +16,20 @@ name: sing-box state: restarted enabled: true + when: ansible_facts['service_mgr'] == "systemd" listen: "Reload systemd and restart sing-box" - name: Restart sing-box service ansible.builtin.systemd: name: sing-box state: restarted + daemon_reload: true + when: ansible_facts['service_mgr'] == "systemd" listen: "Restart sing-box service" - name: Reload sing-box configuration ansible.builtin.systemd: name: sing-box state: reloaded + when: ansible_facts['service_mgr'] == "systemd" listen: "Reload sing-box configuration" diff --git a/roles/sing-box-playbook/tasks/config.yml b/roles/sing-box-playbook/tasks/config.yml new file mode 100644 index 0000000..5b49a64 --- /dev/null +++ b/roles/sing-box-playbook/tasks/config.yml @@ -0,0 +1,51 @@ +--- +- name: sing-box | Create configuration directory + ansible.builtin.file: + path: "{{ singbox_config_dir }}" + state: directory + owner: root + group: root + mode: "0755" + +- name: sing-box | Create ACME certificate directory + ansible.builtin.file: + path: "{{ singbox.tls_acme_data_directory }}" + state: directory + owner: root + group: root + mode: "0700" + when: singbox.tls_enabled | default(true) + +- name: sing-box | Create log directory + ansible.builtin.file: + path: "{{ singbox_log_output | dirname }}" + state: directory + owner: root + group: root + mode: "0755" + +- name: sing-box | Download GeoIP database + ansible.builtin.get_url: + url: "{{ singbox_geoip_url }}" + dest: "{{ singbox_geoip_path }}" + mode: "0644" + timeout: 300 + when: singbox_geoip_enabled + +- name: sing-box | Download GeoSite database + ansible.builtin.get_url: + url: "{{ singbox_geosite_url }}" + dest: "{{ singbox_geosite_path }}" + mode: "0644" + timeout: 300 + when: singbox_geosite_enabled + +- name: sing-box | Generate configuration from template + ansible.builtin.template: + src: config.json.j2 + dest: "{{ singbox_config_dir }}/config.json" + owner: root + group: root + mode: "0644" + validate: "{{ singbox_install_dir }}/sing-box check -c %s" + notify: Restart sing-box service diff --git a/roles/sing-box-playbook/tasks/install.yml b/roles/sing-box-playbook/tasks/install.yml new file mode 100644 index 0000000..efa14c4 --- /dev/null +++ b/roles/sing-box-playbook/tasks/install.yml @@ -0,0 +1,64 @@ +--- +- name: sing-box | Get latest release from GitHub + ansible.builtin.uri: + url: "https://api.github.com/repos/{{ singbox_repo }}/releases/latest" + return_content: true + headers: + Accept: "application/vnd.github.v3+json" + register: singbox_latest_release + when: singbox_auto_update + ignore_errors: true + +- name: sing-box | Set version from latest release + ansible.builtin.set_fact: + singbox_version: "{{ singbox_latest_release.json.tag_name | default(singbox_version) | regex_replace('^v', '') }}" + when: singbox_auto_update and singbox_latest_release is succeeded + +- name: sing-box | Display version to be installed + ansible.builtin.debug: + msg: "Installing sing-box version: {{ singbox_version }}" + +- name: sing-box | Create installation directory + ansible.builtin.file: + path: "{{ singbox_install_dir }}" + state: directory + mode: "0755" + +- name: sing-box | Download archive + ansible.builtin.get_url: + url: "{{ singbox_url }}/v{{ singbox_version }}/sing-box-{{ singbox_version }}-linux-{{ singbox_architecture }}.tar.gz" + dest: "/tmp/sing-box-{{ singbox_version }}.tar.gz" + mode: "0644" + timeout: 300 + +- name: sing-box | Extract archive + ansible.builtin.unarchive: + src: "/tmp/sing-box-{{ singbox_version }}.tar.gz" + dest: "/tmp" + remote_src: true + +- name: sing-box | Install binary + ansible.builtin.copy: + src: "/tmp/sing-box-{{ singbox_version }}-linux-{{ singbox_architecture }}/sing-box" + dest: "{{ singbox_install_dir }}/sing-box" + remote_src: true + mode: "0755" + owner: root + group: root + +- name: sing-box | Clean up downloaded files + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - "/tmp/sing-box-{{ singbox_version }}.tar.gz" + - "/tmp/sing-box-{{ singbox_version }}-linux-{{ singbox_architecture }}" + +- name: sing-box | Verify installation + ansible.builtin.command: "{{ singbox_install_dir }}/sing-box version" + register: singbox_version_output + changed_when: false + +- name: sing-box | Display installed version + ansible.builtin.debug: + msg: "{{ singbox_version_output.stdout }}" diff --git a/roles/sing-box-playbook/tasks/main.yml b/roles/sing-box-playbook/tasks/main.yml index 3c46918..e8f748d 100644 --- a/roles/sing-box-playbook/tasks/main.yml +++ b/roles/sing-box-playbook/tasks/main.yml @@ -1,259 +1,25 @@ -# tasks/main.yml -# Main tasks for the sing-box role with Hysteria2 and auto-update - -- name: Display OS information +--- +- name: sing-box | Display OS information ansible.builtin.debug: msg: "Operating System: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}" - tags: ["always"] - -# --- System Configuration --- -- name: Enable IPv4 forwarding - ansible.posix.sysctl: - name: net.ipv4.ip_forward - value: "1" - state: present - sysctl_set: true - reload: true - tags: ["full_reinstall"] - -- name: Disable ICMP echo (ping) - ansible.posix.sysctl: - name: net.ipv4.icmp_echo_ignore_all - value: "1" - state: present - sysctl_set: true - reload: true - tags: ["full_reinstall"] - -- name: Optimize network performance - increase TCP buffer sizes - ansible.posix.sysctl: - name: "{{ item.name }}" - value: "{{ item.value }}" - state: present - sysctl_set: true - reload: true - loop: - - { name: "net.core.rmem_max", value: "134217728" } - - { name: "net.core.wmem_max", value: "134217728" } - - { name: "net.ipv4.tcp_rmem", value: "4096 87380 67108864" } - - { name: "net.ipv4.tcp_wmem", value: "4096 65536 67108864" } - - { name: "net.ipv4.tcp_congestion_control", value: "bbr" } - tags: ["full_reinstall"] - -# --- Get Latest Sing-box Version --- -- name: Get latest sing-box release from GitHub - ansible.builtin.uri: - url: "https://api.github.com/repos/{{ singbox_repo }}/releases/latest" - return_content: true - headers: - Accept: "application/vnd.github.v3+json" - register: singbox_latest_release - when: singbox_auto_update - ignore_errors: true - tags: ["full_reinstall"] - -- name: Set singbox_version from latest release - ansible.builtin.set_fact: - singbox_version: "{{ singbox_latest_release.json.tag_name | default(singbox_version) | regex_replace('^v', '') }}" - when: singbox_auto_update and singbox_latest_release is succeeded - tags: ["full_reinstall"] - -- name: Display sing-box version to be installed - ansible.builtin.debug: - msg: "Installing sing-box version: {{ singbox_version }}" - tags: ["full_reinstall"] - -# --- Download and Install Sing-box --- -- name: Create installation directory - ansible.builtin.file: - path: "{{ singbox_install_dir }}" - state: directory - mode: "0755" - tags: ["full_reinstall"] - -- name: Download sing-box archive - ansible.builtin.get_url: - url: "{{ singbox_url }}/v{{ singbox_version }}/sing-box-{{ singbox_version }}-linux-{{ singbox_architecture }}.tar.gz" - dest: "/tmp/sing-box-{{ singbox_version }}.tar.gz" - mode: "0644" - timeout: 300 - tags: ["full_reinstall"] - -- name: Extract sing-box archive - ansible.builtin.unarchive: - src: "/tmp/sing-box-{{ singbox_version }}.tar.gz" - dest: "/tmp" - remote_src: true - tags: ["full_reinstall"] - -- name: Install sing-box binary - ansible.builtin.copy: - src: "/tmp/sing-box-{{ singbox_version }}-linux-{{ singbox_architecture }}/sing-box" - dest: "{{ singbox_install_dir }}/sing-box" - remote_src: true - mode: "0755" - owner: root - group: root - tags: ["full_reinstall"] - -- name: Clean up downloaded files - ansible.builtin.file: - path: "{{ item }}" - state: absent - loop: - - "/tmp/sing-box-{{ singbox_version }}.tar.gz" - - "/tmp/sing-box-{{ singbox_version }}-linux-{{ singbox_architecture }}" - tags: ["full_reinstall"] - -- name: Verify sing-box installation - ansible.builtin.command: "{{ singbox_install_dir }}/sing-box version" - register: singbox_version_output - changed_when: false - tags: ["full_reinstall"] + tags: always -- name: Display sing-box version - ansible.builtin.debug: - msg: "{{ singbox_version_output.stdout }}" - tags: ["full_reinstall"] - -# --- Configuration Setup --- -- name: Create sing-box configuration directory - ansible.builtin.file: - path: "{{ singbox_config_dir }}" - state: directory - owner: root - group: root - mode: "0755" - tags: - - full_reinstall - - config_update - -- name: Create ACME certificate directory - ansible.builtin.file: - path: "{{ singbox.tls_acme_data_directory }}" - state: directory - owner: root - group: root - mode: "0700" - when: singbox.tls_enabled - tags: - - full_reinstall - - config_update - -- name: Create log directory - ansible.builtin.file: - path: "{{ singbox_log_output | dirname }}" - state: directory - owner: root - group: root - mode: "0755" - tags: - - full_reinstall - - config_update - -- name: Download GeoIP database - ansible.builtin.get_url: - url: "{{ singbox_geoip_url }}" - dest: "{{ singbox_geoip_path }}" - mode: "0644" - timeout: 300 - when: singbox_geoip_enabled - tags: - - full_reinstall - - config_update - -- name: Download GeoSite database - ansible.builtin.get_url: - url: "{{ singbox_geosite_url }}" - dest: "{{ singbox_geosite_path }}" - mode: "0644" - timeout: 300 - when: singbox_geosite_enabled - tags: - - full_reinstall - - config_update - -- name: Generate sing-box configuration from template - ansible.builtin.template: - src: config.json.j2 - dest: "{{ singbox_config_dir }}/config.json" - owner: root - group: root - mode: "0644" - validate: "{{ singbox_install_dir }}/sing-box check -c %s" - notify: Restart sing-box service - tags: - - full_reinstall - - config_update +- name: sing-box | Validate + ansible.builtin.import_tasks: validate.yml + tags: always -# --- Systemd Service Setup --- -- name: Create systemd service file - ansible.builtin.template: - src: sing-box.service.j2 - dest: /etc/systemd/system/sing-box.service - owner: root - group: root - mode: "0644" - notify: Reload systemd and restart sing-box - tags: ["full_reinstall"] +- name: sing-box | System tuning + ansible.builtin.import_tasks: system.yml + tags: singbox_system -- name: Reload systemd daemon - ansible.builtin.systemd: - daemon_reload: true - tags: ["full_reinstall"] - -- name: Enable and start sing-box service - ansible.builtin.systemd: - name: sing-box - enabled: true - state: started - tags: ["full_reinstall"] - -# --- Final Status Check --- -- name: Wait for sing-box to start - ansible.builtin.wait_for: - timeout: 10 - tags: - - full_reinstall - - config_update - -- name: Check sing-box service status - ansible.builtin.systemd: - name: sing-box - register: singbox_service_status - tags: - - full_reinstall - - config_update - -- name: Display sing-box service status - ansible.builtin.debug: - msg: "sing-box service is {{ singbox_service_status.status.ActiveState }}" - tags: - - full_reinstall - - config_update - -- name: Display connection information - ansible.builtin.debug: - msg: | - ======================================== - Sing-box Hysteria2 Server Configuration - ======================================== - Server: {{ singbox.tls_server_name }} - Port: {{ singbox_hysteria2_listen_port }} - Protocol: Hysteria2 - TLS: Enabled (ACME) - Obfuscation: {{ singbox_hysteria2_obfs_type if singbox_hysteria2_obfs_enabled else 'Disabled' }} +- name: sing-box | Install + ansible.builtin.import_tasks: install.yml + tags: singbox_install - Client Configuration: - - Server: {{ singbox.tls_server_name }}:{{ singbox_hysteria2_listen_port }} - - Password: (check your secrets.yml) - - SNI: {{ singbox.tls_server_name }} - - ALPN: h3 - - Obfs Type: {{ singbox_hysteria2_obfs_type if singbox_hysteria2_obfs_enabled else 'none' }} +- name: sing-box | Configure + ansible.builtin.import_tasks: config.yml + tags: singbox_config - Logs: {{ singbox_log_output }} - Config: {{ singbox_config_dir }}/config.json - ======================================== - tags: - - full_reinstall - - config_update +- name: sing-box | Service + ansible.builtin.import_tasks: service.yml + tags: singbox_service diff --git a/roles/sing-box-playbook/tasks/service.yml b/roles/sing-box-playbook/tasks/service.yml new file mode 100644 index 0000000..66fe93b --- /dev/null +++ b/roles/sing-box-playbook/tasks/service.yml @@ -0,0 +1,55 @@ +--- +- name: sing-box | Deploy systemd service file + ansible.builtin.template: + src: sing-box.service.j2 + dest: /etc/systemd/system/sing-box.service + owner: root + group: root + mode: "0644" + notify: Reload systemd and restart sing-box + +- name: sing-box | Reload systemd daemon + ansible.builtin.systemd: + daemon_reload: true + +- name: sing-box | Enable and start service + ansible.builtin.systemd: + name: sing-box + enabled: true + state: started + +- name: sing-box | Wait for service to start + ansible.builtin.wait_for: + timeout: 10 + +- name: sing-box | Check service status + ansible.builtin.systemd: + name: sing-box + register: singbox_service_status + +- name: sing-box | Display service status + ansible.builtin.debug: + msg: "sing-box service is {{ singbox_service_status.status.ActiveState }}" + +- name: sing-box | Display connection information + ansible.builtin.debug: + msg: | + ======================================== + Sing-box Hysteria2 Server Configuration + ======================================== + Server: {{ singbox.tls_server_name }} + Port: {{ singbox_hysteria2_listen_port }} + Protocol: Hysteria2 + TLS: Enabled (ACME) + Obfuscation: {{ singbox_hysteria2_obfs_type if singbox_hysteria2_obfs_enabled else 'Disabled' }} + + Client Configuration: + - Server: {{ singbox.tls_server_name }}:{{ singbox_hysteria2_listen_port }} + - Password: (check your secrets.yml) + - SNI: {{ singbox.tls_server_name }} + - ALPN: h3 + - Obfs Type: {{ singbox_hysteria2_obfs_type if singbox_hysteria2_obfs_enabled else 'none' }} + + Logs: {{ singbox_log_output }} + Config: {{ singbox_config_dir }}/config.json + ======================================== diff --git a/roles/sing-box-playbook/tasks/system.yml b/roles/sing-box-playbook/tasks/system.yml new file mode 100644 index 0000000..dea5102 --- /dev/null +++ b/roles/sing-box-playbook/tasks/system.yml @@ -0,0 +1,30 @@ +--- +- name: sing-box | Enable IPv4 forwarding + ansible.posix.sysctl: + name: net.ipv4.ip_forward + value: "1" + state: present + sysctl_set: true + reload: true + +- name: sing-box | Disable ICMP echo (ping) + ansible.posix.sysctl: + name: net.ipv4.icmp_echo_ignore_all + value: "1" + state: present + sysctl_set: true + reload: true + +- name: sing-box | Optimize network — increase TCP buffer sizes and enable BBR + ansible.posix.sysctl: + name: "{{ item.name }}" + value: "{{ item.value }}" + state: present + sysctl_set: true + reload: true + loop: + - { name: "net.core.rmem_max", value: "134217728" } + - { name: "net.core.wmem_max", value: "134217728" } + - { name: "net.ipv4.tcp_rmem", value: "4096 87380 67108864" } + - { name: "net.ipv4.tcp_wmem", value: "4096 65536 67108864" } + - { name: "net.ipv4.tcp_congestion_control", value: "bbr" } diff --git a/roles/sing-box-playbook/tasks/validate.yml b/roles/sing-box-playbook/tasks/validate.yml new file mode 100644 index 0000000..49fe57d --- /dev/null +++ b/roles/sing-box-playbook/tasks/validate.yml @@ -0,0 +1,56 @@ +--- +- name: sing-box | Validate singbox_hysteria2_users is defined and non-empty + ansible.builtin.assert: + that: + - singbox_hysteria2_users is defined + - singbox_hysteria2_users | length > 0 + fail_msg: >- + singbox_hysteria2_users is not defined or empty. + Define at least one user in secrets.yml. + success_msg: "singbox_hysteria2_users is valid" + +- name: sing-box | Validate each user has name and password + ansible.builtin.assert: + that: + - item.name is defined and item.name != '' + - item.password is defined and item.password != '' + fail_msg: >- + User entry is missing required fields. + Each user must have 'name' and 'password'. + Offending entry: {{ item }} + success_msg: "User {{ item.name }} is valid" + loop: "{{ singbox_hysteria2_users }}" + +- name: sing-box | Validate TLS server_name is defined + ansible.builtin.assert: + that: + - singbox.tls_server_name is defined + - singbox.tls_server_name != '' + fail_msg: >- + singbox.tls_server_name is required. + Set it in secrets.yml (e.g. your-server.com). + success_msg: "singbox.tls_server_name is valid" + +- name: sing-box | Validate ACME domain and email are defined + ansible.builtin.assert: + that: + - singbox.tls_acme_domain is defined + - singbox.tls_acme_domain != '' + - singbox.tls_acme_email is defined + - singbox.tls_acme_email != '' + fail_msg: >- + singbox.tls_acme_domain and singbox.tls_acme_email are required for TLS/ACME. + Set them in secrets.yml. + success_msg: "ACME config is valid" + when: singbox.tls_enabled | default(true) + +- name: sing-box | Validate obfs password is defined when obfs is enabled + ansible.builtin.assert: + that: + - singbox_hysteria2_obfs_password is defined + - singbox_hysteria2_obfs_password != '' + fail_msg: >- + singbox_hysteria2_obfs_password is required when singbox_hysteria2_obfs_enabled is true. + Set it in secrets.yml. + success_msg: "Obfuscation password is valid" + when: singbox_hysteria2_obfs_enabled | default(false) diff --git a/roles/sing-box-playbook/templates/config.json.j2 b/roles/sing-box-playbook/templates/config.json.j2 index 4ab7e5a..79d4396 100644 --- a/roles/sing-box-playbook/templates/config.json.j2 +++ b/roles/sing-box-playbook/templates/config.json.j2 @@ -27,9 +27,8 @@ "detour": "direct" } ], - "strategy": "prefer_ipv4", - "disable_cache": false, - "disable_expire": false + "strategy": "{{ singbox_dns_strategy }}", + "final": "{{ singbox_dns_final }}" }, "inbounds": [ @@ -51,10 +50,12 @@ {% endfor %} ], {% endif %} + {% if singbox_hysteria2_obfs_enabled | default(false) and singbox_hysteria2_obfs_password | default('') != '' %} "obfs": { "type": "{{ singbox_hysteria2_obfs_type }}", "password": "{{ singbox_hysteria2_obfs_password }}" }, + {% endif %} "masquerade": "{{ singbox_hysteria2_masquerade }}", "tls": { "enabled": {{ singbox.tls_enabled | lower }}, diff --git a/roles/xray/defaults/main.yml b/roles/xray/defaults/main.yml index bf6a17a..d48509e 100644 --- a/roles/xray/defaults/main.yml +++ b/roles/xray/defaults/main.yml @@ -138,6 +138,17 @@ raven_subscribe_api_inbound_tag: "{{ xray_common.inbound_tag.vless_reality_in }} # Requires xray_api.enable = true. Value: "127.0.0.1:" raven_subscribe_xray_api_addr: "127.0.0.1:{{ xray_api.inbound.port }}" +# Path to sing-box config file. When set, Raven additionally parses sing-box inbounds +# (currently hysteria2) and syncs their users to DB. Leave empty to disable. +# Example: "/etc/sing-box/config.json" +raven_subscribe_singbox_config: "" + +# Enable/disable Xray and sing-box sync independently. +# Set xray_enabled: false if Xray is not installed on this server. +# singbox_enabled defaults to true when singbox_config is set. +raven_subscribe_xray_enabled: true +raven_subscribe_singbox_enabled: false + ##### Set these in secrets.yml (ansible-vault encrypted) ##### # raven_subscribe_server_host: "your-server.com" # Public IP or domain # raven_subscribe_base_url: "http://your-server.com:8080" diff --git a/roles/xray/templates/raven-subscribe/config.json.j2 b/roles/xray/templates/raven-subscribe/config.json.j2 index ee168e3..96c65a8 100644 --- a/roles/xray/templates/raven-subscribe/config.json.j2 +++ b/roles/xray/templates/raven-subscribe/config.json.j2 @@ -9,9 +9,12 @@ "rate_limit_sub_per_min": {{ raven_subscribe_rate_limit_sub_per_min }}, "rate_limit_admin_per_min": {{ raven_subscribe_rate_limit_admin_per_min }}, "api_user_inbound_tag": "{{ raven_subscribe_api_inbound_tag }}", - "xray_api_addr": "{{ raven_subscribe_xray_api_addr }}"{% if xray_vless_client_encryption | default('none') != 'none' %}, + "xray_api_addr": "{{ raven_subscribe_xray_api_addr }}", + "xray_enabled": {{ raven_subscribe_xray_enabled | lower }}, + "singbox_enabled": {{ raven_subscribe_singbox_enabled | lower }}{% if xray_vless_client_encryption | default('') | string | trim not in ('', 'none', 'false', 'False') %}, "vless_client_encryption": { "{{ xray_common.inbound_tag.vless_reality_in }}": "{{ xray_vless_client_encryption }}", "{{ xray_common.inbound_tag.vless_xhttp_in }}": "{{ xray_vless_client_encryption }}" - }{% endif %} + }{% endif %}{% if raven_subscribe_singbox_config | default('') != '' %}, + "singbox_config": "{{ raven_subscribe_singbox_config }}"{% endif %} }