Маршрутизация VLESS-REALITY через HAProxy с маскировкой под свой сайт (steal-oneself)

от автора

Это третья часть маршрутизации популярного VLESS силами HAProxy, с первой и второй рекомендуется ознакомиться.

Что такое steal oneself спросите вы — это «кража» отпечатка вашего сайта, с полной маскировкой, если клиент подключается к серверу (со включенным xtls-rprx-vision), а домен использует соединение TLS1.3 то будет зашифрован только заголовок после шифрование будет отключено для защиты от инспекции на двойной TLS, однако если НЕ клиент решит постучаться по адресу то «вжух» и соединение магически перенаправляется на ваш сайт (сервис) под который маскируемся, у данного метода есть НО — и это но белый список разрешенных доменов, тут можно прочитать подробнее и тут.

Собственно приступим подготовке конфигурации, нам потребуется два домена(поддомена) например mydomain.com и cats.mydomain.com, если отталкиваться от конфигурации во второй статье то изменений будет не много сначала приведу пример для этого варианта:

Необходимые изменения

Секцию frontend TCP из второй статьи

frontend tcp         bind *:443 # ssl passthrough         mode tcp         option tcplog         tcp-request inspect-delay 6s          stick-table type ip size 1m expire 10s store conn_cur         tcp-request content track-sc0 src         tcp-request content reject if { sc_conn_cur(0) gt 30 }          tcp-request content capture req.ssl_sni len 10         tcp-request content accept if { req_ssl_hello_type 1 } or !{ req_ssl_hello_type 1 }          use_backend tcp-ssh if !{ req.ssl_hello_type 1 } { payload(0,7) -m bin 5353482d322e30 } or !{ req.ssl_hello_type 1 } { req.len 0 } # Я бы не рекомендовал, вы лешитесь доступа если haproxy упадет          default_backend tcp_to_https

Изменим на:

frontend tcp         bind *:443 # SSL Passthrough         mode tcp         option tcplog         tcp-request inspect-delay 5s      # Защитим от перегрузки, если с одного IP за 10сек открыто более 30 соединений, отклоним все запросы и закроем все соединения      # Нужно учитывать что WsTunnel с активным параметром --connection-min-idle <n> будет занимать указанное колличество при старте      # У VLESS так же есть мультилексор, тоже нужно учитывать при настройке      # Может так случиться если несколько клиентов в одно и тоже время с одного IP решат подключиться, все они потеряют доступ к серверу.          stick-table type ip size 1m expire 10s store conn_cur         tcp-request content track-sc0 src         tcp-request content reject if { sc_conn_cur(0) gt 30 }         tcp-request content capture req.ssl_sni len 10         tcp-request content accept if { req_ssl_hello_type 1 } or !{ req_ssl_hello_type 1 }          use_backend tcp-ssh if !{ req.ssl_hello_type 1 } { payload(0,7) -m bin 5353482d322e30 } or !{ req.ssl_hello_type 1 } { req.len 0 } # Я бы не рекомендовал, вы лишитесь доступа если haproxy упадет         use_backend tcp_to_https if { req.ssl_sni -i mydomain.com }          default_backend tcp_to_reality # cats.mydomain.com

Данные изменения сводятся к тому что бы весь трафик не прошедший по условиям перенаправить на backend tcp_to_reality, и отказаться от TCP+VLESS+TLS (можно и оставить на другом домене).
use_backend tcp_to_https отвечает за второй домен на котором висит сайт, wstunnel vless-ws и тд.
Так же у нас на 443 порту будет работать SSH, нужно ли оно вам решать вам.

Теперь добавим frontend для cats.mydomain.com под основной секцией frontend домена

frontend https_cats # Заглушка для Reality { ssl_fc_sni -i cats.mydomain.com }         bind 127.0.0.1:49002 accept-proxy ssl crt /etc/haproxy/certs alpn h2,http/1.1 strict-sni         http-request reject if { req.hdr(user-agent) -m sub evil }        # acl url_discovery path /.well-known/caldav /.well-known/carddav # для правильной работы NextCloud        # http-request redirect location /remote.php/dav/ code 301 if url_discovery # для правильной работы NextCloud         http-request deny if { path -m sub /. }         stick-table type ip size 100k expire 2m store http_req_rate(1m)         http-request track-sc0 src         http-request deny deny_status 429 content-type text/html lf-string "<p>Per our policy, you are limited to 30 requests per minute, but you have exceeded that limit with %[sc_http_req_rate(0)] requests per minute.</p>" if { sc_http_req_rate(0) gt 30 }         http-response set-header Strict-Transport-Security "max-age=16000000; includeSubDomains; preload;" # Устанавливаем HSTS         http-request return status 200 content-type text/plain lf-string "Status 200 OK! Your IP %[src]." if { path /https-status-443 }         default_backend cats

http_req_rate(1m) и if { sc_http_req_rate(0) gt 30 } отвечают за защиту от перегрузки, если придет более 30 запросов в течении минуты все соединения будут закрыты, а новые будут показывать ошибку 429.
http-request return status 200 content-type text/plain lf-string «Status 200 OK! Your IP %[src].» if { path /https-status-443 } будет отвечать «200 OK» по пути https-status-443, полезно для мониторинга доступности.
acl url_discovery path и http-request redirect location потребуются если решите маскироваться под nextcloud (настройка оного не будет описана здесь, главное настройте trusted_proxies, overwrite.cli.url, trusted_domains в config.php).
default_backend cats перенаправит все на ваш сервис.

Добавим backend reality

backend tcp_to_reality # Бекенд для передачи всего TCP трафика в X-UI не прошедшего по правилам в TCP фронтенде.         mode tcp         server https 127.0.0.1:48660 send-proxy check port 48660

Подготовим backend в виде панели X-UI, 3X-UI и другие, показываю на примере X-UI

Необходимые настройки для reality
настройки x-ui для reality

настройки x-ui для reality

Включаем прием Proxy Protocol для сохранения IP клиента.
TPROXY необязательно.
External Proxy указываем или основной домен или второй «cats.mydomain.com».
Соответственно выбираем Reality.
Xver 1 — это отправка прокси протокола необходимого для backend/frontend cats.
uTLS обязателен, у меня работает с firefox, uTLS нужен для имитации отпечатка браузера.
В Dest указываем IP и порт frontend cats.
SNI соответственно наш домен cats.mydomain.com.
И далее Get New Cert

При использовании TPROXY всю маршрутизацию настраивать на клиенте. TFO (TCP Fast Open) позволяет быстрее устанавливать соединение, однако данное решение имеет риски конфиденциальности, использовать или нет решайте сами, если не использовать TFO то TPROXY можно отключить, тогда настройки будут выглядеть так:

без TPROXY и TFO

без TPROXY и TFO

Данные настройки так же применимы и для VLESS-WS

Но ведь можно настроить и VLESS + WS и вы будите правы, данный вариант будет работать и за CDN только нужно будет произвести дополнительные настройки.

Пример VLESS + WS

Проведем конфигурацию HAProxy добавим в frontend основного домена строку под use_backend

use_backend ws-vless1 if { req.hdr(Host) -i mydomain.com } { path /ws-vless-secret-path1 } || { path_beg /ws-vless-secret-path1/ }

Добавим теперь backend, XRay при работе с WebSocket, ставит более высокий приоритет заголовкам X-Forwarded чем для proxy protocol

backend ws-vless1         mode http         http-request set-header X-Forwarded-For %[src]         http-request set-header X-Forwarded-Host %[req.hdr(host)]         timeout tunnel 1h         server s1 127.0.0.1:49111 send-proxy check port 49111

С HAProxy все, настроим панель, добавим подключение с протоколом VLESS и транспортом WebSocket

TLS должен быть отключен, за терминацию SSL отвечает HAProxy, так же включен proxy protocol для сохранения IP адреса клиента.
В данном варианте, не возможно включить xtls-rprx-vision, да и он не будет работать за CDN, за защиту от инспекции будет отвечать мультиплексирование, на сколько эффективно время покажет.

Пример полной конфигурации

В данном примере отключил все лишнее, все WebSocket сервисы и DoH, оставил только для работы reality и сайта

global         log /dev/log    local0         log /dev/log    local1 notice         chroot /var/lib/haproxy         stats socket /var/run/haproxy/admin.sock level admin mode 660         setenv ACCOUNT_THUMBPRINT '*****************************' # поменять на полученный из acme         stats timeout 30s         user    haproxy         group   haproxy         daemon         ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305         ssl-default-bind-options prefer-client-ciphers no-tls-tickets ssl-min-ver TLSv1.2         ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305         ssl-default-server-options no-tls-tickets ssl-min-ver TLSv1.2         ssl-dh-param-file /etc/haproxy/dh4096.pem       # Тюнинг http/2 для WebSocket         tune.h2.initial-window-size 536870912 # Увеличиваем начальный размер окна для входящих и исходящих соединений.         tune.h2.fe.max-concurrent-streams 512 # Установим кол-во одновременных потоков на входящие соединений.         tune.h2.fe.glitches-threshold 1024 # Установим порог автоматического завершения соединения при превышении заданного кол-ва ошибок.         tune.h2.be.max-concurrent-streams 512 # Установим кол-во одновременных потоков на исходящие соединений.         tune.h2.be.glitches-threshold 1024 # Установим порог автоматического завершения соединения при превышении заданного кол-ва ошибок в backend соединениях. #------------------------------------------ defaults        log global        mode http        option httplog        option dontlognull        timeout connect 40s        timeout client  1m        timeout server  1m        timeout tunnel 1h        timeout http-request 30s        errorfile 400 /etc/haproxy/errors/400.http        errorfile 403 /etc/haproxy/errors/403.http        errorfile 408 /etc/haproxy/errors/408.http        errorfile 500 /etc/haproxy/errors/500.http        errorfile 502 /etc/haproxy/errors/502.http        errorfile 503 /etc/haproxy/errors/503.http        errorfile 504 /etc/haproxy/errors/504.http #------------------------------------------ resolvers dnsserver         nameserver ns1 127.0.0.53:53         nameserver ns2 127.0.0.1:53         nameserver ns2 127.0.0.3:53         parse-resolv-conf         resolve_retries       3         timeout resolve       1s         timeout retry         1s         hold other           30s         hold refused         30s         hold nx              30s         hold timeout         30s         hold valid           10s         hold obsolete        30s #------------------------------------------ frontend stats         mode http         bind 127.0.0.1:49003         stats enable         stats uri /stats         stats realm Haproxy\ Statistics         stats refresh 10s         stats auth sdvhsis3w:opsdiv90-ikps         stats show-legends         stats hide-version #------------------------------------------ frontend http         bind *:80         mode http         http-request reject if { req.hdr(user-agent) -m len le 32 }         http-request reject if { req.hdr(user-agent) -m sub evil }         # Защитим от перегрузки         # Если в течении 1m будет выполнено более 10 запросов отклоним ответом 429 Too Many Requests         stick-table type ip size 100k expire 2m store http_req_rate(30s)         http-request track-sc0 src         # Отклоним с ответом         http-request deny deny_status 429 content-type text/html lf-string "<p>Per our policy, you are limited to 10 requests per minute, but you have exceeded that limit with %[sc_http_req_rate(0)] requests per minute.</p>" if { sc_http_req_rate(0) gt 30 }         http-request return status 200 content-type text/plain lf-string "%[path,field(-1,/)].${ACCOUNT_THUMBPRINT}\n" if { path_beg '/.well-known/acme-challenge/' }         http-request return status 200 content-type text/plain lf-string "Status 200 OK! Your IP %[src]." if { path /http-status-80 }         http-request deny if { path -m sub /. } # запрет доступа к скрытым файлам         http-request redirect scheme https unless { ssl_fc } #------------------------------------------ frontend tcp         bind *:443 # SSL Passthrough         mode tcp         option tcplog         tcp-request inspect-delay 5s      # Защитим от перегрузки, если с одного IP за 10сек открыто более 30 соединений, отклоним все запросы и закроем все соединения      # Нужно учитывать что WsTunnel с активным параметром --connection-min-idle <n> будет занимать указанное колличество при старте      # У VLESS так же есть мультилексор, тоже нужно учитывать при настройке      # Может так случиться если несколько клиентов в одно и тоже время с одного IP решат подключиться, все они потеряют доступ к серверу.          stick-table type ip size 1m expire 10s store conn_cur         tcp-request content track-sc0 src         tcp-request content reject if { sc_conn_cur(0) gt 30 }         tcp-request content capture req.ssl_sni len 10         tcp-request content accept if { req_ssl_hello_type 1 } or !{ req_ssl_hello_type 1 }          use_backend tcp-ssh if !{ req.ssl_hello_type 1 } { payload(0,7) -m bin 5353482d322e30 } or !{ req.ssl_hello_type 1 } { req.len 0 } # Я бы не рекомендовал, вы лишитесь доступа если haproxy упадет         use_backend tcp_to_https if { req.ssl_sni -i mydomain.com }          default_backend tcp_to_reality # cats.mydomain.com  данный домен используется для reality в секции tcp он не должен фигурировать, по дефолту перенаправляем все на backend x-ui с reality #------------------------------------------ frontend https # { ssl_fc_sni -i mydomain.com } # тут висит панель x-ui, Ws-VLESS, wstunnel, DoH adguard, и статистика HA тут же можно дополнить сайтом бизобидным.         bind 127.0.0.1:49001 accept-proxy ssl crt /etc/haproxy/certs alpn h2,http/1.1 strict-sni         http-request reject if { req.hdr(user-agent) -m sub evil }        # acl url_discovery path /.well-known/caldav /.well-known/carddav # для правильной работы NextCloud        # http-request redirect location /remote.php/dav/ code 301 if url_discovery # для правильной работы NextCloud         http-request deny if { path -m sub /. } # запрет доступа к скрытым файлам      # Защитим от перегрузки, если перестанет работать WsTunnel (чем больше клиентов тем выше установить счетчик)      # Если в течении 30с будет выполнено более 30 запросов отклоним ответом 429 Too Many Requests         stick-table type ip size 100k expire 5m store http_req_rate(30s)         http-request track-sc0 src      # Отклоним с ответом о превышенном кол-ве запросов         http-request deny deny_status 429 content-type text/html lf-string "<p>Per our policy, you are limited to 30 requests per 30s, but you have exceeded that limit with %[sc_http_req_rate(0)] requests per 30s.</p>" if { sc_http_req_rate(0) gt 30 }         http-response set-header Strict-Transport-Security "max-age=16000000; includeSubDomains; preload;" # Устанавливаем HSTS         http-request return status 200 content-type text/plain lf-string "Status 200 OK! Your IP %[src]." if { path /https-status-443 }          use_backend http_stats if { ssl_fc_sni -i mydomain.com } { path_beg /ha-stats-secret-path/ }         use_backend http_xui if { ssl_fc_sni -i mydomain.com } { path_beg /my-secret-path2/ } # { path_beg /xui/ }        # use_backend dns_query if { ssl_fc_sni -i mydomain.com } { path_beg /dns-query/ } || { path /dns-query }                 # use_backend ws-socks-admin if { ssl_fc_sni -i mydomain.com } { path /ws-socks-secret-path } || { path_beg /ws-socks-secret-path/ }        # use_backend ws-adguard if { ssl_fc_sni -i mydomain.com } { path /ws-adguard-secret-path1 } || { path_beg /ws-adguard-secret-path1/ }        # use_backend ws-ssh if { ssl_fc_sni -i mydomain.com } { path /ws-ssh-secret-path2 } || { path_beg /ws-ssh-secret-path2/ }        # use_backend ws-wg if { ssl_fc_sni -i mydomain.com } { path /ws-wg-secret-path3 } || { path_beg /ws-wg-secret-path3/ }         # use_backend ws-vless1 if { req.hdr(Host) -i mydomain.com } { path /ws-vless-secret-path1 } || { path_beg /ws-vless-secret-path1/ } # в панели вкл proxy-protocol, path указывается как в haproxy, хост mydomain.com, external proxy tls mydomain.com 443 security None        # use_backend ws-vless2 if { req.hdr(Host) -i mydomain.com } { path /ws-vless-secret-path2 } || { path_beg /ws-vless-secret-path2/ }         # default_backend http_adh # панель настройки AdGuardHome        default_backend cats # раскомментируйте после добавления сайта обманки #------- Reality -------------------------- frontend https_cats # Заглушка для Reality { ssl_fc_sni -i cats.mydomain.com }         bind 127.0.0.1:49002 accept-proxy ssl crt /etc/haproxy/certs alpn h2,http/1.1 strict-sni         http-request reject if { req.hdr(user-agent) -m sub evil }        # acl url_discovery path /.well-known/caldav /.well-known/carddav # для правильной работы NextCloud        # http-request redirect location /remote.php/dav/ code 301 if url_discovery # для правильной работы NextCloud         http-request deny if { path -m sub /. }         stick-table type ip size 100k expire 2m store http_req_rate(1m)         http-request track-sc0 src         http-request deny deny_status 429 content-type text/html lf-string "<p>Per our policy, you are limited to 30 requests per minute, but you have exceeded that limit with %[sc_http_req_rate(0)] requests per minute.</p>" if { sc_http_req_rate(0) gt 30 }         http-response set-header Strict-Transport-Security "max-age=16000000; includeSubDomains; preload;" # Устанавливаем HSTS         http-request return status 200 content-type text/plain lf-string "Status 200 OK! Your IP %[src]." if { path /https-status-443 }         default_backend cats #------- BACKEND -------------------------- #[ tcp backend tcp-ssh # Бекенд для SSH         mode tcp         option http-keep-alive         timeout http-keep-alive 30s         server ssh 127.0.0.1:22 check port 22 backend tcp_to_https # Бекенд для передачи TCP трафика домена на http фронтенд, для основных сайтов.          mode tcp         server https 127.0.0.1:49001 send-proxy-v2-ssl-cn check port 49001 backend tcp_to_reality # Бекенд для передачи всего TCP трафика в X-UI не прошедшего по правилам в TCP фронтенде.         mode tcp         server https 127.0.0.1:48660 send-proxy check port 48660 # end tcp ] [ http backend http_stats # Статистика HA         mode http         http-request replace-path /ha-stats-secret-path(/)?(.*) /\2         server stats 127.0.0.1:49003 backend http_xui # Админ панель X-UI (3X-UI) и тд         mode http         option httpchk GET /xui/ #изменить после настройки панели на /my-secret-path2/xui         option forwardfor if-none         http-response set-header X-Content-Type-Options nosniff         http-response set-header X-XSS-Protection 1;mode=block         http-response set-header X-Frame-Options SAMEORIGIN         http-request add-header X-Real-Ip %[src]         http-request set-header Host %[req.hdr(Host)]         http-request set-header X-Forwarded-For %[src]         http-request set-header X-Forwarded-Host %[req.hdr(host)]         server s1 127.0.0.1:54321 check #поменять порт на 49004 после настройки панели  #backend dns_query # DOH AdGuardHome #        mode http #        option httpchk #        option forwardfor if-none #        http-response set-header X-Content-Type-Options nosniff #        http-response set-header X-XSS-Protection 1;mode=block #        http-response set-header X-Frame-Options SAMEORIGIN #        http-request add-header X-Real-Ip %[src] #        http-request set-header Host %[req.hdr(Host)] #        http-request set-header X-Forwarded-For %[src] #        http-request set-header X-Forwarded-Host %[req.hdr(host)] #        server doh 127.0.0.1:49005 #check port 49005 # end http ] [ WebSocket  #backend ws-socks-admin # WsTunnel #        mode http #        option http-keep-alive #        timeout http-keep-alive 25s #        timeout tunnel 1h #        server s1 127.0.0.1:49101 check port 49101 #backend ws-adguard # WsTunnel #        mode http #        option http-keep-alive #        timeout http-keep-alive 25s #        timeout tunnel 1h #        server s1 127.0.0.1:49102 check port 49102 #backend ws-ssh # WsTunnel #        mode http #        option http-keep-alive #        timeout http-keep-alive 25s #        timeout tunnel 1h #        server s1 127.0.0.1:49103 check port 49103 #backend ws-wg # WsTunnel #        mode http #        option http-keep-alive #        timeout http-keep-alive 25s #        timeout tunnel 1h #        server s1 127.0.0.1:49104 check port 49104 #---------------- #backend ws-vless1 # Admin #        mode http #        http-request set-header X-Forwarded-For %[src] #        http-request set-header X-Forwarded-Host %[req.hdr(host)] #        timeout tunnel 1h #        server s1 127.0.0.1:49111 send-proxy check port 49111 #backend ws-vless2 # Clients-2 #        mode http #        http-request set-header X-Forwarded-For %[src] #        http-request set-header X-Forwarded-Host %[req.hdr(host)] #        timeout tunnel 1h #        server s1 127.0.0.1:49112 send-proxy check port 49112 # end WebSocket ] #----------AdGuardHome---------------------- #backend http_adh                    #только при первоначальной настройке  #        mode http                   #лучше исключить попадание данного сервиса в открытый доступ #        server adh 127.0.0.1:49005  #доступ через проброс ssh или wstunnel #------------------------------------------ #------------------------------------------ backend cats #обманка         mode http         option forwardfor         http-request set-header X-Forwarded-Proto https if { ssl_fc }         http-request set-header X-Forwarded-Proto http if !{ ssl_fc }         http-request set-header X-Forwarded-Host %[req.hdr(host)]         http-request set-header X-Forwarded-For %[src]         http-request add-header X-Real-Ip %[src]         server s1 127.0.0.1:49006 check port 49006 #------------------------------------------  #------------IP Table---------------------- # Range 48658—48999 - TCP // 49001—49100 - http сервисы // 49101-49150 - WS # --- TCP --- #48658 - ocserv #48659 -  #48660 - tcp_to_reality #48661 -  #48662 -  #48663 #48664 # --- http --- #49001 - frontend https #49002 - frontend reality #49003 - http_stats #49004 - http_xui #49005 - dns_query || http_adh  #49006 - http_cats #49007 -  #49008 #49009 #49010 #49011 # --- WebSocket --- #49101 - ws-socks # WsTunnel #49102 - ws-adguard # WsTunnel #49103 - ws-ssh # WsTunnel #49104 - ws-wg # WsTunnel # #49111 - ws-vless1 # Admin #49112 - ws-vless2 # Clients #49113 -  #49114 -   #49121 -  #49122 - 

В IP Table я храню порт=сервис, использую диапазоны свободных портов согласно IANA.

Пару слов про ответ «200 OK!», я использую его для мониторинга доступности, а так же для поддержания соединения при работе с wstunnel, для этого использую следующий скрипт в cron

Пример скрипта мониторинга
#!/bin/bash  for i in {1..60}; do     response=$(curl --socks5 127.0.0.1:2080 -Is http://mydomain.com/http-status-80/ | head -n 1)      if [[ "$response" == *"200 OK"* ]]; then         echo "Received 200 OK. Exiting loop."         break     elif [[ -z "$response" ]]; then         echo "Empty response. Attempt $i of 60."     fi      sleep 1  # Задержка между запросами done  # Проверка, если все ответы были пустыми if [[ -z "$response" ]]; then     echo "All responses were empty. Restarting wstunnel.service."     systemctl restart ws-socks.service fi

Скрипт будет пытаться 60 раз, достучаться до сайта, если не получит ответ «200 OK» — перезапустит сервис. Аналогичный скрипт я применяю на роутере с sign box, если статус не получен перезапускается sign box.
Если заменить mydomain.com на https://cats.mydomain.com/https-status-443/ будем одновременно мониторить и сервис Reality и HAProxy однако помним про ограничение частоты запросов на tcp frontend.

Про GeoIP из второй статьи

В одной из статей на хабре, в комментариях невежливо указали что по GeoIP блочат только не хорошие люди, что-ж, исправляюсь, есть разнообразные списки «плохих» адресов, я взял FireHOL списки и написал скрипт для их загрузки и подключения в haproxy, для начала необходимо создать директорию для хранения списков
mkdir /etc/haproxy/firehol

Теперь создадим файл например firehol в директории /etc/cron.daily для ежедневого обновления со следующим содержимым

#!/bin/bash  # Определяем директории TMP_DIR="/tmp/firehol" DEST_DIR="/etc/haproxy/firehol"  # Создаем временную директорию mkdir -p "$TMP_DIR"  # Скачиваем файлы urls=(     "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset"     "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level2.netset"     "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level3.netset"     "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_abusers_1d.netset" )  files=("level1.acl" "level2.acl" "level3.acl" "abusers_1d.acl")  for i in "${!urls[@]}"; do     curl -s "${urls[$i]}" -o "$TMP_DIR/${files[$i]%.acl}.netset" done  # Очищаем файлы от комментариев и пустых строк for file in "${files[@]}"; do     netset_file="$TMP_DIR/${file%.acl}.netset"     acl_file="$TMP_DIR/$file"     grep -vE '^\s*#|^\s*$' "$netset_file" > "$acl_file" done  # Генерируем md5 для файлов declare -A md5s for file in "${files[@]}"; do     md5s["$file"]=$(md5sum "$TMP_DIR/$file" | awk '{ print $1 }') done  # Проверяем наличие файлов в целевой директории и обновляем их при необходимости for file in "${files[@]}"; do     dest_file="$DEST_DIR/$file"     if [[ ! -f "$dest_file" ]] || [[ "$(md5sum "$dest_file" | awk '{ print $1 }')" != "${md5s[$file]}" ]]; then         cp "$TMP_DIR/$file" "$dest_file"         echo "Обновлен файл: $dest_file"     fi done  # Перезапускаем haproxy systemctl restart haproxy  # Удаляем временную директорию rm -rf "$TMP_DIR"

Необходимо сделать его исполняемым
chmod 700 /etc/cron.daily/firehol

Теперь добавим в секцию с frontend tcp следующую строку сразу после «tcp-request inspect-delay 5s»

     # FireHOL IP List         tcp-request connection reject if { src -f /etc/haproxy/firehol/level1.acl } || { src -f /etc/haproxy/firehol/level2.acl } || { src -f /etc/haproxy/firehol/level3.acl } || { src -f /etc/haproxy/firehol/abusers_1d.acl }

Выполним скрипт командой /etc/cron.daily/firehol и перезапустим haproxy командой systemctl restart haproxy

На этом я закончу цикл про совмещение HAProxy и VLESS. В будущем возможно напишу про проксирование VLESS+WS через CDN.

P.s.

Я дал общие конфигурации и примеры, как можно скрыть разнообразные сервисы за HAProxy, и данный цикл статей ни в коем образе не является пособием по обходу блокировок и доступом к запрещенной информации.

Подключении подписки

Включите в настройках службу подписки:

подписка

подписка

И подписку json

подписка json

подписка json

Теперь добавьте в основной http frontend под http_xui строку
use_backend http_xui_sub if { path_beg /submyserver/ } || { path_beg /jsubmyserver/ }

Путь submyserver и jsubmyserver измените на свой, как в панели так и конфиге HAProxy

Теперь добавьте backend

backend http_xui_sub         mode http         option forwardfor         http-response set-header X-Content-Type-Options nosniff         http-response set-header X-XSS-Protection 1;mode=block         http-response set-header X-Frame-Options SAMEORIGIN         http-request set-header X-Forwarded-Host %[req.hdr(host)]         http-request set-header X-Forwarded-For %[src]         http-request set-header X-Forwarded-Proto https if { ssl_fc }         http-request set-header X-Forwarded-Proto http if !{ ssl_fc }         http-request add-header X-Real-Ip %[src]         server s1 127.0.0.1:2096

После сохраните изменения в панели и конфиге haproxy, и перезапустите сервисы. Теперь у вас появится возможность добавлять пользователей через подписку, как показала практика это удобнее, не нужно изменять параметры для каждого клиента, если что то изменится в настройках подключения, например изменится uTLS или будут сгенерированы новые сертификаты Reality.


ссылка на оригинал статьи https://habr.com/ru/articles/885276/