From f9e07103b9e20c1f1373243da1f95e4532e7f6bc Mon Sep 17 00:00:00 2001 From: findias Date: Tue, 24 Mar 2026 11:01:46 +0300 Subject: [PATCH] feat: extract raven_subscribe, nginx_frontend, relay into separate roles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New role: raven_subscribe — standalone subscription server deployment, decoupled from xray/sing-box playbooks. Supports per-inbound host/port overrides (inbound_hosts, inbound_ports) for unified media.zirgate.com routing. - New role: nginx_frontend — TLS proxy on EU server (media.zirgate.com), listens on 8443 (not 443, reserved by Xray Reality). Adds nginx stream TCP relay on port 8445 → 127.0.0.1:443 for VLESS Reality passthrough. - New role: relay — nginx reverse proxy on RU VPS (zirgate.com/my.zirgate.com), TCP stream relay on 8444 → EU:8445 for VLESS Reality via RU server. - xray role: remove raven_subscribe vars/tasks (moved to raven_subscribe role), fix DNS query strategy UseIP → UseIPv4 to avoid IPv6 unreachable errors. - sing-box: update hysteria2 default port 8443 → 8444 (8443 now used by nginx_frontend). - raven-subscribe config.j2: add balancer_strategy/probe_url/probe_interval fields. - .gitignore: add **/*_secrets.yml pattern for raven_subscribe secrets files. --- .gitignore | 1 + roles/nginx_frontend/defaults/main.yml | 32 ++++++ .../defaults/secrets.yml.example | 5 + roles/nginx_frontend/handlers/main.yml | 10 ++ roles/nginx_frontend/inventory.ini | 2 + roles/nginx_frontend/tasks/certbot.yml | 23 ++++ roles/nginx_frontend/tasks/install.yml | 15 +++ roles/nginx_frontend/tasks/main.yml | 24 +++++ roles/nginx_frontend/tasks/nginx.yml | 20 ++++ roles/nginx_frontend/tasks/nginx_ssl.yml | 9 ++ roles/nginx_frontend/tasks/stream.yml | 36 +++++++ roles/nginx_frontend/tasks/validate.yml | 11 ++ .../templates/nginx/http.conf.j2 | 20 ++++ .../templates/nginx/https.conf.j2 | 76 +++++++++++++ .../templates/nginx/stream.conf.j2 | 15 +++ roles/raven_subscribe/defaults/main.yml | 55 ++++++++++ .../defaults/secrets.yml.example | 13 +++ roles/raven_subscribe/handlers/main.yml | 9 ++ roles/raven_subscribe/meta/main.yml | 8 ++ roles/raven_subscribe/tasks/main.yml | 100 ++++++++++++++++++ .../raven_subscribe/templates/config.json.j2 | 22 ++++ .../templates/xray-subscription.service.j2 | 23 ++++ roles/relay/defaults/main.yml | 38 +++++++ roles/relay/defaults/secrets.yml.example | 6 ++ roles/relay/handlers/main.yml | 10 ++ roles/relay/inventory.ini | 2 + roles/relay/tasks/certbot.yml | 24 +++++ roles/relay/tasks/install.yml | 15 +++ roles/relay/tasks/main.yml | 28 +++++ roles/relay/tasks/nginx.yml | 14 +++ roles/relay/tasks/nginx_ssl.yml | 11 ++ roles/relay/tasks/stream.yml | 36 +++++++ roles/relay/tasks/stub.yml | 16 +++ roles/relay/tasks/validate.yml | 11 ++ roles/relay/templates/nginx/http.conf.j2 | 14 +++ roles/relay/templates/nginx/https.conf.j2 | 52 +++++++++ roles/relay/templates/nginx/stream.conf.j2 | 15 +++ roles/relay/templates/stub/index.html.j2 | 53 ++++++++++ roles/role_nginx_frontend.yml | 22 ++++ roles/role_raven_subscribe.yml | 11 ++ roles/role_relay.yml | 23 ++++ roles/role_xray.yml | 2 +- roles/sing-box-playbook/defaults/main.yml | 2 +- roles/xray/defaults/main.yml | 40 +------ .../raven_subscribe_secrets.yml.example | 13 +++ roles/xray/handlers/main.yml | 1 + roles/xray/tasks/main.yml | 4 +- .../inbounds/200-in-vless-reality.json.j2 | 2 +- .../conf/inbounds/210-in-xhttp.json.j2 | 2 +- .../templates/raven-subscribe/config.json.j2 | 3 + 50 files changed, 953 insertions(+), 46 deletions(-) create mode 100644 roles/nginx_frontend/defaults/main.yml create mode 100644 roles/nginx_frontend/defaults/secrets.yml.example create mode 100644 roles/nginx_frontend/handlers/main.yml create mode 100644 roles/nginx_frontend/inventory.ini create mode 100644 roles/nginx_frontend/tasks/certbot.yml create mode 100644 roles/nginx_frontend/tasks/install.yml create mode 100644 roles/nginx_frontend/tasks/main.yml create mode 100644 roles/nginx_frontend/tasks/nginx.yml create mode 100644 roles/nginx_frontend/tasks/nginx_ssl.yml create mode 100644 roles/nginx_frontend/tasks/stream.yml create mode 100644 roles/nginx_frontend/tasks/validate.yml create mode 100644 roles/nginx_frontend/templates/nginx/http.conf.j2 create mode 100644 roles/nginx_frontend/templates/nginx/https.conf.j2 create mode 100644 roles/nginx_frontend/templates/nginx/stream.conf.j2 create mode 100644 roles/raven_subscribe/defaults/main.yml create mode 100644 roles/raven_subscribe/defaults/secrets.yml.example create mode 100644 roles/raven_subscribe/handlers/main.yml create mode 100644 roles/raven_subscribe/meta/main.yml create mode 100644 roles/raven_subscribe/tasks/main.yml create mode 100644 roles/raven_subscribe/templates/config.json.j2 create mode 100644 roles/raven_subscribe/templates/xray-subscription.service.j2 create mode 100644 roles/relay/defaults/main.yml create mode 100644 roles/relay/defaults/secrets.yml.example create mode 100644 roles/relay/handlers/main.yml create mode 100644 roles/relay/inventory.ini create mode 100644 roles/relay/tasks/certbot.yml create mode 100644 roles/relay/tasks/install.yml create mode 100644 roles/relay/tasks/main.yml create mode 100644 roles/relay/tasks/nginx.yml create mode 100644 roles/relay/tasks/nginx_ssl.yml create mode 100644 roles/relay/tasks/stream.yml create mode 100644 roles/relay/tasks/stub.yml create mode 100644 roles/relay/tasks/validate.yml create mode 100644 roles/relay/templates/nginx/http.conf.j2 create mode 100644 roles/relay/templates/nginx/https.conf.j2 create mode 100644 roles/relay/templates/nginx/stream.conf.j2 create mode 100644 roles/relay/templates/stub/index.html.j2 create mode 100644 roles/role_nginx_frontend.yml create mode 100644 roles/role_raven_subscribe.yml create mode 100644 roles/role_relay.yml create mode 100644 roles/xray/defaults/raven_subscribe_secrets.yml.example diff --git a/.gitignore b/.gitignore index b02fbf1..545906f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Secrets — never commit real credentials vault_password.txt **/secrets.yml +**/*_secrets.yml **/vault_password.txt **/*.secret **/*.vault diff --git a/roles/nginx_frontend/defaults/main.yml b/roles/nginx_frontend/defaults/main.yml new file mode 100644 index 0000000..36ae905 --- /dev/null +++ b/roles/nginx_frontend/defaults/main.yml @@ -0,0 +1,32 @@ +--- +# nginx_frontend role — TLS frontend for EU server (media.zirgate.com) +# +# Responsibilities: +# - Install nginx + certbot +# - Obtain Let's Encrypt certificate for nginx_frontend_domain +# - Proxy Xray XHTTP (nginx_frontend_xhttp_path) → 127.0.0.1:nginx_frontend_xhttp_port + +# ── Domain ──────────────────────────────────────────────────────────────────── +nginx_frontend_domain: "media.zirgate.com" + +# ── Certbot ─────────────────────────────────────────────────────────────────── +nginx_frontend_certbot_email: "" # Set in secrets.yml + +# ── nginx listen port ───────────────────────────────────────────────────────── +# IMPORTANT: Xray VLESS Reality already binds to 443 (TCP). +# nginx_frontend must listen on a different port (e.g., 8443, 9443). +# The relay role will proxy to this port over HTTPS with SNI. +nginx_frontend_listen_port: 8443 # Must NOT conflict with xray_vless_port (443) + +# ── Raven-subscribe upstream ────────────────────────────────────────────────── +nginx_frontend_raven_port: 8080 # Must match raven_subscribe_listen_addr port + +# ── Xray XHTTP upstream ─────────────────────────────────────────────────────── +nginx_frontend_xhttp_port: 2053 # Must match xray_xhttp.port +nginx_frontend_xhttp_path: "/api/v3/data-sync" # Must match xray_xhttp.xhttpSettings.path + +# ── TCP stream relay for Xray VLESS Reality ─────────────────────────────────── +# Stream proxy: nginx_frontend_reality_port → 127.0.0.1:443 (Xray) +# Allows clients to reach Reality via media.zirgate.com instead of direct EU IP. +nginx_frontend_reality_stream_enabled: true +nginx_frontend_reality_port: 8445 # External TCP port for Reality stream diff --git a/roles/nginx_frontend/defaults/secrets.yml.example b/roles/nginx_frontend/defaults/secrets.yml.example new file mode 100644 index 0000000..77b7f56 --- /dev/null +++ b/roles/nginx_frontend/defaults/secrets.yml.example @@ -0,0 +1,5 @@ +--- +# Copy to secrets.yml and encrypt with ansible-vault: +# ansible-vault encrypt roles/nginx_frontend/defaults/secrets.yml + +nginx_frontend_certbot_email: "admin@admin.com" diff --git a/roles/nginx_frontend/handlers/main.yml b/roles/nginx_frontend/handlers/main.yml new file mode 100644 index 0000000..fc320fa --- /dev/null +++ b/roles/nginx_frontend/handlers/main.yml @@ -0,0 +1,10 @@ +--- +- name: Reload nginx + ansible.builtin.service: + name: nginx + state: reloaded + +- name: Restart nginx + ansible.builtin.service: + name: nginx + state: restarted diff --git a/roles/nginx_frontend/inventory.ini b/roles/nginx_frontend/inventory.ini new file mode 100644 index 0000000..763a413 --- /dev/null +++ b/roles/nginx_frontend/inventory.ini @@ -0,0 +1,2 @@ +[eu] +vpn ansible_host=EU_VPS_IP ansible_user=deploy diff --git a/roles/nginx_frontend/tasks/certbot.yml b/roles/nginx_frontend/tasks/certbot.yml new file mode 100644 index 0000000..b609153 --- /dev/null +++ b/roles/nginx_frontend/tasks/certbot.yml @@ -0,0 +1,23 @@ +--- +- name: Nginx frontend | Check if certificate exists + ansible.builtin.stat: + path: "/etc/letsencrypt/live/{{ nginx_frontend_domain }}/fullchain.pem" + register: nginx_frontend_cert + +- name: Nginx frontend | Obtain Let's Encrypt certificate + ansible.builtin.command: + cmd: > + certbot certonly --webroot + --webroot-path /var/www/letsencrypt + --non-interactive + --agree-tos + --email {{ nginx_frontend_certbot_email }} + -d {{ nginx_frontend_domain }} + when: not nginx_frontend_cert.stat.exists + notify: Reload nginx + +- name: Nginx frontend | Ensure certbot renewal timer is enabled + ansible.builtin.service: + name: certbot.timer + enabled: true + state: started diff --git a/roles/nginx_frontend/tasks/install.yml b/roles/nginx_frontend/tasks/install.yml new file mode 100644 index 0000000..632858d --- /dev/null +++ b/roles/nginx_frontend/tasks/install.yml @@ -0,0 +1,15 @@ +--- +- name: Nginx frontend | Install nginx and certbot + ansible.builtin.apt: + name: + - nginx + - certbot + - python3-certbot-nginx + state: present + update_cache: true + +- name: Nginx frontend | Ensure nginx is enabled and started + ansible.builtin.service: + name: nginx + enabled: true + state: started diff --git a/roles/nginx_frontend/tasks/main.yml b/roles/nginx_frontend/tasks/main.yml new file mode 100644 index 0000000..0519d62 --- /dev/null +++ b/roles/nginx_frontend/tasks/main.yml @@ -0,0 +1,24 @@ +--- +- name: Nginx frontend | Validate + ansible.builtin.import_tasks: validate.yml + tags: always + +- name: Nginx frontend | Install packages + ansible.builtin.import_tasks: install.yml + tags: nginx_frontend_install + +- name: Nginx frontend | Configure HTTP (pre-certbot) + ansible.builtin.import_tasks: nginx.yml + tags: nginx_frontend_nginx + +- name: Nginx frontend | Obtain TLS certificate + ansible.builtin.import_tasks: certbot.yml + tags: nginx_frontend_certbot + +- name: Nginx frontend | Deploy HTTPS config + ansible.builtin.import_tasks: nginx_ssl.yml + tags: nginx_frontend_ssl + +- name: Nginx frontend | Configure TCP stream relay + ansible.builtin.import_tasks: stream.yml + tags: nginx_frontend_stream diff --git a/roles/nginx_frontend/tasks/nginx.yml b/roles/nginx_frontend/tasks/nginx.yml new file mode 100644 index 0000000..3778a36 --- /dev/null +++ b/roles/nginx_frontend/tasks/nginx.yml @@ -0,0 +1,20 @@ +--- +- name: Nginx frontend | Create letsencrypt webroot + ansible.builtin.file: + path: /var/www/letsencrypt + state: directory + owner: root + group: root + mode: "0755" + +- name: Nginx frontend | Deploy HTTP config (pre-certbot) + ansible.builtin.template: + src: nginx/http.conf.j2 + dest: "/etc/nginx/conf.d/{{ nginx_frontend_domain }}.conf" + owner: root + group: root + mode: "0644" + notify: Reload nginx + +- name: Nginx frontend | Reload nginx before certbot + ansible.builtin.meta: flush_handlers diff --git a/roles/nginx_frontend/tasks/nginx_ssl.yml b/roles/nginx_frontend/tasks/nginx_ssl.yml new file mode 100644 index 0000000..cedb92e --- /dev/null +++ b/roles/nginx_frontend/tasks/nginx_ssl.yml @@ -0,0 +1,9 @@ +--- +- name: Nginx frontend | Deploy HTTPS config + ansible.builtin.template: + src: nginx/https.conf.j2 + dest: "/etc/nginx/conf.d/{{ nginx_frontend_domain }}.conf" + owner: root + group: root + mode: "0644" + notify: Reload nginx diff --git a/roles/nginx_frontend/tasks/stream.yml b/roles/nginx_frontend/tasks/stream.yml new file mode 100644 index 0000000..7ea512c --- /dev/null +++ b/roles/nginx_frontend/tasks/stream.yml @@ -0,0 +1,36 @@ +--- +- name: Nginx frontend | Ensure stream.d directory exists + ansible.builtin.file: + path: /etc/nginx/stream.d + state: directory + owner: root + group: root + mode: "0755" + +- name: Nginx frontend | Ensure stream block include in nginx.conf + ansible.builtin.blockinfile: + path: /etc/nginx/nginx.conf + marker: "# {mark} ANSIBLE MANAGED stream block" + block: | + stream { + include /etc/nginx/stream.d/*.conf; + } + insertafter: EOF + notify: Reload nginx + +- name: Nginx frontend | Deploy Reality stream config + ansible.builtin.template: + src: nginx/stream.conf.j2 + dest: "/etc/nginx/stream.d/{{ nginx_frontend_domain }}.conf" + owner: root + group: root + mode: "0644" + notify: Reload nginx + when: nginx_frontend_reality_stream_enabled + +- name: Nginx frontend | Remove Reality stream config (disabled) + ansible.builtin.file: + path: "/etc/nginx/stream.d/{{ nginx_frontend_domain }}.conf" + state: absent + notify: Reload nginx + when: not nginx_frontend_reality_stream_enabled diff --git a/roles/nginx_frontend/tasks/validate.yml b/roles/nginx_frontend/tasks/validate.yml new file mode 100644 index 0000000..4e5767d --- /dev/null +++ b/roles/nginx_frontend/tasks/validate.yml @@ -0,0 +1,11 @@ +--- +- name: Nginx frontend | Validate required vars + ansible.builtin.assert: + that: + - nginx_frontend_domain is defined + - nginx_frontend_domain != '' + - nginx_frontend_certbot_email is defined + - nginx_frontend_certbot_email != '' + fail_msg: >- + nginx_frontend_domain and nginx_frontend_certbot_email must be set in secrets.yml. + success_msg: "Nginx frontend vars are valid" diff --git a/roles/nginx_frontend/templates/nginx/http.conf.j2 b/roles/nginx_frontend/templates/nginx/http.conf.j2 new file mode 100644 index 0000000..7c8ba7a --- /dev/null +++ b/roles/nginx_frontend/templates/nginx/http.conf.j2 @@ -0,0 +1,20 @@ +# {{ nginx_frontend_domain }} — HTTP only (pre-certbot) +# Managed by Ansible nginx_frontend role +# +# This config is temporary and is replaced by https.conf.j2 after certbot obtains the certificate. +# It must allow certbot HTTP-01 validation for the Let's Encrypt certificate. + +server { + listen 80; + server_name {{ nginx_frontend_domain }}; + + # Allow certbot HTTP-01 challenge + location /.well-known/acme-challenge/ { + root /var/www/letsencrypt; + } + + # Redirect all other traffic to HTTPS (when cert is available) + location / { + return 301 https://$host$request_uri; + } +} diff --git a/roles/nginx_frontend/templates/nginx/https.conf.j2 b/roles/nginx_frontend/templates/nginx/https.conf.j2 new file mode 100644 index 0000000..bed7ef5 --- /dev/null +++ b/roles/nginx_frontend/templates/nginx/https.conf.j2 @@ -0,0 +1,76 @@ +# {{ nginx_frontend_domain }} — HTTPS frontend for EU server +# Managed by Ansible nginx_frontend role +# +# Routes: +# /sub/, /c/ → Raven-subscribe (127.0.0.1:{{ nginx_frontend_raven_port }}) +# /api/ → Raven-subscribe admin API +# /health → Raven-subscribe health check +# {{ nginx_frontend_xhttp_path }} → Xray XHTTP (127.0.0.1:{{ nginx_frontend_xhttp_port }}) + +# ── Redirect HTTP → HTTPS ──────────────────────────────────────────────────── +server { + listen 80; + server_name {{ nginx_frontend_domain }}; + return 301 https://$host$request_uri; +} + +# ── HTTPS ───────────────────────────────────────────────────────────────────── +server { + listen {{ nginx_frontend_listen_port }} ssl; + http2 on; + server_name {{ nginx_frontend_domain }}; + + ssl_certificate /etc/letsencrypt/live/{{ nginx_frontend_domain }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ nginx_frontend_domain }}/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + # ── Raven-subscribe: subscriptions ────────────────────────────────────── + location ~ ^/(sub|c)/ { + proxy_pass http://127.0.0.1:{{ nginx_frontend_raven_port }}; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 30s; + proxy_connect_timeout 5s; + } + + # ── Raven-subscribe: admin API ─────────────────────────────────────────── + location /api/ { + proxy_pass http://127.0.0.1:{{ nginx_frontend_raven_port }}; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 30s; + proxy_connect_timeout 5s; + } + + # ── Raven-subscribe: health check ──────────────────────────────────────── + location /health { + proxy_pass http://127.0.0.1:{{ nginx_frontend_raven_port }}; + proxy_set_header Host $host; + proxy_read_timeout 5s; + proxy_connect_timeout 5s; + } + + # ── Xray XHTTP ─────────────────────────────────────────────────────────── + location {{ nginx_frontend_xhttp_path }} { + proxy_pass http://127.0.0.1:{{ nginx_frontend_xhttp_port }}; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection ""; + proxy_read_timeout 3600s; + proxy_connect_timeout 5s; + proxy_buffering off; + } + + # ── Everything else → 404 ──────────────────────────────────────────────── + location / { + return 404; + } +} diff --git a/roles/nginx_frontend/templates/nginx/stream.conf.j2 b/roles/nginx_frontend/templates/nginx/stream.conf.j2 new file mode 100644 index 0000000..c7de9a6 --- /dev/null +++ b/roles/nginx_frontend/templates/nginx/stream.conf.j2 @@ -0,0 +1,15 @@ +# {{ nginx_frontend_domain }} — nginx stream TCP relay for Xray VLESS Reality +# Managed by Ansible nginx_frontend role +# Proxies: external:{{ nginx_frontend_reality_port }} → 127.0.0.1:443 (Xray) +# This file is included inside stream {} block in nginx.conf + +upstream xray_reality_local { + server 127.0.0.1:443; +} + +server { + listen {{ nginx_frontend_reality_port }}; + proxy_pass xray_reality_local; + proxy_connect_timeout 10s; + proxy_timeout 600s; +} diff --git a/roles/raven_subscribe/defaults/main.yml b/roles/raven_subscribe/defaults/main.yml new file mode 100644 index 0000000..aae8e04 --- /dev/null +++ b/roles/raven_subscribe/defaults/main.yml @@ -0,0 +1,55 @@ +--- + +raven_subscribe_github_repo: "alchemylink/raven-subscribe" +raven_subscribe_install_dir: "/usr/local/bin" +raven_subscribe_config_dir: "/etc/xray-subscription" +raven_subscribe_db_dir: "/var/lib/xray-subscription" +raven_subscribe_service_name: "xray-subscription" + +raven_subscribe_listen_addr: ":8080" +raven_subscribe_sync_interval_seconds: 60 +raven_subscribe_rate_limit_sub_per_min: 60 +raven_subscribe_rate_limit_admin_per_min: 30 + +# Balancer settings (used in generated client subscription configs) +# Strategy: random, roundRobin, leastPing, leastLoad +raven_subscribe_balancer_strategy: "leastPing" +raven_subscribe_balancer_probe_url: "https://www.gstatic.com/generate_204" +raven_subscribe_balancer_probe_interval: "30s" + +# The inbound tag Raven manages users in (must match an inbound in config.d) +raven_subscribe_api_inbound_tag: "vless-reality-in" + +# Xray API address for user sync via gRPC. Requires xray_api enabled. +raven_subscribe_xray_api_addr: "127.0.0.1:10085" + +# Xray config.d directory (must match xray role) +raven_subscribe_xray_config_dir: "/etc/xray/config.d" + +# Per-inbound host overrides. Falls back to raven_subscribe_server_host when tag not listed. +# Set in secrets.yml. Empty = all inbounds use server_host. +raven_subscribe_inbound_hosts: {} + +# Per-inbound port overrides. Falls back to inbound's own port when tag not listed. +# Set in secrets.yml. Example: {"vless-reality-in": 8444} for TCP relay on RU. +raven_subscribe_inbound_ports: {} + +# Path to sing-box config file. Leave empty to disable sing-box sync. +# Example: "/etc/sing-box/config.json" +raven_subscribe_singbox_config: "" + +# Enable/disable Xray and sing-box sync independently. +raven_subscribe_xray_enabled: true +raven_subscribe_singbox_enabled: false + +# System user/group (shared with xray role — do NOT change) +raven_subscribe_user: "xrayuser" +raven_subscribe_group: "xrayuser" + +# Xray service name (for systemd After= dependency) +raven_subscribe_xray_service_name: "xray" + +##### Set these in secrets.yml (ansible-vault encrypted) ##### +# raven_subscribe_server_host: "" # EU VPS public IP or domain +# raven_subscribe_base_url: "" # Public URL — must be relay domain, NOT direct EU IP +# raven_subscribe_admin_token: "" # Generate: openssl rand -hex 32 diff --git a/roles/raven_subscribe/defaults/secrets.yml.example b/roles/raven_subscribe/defaults/secrets.yml.example new file mode 100644 index 0000000..f87c35d --- /dev/null +++ b/roles/raven_subscribe/defaults/secrets.yml.example @@ -0,0 +1,13 @@ +--- +# Raven-subscribe secrets — copy to secrets.yml and encrypt: +# ansible-vault encrypt roles/raven_subscribe/defaults/secrets.yml + +# Admin token for Raven-subscribe API (required) +# Generate: openssl rand -hex 32 +raven_subscribe_admin_token: "" + +# Public URL used in subscription links — must be the relay domain +raven_subscribe_base_url: "https://my.zirgate.com" + +# EU VPS public IP or domain (used in generated client outbound addresses) +raven_subscribe_server_host: "" diff --git a/roles/raven_subscribe/handlers/main.yml b/roles/raven_subscribe/handlers/main.yml new file mode 100644 index 0000000..47e923f --- /dev/null +++ b/roles/raven_subscribe/handlers/main.yml @@ -0,0 +1,9 @@ +--- +- name: Reload systemd + ansible.builtin.systemd: + daemon_reload: true + +- name: Restart raven-subscribe + ansible.builtin.service: + name: "{{ raven_subscribe_service_name }}" + state: restarted diff --git a/roles/raven_subscribe/meta/main.yml b/roles/raven_subscribe/meta/main.yml new file mode 100644 index 0000000..e6cf843 --- /dev/null +++ b/roles/raven_subscribe/meta/main.yml @@ -0,0 +1,8 @@ +--- +galaxy_info: + role_name: raven_subscribe + author: findias + description: Raven-subscribe subscription server for Xray + min_ansible_version: "2.9" + +dependencies: [] diff --git a/roles/raven_subscribe/tasks/main.yml b/roles/raven_subscribe/tasks/main.yml new file mode 100644 index 0000000..da92cc7 --- /dev/null +++ b/roles/raven_subscribe/tasks/main.yml @@ -0,0 +1,100 @@ +--- +- name: Raven-subscribe | Validate required vars + ansible.builtin.assert: + that: + - raven_subscribe_admin_token is defined + - raven_subscribe_admin_token != '' + - raven_subscribe_server_host is defined + - raven_subscribe_server_host != '' + fail_msg: >- + raven_subscribe_admin_token and raven_subscribe_server_host must be set in secrets.yml. + Generate a strong token: openssl rand -hex 32 + success_msg: "Raven-subscribe vars are valid" + +- name: Raven-subscribe | Get latest release info + ansible.builtin.uri: + url: "https://api.github.com/repos/{{ raven_subscribe_github_repo }}/releases/latest" + method: GET + return_content: true + headers: + Accept: "application/vnd.github.v3+json" + status_code: 200 + register: raven_release_info + run_once: true + retries: 3 + delay: 3 + until: raven_release_info.status == 200 + +- name: Raven-subscribe | Set version and arch facts + ansible.builtin.set_fact: + raven_subscribe_version: "{{ raven_release_info.json.tag_name }}" + raven_subscribe_arch: >- + {{ + 'linux-amd64' if ansible_architecture in ['x86_64', 'amd64'] + else 'linux-arm64' if ansible_architecture in ['aarch64', 'arm64'] + else 'linux-arm' + }} + +- name: Raven-subscribe | Download binary + ansible.builtin.get_url: + url: "https://github.com/{{ raven_subscribe_github_repo }}/releases/download/\ + {{ raven_subscribe_version }}/xray-subscription-{{ raven_subscribe_arch }}" + dest: "{{ raven_subscribe_install_dir }}/xray-subscription" + mode: "0755" + owner: root + group: root + notify: Restart raven-subscribe + +- name: Raven-subscribe | Ensure config directory exists + ansible.builtin.file: + path: "{{ raven_subscribe_config_dir }}" + state: directory + owner: root + group: "{{ raven_subscribe_group }}" + mode: "0750" + +- name: Raven-subscribe | Ensure data directory exists + ansible.builtin.file: + path: "{{ raven_subscribe_db_dir }}" + state: directory + owner: "{{ raven_subscribe_user }}" + group: "{{ raven_subscribe_group }}" + mode: "0750" + +- name: Raven-subscribe | Deploy config + ansible.builtin.template: + src: config.json.j2 + dest: "{{ raven_subscribe_config_dir }}/config.json" + owner: root + group: "{{ raven_subscribe_group }}" + mode: "0640" + notify: Restart raven-subscribe + +- name: Raven-subscribe | Deploy systemd service + ansible.builtin.template: + src: xray-subscription.service.j2 + dest: "/etc/systemd/system/{{ raven_subscribe_service_name }}.service" + owner: root + group: root + mode: "0644" + when: ansible_facts.service_mgr == "systemd" + notify: + - Reload systemd + - Restart raven-subscribe + +- name: Raven-subscribe | Enable and start service + ansible.builtin.service: + name: "{{ raven_subscribe_service_name }}" + enabled: true + state: started + +- name: Raven-subscribe | Gather service facts + ansible.builtin.service_facts: + +- name: Raven-subscribe | Validate service is running + ansible.builtin.fail: + msg: "xray-subscription service is not running" + when: + - ansible_facts.services is defined + - ansible_facts.services[raven_subscribe_service_name + '.service'] is defined + - ansible_facts.services[raven_subscribe_service_name + '.service'].state != 'running' diff --git a/roles/raven_subscribe/templates/config.json.j2 b/roles/raven_subscribe/templates/config.json.j2 new file mode 100644 index 0000000..45b2b56 --- /dev/null +++ b/roles/raven_subscribe/templates/config.json.j2 @@ -0,0 +1,22 @@ +{ + "listen_addr": "{{ raven_subscribe_listen_addr }}", + "server_host": "{{ raven_subscribe_server_host }}", + "config_dir": "{{ raven_subscribe_xray_config_dir }}", + "db_path": "{{ raven_subscribe_db_dir }}/db.sqlite", + "sync_interval_seconds": {{ raven_subscribe_sync_interval_seconds }}, + "base_url": "{{ raven_subscribe_base_url }}", + "admin_token": "{{ raven_subscribe_admin_token }}", + "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 }}", + "balancer_strategy": "{{ raven_subscribe_balancer_strategy }}", + "balancer_probe_url": "{{ raven_subscribe_balancer_probe_url }}", + "balancer_probe_interval": "{{ raven_subscribe_balancer_probe_interval }}", + "xray_enabled": {{ raven_subscribe_xray_enabled | lower }}, + "singbox_enabled": {{ raven_subscribe_singbox_enabled | lower }}{% if raven_subscribe_inbound_hosts | default({}) | length > 0 %}, + "inbound_hosts": {{ raven_subscribe_inbound_hosts | to_json }}{% endif %}{% if raven_subscribe_inbound_ports | default({}) | length > 0 %}, + "inbound_ports": {{ raven_subscribe_inbound_ports | to_json }}{% endif %}{% if raven_subscribe_vless_client_encryption | default({}) | length > 0 %}, + "vless_client_encryption": {{ raven_subscribe_vless_client_encryption | to_json }}{% endif %}{% if raven_subscribe_singbox_config | default('') != '' %}, + "singbox_config": "{{ raven_subscribe_singbox_config }}"{% endif %} +} diff --git a/roles/raven_subscribe/templates/xray-subscription.service.j2 b/roles/raven_subscribe/templates/xray-subscription.service.j2 new file mode 100644 index 0000000..5bdeaca --- /dev/null +++ b/roles/raven_subscribe/templates/xray-subscription.service.j2 @@ -0,0 +1,23 @@ +[Unit] +Description=Xray Subscription Server (Raven-subscribe) +Documentation=https://github.com/AlchemyLink/Raven-subscribe +After=network.target {{ raven_subscribe_xray_service_name }}.service + +[Service] +Type=simple +User={{ raven_subscribe_user }} +Group={{ raven_subscribe_group }} +ExecStart={{ raven_subscribe_install_dir }}/xray-subscription -config {{ raven_subscribe_config_dir }}/config.json +Restart=on-failure +RestartSec=5s + +# Security hardening +NoNewPrivileges=yes +ProtectSystem=strict +ReadWritePaths={{ raven_subscribe_db_dir }} {{ raven_subscribe_xray_config_dir }} +ReadOnlyPaths={{ raven_subscribe_config_dir }} +PrivateTmp=yes +ProtectHome=yes + +[Install] +WantedBy=multi-user.target diff --git a/roles/relay/defaults/main.yml b/roles/relay/defaults/main.yml new file mode 100644 index 0000000..574c931 --- /dev/null +++ b/roles/relay/defaults/main.yml @@ -0,0 +1,38 @@ +--- +# Relay role — nginx reverse proxy on RU VPS +# Domain: zirgate.com +# zirgate.com A → RU VPS IP (static stub site) +# my.zirgate.com A → RU VPS IP (relay → Raven subscriptions + API) +# +# EU server (managed by nginx_frontend role, not this role): +# media.zirgate.com A → EU VPS IP (nginx_frontend → Xray XHTTP) + +# ── Domain ─────────────────────────────────────────────────────────────────── +relay_domain: "zirgate.com" +relay_sub_my: "my.{{ relay_domain }}" # Raven-subscribe relay (RU VPS) + +# ── Upstream EU server ──────────────────────────────────────────────────────── +# Set in secrets.yml +# relay_upstream_host: "1.2.3.4" # EU server IP address + +# Port where nginx_frontend listens on EU server (Raven-subscribe is behind it) +# Must match nginx_frontend_listen_port (default: 8443, NOT 443 which is taken by Xray) +relay_upstream_raven_port: 8443 + +# ── TCP stream relay (VLESS Reality) ───────────────────────────────────────── +# Proxies raw TCP on relay_stream_port → EU server:relay_upstream_xray_port +# Clients connect to zirgate.com:relay_stream_port instead of EU IP directly. +relay_stream_enabled: true +relay_stream_port: 8444 # Listening port on RU server (must be free) +relay_upstream_xray_port: 8445 # nginx_frontend Reality stream port on EU server + +# ── nginx ───────────────────────────────────────────────────────────────────── +relay_nginx_user: "www-data" +relay_webroot: "/var/www/{{ relay_domain }}" + +# ── Certbot ─────────────────────────────────────────────────────────────────── +relay_certbot_email: "" # Set in secrets.yml: relay_certbot_email: "admin@zirgate.com" + +# ── Stub site ───────────────────────────────────────────────────────────────── +relay_stub_title: "Welcome" +relay_stub_description: "Personal website" diff --git a/roles/relay/defaults/secrets.yml.example b/roles/relay/defaults/secrets.yml.example new file mode 100644 index 0000000..02edda0 --- /dev/null +++ b/roles/relay/defaults/secrets.yml.example @@ -0,0 +1,6 @@ +--- +# Copy to secrets.yml and encrypt with ansible-vault: +# ansible-vault encrypt roles/relay/defaults/secrets.yml + +relay_upstream_host: "1.2.3.4" # EU server IP address +relay_certbot_email: "admin@admin.com" diff --git a/roles/relay/handlers/main.yml b/roles/relay/handlers/main.yml new file mode 100644 index 0000000..fc320fa --- /dev/null +++ b/roles/relay/handlers/main.yml @@ -0,0 +1,10 @@ +--- +- name: Reload nginx + ansible.builtin.service: + name: nginx + state: reloaded + +- name: Restart nginx + ansible.builtin.service: + name: nginx + state: restarted diff --git a/roles/relay/inventory.ini b/roles/relay/inventory.ini new file mode 100644 index 0000000..b71a672 --- /dev/null +++ b/roles/relay/inventory.ini @@ -0,0 +1,2 @@ +[relay] +zirgate ansible_host=RU_VPS_IP ansible_user=deploy diff --git a/roles/relay/tasks/certbot.yml b/roles/relay/tasks/certbot.yml new file mode 100644 index 0000000..4954eaf --- /dev/null +++ b/roles/relay/tasks/certbot.yml @@ -0,0 +1,24 @@ +--- +- name: Relay | Check if certificate already exists + ansible.builtin.stat: + path: "/etc/letsencrypt/live/{{ relay_domain }}/fullchain.pem" + register: relay_cert + +- name: Relay | Obtain Let's Encrypt certificate + ansible.builtin.command: + cmd: > + certbot certonly --webroot + --webroot-path {{ relay_webroot }} + --non-interactive + --agree-tos + --email {{ relay_certbot_email }} + -d {{ relay_domain }} + -d {{ relay_sub_my }} + when: not relay_cert.stat.exists + notify: Reload nginx + +- name: Relay | Ensure certbot renewal timer is enabled + ansible.builtin.service: + name: certbot.timer + enabled: true + state: started diff --git a/roles/relay/tasks/install.yml b/roles/relay/tasks/install.yml new file mode 100644 index 0000000..d3826fb --- /dev/null +++ b/roles/relay/tasks/install.yml @@ -0,0 +1,15 @@ +--- +- name: Relay | Install nginx and certbot + ansible.builtin.apt: + name: + - nginx + - certbot + - python3-certbot-nginx + state: present + update_cache: true + +- name: Relay | Ensure nginx is enabled + ansible.builtin.service: + name: nginx + enabled: true + state: started diff --git a/roles/relay/tasks/main.yml b/roles/relay/tasks/main.yml new file mode 100644 index 0000000..ff8e5db --- /dev/null +++ b/roles/relay/tasks/main.yml @@ -0,0 +1,28 @@ +--- +- name: Relay | Validate + ansible.builtin.import_tasks: validate.yml + tags: always + +- name: Relay | Install packages + ansible.builtin.import_tasks: install.yml + tags: relay_install + +- name: Relay | Configure stub site + ansible.builtin.import_tasks: stub.yml + tags: relay_stub + +- name: Relay | Configure nginx + ansible.builtin.import_tasks: nginx.yml + tags: relay_nginx + +- name: Relay | Obtain TLS certificates + ansible.builtin.import_tasks: certbot.yml + tags: relay_certbot + +- name: Relay | Deploy nginx HTTPS config + ansible.builtin.import_tasks: nginx_ssl.yml + tags: relay_nginx_ssl + +- name: Relay | Configure TCP stream relay + ansible.builtin.import_tasks: stream.yml + tags: relay_stream diff --git a/roles/relay/tasks/nginx.yml b/roles/relay/tasks/nginx.yml new file mode 100644 index 0000000..b7b31b1 --- /dev/null +++ b/roles/relay/tasks/nginx.yml @@ -0,0 +1,14 @@ +--- +# Initial HTTP-only config — needed for certbot HTTP-01 challenge + +- name: Relay | Deploy HTTP nginx config (pre-certbot) + ansible.builtin.template: + src: nginx/http.conf.j2 + dest: "/etc/nginx/conf.d/{{ relay_domain }}.conf" + owner: root + group: root + mode: "0644" + notify: Reload nginx + +- name: Relay | Reload nginx before certbot + ansible.builtin.meta: flush_handlers diff --git a/roles/relay/tasks/nginx_ssl.yml b/roles/relay/tasks/nginx_ssl.yml new file mode 100644 index 0000000..340e0c2 --- /dev/null +++ b/roles/relay/tasks/nginx_ssl.yml @@ -0,0 +1,11 @@ +--- +# Full HTTPS config with proxy_pass — deployed after certbot + +- name: Relay | Deploy HTTPS nginx config + ansible.builtin.template: + src: nginx/https.conf.j2 + dest: "/etc/nginx/conf.d/{{ relay_domain }}.conf" + owner: root + group: root + mode: "0644" + notify: Reload nginx diff --git a/roles/relay/tasks/stream.yml b/roles/relay/tasks/stream.yml new file mode 100644 index 0000000..f3d9241 --- /dev/null +++ b/roles/relay/tasks/stream.yml @@ -0,0 +1,36 @@ +--- +- name: Relay | Ensure stream.d directory exists + ansible.builtin.file: + path: /etc/nginx/stream.d + state: directory + owner: root + group: root + mode: "0755" + +- name: Relay | Ensure stream block include in nginx.conf + ansible.builtin.blockinfile: + path: /etc/nginx/nginx.conf + marker: "# {mark} ANSIBLE MANAGED stream block" + block: | + stream { + include /etc/nginx/stream.d/*.conf; + } + insertafter: EOF + notify: Reload nginx + +- name: Relay | Deploy nginx stream config + ansible.builtin.template: + src: nginx/stream.conf.j2 + dest: "/etc/nginx/stream.d/{{ relay_domain }}.conf" + owner: root + group: root + mode: "0644" + notify: Reload nginx + when: relay_stream_enabled + +- name: Relay | Remove nginx stream config (disabled) + ansible.builtin.file: + path: "/etc/nginx/stream.d/{{ relay_domain }}.conf" + state: absent + notify: Reload nginx + when: not relay_stream_enabled diff --git a/roles/relay/tasks/stub.yml b/roles/relay/tasks/stub.yml new file mode 100644 index 0000000..ae00c73 --- /dev/null +++ b/roles/relay/tasks/stub.yml @@ -0,0 +1,16 @@ +--- +- name: Relay | Create webroot directory + ansible.builtin.file: + path: "{{ relay_webroot }}" + state: directory + owner: "{{ relay_nginx_user }}" + group: "{{ relay_nginx_user }}" + mode: "0755" + +- name: Relay | Deploy stub site index.html + ansible.builtin.template: + src: stub/index.html.j2 + dest: "{{ relay_webroot }}/index.html" + owner: "{{ relay_nginx_user }}" + group: "{{ relay_nginx_user }}" + mode: "0644" diff --git a/roles/relay/tasks/validate.yml b/roles/relay/tasks/validate.yml new file mode 100644 index 0000000..1d08242 --- /dev/null +++ b/roles/relay/tasks/validate.yml @@ -0,0 +1,11 @@ +--- +- name: Relay | Validate required vars + ansible.builtin.assert: + that: + - relay_upstream_host is defined + - relay_upstream_host != '' + - relay_certbot_email is defined + - relay_certbot_email != '' + fail_msg: >- + relay_upstream_host and relay_certbot_email must be set in secrets.yml. + success_msg: "Relay vars are valid" diff --git a/roles/relay/templates/nginx/http.conf.j2 b/roles/relay/templates/nginx/http.conf.j2 new file mode 100644 index 0000000..0e8c7d7 --- /dev/null +++ b/roles/relay/templates/nginx/http.conf.j2 @@ -0,0 +1,14 @@ +# {{ relay_domain }} — HTTP only (pre-certbot) +# Managed by Ansible relay role + +server { + listen 80; + server_name {{ relay_domain }} {{ relay_sub_my }}; + + root {{ relay_webroot }}; + index index.html; + + location / { + try_files $uri $uri/ =404; + } +} diff --git a/roles/relay/templates/nginx/https.conf.j2 b/roles/relay/templates/nginx/https.conf.j2 new file mode 100644 index 0000000..adbe8eb --- /dev/null +++ b/roles/relay/templates/nginx/https.conf.j2 @@ -0,0 +1,52 @@ +# {{ relay_domain }} — HTTPS relay config +# Managed by Ansible relay role + +# ── Redirect HTTP → HTTPS ──────────────────────────────────────────────────── +server { + listen 80; + server_name {{ relay_domain }} {{ relay_sub_my }}; + return 301 https://$host$request_uri; +} + +# ── zirgate.com — stub site ────────────────────────────────────────────────── +server { + listen 443 ssl; + http2 on; + server_name {{ relay_domain }}; + + ssl_certificate /etc/letsencrypt/live/{{ relay_domain }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ relay_domain }}/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + root {{ relay_webroot }}; + index index.html; + + location / { + try_files $uri $uri/ =404; + } +} + +# ── my.zirgate.com — Raven-subscribe relay ─────────────────────────────────── +server { + listen 443 ssl; + http2 on; + server_name {{ relay_sub_my }}; + + ssl_certificate /etc/letsencrypt/live/{{ relay_domain }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ relay_domain }}/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + location / { + proxy_pass https://{{ relay_upstream_host }}:{{ relay_upstream_raven_port }}; + proxy_ssl_server_name on; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 60s; + proxy_connect_timeout 10s; + } +} + diff --git a/roles/relay/templates/nginx/stream.conf.j2 b/roles/relay/templates/nginx/stream.conf.j2 new file mode 100644 index 0000000..4e7ba87 --- /dev/null +++ b/roles/relay/templates/nginx/stream.conf.j2 @@ -0,0 +1,15 @@ +# {{ relay_domain }} — nginx stream TCP relay +# Managed by Ansible relay role +# Proxies VLESS Reality TCP traffic: RU:{{ relay_stream_port }} → EU:{{ relay_upstream_xray_port }} +# This file is included inside stream {} block in nginx.conf + +upstream xray_reality { + server {{ relay_upstream_host }}:{{ relay_upstream_xray_port }}; +} + +server { + listen {{ relay_stream_port }}; + proxy_pass xray_reality; + proxy_connect_timeout 10s; + proxy_timeout 600s; +} diff --git a/roles/relay/templates/stub/index.html.j2 b/roles/relay/templates/stub/index.html.j2 new file mode 100644 index 0000000..2904e26 --- /dev/null +++ b/roles/relay/templates/stub/index.html.j2 @@ -0,0 +1,53 @@ + + + + + + {{ relay_stub_title }} + + + +
+

{{ relay_domain }}

+
+
+

{{ relay_stub_title }}

+

{{ relay_stub_description }}

+

This site is currently under construction.

+
+ + + diff --git a/roles/role_nginx_frontend.yml b/roles/role_nginx_frontend.yml new file mode 100644 index 0000000..1ac9e5f --- /dev/null +++ b/roles/role_nginx_frontend.yml @@ -0,0 +1,22 @@ +--- +# nginx frontend playbook — EU server (media.zirgate.com) +# Usage: +# ansible-playbook roles/role_nginx_frontend.yml -i roles/nginx_frontend/inventory.ini \ +# --vault-password-file vault_password.txt +# +# Tags: +# nginx_frontend_install — install nginx + certbot +# nginx_frontend_nginx — deploy HTTP config +# nginx_frontend_certbot — obtain TLS certificate +# nginx_frontend_ssl — deploy HTTPS config with proxy_pass + +- name: Configure nginx frontend (vpn.zirgate.com) + hosts: vm_my_srv + become: true + + vars_files: + - nginx_frontend/defaults/main.yml + - nginx_frontend/defaults/secrets.yml + + roles: + - role: nginx_frontend diff --git a/roles/role_raven_subscribe.yml b/roles/role_raven_subscribe.yml new file mode 100644 index 0000000..9b567bf --- /dev/null +++ b/roles/role_raven_subscribe.yml @@ -0,0 +1,11 @@ +--- +- name: Deploy Raven-subscribe + hosts: vm_my_srv + become: true + gather_facts: true + + vars_files: + - "raven_subscribe/defaults/secrets.yml" + + roles: + - role: raven_subscribe diff --git a/roles/role_relay.yml b/roles/role_relay.yml new file mode 100644 index 0000000..a731db4 --- /dev/null +++ b/roles/role_relay.yml @@ -0,0 +1,23 @@ +--- +# Relay playbook — RU VPS (zirgate.com) +# Usage: +# ansible-playbook roles/role_relay.yml -i roles/relay/inventory.ini \ +# --vault-password-file vault_password.txt +# +# Tags: +# relay_install — install nginx + certbot +# relay_stub — deploy stub site +# relay_nginx — deploy HTTP nginx config +# relay_certbot — obtain TLS certificates +# relay_nginx_ssl — deploy HTTPS nginx config with proxy_pass + +- name: Configure relay server (zirgate.com) + hosts: vm_my_ru + become: true + + vars_files: + - relay/defaults/main.yml + - relay/defaults/secrets.yml + + roles: + - role: relay diff --git a/roles/role_xray.yml b/roles/role_xray.yml index 946b363..83dd611 100644 --- a/roles/role_xray.yml +++ b/roles/role_xray.yml @@ -6,7 +6,7 @@ gather_facts: true vars_files: - - "xray/defaults/secrets.yml" # secrets для Xray (UUID, email и т.п.) + - "xray/defaults/secrets.yml" # Xray secrets (UUID, reality keys и т.п.) roles: - role: srv_prepare diff --git a/roles/sing-box-playbook/defaults/main.yml b/roles/sing-box-playbook/defaults/main.yml index eb9b2f9..646eceb 100644 --- a/roles/sing-box-playbook/defaults/main.yml +++ b/roles/sing-box-playbook/defaults/main.yml @@ -26,7 +26,7 @@ singbox_log_timestamp: true singbox_hysteria2_enabled: true singbox_hysteria2_tag: "hysteria-in" singbox_hysteria2_listen: "::" # Replace with your server's public IP or " -singbox_hysteria2_listen_port: 8443 +singbox_hysteria2_listen_port: 8444 singbox_hysteria2_up_mbps: 100 singbox_hysteria2_down_mbps: 100 diff --git a/roles/xray/defaults/main.yml b/roles/xray/defaults/main.yml index d48509e..976396d 100644 --- a/roles/xray/defaults/main.yml +++ b/roles/xray/defaults/main.yml @@ -48,7 +48,7 @@ xray_dns_servers: # List of DNS servers for Xray # DoH servers (https://) are NOT recommended here — they route # through the proxy chain and fail with "closed pipe" on reconnect. xray_dns_disable_fallback: false # Set to true to disable fallback to system DNS -xray_dns_query_strategy: "UseIP" # DNS query strategy: "UseIP", "UseIPIfNonMatch", "UseIPv4", "UseIPv6" +xray_dns_query_strategy: "UseIPv4" # DNS query strategy: "UseIP", "UseIPIfNonMatch", "UseIPv4", "UseIPv6" # Log vars xray_log_config: @@ -115,41 +115,3 @@ xray_xhttp: # - id: UUID_3" # flow: "xtls-rprx-vision" # email: "someEmailForIdentyfy" - -# --------------------------------------------------------------------------- -# Raven-subscribe (subscription server) -# --------------------------------------------------------------------------- - -raven_subscribe_github_repo: "alchemylink/raven-subscribe" -raven_subscribe_install_dir: "/usr/local/bin" -raven_subscribe_config_dir: "/etc/xray-subscription" -raven_subscribe_db_dir: "/var/lib/xray-subscription" -raven_subscribe_service_name: "xray-subscription" - -raven_subscribe_listen_addr: ":8080" -raven_subscribe_sync_interval_seconds: 60 -raven_subscribe_rate_limit_sub_per_min: 60 -raven_subscribe_rate_limit_admin_per_min: 30 - -# The inbound tag Raven manages users in (must match an inbound in config.d) -raven_subscribe_api_inbound_tag: "{{ xray_common.inbound_tag.vless_reality_in }}" - -# Use Xray gRPC API for user sync instead of file writes. -# 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" -# raven_subscribe_admin_token: "" # Strong random secret (required) diff --git a/roles/xray/defaults/raven_subscribe_secrets.yml.example b/roles/xray/defaults/raven_subscribe_secrets.yml.example new file mode 100644 index 0000000..9c2f1f1 --- /dev/null +++ b/roles/xray/defaults/raven_subscribe_secrets.yml.example @@ -0,0 +1,13 @@ +--- +# Raven-subscribe secrets — copy to raven_subscribe_secrets.yml and encrypt: +# ansible-vault encrypt roles/xray/defaults/raven_subscribe_secrets.yml + +# Admin token for Raven-subscribe API (required) +# Generate: openssl rand -hex 32 +raven_subscribe_admin_token: "" + +# Public URL used in subscription links — must be the relay domain +raven_subscribe_base_url: "https://my.zirgate.com" + +# EU VPS public IP or domain (used in generated client outbound addresses) +raven_subscribe_server_host: "64.226.79.239" diff --git a/roles/xray/handlers/main.yml b/roles/xray/handlers/main.yml index b9d8cc9..a2dca5c 100644 --- a/roles/xray/handlers/main.yml +++ b/roles/xray/handlers/main.yml @@ -39,3 +39,4 @@ state: restarted daemon_reload: true when: ansible_facts['service_mgr'] == "systemd" + diff --git a/roles/xray/tasks/main.yml b/roles/xray/tasks/main.yml index f66373c..33d8f2a 100644 --- a/roles/xray/tasks/main.yml +++ b/roles/xray/tasks/main.yml @@ -39,6 +39,4 @@ ansible.builtin.import_tasks: grpcurl.yml tags: grpcurl -- name: Raven-subscribe | Deploy subscription server - ansible.builtin.import_tasks: raven_subscribe.yml - tags: raven_subscribe + diff --git a/roles/xray/templates/conf/inbounds/200-in-vless-reality.json.j2 b/roles/xray/templates/conf/inbounds/200-in-vless-reality.json.j2 index 3db78af..1ec0d8d 100644 --- a/roles/xray/templates/conf/inbounds/200-in-vless-reality.json.j2 +++ b/roles/xray/templates/conf/inbounds/200-in-vless-reality.json.j2 @@ -10,7 +10,7 @@ {% for user in xray_users %} { "id": "{{ user.id }}", - "flow": "{{ 'xtls-rprx-vision' if _pq else (user.flow | default(xray_vless_default_flow)) }}", + "flow": "{{ 'xtls-rprx-vision' if _pq else user.flow }}", "email": "{{ user.email | default('') }}", "level": 0 }{{ "," if not loop.last }} diff --git a/roles/xray/templates/conf/inbounds/210-in-xhttp.json.j2 b/roles/xray/templates/conf/inbounds/210-in-xhttp.json.j2 index 4212c84..76941f2 100644 --- a/roles/xray/templates/conf/inbounds/210-in-xhttp.json.j2 +++ b/roles/xray/templates/conf/inbounds/210-in-xhttp.json.j2 @@ -8,7 +8,7 @@ "clients": [ {% set _pq = xray_vless_decryption | default('none') != 'none' %} {% for user in xray_users %} - {% set _flow = user.flow | default(xray_vless_default_flow) %} + {% set _flow = user.flow | default('') %} { "id": "{{ user.id }}", "flow": "{{ 'xtls-rprx-vision' if _pq else _flow }}", diff --git a/roles/xray/templates/raven-subscribe/config.json.j2 b/roles/xray/templates/raven-subscribe/config.json.j2 index 96c65a8..90ec83e 100644 --- a/roles/xray/templates/raven-subscribe/config.json.j2 +++ b/roles/xray/templates/raven-subscribe/config.json.j2 @@ -10,6 +10,9 @@ "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 }}", + "balancer_strategy": "{{ raven_subscribe_balancer_strategy }}", + "balancer_probe_url": "{{ raven_subscribe_balancer_probe_url }}", + "balancer_probe_interval": "{{ raven_subscribe_balancer_probe_interval }}", "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": {