I have different servers in a couple of western countries as personal VPNs for myself and family and friends. Because of staggering internet censorship in Iran, using a domestic VPS as the relay is almost inevitable to bypass GFW. So, to deceive DPI, I use a decoy website with some arbitrary activity to minimize the risk of exposing the true nature of domestic VPS. All in all, it works to a great degree but the problem is, that I can only use it for one external VPS by addressing it in “default_backend” of haproxy. That is, if the SNI doesn’t match with the websites of the server it goes to default, and from there, it relays to the foreign server. Now, I want to implement a system, in which the subdomain of an fqdn can pinpoint the exact server we want to connect to; i.e. US.mydomain.tld connects to US vps and GER.mydomain.tld connects to the server in Germany. This is my config file of haproxy but it doesn’t work.
frontend HTTPS
bind myIP:443
mode tcp
option tcplog
option forwardfor
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend nginx if { ssl_fc_sni -i myDomain.tld }
use_backend nginx if { ssl_fc_sni -i www.myDomain.tld }
use_backend GERrelay if { ssl_fc_sni -i ger.myDomain.tld }
use_backend USrelay if { ssl_fc_sni -i us.myDomain.tld }
default_backend nginx
frontend GERterminatedSSL
mode http
bind myIP:445 ssl crt /etc/haproxy/certs/fullchain.pem
default_backend GERbackend
backend GERbackend
mode http
server 6tunnel 127.0.0.1:4445
frontend USterminatedSSL
mode http
bind myIP:446 ssl crt /etc/haproxy/certs/fullchain.pem
default_backend USbackend
backend USbackend
mode http
server 6tunnel 127.0.0.1:4446
backend nginx
mode tcp
option ssl-hello-chk
option forwardfor
server nginx 127.0.0.1:443 send-proxy-v2 check
backend GERrelay
mode tcp
server local 127.0.0.1:445
backend USrelay
mode tcp
server local 127.0.0.1:446
Whatever approach I choose doesn’t work or better said, I can’t make it work. Can someone show the correct way of rectifying this method?
P.S. I originally posted this in stack overflow but there was no answer up until posting this
Thanks for the reply. You are absolutely right. The frustration and lack of understanding/knowledge got the best of me and I didn’t draw a clear picture of the problem and desired outcomes.
What is the result that you expect?
I wanted to re-route the incoming connections to the external/foreign servers based on the SNI.
The domestic server is just a facade to minimize the risk of getting identified and blocked by DPI and Iran’s GFW. The attempt is to redirect specific connections to external servers based in the US and EU to circumvent the censorship.
To achieve this, the haproxy should decide which connections are gonna redirected to outside servers. My mistake was redirecting it based on SNI which is not the part of domestic webserver and belongs to the external VPS and webserver. That is, the domestic server wouldn’t recognize the SNI and would drop the connection.
In the end, I did resolve this method by:
1- Including the foreign SNIs in the frontend and creating respective backend for each one of them.
2- Getting rid of the secondary frontend and SNI termination altogether.
3- Changing all the modes to tcp.
With these steps, the system works fine but I am trying to implement a new method in which, the header and SNI are the same, unlike the current approach.
For this, I must come up with a frontend that redirects the incoming connections based on the header, (e.g. US.myDomesticDomain.tld gets re-routed to US based vps and GER.myDomesticDomain.tld gets re-routed to Germany’s vps) and haproxy must set the SNI so that the connection gets accepted by the foreign/external server.
I don’t know if this is feasible or not, but any suggestion or guidance is much appreciated.
Well it is likely your previous issue was caused by sending unencrypted cleartext HTTP from the domestic to the foreign VPS, because you actually decrypted SSL without reencrypting it.
But again, I don’t know what 127.0.0.1:4445 is and how it is configured. I also don’t know how your foreign VPS is configured.
But again, I don’t know what 127.0.0.1:4445 is and how it is configured
It is just a simple relay. It receives the packet and sends it as it is to the foreign server.
I was experimenting with different types of relaying data packets and settled on haproxy’s own embedded function. The other methods work too but for now, haproxy is sufficient for handling this task.
server ip myExternalDomain:443 check resolvers mynameserver
I also don’t know how your foreign VPS is configured.
It is a simple proxying task. If the SNI and other parameters match with Xray and V2ray servers, the data is gonna handed to them, if not, the default backend which is nginx, gonna process it. It works on both sides and I haven’t encountered a problem so far.
Well it is likely your previous issue was caused by sending unencrypted cleartext HTTP from the domestic to the foreign VPS, because you actually decrypted SSL without reencrypting it.
Most likely this is the problem. My first approach was wrong and I should have worked with header instead of SNI.
Now, I’m working on parsing the received data by:
Haproxy listens to port 443 on tcp mode.
If the received SNI is the same as the foreign server’s header(e.g. US.myDomesticDomain.tld) it’s gonna send it to a backend that unencrypts data in http mode and extracts the header.
Based on that header, the server should set the external server’s SNI and send it to the external server in tcp mode.
I don’t know if it’s gonna work or not, so, what is your assessment to this approach?
I haven’t even heard of these programs. If I can solve it with haproxy it would be wonderful but if it gets frustrating or wearisome, then I try your recommendation.
Thanks again for your time