Skip to content

Commit

Permalink
multiple configs on one port (#100)
Browse files Browse the repository at this point in the history
* added all-in-one(everything on https) config

* Commented http sub-config
  • Loading branch information
UZziell committed Jan 2, 2023
1 parent 6517444 commit 648e771
Show file tree
Hide file tree
Showing 3 changed files with 560 additions and 0 deletions.
41 changes: 41 additions & 0 deletions All-in-One-fallbacks-Nginx/README.md
@@ -0,0 +1,41 @@
# Xray - All-in-one Configuration + Nginx(decoy website)

The configuration uses xray's `fallbacks` feature to enable these combinations at the same time on port 443:
* HTTPS:443
* Trojan-TCP-TLS
* Trojan-WS-TLS
* Trojan-gRPC-TLS
* Trojan-TCP-XTLS(flow: xtls-rprx-direct)
* Vless-TCP-TLS
* Vless-WS-TLS
* Vless-gRPC-TLS
* VMESS-TCP-TLS
* VMESS-WS-TLS
* VMESS-gRPC-TLS
* ShadowSocks-gRPC

Nginx is used to serve a decory website and route gRPC traffic.

## How it works?
The Trojan-TCP-XTLS is the HTTPS entrypoint. For every incoming request after doing TLS-Termination, based on the **Path** or **ALPN type**, the request is passed to another sub-config. For example:
* If the **Path=/vlessws**, the request is passed to **@vless-ws** sub-config.
* If the **Path=/vmtc**, the request is passed to **@vmess-tcp**.
* In case of **ALPN=HTTP2**, it's first passed to **@trojan-tcp**. In trojan-tcp, if if it's not a valid request(for example the trojan password is wrong), another fallback is set, to once more pass the request to Nginx HTTP2 Unix Domain Socket and a decory website is served. When the request is using HTTP2, it could also be gRPC, so that is also checked in Nginx. This is how a VMESS-gRPC request is processed:

VMESS-gRPC Request ------> Xray Trojan-TCP-XTLS(443) ----**alpn=h2**----> fallback to xray trojan-tcp ------> fallback to nginx /dev/shm/h2c.sock ---**path=/vmgrpc**---> grpc_pass to xray vmess-gRPC listener on 127.0.0.1:3003

## What to change before use?
* Xray server.json
* **SSL Certificates and keys** absolute paths in Trojan-TCP-XTLS
* **Password** of Trojan and ShadowSocks configs
* **UUID** of Vless and VMESS configs
* **(Optional)** Path of all sub-configs. For **Websocket**->`wsSettings.path`, for **TCP**->`tcpSettings.header.request.path` and for **gRPC**->`grpcSettings.serviceName`.
* Nginx nginx.conf
* Domain names
* **(Optional)** If gRPC serviceNames are changed server.json, they **should** also be changed in Nginx config


## Notes:
* Tested with **Xray 1.6.1** (Xray, Penetrates Everything.) Custom (go1.19.2 linux/amd64)
* For a little better performance, a DNS Cache could be setup (on 127.0.0.53 in this case) and used for resolving DNS queries. To enable xray to use it uncomment the corresponding rule from the `routing.settings.rules` in server.json.
* Multiple domains could be used at the same time, including domains behind cloudflare CDN. (For cloudflare, make sure websocket and gRPC are enabled in Network section). In this configuration these domains are **example.com** and **behindcdn.com**
85 changes: 85 additions & 0 deletions All-in-One-fallbacks-Nginx/nginx.conf
@@ -0,0 +1,85 @@
server {
listen unix:/dev/shm/h1.sock proxy_protocol default_server;
listen unix:/dev/shm/h2c.sock http2 proxy_protocol default_server;

This comment has been minimized.

Copy link
@PouriaMzn

PouriaMzn Jan 3, 2023

Deer @UZziell, thank you for your awesome work.
I've never used nginx with unix sock, would you care to share the config for these two listen addresses or elaborate on how to config them?

listen unix:/dev/shm/h1.sock proxy_protocol default_server;
listen unix:/dev/shm/h2c.sock http2 proxy_protocol default_server;

This comment has been minimized.

Copy link
@UZziell

UZziell Jan 3, 2023

Author Contributor

I'm glad it was helpful.
Instead of using a normal network socket like listen 80 or listen 443 ssl, nginx could be configured to listen on a unix socket . Listen on unix domain socket
Maybe I misunderstood your question.
The first server block in nginx.conf with an invalid server_name ensures that if the website is accessed directly with IP address or a domain name other than the ones configured in HTTP1 and HTTP2 server blocks, server will return HTTP Bad Request 400.

This comment has been minimized.

Copy link
@PouriaMzn

PouriaMzn Jan 3, 2023

Thank you for your response, I think the main problem is my lack of knowledge :) so let me explain my question,
normally for nginx, we listen on a given port, as you said, 80 or 443, but now, we're not saying to listen on a port, but we are saying to listen on a socket and we are referring to a file for this socket, in your case:

/dev/shm/h1.sock
/dev/shm/h2c.sock

my question is how to create these files, is it something like creating a service and a socket file for gunicorn, containing for example:

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

or is it autogenerated by the nginx itself?

This comment has been minimized.

Copy link
@UZziell

UZziell Jan 3, 2023

Author Contributor

Yes. Nginx process will create them automatically once they are present in the configuration file. But apparently it has a problem with deleting them afterwards 😄

This comment has been minimized.

Copy link
@PouriaMzn

PouriaMzn Jan 3, 2023

So if that's the case, why not to use ports instead of socket? 🤔

This comment has been minimized.

Copy link
@UZziell

UZziell Jan 3, 2023

Author Contributor

Using a TCP socket is also possible.
Not sure if it's true but I thought the performance might be better since UDS works on the kernel level.

set_real_ip_from unix:;
real_ip_header proxy_protocol;
server_name _;
return 400;
} #Restrict domain name access (prohibit access to the website by IP) and return 400

# HTTP1 UDS listener
server {
listen unix:/dev/shm/h1.sock proxy_protocol; #HTTP/1.1 server monitor process and enable PROXY protocol reception
set_real_ip_from unix:;
real_ip_header proxy_protocol;
server_name examle.com behindcdn.com; #Change to your own domain name(s)

location / {
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; #启用HSTS
root /var/www/html; #Modify to the path of the WEB file stored by yourself (check the permissions)
index index.html index.htm;
}
}

# HTTP2 UDS listener
server {
listen unix:/dev/shm/h2c.sock http2 proxy_protocol; #H2C server monitor process and enable PROXY protocol reception
set_real_ip_from unix:;
real_ip_header proxy_protocol;
server_name examle.com behindcdn.com; #Change to your own domain name(s) (don't forget to add the certificates to xray config)

# grpc settings
grpc_read_timeout 1h;
grpc_send_timeout 1h;
grpc_set_header X-Real-IP $remote_addr;

location /trgrpc { #corresponds to serviceName in trojan-grpc config of xray
if ($request_method != "POST") {
return 404;
} #POST returns 404 when negotiation fails
client_body_buffer_size 1m;
client_body_timeout 1h;
client_max_body_size 0;
grpc_pass grpc://127.0.0.1:3001;

}

location /vlgrpc { #corresponds to serviceName in vless-grpc config of xray
if ($request_method != "POST") {
return 404;
} #POST returns 404 when negotiation fails
client_body_buffer_size 1m;
client_body_timeout 1h;
client_max_body_size 0;
grpc_pass grpc://127.0.0.1:3002;

}

location /vmgrpc { #corresponds to serviceName in vmess-grpc config of xray
if ($request_method != "POST") {
return 404;
} #POST returns 404 when negotiation fails
client_body_buffer_size 1m;
client_body_timeout 1h;
client_max_body_size 0;
grpc_pass grpc://127.0.0.1:3003;

}

location /ssgrpc { #corresponds to serviceName in shadowsocks-grpc config of xray
if ($request_method != "POST") {
return 404;
} #POST returns 404 when negotiation fails
client_body_buffer_size 1m;
client_body_timeout 1h;
client_max_body_size 0;
grpc_pass grpc://127.0.0.1:3004;
}

# Decoy website
location / {
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; #HSTS
root /var/www/html; # Modify to the path of the WEB file stored by yourself (check the permissions)
index index.html index.htm;
}
}

2 comments on commit 648e771

@mr-meteor
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @UZziell ، thanks for this config and solution for nginx problem
Is it possible to add vless-vission to this config?
and Should we add fallback for all path like "/vlessws" when we have a wrong id

@UZziell
Copy link
Contributor Author

@UZziell UZziell commented on 648e771 Jan 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi.
Update:
Changed default entrypoint to vless-vision.

"Should we add fallback for all path like "/vlessws" when we have a wrong id?"
Yes and No.
If you are using only the TLS inbounds, eavesdroppers can't see the path. They can only see the SNI, so it's not really needed.
But if you are also using HTTP inbound 80, then yes it's a good idea to add nginx h1.sock as their fallbacks. So that if any path like /vlessws is visited the decoy website is served.

Please sign in to comment.