From a6d2623802d7a30d38d68fd3078420253f4e1b3d Mon Sep 17 00:00:00 2001 From: Gabenov Stanislav Date: Mon, 9 Feb 2026 20:42:24 +0300 Subject: [PATCH] vpn --- inventory/group_vars/all.yml | 2 + inventory/hosts | 2 +- playbooks/vpn.yml | 12 + requirements.yml | 5 + roles/xray-vps-setup/.gitignore | 4 + roles/xray-vps-setup/README.md | 60 +++ roles/xray-vps-setup/defaults/main.yml | 2 + roles/xray-vps-setup/handlers/main.yml | 15 + roles/xray-vps-setup/install_in_docker.md | 356 ++++++++++++++++++ .../xray-vps-setup/meta/.galaxy_install_info | 2 + roles/xray-vps-setup/meta/main.yml | 18 + roles/xray-vps-setup/tasks/bbr.yml | 10 + roles/xray-vps-setup/tasks/end_xray.yml | 63 ++++ roles/xray-vps-setup/tasks/install_docker.yml | 13 + .../xray-vps-setup/tasks/install_marzban.yml | 31 ++ roles/xray-vps-setup/tasks/install_xray.yml | 16 + roles/xray-vps-setup/tasks/install_yq.yml | 5 + roles/xray-vps-setup/tasks/iptables.yml | 46 +++ roles/xray-vps-setup/tasks/main.yml | 54 +++ roles/xray-vps-setup/tasks/setup_warp.yml | 61 +++ roles/xray-vps-setup/tasks/ssh.yml | 14 + roles/xray-vps-setup/tasks/user.yml | 14 + roles/xray-vps-setup/templates/caddyfile.j2 | 50 +++ roles/xray-vps-setup/templates/confluence.j2 | 272 +++++++++++++ roles/xray-vps-setup/templates/marzban.j2 | 95 +++++ .../templates/marzban_docker.j2 | 20 + roles/xray-vps-setup/templates/xray.json.j2 | 76 ++++ roles/xray-vps-setup/templates/xray_docker.j2 | 19 + .../xray-vps-setup/templates_for_script/caddy | 47 +++ .../templates_for_script/compose | 9 + .../templates_for_script/confluence_page | 272 +++++++++++++ .../templates_for_script/marzban | 95 +++++ .../templates_for_script/sing_box_outbound | 21 ++ .../xray-vps-setup/templates_for_script/xray | 77 ++++ .../templates_for_script/xray_outbound | 30 ++ roles/xray-vps-setup/tests/test.yml | 5 + roles/xray-vps-setup/vars/main.yml | 2 + roles/xray-vps-setup/vps-setup.sh | 304 +++++++++++++++ 38 files changed, 2198 insertions(+), 1 deletion(-) create mode 100644 playbooks/vpn.yml create mode 100644 roles/xray-vps-setup/.gitignore create mode 100644 roles/xray-vps-setup/README.md create mode 100644 roles/xray-vps-setup/defaults/main.yml create mode 100644 roles/xray-vps-setup/handlers/main.yml create mode 100644 roles/xray-vps-setup/install_in_docker.md create mode 100644 roles/xray-vps-setup/meta/.galaxy_install_info create mode 100644 roles/xray-vps-setup/meta/main.yml create mode 100644 roles/xray-vps-setup/tasks/bbr.yml create mode 100644 roles/xray-vps-setup/tasks/end_xray.yml create mode 100644 roles/xray-vps-setup/tasks/install_docker.yml create mode 100644 roles/xray-vps-setup/tasks/install_marzban.yml create mode 100644 roles/xray-vps-setup/tasks/install_xray.yml create mode 100644 roles/xray-vps-setup/tasks/install_yq.yml create mode 100644 roles/xray-vps-setup/tasks/iptables.yml create mode 100644 roles/xray-vps-setup/tasks/main.yml create mode 100644 roles/xray-vps-setup/tasks/setup_warp.yml create mode 100644 roles/xray-vps-setup/tasks/ssh.yml create mode 100644 roles/xray-vps-setup/tasks/user.yml create mode 100644 roles/xray-vps-setup/templates/caddyfile.j2 create mode 100644 roles/xray-vps-setup/templates/confluence.j2 create mode 100644 roles/xray-vps-setup/templates/marzban.j2 create mode 100644 roles/xray-vps-setup/templates/marzban_docker.j2 create mode 100644 roles/xray-vps-setup/templates/xray.json.j2 create mode 100644 roles/xray-vps-setup/templates/xray_docker.j2 create mode 100644 roles/xray-vps-setup/templates_for_script/caddy create mode 100644 roles/xray-vps-setup/templates_for_script/compose create mode 100644 roles/xray-vps-setup/templates_for_script/confluence_page create mode 100644 roles/xray-vps-setup/templates_for_script/marzban create mode 100644 roles/xray-vps-setup/templates_for_script/sing_box_outbound create mode 100644 roles/xray-vps-setup/templates_for_script/xray create mode 100644 roles/xray-vps-setup/templates_for_script/xray_outbound create mode 100644 roles/xray-vps-setup/tests/test.yml create mode 100644 roles/xray-vps-setup/vars/main.yml create mode 100644 roles/xray-vps-setup/vps-setup.sh diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml index e69de29..d69b160 100644 --- a/inventory/group_vars/all.yml +++ b/inventory/group_vars/all.yml @@ -0,0 +1,2 @@ +--- +ssh_public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQChdhIFLJ1nwmqkFJzgHKvPJXPdGRZ3tmN0IqAJyP61DSsQf4rJcw4fL9Z4UKGfIw4Mn4f8FFcAUCmD/2OZxSKjjQBYiq/+q3AS12PVUbDR3fE5IyZx3uDmAB3m9yJuIFGl3mqldefnnH98UA3+kwZgFoJXJwHgp6mTV+S5N0aJdX1gCwoVMz3imkUAkGQrK4eDp9T4YH94yVh8or3si+mQJe+5j5xjF7oFGWWVYIr7iNS6zrtgRQdFklAt8cFIx2Mxql6PuTNJo83zS1NUxijEEGC/aZMLhafsOWm8M63EvkXsGOYS2JN5ycKJaTTDiD22tyXP4a1Oe6SGzB7of2NJ9RUXYnq7IYNlMpLJ4D7tHyYJUEckRQy9yugYWSUFxPgLc6n1PxDUEk1hTVwm5xsha9kYYXtuAY4RI3uXkvYIMsuO92kwqnOwt6Yw285DrXQQYSLt2NGBYvGfVczrSM8TYwsCZ0wHOaNeZKieeOmNDeHcOX8smSsiYlF08NOJ6pk= stanito@MacM5" \ No newline at end of file diff --git a/inventory/hosts b/inventory/hosts index e68604d..3a9d4f6 100644 --- a/inventory/hosts +++ b/inventory/hosts @@ -8,7 +8,7 @@ ansible_port=22 ansible_ssh_private_key_file=~/.ssh/id_rsa # VPN серверы -[vpnservers] +[vpn] access.stanito.me ansible_user=root # Группы по ОС diff --git a/playbooks/vpn.yml b/playbooks/vpn.yml new file mode 100644 index 0000000..8495251 --- /dev/null +++ b/playbooks/vpn.yml @@ -0,0 +1,12 @@ +- name: Setup VLESS VPN server + hosts: vpn + become: yes + + roles: + - role: xray-vps-setup + + vars: + domain: access.stanito.me + setup_variant: xray + user_to_create: vpnuser + ssh_public_key: "{{ ssh_public_key }}" \ No newline at end of file diff --git a/requirements.yml b/requirements.yml index 6408107..b11a499 100644 --- a/requirements.yml +++ b/requirements.yml @@ -2,6 +2,11 @@ roles: # Install a role from Ansible Galaxy. # note that ranges are not supported for roles + - name: xray-vps-setup + src: https://github.com/Akiyamov/xray-vps-setup.git + scm: git + version: master + - name: geerlingguy.certbot version: "5.4.1" diff --git a/roles/xray-vps-setup/.gitignore b/roles/xray-vps-setup/.gitignore new file mode 100644 index 0000000..3a74357 --- /dev/null +++ b/roles/xray-vps-setup/.gitignore @@ -0,0 +1,4 @@ +gist*.md +ansible.cfg +inventory.yml +playbook.yml \ No newline at end of file diff --git a/roles/xray-vps-setup/README.md b/roles/xray-vps-setup/README.md new file mode 100644 index 0000000..2dbb7a2 --- /dev/null +++ b/roles/xray-vps-setup/README.md @@ -0,0 +1,60 @@ +# xray-vps-setup +VLESS со своим доменом. А что еще нужно для счастья? + +В данном варианте VLESS слушает на 443 и принимате все запросы, делая запрос на локальный Caddy только для сертификатов. В таком варианте задержка будет меньше, чем в варианте с Caddy/NGINX перед VLESS, где происходит множество лишних запросов. +## Скрипт + +- Установит Xray/Marzban на ваш выбор. Для маскировки страницы используется [Conflunce](https://github.com/Jolymmiles/confluence-marzban-home) +- На ваше усмотрение настроит: +- - Iptables, запретив все подключения, кроме SSH, 80 и 443. +- - Создаст пользователя для подключения, запретив вход от рута +- - Добавит этому пользователю ключ для SSH, запретив вход по паролю +- Настроит WARP для ру-сайтов. +```bash +tmux +bash <(wget -qO- https://raw.githubusercontent.com/Akiyamov/xray-vps-setup/refs/heads/main/vps-setup.sh) +``` + +## Плейбук + +[Ansible-galaxy](https://galaxy.ansible.com/ui/standalone/roles/Akiyamov/xray-vps-setup/install/) +```yaml +- name: Setup vps + hosts: some_host + roles: + - Akiyamov.xray-vps-setup + vars: + domain: example.com # домен, уровень неважен + setup_variant: marzban # marzban or xray + setup_warp: false # true or false + configure_security: true # true or false + user_to_create: xray_user # если configure_security: true, то обязательно + user_password: "xray_password" # если configure_security: true, то обязательно + SSH_PORT: 22 # если configure_security: true, то обязательно + ssh_public_key: "" # если configure_security: true, то обязательно +``` + +## Добавляем подписку и поддержку Mihomo + +``` +bash <(wget -qO- https://github.com/legiz-ru/marz-sub/raw/main/marz-sub.sh) +``` +После этого сделайте `docker compose -f /opt/xray-vps-setup/docker-compose.yml down && docker compose -f /opt/xray-vps-setup/docker-compose.yml up -d` + + +## Ручная установка + +Описана [здесь](https://github.com/Akiyamov/xray-vps-setup/blob/main/install_in_docker.md). + +## Почему не nginx, haproxy, 3x-ui, x-ui, sing-box... + +Caddy сам получит сертификаты, поэтому нам не придется их получать через `acme.sh` или `certbot`. +3X-ui мерзотная панель. +Sing-box не очень. +XHTTP позже, а больше не надо. Уже точно. + +## Связь +Issues, PR ну или мой [тг](https://t.me/Akiyamov). + +> [!IMPORTANT] +> Дайте секс \ No newline at end of file diff --git a/roles/xray-vps-setup/defaults/main.yml b/roles/xray-vps-setup/defaults/main.yml new file mode 100644 index 0000000..3adfd95 --- /dev/null +++ b/roles/xray-vps-setup/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for vps-setup diff --git a/roles/xray-vps-setup/handlers/main.yml b/roles/xray-vps-setup/handlers/main.yml new file mode 100644 index 0000000..0afe763 --- /dev/null +++ b/roles/xray-vps-setup/handlers/main.yml @@ -0,0 +1,15 @@ +--- +# handlers file for vps-setup +- name: Restart xray + service: + name: xray + state: restarted +- name: Restart caddy + service: + name: caddy + state: restarted +- name: Restart ssh + service: + name: ssh + state: restarted + daemon_reload: true \ No newline at end of file diff --git a/roles/xray-vps-setup/install_in_docker.md b/roles/xray-vps-setup/install_in_docker.md new file mode 100644 index 0000000..fa02f3f --- /dev/null +++ b/roles/xray-vps-setup/install_in_docker.md @@ -0,0 +1,356 @@ +

VLESS + Reality Self Steal в Docker

+ +### Что потребуется: +- VPS +- Свой домен + +В статье будет рассмотрена установка как чистого Xray, так и Marzban. + +## Настройка сервера + +### Настройка SSH + +На своем ПК, неважно, GNU/Linux или Windows. __На Windows используйте Powershell__. Открываем терминал и выполняем следующую команду: +```bash +ssh-keygen -t ed25519 +``` +После выполнения команды вам предложат изменить место хранения ключа и добавить пароль к нему. Менять локацию не надо, пароль же можете добавить ради безопасности. +Создав ключ, вам будет выведена локация публичной и приватной его части, нам нужно перекинуть публичную часть этого ключа на нашу VPS. +На Linux: +```bash +ssh-copy-id -i ~/.ssh/id_ed25519.pub ваш_пользователь@ваша_vps +``` +На Windows: +```powershell +ssh-copy-id -i $env:USERPROFILE\.ssh\id_ed25519.pub ваш_пользователь@ваша_vps +``` +Если данная команда у вас не сработала на Windows, то нужно выполнить следующую: +```powershell +type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh ваш_пользователь@ваша_vps "cat >> .ssh/authorized_keys" +``` +__Далее все делается на VPS.__ +Для отключения входа по паролю выполняем следующую команду: +```bash +grep -r PasswordAuthentication /etc/ssh -l | xargs -n 1 sed -i -e "/PasswordAuthentication /c\PasswordAuthentication no" +``` +Сделав это можно перезапустить SSH. +```bash +sudo systemctl restart ssh +``` + +### Настройки iptables +Нам нужно оставить открытыми порты для SSH, 80(HTTP) и 443(HTTPS). +Для этого нужно выполнить следующие команды: +```bash +iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT +iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT +iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT +iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT +iptables -A INPUT -i lo -j ACCEPT +iptables -A OUTPUT -o lo -j ACCEPT +iptables -P INPUT DROP +iptables-save > /etc/network/iptables.rules +``` + +### Включение BBR +Достаточно выполнить следующие команды: +```bash +echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf +echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf +sysctl -p +``` + +## Создание прокси + +### Установка Docker +Для установки нужно выполнить следующую команду: +```bash +bash <(wget -qO- https://get.docker.com) @ -o get-docker.sh +``` +Если вы работаете не от админа, то выполните следующие команды, чтобы не писать `sudo` каждый раз: +```bash +sudo groupadd docker +sudo usermod -aG docker $USER +``` + +### Получение данных для прокси +В этой части будут описаны необходимые данные, а также способ их получения. Позже эти данные будут использованы в конфигурации. +- __VLESS_DOMAIN__: Ваш домен. Если используется punycode, то далее используется ТОЛЬКО на латинице. +- __XRAY_PBK+PIK__: `docker run --rm ghcr.io/xtls/xray-core x25519` +Оба значения для нас важны, Public key = PBK, Private key = PIK. +- __XRAY_SID__: `openssl rand -hex 8` +Short id, используется для различения разных клиентов + +Следующие данные нужны только если вы будете устанавливать панель Marzban. +- __MARZBAN_USER__: `tr -dc A-Za-z0-9 + Marzban + +```yaml +services: + caddy: + image: caddy:2.9 + restart: always + network_mode: host + volumes: + - ./caddy/data:/data + - ./caddy/Caddyfile:/etc/caddy/Caddyfile + - ./marzban_lib:/run/marzban + marzban: + image: gozargah/marzban:latest + restart: always + env_file: ./marzban/.env + network_mode: host + volumes: + - ./marzban_lib:/var/lib/marzban + - ./marzban/xray_config.json:/code/xray_config.json + - ./marzban/templates:/var/lib/marzban/templates +``` + +
+ Xray + +```yaml +services: + caddy: + image: caddy:2.9 + restart: always + network_mode: host + volumes: + - ./caddy/data:/data + - ./caddy/Caddyfile:/etc/caddy/Caddyfile + - ./caddy/templates:/srv + xray: + image: ghcr.io/xtls/xray-core:latest + restart: always + network_mode: host + volumes: + - ./xray:/etc/xray +``` +
+Создаем папку `/opt/xray-vps-setup/caddy` и в ней создаем файл `Caddyfile` и меняем его следующим образом. +
Marzban + +```yaml +{ + https_port 4123 + default_bind 127.0.0.1 + servers { + listener_wrappers { + proxy_protocol { + allow 127.0.0.1/32 + } + tls + } + } + auto_https disable_redirects +} +https://$VLESS_DOMAIN { + reverse_proxy * unix//run/marzban/marzban.socket +} +http://$VLESS_DOMAIN { + bind 0.0.0.0 + redir https://$VLESS_DOMAIN{uri} permanent +} +:4123 { + tls internal + respond 204 +} +:80 { + bind 0.0.0.0 + respond 204 +} +``` + +
+
Чистый Xray + +```yaml +{ + https_port 4123 + default_bind 127.0.0.1 + servers { + listener_wrappers { + proxy_protocol { + allow 127.0.0.1/32 + } + tls + } + } + auto_https disable_redirects +} +https://$VLESS_DOMAIN { + root * /srv + file_server +} +http://$VLESS_DOMAIN { + bind 0.0.0.0 + redir https://$VLESS_DOMAIN{uri} permanent +} +:4123 { + tls internal + respond 204 +} +:80 { + bind 0.0.0.0 + respond 204 +} +``` + +
+Настроив caddy требуется добавить страницу для маскировки. Для xray и marzban команды отличаются: +Xray + +```bash +wget -qO- https://raw.githubusercontent.com/Jolymmiles/confluence-marzban-home/main/index.html | envsubst > /opt/xray-vps-setup/caddy/templates/index.html +``` +Marzban +```bash +wget -qO- https://raw.githubusercontent.com/Jolymmiles/confluence-marzban-home/main/index.html | envsubst > /opt/xray-vps-setup/marzban/templates/home/index.html +``` + +После этого надо создать файл конфигурации Xray, если вы ставите marzban, то он будет находится в `/opt/xray-vps-setup/marzban/xray_config.json`, если чистый xray, то `/opt/xray-vps-setup/xray/config.json` + +```json +{ + "log": { + "loglevel": "debug" + }, + "inbounds": [ + { + "tag": "VLESS TCP VISION REALITY", + "listen": "0.0.0.0", + "port": 443, + "protocol": "vless", + "settings": { + "clients": [ + { + "id": "XRAY_UUDI", // ПОМЕНЯТЬ НА СВОЕ + "email": "default", + "flow": "xtls-rprx-vision" + } + ], + "decryption": "none" + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "xver": 1, + "dest": "127.0.0.1:4123", + "serverNames": [ + "VLESS_DOMAIN" // ПОМЕНЯТЬ НА СВОЕ + ], + "privateKey": "XRAY_PIK", // ПОМЕНЯТЬ НА СВОЕ + "shortIds": [ + "XRAY_SID" // ПОМЕНЯТЬ НА СВОЕ + ] + } + }, + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls" + ], + "routeOnly": true + } + } + ], + "outbounds": [ + { + "protocol": "freedom", + "tag": "direct", + "settings": { + "domainStrategy": "UseIPv4" + } + }, + { + "protocol": "blackhole", + "tag": "block" + } + ], + "routing": { + "rules": [ + { + "protocol": "bittorrent", + "outboundTag": "block" + } + ], + "domainStrategy": "IPIfNonMatch" + }, + "dns": { + "servers": [ + "1.1.1.1", + "8.8.8.8" + ], + "queryStrategy": "UseIPv4", + "disableFallback": false, + "tag": "dns-aux" + } +} +``` + +Для Marzban необходимо также добавить `.env` файл. Создайте файл `/opt/xray-vps-setup/marzban/.env` и вставьте следующее: +``` +SUDO_USERNAME = "xray_admin" +SUDO_PASSWORD = "$MARZBAN_PASS" +UVICORN_UDS = "/var/lib/marzban/marzban.socket" +DASHBOARD_PATH = "/$MARZBAN_PATH/" +XRAY_JSON = "xray_config.json" +XRAY_SUBSCRIPTION_URL_PREFIX = "https://$VLESS_DOMAIN" +XRAY_SUBSCRIPTION_PATH = "$MARZBAN_SUB_PATH" +SQLALCHEMY_DATABASE_URL = "sqlite:////var/lib/marzban/db.sqlite3" +CUSTOM_TEMPLATES_DIRECTORY="/var/lib/marzban/templates/" +SUBSCRIPTION_PAGE_TEMPLATE="subscription/index.html" +HOME_PAGE_TEMPLATE="home/index.html" +``` + +## Настройка WARP + +Для того, чтобы доабвить WARP для того, чтобы в Россию наш юзер ходил черзе него, то надо сделать следующее. +Устанавливаем WARP: +```bash +curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg +echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/cloudflare-client.list +apt update +apt install cloudflare-warp -y +``` +Настроим WARP: +```bash +warp-cli registration new +warp-cli mode proxy +warp-cli proxy port 40000 +warp-cli connect +``` +Если на этом этапе ловим ошибку подключения, то не продолжайте, WARP не рабоатет. +Установка `yq`: +```bash +wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq && chmod +x /usr/bin/yq +``` +Далее с помощью `yq` мы установим в уже существующий кофниг WARP: +```bash +yq eval '.outbounds += {"tag": "warp","protocol": "socks","settings": {"servers": [{"address": "127.0.0.1","port": 40000}]}}' -i $XRAY_CONFIG_WARP +yq eval '.routing.rules += {"outboundTag": "warp", "domain": ["geosite:category-ru", "regexp:.*\\.xn--$", "regexp:.*\\.ru$", "regexp:.*\\.su$"]}' -i $XRAY_CONFIG_WARP + +``` +Заменяем $XRAY_CONFIG_WARP на `/opt/xray-vps-setup/marzban/xray_config.json` для marzban и на `/opt/xray-vps-setup/xray/config.json` для чистого xray. После этого перезапускаем все: +```bash +docker compose -f /opt/xray-vps-setup/docker-compose.yml down && docker compose -f /opt/xray-vps-setup/docker-compose.yml up -d +``` + +# + +Если вы хотите помочь что-то исправить, добавить и тд, то делайте PR или пишите в [ТГ](https://t.me/Akiyamov). \ No newline at end of file diff --git a/roles/xray-vps-setup/meta/.galaxy_install_info b/roles/xray-vps-setup/meta/.galaxy_install_info new file mode 100644 index 0000000..7567566 --- /dev/null +++ b/roles/xray-vps-setup/meta/.galaxy_install_info @@ -0,0 +1,2 @@ +install_date: Mon Feb 9 17:35:32 2026 +version: null diff --git a/roles/xray-vps-setup/meta/main.yml b/roles/xray-vps-setup/meta/main.yml new file mode 100644 index 0000000..8e546c9 --- /dev/null +++ b/roles/xray-vps-setup/meta/main.yml @@ -0,0 +1,18 @@ +galaxy_info: + author: Akiyamov + description: Setup VPS for XRay + company: your company (optional) + license: BSD-3-Clause + min_ansible_version: 2.1 + platforms: + - name: Ubuntu + versions: + - 16 + - 18 + - 20 + - 22 + - 24 + galaxy_tags: + - xray + - vps +dependencies: [] diff --git a/roles/xray-vps-setup/tasks/bbr.yml b/roles/xray-vps-setup/tasks/bbr.yml new file mode 100644 index 0000000..9746ffc --- /dev/null +++ b/roles/xray-vps-setup/tasks/bbr.yml @@ -0,0 +1,10 @@ +- name: Set BBR + ansible.posix.sysctl: + name: net.core.default_qdisc + value: "fq" + state: present +- name: Set queue + ansible.posix.sysctl: + name: net.ipv4.tcp_congestion_control + value: "bbr" + state: present \ No newline at end of file diff --git a/roles/xray-vps-setup/tasks/end_xray.yml b/roles/xray-vps-setup/tasks/end_xray.yml new file mode 100644 index 0000000..8c82448 --- /dev/null +++ b/roles/xray-vps-setup/tasks/end_xray.yml @@ -0,0 +1,63 @@ +- name: Print clipboard string + debug: + msg: "vless://{{ xray_uuid.stdout }}@{{ vless.domain }}:443?type=tcp&security=reality&pbk={{ x25519_pbk.stdout }}&fp=chrome&sni={{ vless.domain }}&sid={{ short_id.stdout }}&spx=%2F&flow=xtls-rprx-vision" +- name: XRay outbound config + debug: + msg: | + { + "tag": "default", + "protocol": "vless", + "settings": { + "vnext": [ + { + "address": "{{ vless.domain }}", + "port": 443, + "users": [ + { + "id": "{{ xray_uuid.stdout }}", + "encryption": "none", + "flow": "xtls-rprx-vision" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "serverName": "{{ vless.domain }}", + "fingerprint": "chrome", + "publicKey": "{{ x25519_pbk.stdout }}", + "shortId": "{{ short_id.stdout }}", + "spiderX": "" + } + } + } +- name: Sing-box outbound config + debug: + msg: | + { + "type": "vless", + "server": "{{ vless.domain }}", + "server_port": 443, + "uuid": "{{ xray_uuid.stdout }}", + "flow": "xtls-rprx-vision", + "tls": { + "enabled": true, + "insecure": false, + "server_name": "{{ vless.domain }}", + "utls": { + "enabled": true, + "fingerprint": "chrome" + }, + "reality": { + "enabled": true, + "public_key": "{{ x25519_pbk.stdout }}", + "short_id": "{{ short_id.stdout }}" + } + } + } +- name: Print PBK, SID and UUID to connect to server. + debug: + msg: "UUID: {{ xray_uuid.stdout }}, SID: {{ short_id.stdout }}, PBK: {{ x25519_pbk.stdout }}" diff --git a/roles/xray-vps-setup/tasks/install_docker.yml b/roles/xray-vps-setup/tasks/install_docker.yml new file mode 100644 index 0000000..33630b5 --- /dev/null +++ b/roles/xray-vps-setup/tasks/install_docker.yml @@ -0,0 +1,13 @@ +- name: Add Docker GPG apt Key + ansible.builtin.apt_key: + url: https://download.docker.com/linux/ubuntu/gpg + state: present +- name: Add Docker Repository + ansible.builtin.apt_repository: + repo: deb https://download.docker.com/linux/ubuntu focal stable + state: present +- name: Update install docker-ce + ansible.builtin.apt: + name: docker-ce + state: latest + update_cache: true diff --git a/roles/xray-vps-setup/tasks/install_marzban.yml b/roles/xray-vps-setup/tasks/install_marzban.yml new file mode 100644 index 0000000..1b66ceb --- /dev/null +++ b/roles/xray-vps-setup/tasks/install_marzban.yml @@ -0,0 +1,31 @@ +- name: Generate marzban specific values + block: + - name: Generate marzban password + set_fact: + MARZBAN_PASS: "{{ lookup('password', '/dev/null length=13 chars=ascii_letters') }}" + - name: Generate marzban password + set_fact: + MARZBAN_PATH: "{{ lookup('password', '/dev/null length=8 chars=ascii_letters') }}" + - name: Generate marzban password + set_fact: + MARZBAN_SUB_PATH: "{{ lookup('password', '/dev/null length=8 chars=ascii_letters') }}" +- name: Create dirs + file: + path: "{{ item }}" + state: directory + loop: + - /opt/xray-vps-setup/caddy + - /opt/xray-vps-setup/marzban + - /opt/xray-vps-setup/marzban/templates/home +- name: Copy config files + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + loop: + - { src: "caddyfile.j2", dest: "/opt/xray-vps-setup/caddy/Caddyfile" } + - { src: "xray.json.j2", dest: "/opt/xray-vps-setup/marzban/xray_config.json" } + - { src: "marzban.j2", dest: "/opt/xray-vps-setup/marzban/.env" } + - { src: "confluence.j2", dest: "/opt/xray-vps-setup/marzban/templates/home/index.html" } + - { src: "marzban_docker.j2", dest: "/opt/xray-vps-setup/docker-compose.yml" } +- debug: + msg: "Marzban password: {{ MARZBAN_PASS }}, marzban path: {{ MARZBAN_PATH }}" \ No newline at end of file diff --git a/roles/xray-vps-setup/tasks/install_xray.yml b/roles/xray-vps-setup/tasks/install_xray.yml new file mode 100644 index 0000000..8a20b77 --- /dev/null +++ b/roles/xray-vps-setup/tasks/install_xray.yml @@ -0,0 +1,16 @@ +- name: Create dirs + file: + path: "{{ item }}" + state: directory + loop: + - /opt/xray-vps-setup/caddy/templates + - /opt/xray-vps-setup/xray +- name: Copy config files + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + loop: + - { src: "caddyfile.j2", dest: "/opt/xray-vps-setup/caddy/Caddyfile" } + - { src: "confluence.j2", dest: "/opt/xray-vps-setup/caddy/templates/index.html" } + - { src: "xray.json.j2", dest: "/opt/xray-vps-setup/xray/config.json" } + - { src: "xray_docker.j2", dest: "/opt/xray-vps-setup/docker-compose.yml" } diff --git a/roles/xray-vps-setup/tasks/install_yq.yml b/roles/xray-vps-setup/tasks/install_yq.yml new file mode 100644 index 0000000..41e2c20 --- /dev/null +++ b/roles/xray-vps-setup/tasks/install_yq.yml @@ -0,0 +1,5 @@ +- name: Download yq + ansible.builtin.get_url: + url: https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 + dest: /usr/bin/yq + mode: '0755' \ No newline at end of file diff --git a/roles/xray-vps-setup/tasks/iptables.yml b/roles/xray-vps-setup/tasks/iptables.yml new file mode 100644 index 0000000..3ecd1f6 --- /dev/null +++ b/roles/xray-vps-setup/tasks/iptables.yml @@ -0,0 +1,46 @@ +- name: IPTables rules + block: + - name: Install netfilter-persistent + apt: + name: netfilter-persistent + state: present + - name: Allow related and established connections + ansible.builtin.iptables: + chain: INPUT + ctstate: ESTABLISHED,RELATED + jump: ACCEPT + become: yes + - name: Allow new incoming SYN packets on specified port + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + destination_port: "{{ SSH_PORT }}" + ctstate: NEW + syn: match + jump: ACCEPT + - name: Allow ICMP + ansible.builtin.iptables: + chain: INPUT + protocol: icmp + jump: ACCEPT + - name: Allow 80, 443 connections + ansible.builtin.iptables: + chain: INPUT + protocol: tcp + destination_ports: + - "80" + - "443" + jump: ACCEPT + - name: Allow loopback in + shell: + cmd: iptables -A INPUT -i lo -j ACCEPT + - name: Allow loopback out + shell: + cmd: iptables -A OUTPUT -o lo -j ACCEPT + - name: INPUT DROP + ansible.builtin.iptables: + chain: INPUT + policy: DROP + - name: Save iptables rules + shell: + cmd: netfilter-persistent save \ No newline at end of file diff --git a/roles/xray-vps-setup/tasks/main.yml b/roles/xray-vps-setup/tasks/main.yml new file mode 100644 index 0000000..b429189 --- /dev/null +++ b/roles/xray-vps-setup/tasks/main.yml @@ -0,0 +1,54 @@ +--- +- name: Populate service facts + ansible.builtin.service_facts: +- name: Enable BBR + include_tasks: bbr.yml +- name: Install docker + include_tasks: install_docker.yml + when: ansible_facts.services['docker'] is undefined +- name: Install/update yq + include_tasks: install_yq.yml +- name: Security block + block: + - name: Edit SSHD config + include_tasks: ssh.yml + - name: Edit iptables + include_tasks: iptables.yml + - name: Add user + include_tasks: user.yml + when: configure_security|default(false)|bool == true +- name: Generate values + block: + - name: Generate x25519 PIK + shell: + cmd: docker run --rm ghcr.io/xtls/xray-core x25519 | head -n1 | cut -d' ' -f 3 + register: x25519_pik + - name: Generate x25519 PBK + shell: + cmd: docker run --rm ghcr.io/xtls/xray-core x25519 -i {{ x25519_pik.stdout }} | tail -1 | cut -d' ' -f 3 + register: x25519_pbk + - name: Generate SID + shell: + cmd: openssl rand -hex 8 + register: short_id + - name: Generate default user + shell: + cmd: docker run --rm ghcr.io/xtls/xray-core uuid + register: xray_uuid +- name: Install marzban + include_tasks: install_marzban.yml + when: setup_variant == "marzban" +- name: Install xray + include_tasks: install_xray.yml + when: setup_variant == "xray" +- name: Install warp + include_tasks: setup_warp.yml + when: setup_warp|default(false)|bool == true +- name: Start proxy + community.docker.docker_compose_v2: + project_src: /opt/xray-vps-setup + files: + - docker-compose.yml +- name: End xray + include_tasks: end_xray.yml + when: setup_variant == "xray" \ No newline at end of file diff --git a/roles/xray-vps-setup/tasks/setup_warp.yml b/roles/xray-vps-setup/tasks/setup_warp.yml new file mode 100644 index 0000000..5c638d3 --- /dev/null +++ b/roles/xray-vps-setup/tasks/setup_warp.yml @@ -0,0 +1,61 @@ +#- name: Add WARP GPG key +# ansible.builtin.get_url: +# url: https://pkg.cloudflareclient.com/pubkey.gpg +# dest: /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg +# mode: '0644' +# force: true +- name: Add WARP GPG key + ansible.builtin.shell: + cmd: curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg +- name: Add WARP repo + ansible.builtin.apt_repository: + filename: cloudflare-client + repo: "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ {{ ansible_facts['distribution_release'] }} main" +- name: + apt: + name: cloudflare-warp + state: present + update_cache: yes +- name: Register WARP + shell: + cmd: echo "y" | warp-cli registration new +- shell: + cmd: warp-cli mode proxy +- shell: + cmd: warp-cli proxy port 40000 +- shell: + cmd: warp-cli connect +- name: Edit xray config + block: + - command: + argv: + - yq + - eval + - '.outbounds += {"tag": "warp","protocol": "socks","settings": {"servers": [{"address": "127.0.0.1","port": 40000}]}}' + - -i + - /opt/xray-vps-setup/xray/config.json + - command: + argv: + - yq + - eval + - '.routing.rules += {"outboundTag": "warp", "domain": ["geosite:category-ru", "regexp:.*\\.xn--$", "regexp:.*\\.ru$", "regexp:.*\\.su$"]}' + - -i + - /opt/xray-vps-setup/xray/config.json + when: setup_variant == "xray" +- name: Edit marzban config + block: + - command: + argv: + - yq + - eval + - '.outbounds += {"tag": "warp","protocol": "socks","settings": {"servers": [{"address": "127.0.0.1","port": 40000}]}}' + - -i + - /opt/xray-vps-setup/marzban/xray_config.json + - command: + argv: + - yq + - eval + - '.routing.rules += {"outboundTag": "warp", "domain": ["geosite:category-ru", "regexp:.*\\.xn--$", "regexp:.*\\.ru$", "regexp:.*\\.su$"]}' + - -i + - /opt/xray-vps-setup/marzban/xray_config.json + when: setup_variant == "marzban" \ No newline at end of file diff --git a/roles/xray-vps-setup/tasks/ssh.yml b/roles/xray-vps-setup/tasks/ssh.yml new file mode 100644 index 0000000..95f9e57 --- /dev/null +++ b/roles/xray-vps-setup/tasks/ssh.yml @@ -0,0 +1,14 @@ +- name: Change SSH port + shell: + cmd: grep -r Port /etc/ssh -l | xargs -n 1 sed -i -e "/Port /c\Port {{ SSH_PORT }}" +- name: Disable password login + shell: + cmd: grep -r PasswordAuthentication /etc/ssh -l | xargs -n 1 sed -i -e "/PasswordAuthentication /c\PasswordAuthentication no" +- name: Disable root login + shell: + cmd: grep -r PermitRootLogin /etc/ssh -l | xargs -n 1 sed -i -e "/PermitRootLogin /c\PermitRootLogin no" +- name: Restart ssh + service: + name: ssh + state: restarted + daemon_reload: true \ No newline at end of file diff --git a/roles/xray-vps-setup/tasks/user.yml b/roles/xray-vps-setup/tasks/user.yml new file mode 100644 index 0000000..191eb0b --- /dev/null +++ b/roles/xray-vps-setup/tasks/user.yml @@ -0,0 +1,14 @@ +- name: Add user + ansible.builtin.user: + name: "{{ user_to_create }}" + shell: /bin/bash + groups: sudo,docker + password: "{{ user_password | password_hash('sha512') }}" + append: yes + update_password: on_create + register: "xray_user" +- name: Add ssh_pbk to user + ansible.posix.authorized_key: + user: "{{ user_to_create }}" + state: "present" + key: "{{ ssh_public_key }}" diff --git a/roles/xray-vps-setup/templates/caddyfile.j2 b/roles/xray-vps-setup/templates/caddyfile.j2 new file mode 100644 index 0000000..257205a --- /dev/null +++ b/roles/xray-vps-setup/templates/caddyfile.j2 @@ -0,0 +1,50 @@ +{ + https_port 4123 + default_bind 127.0.0.1 + servers { + listener_wrappers { + proxy_protocol { + allow 127.0.0.1/32 + } + tls + } + } + auto_https disable_redirects +} +https://{{ domain }} { +{% if setup_variant == "marzban" %} + reverse_proxy * unix//run/marzban/marzban.socket +{% else %} + root * /srv + file_server +{% endif %} + header { + -Server + } + handle_errors { + header { + -Server + } + } +} +http://{{ domain }} { + bind 0.0.0.0 + redir https://{host}{uri} permanent + + header { + -Server + } + handle_errors { + header { + -Server + } + } +} +:4123 { + tls internal + respond 204 +} +:80 { + bind 0.0.0.0 + respond 204 +} diff --git a/roles/xray-vps-setup/templates/confluence.j2 b/roles/xray-vps-setup/templates/confluence.j2 new file mode 100644 index 0000000..89550a3 --- /dev/null +++ b/roles/xray-vps-setup/templates/confluence.j2 @@ -0,0 +1,272 @@ + + + + + + Вход в Confluence + + + + +
+ +

Войти в Confluence

+
+ + + +
+
Неправильное имя пользователя или пароль.
+ +
+ + + + + + + diff --git a/roles/xray-vps-setup/templates/marzban.j2 b/roles/xray-vps-setup/templates/marzban.j2 new file mode 100644 index 0000000..11b39a8 --- /dev/null +++ b/roles/xray-vps-setup/templates/marzban.j2 @@ -0,0 +1,95 @@ +SUDO_USERNAME = "xray_admin" +SUDO_PASSWORD = "{{ MARZBAN_PASS }}" +UVICORN_UDS = "/var/lib/marzban/marzban.socket" +DASHBOARD_PATH = "/{{ MARZBAN_PATH }}/" +XRAY_JSON = "xray_config.json" +XRAY_SUBSCRIPTION_URL_PREFIX = "https://{{ domain }}" +XRAY_SUBSCRIPTION_PATH = "{{ MARZBAN_SUB_PATH }}" +SQLALCHEMY_DATABASE_URL = "sqlite:////var/lib/marzban/db.sqlite3" +# ALLOWED_ORIGINS=http://localhost,http://localhost:8000,http://example.com +# XRAY_EXECUTABLE_PATH = "/usr/local/bin/xray" +# XRAY_ASSETS_PATH = "/usr/local/share/xray" +# XRAY_EXCLUDE_INBOUND_TAGS = "INBOUND_X INBOUND_Y" +# XRAY_FALLBACKS_INBOUND_TAG = "INBOUND_X" + +# TELEGRAM_API_TOKEN = 123456789:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +# TELEGRAM_ADMIN_ID = 987654321, 123456789 +# TELEGRAM_LOGGER_CHANNEL_ID = -1234567890123 +# TELEGRAM_DEFAULT_VLESS_FLOW = "xtls-rprx-vision" +# TELEGRAM_PROXY_URL = "http://localhost:8080" + +# DISCORD_WEBHOOK_URL = "https://discord.com/api/webhooks/xxxxxxx" + +CUSTOM_TEMPLATES_DIRECTORY="/var/lib/marzban/templates/" +# CLASH_SUBSCRIPTION_TEMPLATE="clash/my-custom-template.yml" +SUBSCRIPTION_PAGE_TEMPLATE="subscription/index.html" +HOME_PAGE_TEMPLATE="home/index.html" + +# V2RAY_SUBSCRIPTION_TEMPLATE="v2ray/default.json" +# V2RAY_SETTINGS_TEMPLATE="v2ray/settings.json" + +# SINGBOX_SUBSCRIPTION_TEMPLATE="singbox/default.json" +# SINGBOX_SETTINGS_TEMPLATE="singbox/settings.json" + +# MUX_TEMPLATE="mux/default.json" + +## Enable JSON config for compatible clients to use mux, fragment, etc. Default False. +# USE_CUSTOM_JSON_DEFAULT=True +## Your preferred config type for different clients +## If USE_CUSTOM_JSON_DEFAULT is set True, all following programs will use the JSON config +# USE_CUSTOM_JSON_FOR_V2RAYN=False +# USE_CUSTOM_JSON_FOR_V2RAYNG=True +# USE_CUSTOM_JSON_FOR_STREISAND=False + +## Set headers for subscription +# SUB_PROFILE_TITLE = "Susbcription" +# SUB_SUPPORT_URL = "https://t.me/support" +# SUB_UPDATE_INTERVAL = "12" + +## External config to import into v2ray format subscription +# EXTERNAL_CONFIG = "config://..." + +# SQLALCHEMY_POOL_SIZE = 10 +# SQLIALCHEMY_MAX_OVERFLOW = 30 + +## Custom text for STATUS_TEXT variable +# ACTIVE_STATUS_TEXT = "Active" +# EXPIRED_STATUS_TEXT = "Expired" +# LIMITED_STATUS_TEXT = "Limited" +# DISABLED_STATUS_TEXT = "Disabled" +# ONHOLD_STATUS_TEXT = "On-Hold" + +### Use negative values to disable auto-delete by default +# USERS_AUTODELETE_DAYS = -1 +# USER_AUTODELETE_INCLUDE_LIMITED_ACCOUNTS = false + +## Customize all notifications +# NOTIFY_STATUS_CHANGE = True +# NOTIFY_USER_CREATED = True +# NOTIFY_USER_UPDATED = True +# NOTIFY_USER_DELETED = True +# NOTIFY_USER_DATA_USED_RESET = True +# NOTIFY_USER_SUB_REVOKED = True +# NOTIFY_IF_DATA_USAGE_PERCENT_REACHED = True +# NOTIFY_IF_DAYS_LEF_REACHED = True +# NOTIFY_LOGIN = True + +## Whitelist of IPs/hosts to disable login notifications +# LOGIN_NOTIFY_WHITE_LIST = '1.1.1.1,127.0.0.1' + +### for developers +# DOCS=True +# DEBUG=True + +# If You Want To Send Webhook To Multiple Server Add Multi Address +# WEBHOOK_ADDRESS = "http://127.0.0.1:9000/,http://127.0.0.1:9001/" +# WEBHOOK_SECRET = "something-very-very-secret" + +# VITE_BASE_API="https://example.com/api/" +# JWT_ACCESS_TOKEN_EXPIRE_MINUTES = 1440 + +# JOB_CORE_HEALTH_CHECK_INTERVAL = 10 +# JOB_RECORD_NODE_USAGES_INTERVAL = 30 +# JOB_RECORD_USER_USAGES_INTERVAL = 10 +# JOB_REVIEW_USERS_INTERVAL = 10 +# JOB_SEND_NOTIFICATIONS_INTERVAL = 30 \ No newline at end of file diff --git a/roles/xray-vps-setup/templates/marzban_docker.j2 b/roles/xray-vps-setup/templates/marzban_docker.j2 new file mode 100644 index 0000000..a2d2ebf --- /dev/null +++ b/roles/xray-vps-setup/templates/marzban_docker.j2 @@ -0,0 +1,20 @@ +services: + caddy: + image: caddy:2.9 + container_name: caddy + restart: always + network_mode: host + volumes: + - ./caddy/data:/data + - ./caddy/Caddyfile:/etc/caddy/Caddyfile + - ./marzban_lib:/run/marzban + marzban: + image: gozargah/marzban:v0.8.4 + container_name: marzban + restart: always + env_file: ./marzban/.env + network_mode: host + volumes: + - ./marzban_lib:/var/lib/marzban + - ./marzban/xray_config.json:/code/xray_config.json + - ./marzban/templates:/var/lib/marzban/templates \ No newline at end of file diff --git a/roles/xray-vps-setup/templates/xray.json.j2 b/roles/xray-vps-setup/templates/xray.json.j2 new file mode 100644 index 0000000..0abde50 --- /dev/null +++ b/roles/xray-vps-setup/templates/xray.json.j2 @@ -0,0 +1,76 @@ +{ + "log": { + "loglevel": "info" + }, + "inbounds": [ + { + "tag": "VLESS TCP VISION REALITY", + "listen": "0.0.0.0", + "port": 443, + "protocol": "vless", + "settings": { + "clients": [ + { + "id": "{{ xray_uuid.stdout}}", + "email": "default", + "flow": "xtls-rprx-vision" + }], + "decryption": "none" + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "xver": 1, + "dest": "127.0.0.1:4123", + "serverNames": [ + "{{ domain }}" + ], + "privateKey": "{{ x25519_pik.stdout }}", + "shortIds": [ + "{{ short_id.stdout }}" + ] + } + }, + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls" + ], + "routeOnly": true + } + } + ], + "outbounds": [ + { + "protocol": "freedom", + "tag": "direct", + "settings": { + "domainStrategy": "UseIPv4" + } + }, + { + "protocol": "blackhole", + "tag": "block" + } + ], + "routing": { + "rules": [ + { + "protocol": "bittorrent", + "outboundTag": "block" + } + ], + "domainStrategy": "IPIfNonMatch" + }, + "dns": { + "servers": [ + "1.1.1.1", + "8.8.8.8" + ], + "queryStrategy": "UseIPv4", + "disableFallback": false, + "tag": "dns-aux" + } +} \ No newline at end of file diff --git a/roles/xray-vps-setup/templates/xray_docker.j2 b/roles/xray-vps-setup/templates/xray_docker.j2 new file mode 100644 index 0000000..86d2207 --- /dev/null +++ b/roles/xray-vps-setup/templates/xray_docker.j2 @@ -0,0 +1,19 @@ +services: + caddy: + image: caddy:2.9 + container_name: caddy + restart: always + network_mode: host + volumes: + - ./caddy/data:/data + - ./caddy/Caddyfile:/etc/caddy/Caddyfile + - ./caddy/templates:/srv + xray: + image: ghcr.io/xtls/xray-core:25.6.8 + restart: always + container_name: xray + user: root + command: run -c /etc/xray/config.json + network_mode: host + volumes: + - ./xray:/etc/xray \ No newline at end of file diff --git a/roles/xray-vps-setup/templates_for_script/caddy b/roles/xray-vps-setup/templates_for_script/caddy new file mode 100644 index 0000000..27b1d25 --- /dev/null +++ b/roles/xray-vps-setup/templates_for_script/caddy @@ -0,0 +1,47 @@ +{ + https_port 4123 + default_bind 127.0.0.1 + servers { + listener_wrappers { + proxy_protocol { + allow 127.0.0.1/32 + } + tls + } + } + auto_https disable_redirects +} +https://$VLESS_DOMAIN { + $CADDY_REVERSE + + header { + -Server + } + handle_errors { + header { + -Server + } + } +} +http://$VLESS_DOMAIN { + bind 0.0.0.0 + redir https://$VLESS_DOMAIN{uri} permanent + + header { + -Server + } + + handle_errors { + header { + -Server + } + } +} +:4123 { + tls internal + respond 204 +} +:80 { + bind 0.0.0.0 + respond 204 +} diff --git a/roles/xray-vps-setup/templates_for_script/compose b/roles/xray-vps-setup/templates_for_script/compose new file mode 100644 index 0000000..74b4634 --- /dev/null +++ b/roles/xray-vps-setup/templates_for_script/compose @@ -0,0 +1,9 @@ +services: + caddy: + image: caddy:2.9 + container_name: caddy + restart: always + network_mode: host + volumes: + - ./caddy/data:/data + - ./caddy/Caddyfile:/etc/caddy/Caddyfile \ No newline at end of file diff --git a/roles/xray-vps-setup/templates_for_script/confluence_page b/roles/xray-vps-setup/templates_for_script/confluence_page new file mode 100644 index 0000000..89550a3 --- /dev/null +++ b/roles/xray-vps-setup/templates_for_script/confluence_page @@ -0,0 +1,272 @@ + + + + + + Вход в Confluence + + + + +
+ +

Войти в Confluence

+
+ + + +
+
Неправильное имя пользователя или пароль.
+ +
+ + + + + + + diff --git a/roles/xray-vps-setup/templates_for_script/marzban b/roles/xray-vps-setup/templates_for_script/marzban new file mode 100644 index 0000000..4a77755 --- /dev/null +++ b/roles/xray-vps-setup/templates_for_script/marzban @@ -0,0 +1,95 @@ +SUDO_USERNAME = "xray_admin" +SUDO_PASSWORD = "$MARZBAN_PASS" +UVICORN_UDS = "/var/lib/marzban/marzban.socket" +DASHBOARD_PATH = "/$MARZBAN_PATH/" +XRAY_JSON = "xray_config.json" +XRAY_SUBSCRIPTION_URL_PREFIX = "https://$VLESS_DOMAIN" +XRAY_SUBSCRIPTION_PATH = "$MARZBAN_SUB_PATH" +SQLALCHEMY_DATABASE_URL = "sqlite:////var/lib/marzban/db.sqlite3" +# ALLOWED_ORIGINS=http://localhost,http://localhost:8000,http://example.com +# XRAY_EXECUTABLE_PATH = "/usr/local/bin/xray" +# XRAY_ASSETS_PATH = "/usr/local/share/xray" +# XRAY_EXCLUDE_INBOUND_TAGS = "INBOUND_X INBOUND_Y" +# XRAY_FALLBACKS_INBOUND_TAG = "INBOUND_X" + +# TELEGRAM_API_TOKEN = 123456789:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +# TELEGRAM_ADMIN_ID = 987654321, 123456789 +# TELEGRAM_LOGGER_CHANNEL_ID = -1234567890123 +# TELEGRAM_DEFAULT_VLESS_FLOW = "xtls-rprx-vision" +# TELEGRAM_PROXY_URL = "http://localhost:8080" + +# DISCORD_WEBHOOK_URL = "https://discord.com/api/webhooks/xxxxxxx" + +CUSTOM_TEMPLATES_DIRECTORY="/var/lib/marzban/templates/" +# CLASH_SUBSCRIPTION_TEMPLATE="clash/my-custom-template.yml" +SUBSCRIPTION_PAGE_TEMPLATE="subscription/index.html" +HOME_PAGE_TEMPLATE="home/index.html" + +# V2RAY_SUBSCRIPTION_TEMPLATE="v2ray/default.json" +# V2RAY_SETTINGS_TEMPLATE="v2ray/settings.json" + +# SINGBOX_SUBSCRIPTION_TEMPLATE="singbox/default.json" +# SINGBOX_SETTINGS_TEMPLATE="singbox/settings.json" + +# MUX_TEMPLATE="mux/default.json" + +## Enable JSON config for compatible clients to use mux, fragment, etc. Default False. +# USE_CUSTOM_JSON_DEFAULT=True +## Your preferred config type for different clients +## If USE_CUSTOM_JSON_DEFAULT is set True, all following programs will use the JSON config +# USE_CUSTOM_JSON_FOR_V2RAYN=False +# USE_CUSTOM_JSON_FOR_V2RAYNG=True +# USE_CUSTOM_JSON_FOR_STREISAND=False + +## Set headers for subscription +# SUB_PROFILE_TITLE = "Susbcription" +# SUB_SUPPORT_URL = "https://t.me/support" +# SUB_UPDATE_INTERVAL = "12" + +## External config to import into v2ray format subscription +# EXTERNAL_CONFIG = "config://..." + +# SQLALCHEMY_POOL_SIZE = 10 +# SQLIALCHEMY_MAX_OVERFLOW = 30 + +## Custom text for STATUS_TEXT variable +# ACTIVE_STATUS_TEXT = "Active" +# EXPIRED_STATUS_TEXT = "Expired" +# LIMITED_STATUS_TEXT = "Limited" +# DISABLED_STATUS_TEXT = "Disabled" +# ONHOLD_STATUS_TEXT = "On-Hold" + +### Use negative values to disable auto-delete by default +# USERS_AUTODELETE_DAYS = -1 +# USER_AUTODELETE_INCLUDE_LIMITED_ACCOUNTS = false + +## Customize all notifications +# NOTIFY_STATUS_CHANGE = True +# NOTIFY_USER_CREATED = True +# NOTIFY_USER_UPDATED = True +# NOTIFY_USER_DELETED = True +# NOTIFY_USER_DATA_USED_RESET = True +# NOTIFY_USER_SUB_REVOKED = True +# NOTIFY_IF_DATA_USAGE_PERCENT_REACHED = True +# NOTIFY_IF_DAYS_LEF_REACHED = True +# NOTIFY_LOGIN = True + +## Whitelist of IPs/hosts to disable login notifications +# LOGIN_NOTIFY_WHITE_LIST = '1.1.1.1,127.0.0.1' + +### for developers +# DOCS=True +# DEBUG=True + +# If You Want To Send Webhook To Multiple Server Add Multi Address +# WEBHOOK_ADDRESS = "http://127.0.0.1:9000/,http://127.0.0.1:9001/" +# WEBHOOK_SECRET = "something-very-very-secret" + +# VITE_BASE_API="https://example.com/api/" +# JWT_ACCESS_TOKEN_EXPIRE_MINUTES = 1440 + +# JOB_CORE_HEALTH_CHECK_INTERVAL = 10 +# JOB_RECORD_NODE_USAGES_INTERVAL = 30 +# JOB_RECORD_USER_USAGES_INTERVAL = 10 +# JOB_REVIEW_USERS_INTERVAL = 10 +# JOB_SEND_NOTIFICATIONS_INTERVAL = 30 \ No newline at end of file diff --git a/roles/xray-vps-setup/templates_for_script/sing_box_outbound b/roles/xray-vps-setup/templates_for_script/sing_box_outbound new file mode 100644 index 0000000..4335abb --- /dev/null +++ b/roles/xray-vps-setup/templates_for_script/sing_box_outbound @@ -0,0 +1,21 @@ +{ + "type": "vless", + "server": "$VLESS_DOMAIN", + "server_port": 443, + "uuid": "$XRAY_UUID", + "flow": "xtls-rprx-vision", + "tls": { + "enabled": true, + "insecure": false, + "server_name": "$VLESS_DOMAIN", + "utls": { + "enabled": true, + "fingerprint": "chrome" + }, + "reality": { + "enabled": true, + "public_key": "$XRAY_PBK", + "short_id": "$XRAY_SID" + } + } +} diff --git a/roles/xray-vps-setup/templates_for_script/xray b/roles/xray-vps-setup/templates_for_script/xray new file mode 100644 index 0000000..6eea0d2 --- /dev/null +++ b/roles/xray-vps-setup/templates_for_script/xray @@ -0,0 +1,77 @@ +{ + "log": { + "loglevel": "none" + }, + "inbounds": [ + { + "tag": "VLESS TCP VISION REALITY", + "listen": "0.0.0.0", + "port": 443, + "protocol": "vless", + "settings": { + "clients": [ + { + "id": "$XRAY_UUID", + "email": "default", + "flow": "xtls-rprx-vision" + } + ], + "decryption": "none" + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "xver": 1, + "dest": "127.0.0.1:4123", + "serverNames": [ + "$VLESS_DOMAIN" + ], + "privateKey": "$XRAY_PIK", + "shortIds": [ + "$XRAY_SID" + ] + } + }, + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls" + ], + "routeOnly": true + } + } + ], + "outbounds": [ + { + "protocol": "freedom", + "tag": "direct", + "settings": { + "domainStrategy": "UseIPv4" + } + }, + { + "protocol": "blackhole", + "tag": "block" + } + ], + "routing": { + "rules": [ + { + "protocol": "bittorrent", + "outboundTag": "block" + } + ], + "domainStrategy": "IPIfNonMatch" + }, + "dns": { + "servers": [ + "1.1.1.1", + "8.8.8.8" + ], + "queryStrategy": "UseIPv4", + "disableFallback": false, + "tag": "dns-aux" + } +} \ No newline at end of file diff --git a/roles/xray-vps-setup/templates_for_script/xray_outbound b/roles/xray-vps-setup/templates_for_script/xray_outbound new file mode 100644 index 0000000..69a1b71 --- /dev/null +++ b/roles/xray-vps-setup/templates_for_script/xray_outbound @@ -0,0 +1,30 @@ +{ + "tag": "default", + "protocol": "vless", + "settings": { + "vnext": [ + { + "address": "$VLESS_DOMAIN", + "port": 443, + "users": [ + { + "id": "$XRAY_UUID", + "encryption": "none", + "flow": "xtls-rprx-vision" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "serverName": "$VLESS_DOMAIN", + "fingerprint": "chrome", + "publicKey": "$XRAY_PBK", + "shortId": "$XRAY_SID", + "spiderX": "" + } + } +} diff --git a/roles/xray-vps-setup/tests/test.yml b/roles/xray-vps-setup/tests/test.yml new file mode 100644 index 0000000..6bda0dc --- /dev/null +++ b/roles/xray-vps-setup/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - vps-setup diff --git a/roles/xray-vps-setup/vars/main.yml b/roles/xray-vps-setup/vars/main.yml new file mode 100644 index 0000000..9addcf1 --- /dev/null +++ b/roles/xray-vps-setup/vars/main.yml @@ -0,0 +1,2 @@ +--- +# vars file for vps-setup diff --git a/roles/xray-vps-setup/vps-setup.sh b/roles/xray-vps-setup/vps-setup.sh new file mode 100644 index 0000000..9f70711 --- /dev/null +++ b/roles/xray-vps-setup/vps-setup.sh @@ -0,0 +1,304 @@ +#/bin/bash + +set -e + +export GIT_BRANCH="main" +export GIT_REPO="Akiyamov/xray-vps-setup" + +# Check if script started as root +if [ "$EUID" -ne 0 ] + then echo "Please run as root" + exit +fi + +# Install idn +apt-get update +apt-get install idn sudo dnsutils -y + +# Read domain input +read -ep "Enter your domain:"$'\n' input_domain + +export VLESS_DOMAIN=$(echo $input_domain | idn) + +SERVER_IPS=($(hostname -I)) + +RESOLVED_IP=$(dig +short $VLESS_DOMAIN | tail -n1) + +if [ -z "$RESOLVED_IP" ]; then + echo "Warning: Domain has no DNS record" + read -ep "Are you sure? That domain has no DNS record. If you didn't add that you will have to restart xray and caddy by yourself [y/N]"$'\n' prompt_response + if [[ "$prompt_response" =~ ^([yY])$ ]]; then + echo "Ok, proceeding without DNS verification" + else + echo "Come back later" + exit 1 + fi +else + MATCH_FOUND=false + for server_ip in "${SERVER_IPS[@]}"; do + if [ "$RESOLVED_IP" == "$server_ip" ]; then + MATCH_FOUND=true + break + fi + done + + if [ "$MATCH_FOUND" = true ]; then + echo "✓ DNS record points to this server ($RESOLVED_IP)" + else + echo "Warning: DNS record exists but points to different IP" + echo " Domain resolves to: $RESOLVED_IP" + echo " This server's IPs: ${SERVER_IPS[*]}" + read -ep "Continue anyway? [y/N]"$'\n' prompt_response + if [[ "$prompt_response" =~ ^([yY])$ ]]; then + echo "Ok, proceeding" + else + echo "Come back later" + exit 1 + fi + fi +fi + +read -ep "Do you want to install marzban? [y/N] "$'\n' marzban_input + +read -ep "Do you want to configure server security? Do this on first run only. [y/N] "$'\n' configure_ssh_input +if [[ ${configure_ssh_input,,} == "y" ]]; then + # Read SSH port + read -ep "Enter SSH port. Default 22, can't use ports: 80, 443 and 4123:"$'\n' input_ssh_port + + while [[ "$input_ssh_port" -eq "80" || "$input_ssh_port" -eq "443" || "$input_ssh_port" -eq "4123" ]]; do + read -ep "No, ssh can't use $input_ssh_port as port, write again:"$'\n' input_ssh_port + done + # Read SSH Pubkey + read -ep "Enter SSH public key:"$'\n' input_ssh_pbk + echo "$input_ssh_pbk" > ./test_pbk + ssh-keygen -l -f ./test_pbk + PBK_STATUS=$(echo $?) + if [ "$PBK_STATUS" -eq 255 ]; then + echo "Can't verify the public key. Try again and make sure to include 'ssh-rsa' or 'ssh-ed25519' followed by 'user@pcname' at the end of the file." + exit + fi + rm ./test_pbk +fi + +read -ep "Do you want to install WARP and use it on russian websites? [y/N] "$'\n' configure_warp_input +if [[ ${configure_warp_input,,} == "y" ]]; then + if ! curl -I https://api.cloudflareclient.com --connect-timeout 10 > /dev/null 2>&1; then + echo "Warp can't be used" + configure_warp_input="n" + fi +fi + +# Check congestion protocol +if sysctl net.ipv4.tcp_congestion_control | grep bbr; then + echo "BBR is already used" +else + echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf + echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf + sysctl -p > /dev/null + echo "Enabled BBR" +fi + +export ARCH=$(dpkg --print-architecture) + +yq_install() { + wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_$ARCH -O /usr/bin/yq && chmod +x /usr/bin/yq +} + +yq_install + +docker_install() { + curl -fsSL https://get.docker.com | sh +} + +if ! command -v docker 2>&1 >/dev/null; then + docker_install +fi + +# Generate values for XRay +export SSH_USER=$(tr -dc A-Za-z0-9 ./docker-compose.yml + yq eval \ + '.services.marzban.image = "gozargah/marzban:v0.8.4" | + .services.marzban.container_name = "marzban" | + .services.marzban.restart = "always" | + .services.marzban.env_file = "./marzban/.env" | + .services.marzban.network_mode = "host" | + .services.marzban.volumes[0] = "./marzban_lib:/var/lib/marzban" | + .services.marzban.volumes[1] = "./marzban/xray_config.json:/code/xray_config.json" | + .services.marzban.volumes[2] = "./marzban/templates:/var/lib/marzban/templates" | + .services.caddy.volumes[2] = "./marzban_lib:/run/marzban"' -i /opt/xray-vps-setup/docker-compose.yml + mkdir -p marzban caddy + wget -qO- https://raw.githubusercontent.com/$GIT_REPO/refs/heads/$GIT_BRANCH/templates_for_script/marzban | envsubst > ./marzban/.env + mkdir -p /opt/xray-vps-setup/marzban/templates/home + wget -qO- https://raw.githubusercontent.com/$GIT_REPO/refs/heads/$GIT_BRANCH/templates_for_script/confluence_page | envsubst > ./marzban/templates/home/index.html + export CADDY_REVERSE="reverse_proxy * unix//run/marzban/marzban.socket" + wget -qO- "https://raw.githubusercontent.com/$GIT_REPO/refs/heads/$GIT_BRANCH/templates_for_script/caddy" | envsubst > ./caddy/Caddyfile + wget -qO- "https://raw.githubusercontent.com/$GIT_REPO/refs/heads/$GIT_BRANCH/templates_for_script/xray" | envsubst > ./marzban/xray_config.json + else + wget -qO- https://raw.githubusercontent.com/$GIT_REPO/refs/heads/$GIT_BRANCH/templates_for_script/compose | envsubst > ./docker-compose.yml + mkdir -p /opt/xray-vps-setup/caddy/templates + yq eval \ + '.services.xray.image = "ghcr.io/xtls/xray-core:25.6.8" | + .services.xray.container_name = "xray" | + .services.xray.user = "root" | + .services.xray.command = "run -c /etc/xray/config.json" | + .services.xray.restart = "always" | + .services.xray.network_mode = "host" | + .services.caddy.volumes[2] = "./caddy/templates:/srv" | + .services.xray.volumes[0] = "./xray:/etc/xray"' -i /opt/xray-vps-setup/docker-compose.yml + wget -qO- https://raw.githubusercontent.com/$GIT_REPO/refs/heads/$GIT_BRANCH/templates_for_script/confluence_page | envsubst > ./caddy/templates/index.html + export CADDY_REVERSE="root * /srv + file_server" + mkdir -p xray caddy + wget -qO- "https://raw.githubusercontent.com/$GIT_REPO/refs/heads/$GIT_BRANCH/templates_for_script/xray" | envsubst > ./xray/config.json + wget -qO- "https://raw.githubusercontent.com/$GIT_REPO/refs/heads/$GIT_BRANCH/templates_for_script/caddy" | envsubst > ./caddy/Caddyfile + fi +} + +xray_setup + +sshd_edit() { + grep -r Port /etc/ssh -l | xargs -n 1 sed -i -e "/Port /c\Port $SSH_PORT" + grep -r PasswordAuthentication /etc/ssh -l | xargs -n 1 sed -i -e "/PasswordAuthentication /c\PasswordAuthentication no" + grep -r PermitRootLogin /etc/ssh -l | xargs -n 1 sed -i -e "/PermitRootLogin /c\PermitRootLogin no" + systemctl daemon-reload + systemctl restart ssh +} + +add_user() { + useradd $SSH_USER -s /bin/bash + usermod -aG sudo $SSH_USER + echo $SSH_USER:$SSH_USER_PASS | chpasswd + mkdir -p /home/$SSH_USER/.ssh + touch /home/$SSH_USER/.ssh/authorized_keys + echo $input_ssh_pbk >> /home/$SSH_USER/.ssh/authorized_keys + chmod 700 /home/$SSH_USER/.ssh/ + chmod 600 /home/$SSH_USER/.ssh/authorized_keys + chown $SSH_USER:$SSH_USER -R /home/$SSH_USER + usermod -aG docker $SSH_USER +} + +debconf-set-selections <