Ник Пост Дата
Kisliy(Андрей)

Всех приветствую! :sunglasses:
Решил овладеть методом “Websocket вместе с XTLS-Reality” по этой замечательной инструкции: Особенности проксирования через CDN/Websocket/gRPC для обхода блокировок.

Увы, что-то пошло не так и при выполнении теста Nekobox в журнале пишет: ошибка теста: Get “http://cp.cloudflare.com/”: websocket: bad handshake: HTTP 301 301 Moved Permanently.

Поиск в интернете ничего не дал :unamused:
Подскажите пожалуйста что может вызывать такую ошибку или в какую сторону “копать”?

2024-05-08T22:35:48.362Z
0ka(0ka)

xtls или reality не могут работать через cdn, особенности протоколов

2024-05-08T22:40:38.356Z
ilyaigpetrov(ilyaigpetrov)

Фраза переводится как “301 Перемещено перманентно/постоянно”.
Возможно, стоит откопать новый адрес, на который происходит перенаправление, и заменить им старый.

2024-05-08T22:45:15.707Z
Kisliy(Андрей)

Зачем менять адрес, если на прямую, минуя CDN, всё исправно работает?

В статье это указано, если не читали, автор подключается к серверу без xtls или reality.

2024-05-08T22:58:42.626Z
ilyaigpetrov(ilyaigpetrov)

Так и напрямую может происходить перенаправление, которого вы не успеваете заметить.
Сравните изначальный адрес с конечным.

Я далёк от темы вопроса, не знаю, какой именно адрес перенаправляется --, может, это не тот, что вы ожидаете.

2024-05-08T23:05:43.080Z
Kisliy(Андрей)

Конечно, я ожидал, что сразу будет всё работать :slightly_smiling_face:
Выходные адреса я не сравню, так как не работает интернет, пока не исправлю “websocket: bad handshake…”.
Т. е. вы ещё не настраивали таким методом, попробуйте, пригодится как-нибудь.

А вы настраивали таким способом, который описан в статье?

2024-05-09T07:49:39.363Z
Xunlei

У вас перенаправление идёт на https://cp.cloudflare.com/.

2024-05-09T11:23:00.252Z
0ka(0ka)

нет, во первых там про вебсокет, а во вторых на этом домене нет перенаправления на https.
что хочет автор темы непонятно

2024-05-09T11:26:14.941Z
Uporoty(Uporoty)

В параметрах Cloudflare включено проксирование вебсокетов?

Если используете Nginx или Caddy, посмотрите ещё логи сервера в момент подключения. Либо попробуйте настроить вообще без веб-сервера, на Хабре пару месяцев назад статья была с этим вариантом (ее забаеил РКН, но VPN она всё ещё доступна)

2024-05-09T18:40:47.341Z
Kisliy(Андрей)

Да, конечно, только у меня Gcore. Журнал теста в nekobox:

INFO[0000] dns: exchanged xxx.dns.com CNAME github.ddnsfree.com. 60 IN CNAME cl-gl5d09f09a.gcdn.co.
INFO[0000] dns: exchanged xxx.dns.com A cl-gl5d09f09a.gcdn.co. 60 IN A 81.28.12.12
INFO[0000] dns: exchanged xxx.dns.com CNAME github.ddnsfree.com. 60 IN CNAME cl-gl5d09f09a.gcdn.co.
INFO[0000] dns: exchanged xxx.dns.com AAAA cl-gl5d09f09a.gcdn.co. 60 IN AAAA 2a03:90c0:999c::12
[[VLESS] VLESS (SNI‑proxy over Websocket)] ошибка теста: Get "http://cp.cloudflare.com/": websocket: bad handshake: HTTP 301 301 Moved Permanently

Посмотрел, что-то не густо там:
/var/log/nginx/access.log вообще пустой.
/var/log/nginx/error.log видимо после перезагрузки пишет что-то:
2024/05/10 17:33:04 [notice] 649#649: signal 15 (SIGTERM) received from 1807, exiting
2024/05/10 17:33:04 [notice] 651#651: exiting
2024/05/10 17:33:04 [notice] 651#651: exit
2024/05/10 17:33:04 [notice] 649#649: signal 17 (SIGCHLD) received from 651
2024/05/10 17:33:04 [notice] 649#649: worker process 651 exited with code 0
2024/05/10 17:33:04 [notice] 649#649: exit
2024/05/10 17:33:32 [notice] 619#619: using the “epoll” event method
2024/05/10 17:33:32 [notice] 619#619: nginx/1.26.0
2024/05/10 17:33:32 [notice] 619#619: built by gcc 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)
2024/05/10 17:33:32 [notice] 619#619: OS: Linux 5.4.0-177-generic
2024/05/10 17:33:32 [notice] 619#619: getrlimit(RLIMIT_NOFILE): 1024:524288
2024/05/10 17:33:32 [notice] 631#631: start worker processes
2024/05/10 17:33:32 [notice] 631#631: start worker process 632

В процессе настройки было как-то, заходил через браузер и видел Ngix страницу, думаю это ничего не даст.

В настройках nekobox - url теста задержки прописан http://cp.cloudflare.com, так что всё нормально здесь.

После подключения клиента nekobox к серверу nginx, должна произойти переадресация на сервер x-ray, который пропустит во внешний инет. Вот содержимое файлов конфигурации nginx:
/etc/nginx/nginx.conf:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;
   include /etc/nginx/conf.d/*.conf;
}

stream {
  map $ssl_preread_server_name $backend {
     XXXXXX.com               reality;
      www.XXXXXX.com             local;
      default                  reality;
  }

  upstream reality {
      server 127.0.0.1:8443;
  }

  upstream local {
      server 127.0.0.1:8444;
  }

  server {
      listen          443 reuseport so_keepalive=on;
      ssl_preread     on;
      proxy_pass      $backend;
  }
}

/etc/nginx/conf.d/default.conf:

server {
	listen 127.0.0.1:8444 so_keepalive=on;
        http2 on;

# ваш домен    
server_name www.XXXXXX.com;

    #access_log  /var/log/nginx/host.access.log  main;

    # сюда можно положить какие-нибудь странички фейкового сайта, или использовать proxy_pass чтобы переадресовать запрос на другой сервер
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    #error_page   500 502 503 504  /50x.html;
    #location = /50x.html {
    #    root   /usr/share/nginx/html;
    #}

# путь к сертификатам, самоподписанным либо от Cloudflare
	ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
	ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

client_header_timeout 52w;
    keepalive_timeout 52w;
# замените TestChatGRPC на какую-нибудь секретную строку
	location /TestChatGRPC {
		if ($content_type !~ "application/grpc") {
			return 404;
		}
		client_max_body_size 0;
		client_body_buffer_size 512k;
		grpc_set_header X-Real-IP $remote_addr;
		client_body_timeout 52w;
		grpc_read_timeout 52w;
		grpc_pass grpc://127.0.0.1:8888;
	}

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}

# аналогично замените TestChatWS на какую-нибудь другую секретную строку
    location /TestChatWS {
		if ($http_upgrade != "websocket") {
			return 404;
		}
		proxy_pass http://127.0.0.1:8889;
		proxy_redirect off;
	    proxy_http_version 1.1;
	    proxy_set_header Upgrade $http_upgrade;
	    proxy_set_header Connection "upgrade";
	    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_read_timeout 52w;
	}
}
2024-05-10T17:24:23.292Z
Uporoty(Uporoty)

Смотрите какая фигня. Судя по логам веб-сервера, до него ничего не долетает. НО - секция stream по умолчанию ничего не логгирует, а я подозреваю что дело где-то там. У вас стоит условие, что запросы с определенным SNI должны обрабатываться веб-сервером, а все остальное уходить на Reality, то есть на чужой маскировочный сайт.

Можно проверить, сходить curl -v на ваш адрес и URL, куда у вас пытается подключиться Nekoray с вебсокетами и посмотреть заголовки ответа. Если вы увидите там домен reality вместо вашего, то истина где-то рядом.

Нужно проверить параметры GCore, там вроде можно чтобы он изменял SNI при проксирование запроса, проверьте что там то же самое, что у вас в Nginx в условии.
Более тупой вариант (для теста, но можно и на постоянку) - сделать так, чтобы веб-сервер с вебсокетами слушал не на 127.0.0.1, а на 0.0.0.0 (задать какой-нибудь нестандартный порт повыше), а в GCore узадать этот порт в параметрах Origin (там можно так делать), чтобы он сразу шел туда напрямую, и посмотреть что получится

2024-05-10T18:40:08.298Z
Kisliy(Андрей)

На адрес сайта я зашёл, вот:

 *   Trying XX.XX.12.12:443...
* Connected to ХХХХХddns.com (XX.XX.12.12) port 443
> GET / HTTP/1.1
> Host: ХХХХХddns.com:443
> User-Agent: curl/8.4.0
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< Server: nginx
< Date: Sat, 11 May 2024 01:51:06 GMT
< Content-Type: text/html
< Content-Length: 248
< Connection: close
<
<html>
<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>The plain HTTP request was sent to HTTPS port</center>
<hr><center>nginx</center>
</body>
</html>
* Closing connection

С заходом по URL пришлось повозится, ссылка, которую выдаёт Nekobox, неполная, без нескольких параметров. Я немного по импровизировал с ней, добавил некоторые параметры, и что-то выдалось:

rdp-user@XXX:~$ vless://XXXX-XXXX-XXXX-XXXX-46e69149af25@ХХХХХddns.com:443?encryption=none&type=ws&path=TestChatWS &ed=2048&eh=Sec-Websocket-Protocol&security=tls&fp=chrome&packetEncoding=xudpс
[87] 3100
bash: vless://XXXX-XXXX-XXXX-XXXX-46e69149af25@ХХХХХddns.com:443?encryption=none: No such file or directory
[88] 3101
[89] 3102
[90] 3103
[91] 3104
[92] 3105
[93] 3106
[84]   Done                    eh=Sec-Websocket-Protocol
[85]   Done                    security=tls
[86]   Done                    fp=chrome
[87]   Exit 127                vless://XXXX-XXXX-XXXX-XXXX-46e69149af25@ХХХХХddns.com:443?encryption=none
[88]   Done                    type=ws
[89]   Done                    path=TestChatWS
[90]   Done                    ed=2048
[91]   Done                    eh=Sec-Websocket-Protocol

Скриншот окна конфига в nekobox прикрепляю:

В Gcore был установлен параметр динамическое имя хоста. С учётом того что автор реализовал sni через backend, может так и оставить?

Также, пока ковырялся с параметрами, подправил некоторые значения в конфиге nginx и стала выходить ошибка уже с другим номером: ошибка теста: Get “http://cp.cloudflare.com/”: websocket: bad handshake: HTTP 502 502 Bad Gateway.

2024-05-11T22:27:41.095Z
Uporoty(Uporoty)

Ну тут ошибка говорит сама за себя. Проверяйте, что у вас там в параметрах Origin на стороне gCore стоит, должен быть HTTPS, а не HTTP.

Под URL я имел в виду host + path (с https://).

Host пропишите правильный тоже.

Он должен совпадать с тем что указано в конфиге Nginx, иначе не будет работать правило stream.

Какие именно?

2024-05-11T22:40:29.882Z
xor

На скриншоте не видно, т.к. замазано, поэтому хочу упомянуть грабли, на которые довелось наступить мне. В той статье, на которую ты опираешься, Path указан что-то вроде /mypath, у меня так заработало, только если early data length ставить 0. Если early data хочется, то нужно уазывать, например, и early data length 2048 и в пути прописывать /mypath?ed=2048

2024-05-12T00:07:48.152Z
Kisliy(Андрей)

Извиняюсь, я не прописал https вначале сайта :frowning:
Вот правильный вариант:

C:\Windows\System32> curl -v https://ХХХХХddns.com:443
*   Trying XX.XX.12.12:443...
* Connected to ХХХХХddns.com (XX.XX.12.12) port 443
* schannel: disabled automatic use of client certificate
* ALPN: curl offers http/1.1
* schannel: next InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake failed). More detail may be available in the Windows System event log.
* Closing connection
* schannel: shutting down SSL/TLS connection with ХХХХХddns.com port 443
curl: (35) schannel: next InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake failed). More detail may be available in the Windows System event log.

Протокол HTTPS всегда включён был:

Такого варианта достаточно будет: scheme://username:password@host:port/path?query#fragment ?

Кстати, у автора тоже не прописан host на скриншоте и ведь строка адрес = строке Host. Хорошо, себе пропишу.

Я только за, в конфиге Nginx указан реалити сайт и мой домен, а также параметр $backend, какой из них прописать?

В stream был прописан вместо моего домена реалити сайт.
В разделе server_name был прописан не мой домен а реалити сайт.

2024-05-12T00:13:10.763Z
Kisliy(Андрей)

Я тоже обратил внимание, но странно, у автора статьи работало с 2048, хоть и времени немного прошло. Я так понимаю, что наклонная черта в начале пароля обязательна, о чём умолчали в статье. Но тогда давайте “сверим часы”, этот пароль упоминается 3 раза и конечно же в строке перед патчем стоит другая наклонная черта, которая, непонятно, влияет или нет на него:
Например, мой патч будет такой: /12345 и я его подставляю в строчки кода:

/etc/nginx/conf.d/default.conf
location //12345 {

/opt/xray/config.json
“path”: “/12345

Окно конфигурации Nekobox:
path: /12345

Нормально всё? :see_no_evil:

2024-05-12T00:44:00.559Z
Uporoty(Uporoty)

Да нет же, просто https://domain/path. Больше ничего, вообще ничего. Просто как обычный URL в
браузере.

Ваш домен. То, что совпадает с ним, Nginx будет отправлять на веб-сайт с вебсокетами, все остальное - на reality-обманку. Поэтому в SNI должен обязательно быть ваш домен.

Слеш должен быть только один

Так, давайте проще. Добейтесь сначала, чтобы у вас подключение к прокси через вебсокеты хотя бы заработало без GCore, а уже потом добавляйте GCore. В Nekobox в адресе сервера задайте не ваш домен, а IP-адрес сервера, а домен пусть будет в Host. Пробуйте подключиться и смотрите логи Nginx. Когда заработает так - будем разбираться с GCore (если в Nginx сертификат самоподписанный, не забудьте галочку allow insecure)

Но судя по тому, что у вас сейчас по вашему домену открывается гитхаб вместо сайта Nginx, проблема где-то именно с SNI. Попробуйте в Nekobox явно заполнить поле SNI вашим доменом, кстати.

А так, в целом, инструкция по которой вы настраиваете, реально переусложненная, и в ней слишком много вещей где что-то можно сделать не так. Варианты с IPv6 (для GCore не подойдёт) или с альтернативным портом (а вот этот очень даже подойдёт) описанные в других статьях, гораздо проще и надёжнее.

2024-05-12T07:41:02.057Z
xor

Ну это не совсем пароль, это URL путь, хотя в данном случае выполняет в некотором роде роль пароля тоже, т.к. не зная его на ws попасть не получится.
И того, если путь будет 12345, то в:
/etc/nginx/conf.d/default.conf
location /12345 {

/opt/xray/config.json
“path”: “12345

Окно конфигурации Nekobox:
Path* /12345?ed=2048
EarlyData Length 2048
EarlyData Name Sec-Websocket-Protocol

2024-05-12T08:28:09.403Z
Kisliy(Андрей)

Хорошо, вот:

C:\Windows\System32>curl -v https://XXXXX.com/XXXXX
*   Trying XX.XX.12.12:443...
* Connected to XXXXX.com (XX.XX.12.12) port 443
* schannel: disabled automatic use of client certificate
* ALPN: curl offers http/1.1
* schannel: next InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake failed). More detail may be available in the Windows System event log.
* Closing connection
* schannel: shutting down SSL/TLS connection with github.ddnsfree.com port 443
curl: (35) schannel: next InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake failed). More detail may be available in the Windows System event log.

Ок, давай попробуем напрямки, какие ещё настройки поменять в nekobox?

При таких настройках: ошибка теста: Get “http://cp.cloudflare.com/”: tls: first record does not look like a TLS handshake.

По сути, добавить в конфиги Nginx несколько строчек :slight_smile:

Отказался в пароле от слэша, сделал как у вас в примере, спасибо.

2024-05-12T18:43:46.365Z
xor

Интересно было бы все же удостовериться что проксируется что надо и куда надо.
Предлагаю добавить логирование в секцию стрима

log_format custom_stream_log 'proxy: $status $protocol remote_addr $remote_addr, sent_to $upstream_addr';
  server {
      listen          443 reuseport so_keepalive=on;
      access_log      syslog:server=unix:/dev/log custom_stream_log;
      proxy_pass      $backend;
  }

И посмотреть, что запрос улетел на слушателя сайта
Логи будут в системном журнале.

2024-05-12T19:17:22.394Z
Kisliy(Андрей)

Просто в секцию стрима не прописать, что-то хочет от меня:
nginx: [emerg] duplicate listen options for 0.0.0.0:443 in /etc/nginx/nginx.conf:57
nginx: configuration file /etc/nginx/nginx.conf test failed

2024-05-12T20:14:10.851Z
xor

Наверное мне стоило расписать подробнее.
Добавляешь в секцию стрима

log_format custom_stream_log 'proxy: $status $protocol remote_addr $remote_addr, sent_to $upstream_addr';

А ниже есть подсекция server, где происходит проксирование на бэкенды, туда нужно добавить строку

access_log      syslog:server=unix:/dev/log custom_stream_log;

дабы логи писались.
т.е. не добавляем еще один server, а добавляем логирование в имеющийся.

2024-05-12T20:23:10.713Z
Kisliy(Андрей)

Сделал, ругается на логи:
nginx: [emerg] unknown log format “custom_stream_log” in /etc/nginx/nginx.conf:53
nginx: configuration file /etc/nginx/nginx.conf test failed

2024-05-12T20:50:05.215Z
xor

А можно на nginx.conf взглянуть?

2024-05-12T21:15:29.411Z
Kisliy(Андрей)

Естественно:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

stream {
  map $ssl_preread_server_name $backend {
      XXXXX.com               reality;
      XXXXX.XXXXX.com             local;
      default                  reality;
  }

  upstream reality {
      server 127.0.0.1:8443;
  }

  upstream local {
      server 127.0.0.1:8444;
  }

  server {
      listen          443 reuseport so_keepalive=on;
      ssl_preread     on;
      proxy_pass      $backend;
      access_log      syslog:server=unix:/dev/log custom_stream_log;
  }

log_format custom_stream_log 'proxy: $status $protocol remote_addr $remote_addr, sent_to $upstream_addr';

  }
}
2024-05-12T21:27:28.616Z
xor

Нужно сначала объявить лог.
т.е. нужно строку

log_format custom_stream_log ...

поместить перед

  server {
      listen          443 reuseport so_keepalive=on;
2024-05-12T21:44:40.903Z
Kisliy(Андрей)

del

2024-05-12T22:41:38.777Z
Kisliy(Андрей)

Да, теперь стало писаться в access.log:

127.0.0.1 - - [13/May/2024:01:23:27 +0300] "\x16\x03\x01\x018\x01\x00\x014\x03\x03\x89\xEF\x9A\xD1\xC8\x8C6\x11\xFB\xE6(s!\x8D=\x90y\x07\x15q\xF1\x04\xE3\xED\xFB\xF1(\xC1{K\x80@ jY\x89\x03\xE3\xFE,\x13\x0C\x1Ek9\x86\xF1\xD9\x85~\xB7\xB0" 400 157 "-" "-" "-"
127.0.0.1 - - [13/May/2024:01:23:40 +0300] "\x16\x03\x01\x018\x01\x00\x014\x03\x03&\xE1\x84\xDFHOhR\xE5H\xB1(\xE7e\xFF\xD0\x8D\xD7\xFE'J\x22\x19\x7FHd\xFA\xEB\xE9[~* \xE5fW%\x04h\x8D" 400 157 "-" "-" "-"
127.0.0.1 - - [13/May/2024:01:24:13 +0300] "\x16\x03\x01\x018\x01\x00\x014\x03\x03D\x8Du\x83\x10\x19\xCB\xCF\x16\xF1z\x1D\x10b\xB2q\x1D\x95\x93Ap\xF0 \x0E$<\x131\x99\x87\xA7m \xAF-T +\xEBS\xEF\x872\xD6\xE8\x8C\xA3\x91\xBAn\xF08\xC6\x1AB\xBC\x0C@\xD4M\x94\xC3\xB3j\xED\x00>\x13\x02\x13\x03\x13\x01\xC0,\xC00\x00\x9F\xCC\xA9\xCC\xA8\xCC\xAA\xC0+\xC0/\x00\x9E\xC0$\xC0(\x00k\xC0#\xC0'\x00g\xC0" 400 157 "-" "-" "-"
127.0.0.1 - - [13/May/2024:01:24:32 +0300] "\x16\x03\x01\x02\x00\x01\x00\x01\xFC\x03\x03M\xF4;(u\x1C\x96\xF2|C\x08M\xC4\xCA\x14\x8B\x03F\xDBT\x98\x10\xB9\x03y\x85U\xC0\xAE\x90<o De\xCB\x06\x9DZ\xF3\x91\xC86Z\xFAt\xBA8*\x04\xEFI_\x83\xF1\x01\xBC\xDF1\xFB\xE9\x96j\x85(\x00 \xEA\xEA\x13\x01\x13\x02\x13\x03\xC0+\xC0/\xC0,\xC00\xCC\xA9\xCC\xA8\xC0\x13\xC0\x14\x00\x9C\x00\x9D\x00/\x005\x01\x00\x01\x93jj\x00\x00\xFF\x01\x00\x01\x00\x00\x10\x00\x0B\x00\x09\x08http/1.1\x00\x17\x00\x00\x00+\x00\x07\x06**\x03\x04\x03\x03\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00" 400 157 "-" "-" "-"
2024-05-12T22:43:04.089Z
xor

Логов самой прокси не видно, они должны начинаться с “proxy:”.
Можно, например, в терминале набрать journalctl -u nginx -f
И просто в браузере открыть свой сайт XXXXX.XXXXX.com, потыкать Ctrl+f5 (обновить с чисткой кэша), и смотреть, появятся ли записи типа:
proxy: 200 5653 TCP remote_addr 123.123.123.123, sent_to 127.0.0.1:8444
Таким образом убедившись, что запросы со своего внешнего адреса remote_addr улетают на слушателя nginx 127.0.0.1:8444, который, в свою очередь, может при знании нужного URL апгрейднуть соединение до ws и послать его в xray.

2024-05-12T23:27:44.320Z
Kisliy(Андрей)

Первая строчка подключение по реалити, вторая - через CDN, третья - напрямую.

May 13 02:43:15 nginx: proxy: 200 TCP remote_addr XX.XX.109.166, sent_to 127.0.0.1:8443
May 13 02:43:26 nginx: proxy: 200 TCP remote_addr XX.XXX.113.11, sent_to 127.0.0.1:8444
May 13 02:44:02 nginx: proxy: 200 TCP remote_addr XX.XX.109.166, sent_to 127.0.0.1:8444
2024-05-12T23:50:30.289Z
xor

Ну пока все выглядит хорошо. В конфиге nginx, приведенном выше, тоже проблем не вижу.
Опять же, для верности, можно посмотреть, есть ли обмен с xray, хоть какой-то.

sudo tcpdump -i lo port 8889

И, если обмен есть, то смотреть логи xray, если обмена нет, то смотреть в nginx

2024-05-13T09:17:37.936Z
Kisliy(Андрей)

Обмена никакого нет, когда я присоединяюсь на прямую или через CDN. Может в этом файле что-то не так, других-то я и не изменял /etc/nginx/conf.d/default.conf

server {
	listen 127.0.0.1:8444 so_keepalive=on;
        http2 on;


# ваш домен    
server_name XXX.XXX.com;

    #access_log  /var/log/nginx/host.access.log  main;

    # сюда можно положить какие-нибудь странички фейкового сайта, или использовать proxy_pass чтобы переадресовать запрос на другой сервер
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    #error_page   500 502 503 504  /50x.html;
    #location = /50x.html {
    #    root   /usr/share/nginx/html;
    #}

# путь к сертификатам, самоподписанным либо от Cloudflare
	ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
	ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

client_header_timeout 52w;
    keepalive_timeout 52w;
# замените TestChatGRPC на какую-нибудь секретную строку
	location /XXXXX {
		if ($content_type !~ "application/grpc") {
			return 404;
		}
		client_max_body_size 0;
		client_body_buffer_size 512k;
		grpc_set_header X-Real-IP $remote_addr;
		client_body_timeout 52w;
		grpc_read_timeout 52w;
		grpc_pass grpc://127.0.0.1:8888;
	}






    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}

# аналогично замените TestChatWS на какую-нибудь другую секретную строку
    location /XXXXX {
		if ($http_upgrade != "websocket") {
			return 404;
		}
		proxy_pass http://127.0.0.1:8889;
		proxy_redirect off;
	    proxy_http_version 1.1;
	    proxy_set_header Upgrade $http_upgrade;
	    proxy_set_header Connection "upgrade";
	    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_read_timeout 52w;
	}
}
2024-05-13T10:28:57.085Z
xor

Ну каких-то особых проблем я не вижу.
Но, во-первых, советую добавить ssl в заголовок, он вроде нужен, если идет работа с сертификатами.
У меня, например, так:

server {
        listen 127.0.0.1:8444 ssl http2 so_keepalive=on;

Во-вторых, интересно было бы посмотреть, что там nginx выдает при попытке соединения.
Предположим, что ws URL - 12345.

    location /12345 {
		if ($http_upgrade != "websocket") {
			return 404;
		}
               ...

Тогда ищем в журнале

journalctl -u nginx -r

Что-то вроде

nginx: 101 4076 "GET /12345 HTTP/1.1" "-" "Go-http-client/1.1"

Не обязательно именно такую строку, т.к. у меня формат логов изменен. Но обращать внимание на путь /12345 и статус. 101 - изменение протокола, т.к. http меняется на ws

2024-05-13T11:17:54.994Z
soulja(Serano)

DEL

2024-05-13T11:23:03.535Z
soulja(Serano)

Немного чище конфиг

server {
	listen 127.0.0.1:8444 ssl so_keepalive=on;
    http2 on;

	server_name XXX.XXX.com;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;


# путь к сертификатам, самоподписанным либо от Cloudflare
	ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
	ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

	location /XXXXX {
		if ($content_type !~ "application/grpc") {
			return 404;
		}
		client_max_body_size 0;
		client_body_buffer_size 512k;
		grpc_set_header X-Real-IP $remote_addr;
		client_body_timeout 52w;
		grpc_read_timeout 52w;
		grpc_pass grpc://127.0.0.1:8888;
	}

    location /XXXXX {
		if ($http_upgrade != "websocket") {
			return 404;
		}
		proxy_pass http://127.0.0.1:8889;
	    proxy_redirect off;
	    proxy_http_version 1.1;
	    proxy_set_header Upgrade $http_upgrade;
	    proxy_set_header Connection "upgrade";
	    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_read_timeout 52w;
	}
2024-05-13T11:29:57.625Z
Kisliy(Андрей)

Кстати, у автора статьи он тоже отсутствует в конфиге. Я добавил ssl в заголовок, получаю следующее сообщение:
ошибка теста: Get "http://cp.cloudflare.com/": x509: certificate signed by unknown authority

Если разрешить небезопасное соединение TLS в nekobox:
ошибка теста: Get "http://cp.cloudflare.com/": context deadline exceeded

2024-05-13T17:18:31.187Z
xor

Получал ли ты сертификат для XXX.XXX.com? Сертификат от того же let’s encrypt, насколько я помню, распространяется только на домены и поддомены, которые явно указаны при запросе.

Ну и логи nginx бы посмотреть. В зависимости от настроек они падают либо в системный журнал, либо в /var/log/nginx

2024-05-13T21:07:19.236Z
Kisliy(Андрей)

Мне let’s encrypt выписал Gcore, но кнопки скачать его нет.

Появилась такая запись при подключении с небезопасным TLS:
/var/log/nginx/access.log
127.0.0.1 - - [14/May/2024:00:43:45 +0300] "GET /XXXXX HTTP/1.1" 101 4 "-" "Go-http-client/1.1" "-"

Кстати, в журнале проскакивает какая то строчка, если что:
systemd[1]: nginx.service: Can't open PID file /run/nginx.pid (yet?) after start: Operation not permitted

2024-05-13T21:51:33.903Z
xor

Мне let’s encrypt выписал Gcore, но кнопки скачать его нет.

А это что за сертификаты тогда?

/etc/nginx/conf.d/default.conf

ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

Самоподписанные?

У меня нет опыта работы с сертификатами, выданными cdn провайдерами. Но как вариант, попробуй настраивать всё на тот домен, который указал при настройке GCore. Если вводил не XXX.XXX.com, а XXX.com, то его и нужно прописать и в настройках nginx - server_name XXX.com;
и в настройках Nekoray тоже

127.0.0.1 - - [14/May/2024:00:43:45 +0300] “GET /XXXXX HTTP/1.1” 101 4 “-” “Go-http-client/1.1” “-”

Это хороший знак, осталось разобраться с сертификатами

2024-05-13T22:23:22.277Z
Kisliy(Андрей)

Да, на XXX.XXX.com. Уже прописан у меня и в server_name и в nekobox.

Из статьи:
Также нам понадобится TLS‑сертификат, если у вас его еще нет. Как я уже говорил, при работе через CDN хватит самоподписанного сертификата (все равно его не будет видно снаружи, он используется только для связи между фронтендом CDN и вашим сервером), либо «внутреннего» сертификата от Cloudflare.

Выходит, эти сертификаты для сервера и CDN, а про прямое подключение ничего не говорится. В nekobox есть такое окошко, может туда чего прописать? Просто скопировать ключ из самоподписного сертификата завершается множественными ошибками.

2024-05-13T23:00:05.450Z
xor
Выходит, эти сертификаты для сервера и CDN, а про прямое подключение ничего не говорится.

Смотря что используется для прямого. Если маскировка под какой-то другой сайт (security reality), то там вообще ни свой домен ни вебсервер не участвуют, за исключением случая маскировки под собственный домен (steal from yourself). Если просто vision (security tls), то нужны сертификаты let’s encrypt.

Глядя на это

127.0.0.1 - - [14/May/2024:00:43:45 +0300] “GET /XXXXX HTTP/1.1” 101 4 “-” “Go-http-client/1.1” “-”

то возможно и зря с сертификатами мучаемся, нужно смотреть логи xray

В nekobox есть такое окошко, может туда чего прописать? Просто скопировать ключ из самоподписного сертификата завершается множественными ошибками.

Не знаю, если честно, для какого случая там это окошко. Может и правда для самоподписанных сертификатов

2024-05-13T23:30:36.966Z
Kisliy(Андрей)

Вот, достал:

May 14 03:04:34 xray[639]: 2024/05/14 03:04:34 127.0.0.1:0 rejected  proxy/vless/encoding: failed to read request version > websocket: close 1000 (normal)
May 14 03:04:34 xray[639]: 2024/05/14 03:04:34 [Info] [3941384672] proxy/vless/inbound: firstLen = 0
May 14 03:04:34 xray[639]: 2024/05/14 03:04:34 [Info] [3941384672] app/proxyman/inbound: connection ends > proxy/vless/inbound: invalid request from 127.0.0.1:0 > proxy/vless/encoding: failed to read request version > websocket: close 1000 (normal)
2024-05-14T00:58:21.116Z
xor

Судя по логам, у меня тоже когда-то такая ошибка была, но какие настройки конкретно ее вызывают, уже никак не узнать.

Могу посоветовать лишь проверить еще раз внимательно все настройки, как nginx, так и xray клиента и сервера.

Указывал ли CNAME, как было сказано в статье? Может быть где-то на сайте GCore можно увидеть, прошел ли через ее cdn трафик?

2024-05-14T02:04:29.036Z
Kisliy(Андрей)

Мы же сначала решили на прямую подключиться, без Gcore.

В двух словах, о чём ошибка то?

2024-05-14T11:44:24.929Z
xor
Мы же сначала решили на прямую подключиться, без Gcore.

А, ну да :slightly_smiling_face:

В двух словах, о чём ошибка то?

Я тут могу сделать только грубое предположение, что при firstLen = 0, данных, как таковых, не долетает до xray, что странно.
nginx мы проверили, скрин nekoray тоже был.
На всякий случай неплохо было бы взглянуть на конфиг xray, хотя я сомневаюсь, что в нем дело.
Эксперимента ради можешь попробовать соединиться с клиента голого xray, чтобы точно никакие косяки настроек neko не были проблемой. Вот пример конфига:

{
  "log": {
    "loglevel": "info"
  },
  "dns": {
    "servers": [
      "https://1.1.1.1/dns-query"
    ],
    "queryStrategy": "UseIPv4"
  },
  "routing":
  {
    "domainStrategy": "IPIfNonMatch",
    "domainMatcher": "hybrid",
    "rules": [
      {
        "type": "field",
        "protocol": ["bittorrent"],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "domain": ["geosite:category-ads-all"],
        "outboundTag": "block"
      },
      {
        "type": "field",
        "domain": [
          "geosite:category-gov-ru",
          "domain:ru",
          "domain:by",
          "domain:su",
          "domain:xn--p1ai", // рф
          "domain:xn--80aswg", // сайт
          "domain:xn--c1avg", // онлайн
          "domain:xn--80asehdb", // москва
          "domain:xn--90ais" // бел
        ],
        "outboundTag": "direct"
      },
      {
        "type": "field",
        "ip": [
          "geoip:ru",
          "geoip:private",
          "geoip:by"
        ],
        "outboundTag": "direct"
      }
    ]
  },
  "inbounds": [
    {
      "listen": "127.0.0.1",
      "port": 2080,
      "protocol": "socks",
      "settings": {
        "udp": true
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "адрес",
            "port": 443,
            "users": [
              {
                "id": "ид",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "wsSettings": {
          "path": "/путь?ed=2048"
        },
        "tlsSettings": {
          "allowInsecure": false,
          "serverName": "домен",
          "fingerprint": "firefox"
        }
      },
      "tag": "proxy"
    },
    {
      "protocol": "freedom",
      "tag": "direct"
    },
    {
      "protocol": "blackhole",
      "tag": "block"
    }
  ]
}

соответственно, в конфие нужно сделать четыре замены - адрес, путь и домен и ид, они там подписаны по-русски.
Пусть тебя не смущает роутинг, он чисто для проверки работоспособностине помешает.
Запускать xray -c conf_name.json
Также, как и neko, откроет socks прокси на порту 2080.

2024-05-15T06:51:47.197Z
Kisliy(Андрей)

Получилось настроить, так что всем спасибо за поддержку и общий вклад в развитие свободного интернета! :sun_with_face: :earth_africa:

Во-первых, ошибка в той статье на хабре по которой настраивал, ssl в /etc/nginx/conf.d/default.conf указывать обязательно, автор почему-то убрал это из финальных конфигураций:

listen 127.0.0.1:8444 ssl so_keepalive=on;
        http2 on;

Ну и во-вторых, с версии Xray-core v1.8.10 обновилось переключение HTTPUpgrade:

Теперь добавьте после пути HTTPUpgrade ?ed=2560, чтобы включить 0-RTT.
В дальнейшем рекомендуется заполнять 2560 вместо 2048 для WebSocket ed.

Подсмотрел в примерах конфигурации, значения earlydata length и earlydata name не заполняются, как ни странно. Прикреплю скриншот с которым у меня всё работает:

2024-05-15T09:38:01.912Z
Uporoty(Uporoty)

Это кажется действительно факап автора, там “ssl” обязательно должно быть, да.

HTTPUpgrade и WS это чуть-чуть разные вещи. WS это настоящие вебсокеты, а у HTTPUpgrade только заголовок “Upgrade” от вебсокетов, а дальше данные шлются как есть. WS совместим со всем, а HTTPUpgrade работает быстрее, но не везде (через GCore кстати работает), и пока что поддерживается не всеми клиентами (большинство мобильных его пока не умеет).

А что до earlydata - это просто оптимизации (более быстрый хендшейк), отсутствие этих параметров на успешность соединения никак не влияет. Можете прописать там 2560 тоже.

2024-05-18T15:21:16.875Z
Kisliy(Андрей)

Я уже попробовал :snowman: Если прописать что-то отличное от 0 в earlydata length - работать не будет :exclamation:
Причём, Sec‑Websocket‑Protocol в earlydata name уже никак не влияет соединение, может работать и без него.

2024-05-18T17:16:52.233Z
Uporoty(Uporoty)

Ну понятно что если length стоит 0, то второй параметр уже не важен, т.к. фича отключена.
А вот то что с 2560 и “Sec-Websocket-Protocol” не работает это очень странно. У меня работает.

Кстати, если у вас в планах пользоваться именно вебсокетами, то в Nekobox лучше переключить ядро на Xray (он станет Nekoray). Там не надо заполнять отдельно эти два поля для early data, XRay-ядро автоматически их подхватит по параметру ?ed= в урле. А во-вторых, там можно включить мультиплексирование (у sing-box’а mux не совместим с xray), что в некоторых случаях сильно ускоряет хендшейки и затрудняет детектирование со стороны

2024-05-18T17:32:50.026Z
Kisliy(Андрей)

Т. е. не во всех случаях лучше использовать xray ядро? Автор тех статей показывает примеры на ядре sing-box, может из-за того что маршруты не работают иначе?

2024-05-18T20:43:56.687Z
Uporoty(Uporoty)

У Sing-box немного выше производительность для ShadowSocks, а ещё он поддерживает Hysteria, других особых преимуществ не вижу.

Насколько я помню, в то время, когда выходили эти статьи, Nekoray ещё не имел в себе XRay, а вместо него был древний V2Ray в котором не было многого нужного, отсюда и совет.

2024-05-18T20:51:02.811Z
Kisliy(Андрей)

Отлично, тогда конечно надо пересесть на xray ядро, да к тому же отсутствие мультиплекса раздражает долгими подключениями, спасибо за дельный совет! :grinning: :+1:

2024-05-18T21:02:20.979Z
xor

Я уже попробовал :snowman: Если прописать что-то отличное от 0 в earlydata length - работать не будет :exclamation:
Причём, Sec‑Websocket‑Protocol в earlydata name уже никак не влияет соединение, может работать и без него.

Работает. Там просто неочевидный финт, что надо и ?ed=… и earlydata length и Sec‑Websocket‑Protocol.

Т. е. не во всех случаях лучше использовать xray ядро? Автор тех статей показывает примеры на ядре sing-box, может из-за того что маршруты не работают иначе?

Вот меня тоже смутило, чем так sing-box хорош, что автор советовал его. Кроме упоминания где-то в комментариях возможности прокидывания ssh, других преимуществ не удалось нагуглить.

2024-05-18T21:57:10.945Z
Kisliy(Андрей)

Достаточно только в клиенте включить mux, а сервер сам подхватит эту настройку?

Маршруты настроил, но вот правила с доменами, в которых есть ключевые слова, не фурычат и символ * не помогает, это конечно не важно, но случаем не знаете как правильно их вбивать?

Будем надеется в следующих версиях SSH добавят.

В итоге я перешёл на ядро xray. Заметил небольшие недоработки: изредка комп чуть подтормаживал; окно taskkill вылетало при перезагрузке клиента; при включённом режиме tun и незапущенном сервере выход в инет блокируется, но текущие соединения не прерываются. В общем, пользоваться можно.

2024-05-20T03:00:00.116Z
Uporoty(Uporoty)

Вот тут расписано: Routing | Project X (xtls.github.io). То, что вы вписываете в окошко, клиент подсовывает в поле “domain” в конфиге

2024-05-20T09:00:54.634Z
Kisliy(Андрей)

Спасибо! :+1:

2024-05-21T05:48:18.400Z
SnakeWeb

Привет

Можешь написать мне?, тут предложение есть для тебя. Тг: Telegram: Contact @snakeweb

2024-09-08T21:04:44.920Z