Getting 404 when call request by haproxy (directly works fine) - reverse-proxy

I directly call a web service with url
curl http://venesh.ir/webservice/oauth/token
and I got error 403,
but when I call it by reverse proxy from some server I got 404,is it possible that haproxy change my address?
haproxy config:
frontend localhost
bind *:8081
option tcplog
mode tcp
acl isVenesh dst_port 8081
use_backend venesh if isVenesh
default_backend venesh
backend venesh
mode tcp
balance roundrobin
server web01 venesh.ir:80 check
when I call mySerevrIp:8081/webservice/oauth/token I expect getting the result that I directly call
curl http://venesh.ir/webservice/oauth/token that is 403,
but when I call curl mySerevrIp:8081/webservice/oauth/token I get error 404,
Is a problem with my haproxy or my config or is it possible that this problem is because of venesh.ir website?

It appears that http://venesh.ir/webservice/oauth/token expects the host header to be venesh.ir. You can test this from the command line. If the host header is not venesh.ir, it will return 404:
$ curl -I -H 'Host: 1.1.1.1' http://venesh.ir/webservice/oauth/token
HTTP/1.1 404 Not Found
Date: Mon, 24 Jun 2019 17:48:56 GMT
Server: Apache/2
Content-Type: text/html; charset=iso-8859-1
You can add the host header to your configuration if you change your mode to http:
frontend localhost
bind *:8081
option httplog
mode http
default_backend venesh
backend venesh
mode http
balance roundrobin
http-request set-header Host venesh.ir
server web01 venesh.ir:80 check

The answer of #mweiss was true, and an alternative way that I found is Setting HOST value to venesh.ir in my request header then the tcp reverse proxy works fine.

Related

Haproxy seemingly substitutes brotli with gzip in "Accept-Encoding" header

Im struggling to figure out why haproxy seemingly replaces br with gzip in "Accept-Encoding" header as request passes haproxy.
My application currently structured like this:
HAPROXY(tls termination) -> varnish -> apache
So I test like this:
curl -I --http2 -H 'Accept-Encoding: br' -I https://mysite.dev:31753?tru
So - sending single GET request to haproxy that strictly asks for brotly only (using curl)...
So that's what I would expect to see coming to varnish, but what is actually coming into varnish is these 2 requests:
HEAD request with br
GET request with gzip value instead...
I'm so confused - why are there 2 requests now? I did not configure compression in haproxy how can it be rewriting br to gzip.
Requests coming to varnish (I get this using tcpflow program):
172.030.000.035.41382-172.030.000.034.00080: HEAD /?tru HTTP/1.1
user-agent: curl/7.68.0
accept: */*
accept-encoding: br
host: mysite.dev:31753
x-client-ip: 192.168.10.103
x-forwarded-port: 31753
x-forwarded-proto: https
x-forwarded-for: 192.168.10.103
connection: close
172.030.000.034.41882-172.030.000.033.00080: GET /?tru HTTP/1.1
user-agent: curl/7.68.0
accept: */*
x-client-ip: 192.168.10.103
x-forwarded-port: 31753
x-forwarded-proto: https
X-Forwarded-For: 192.168.10.103, 172.30.0.35
host: mysite:31753
Accept-Encoding: gzip
X-Varnish: 328479
My haproxy config looks like so:
Haproxy
global
maxconn 1024
log stdout format raw local0
ssl-default-bind-options ssl-min-ver TLSv1.2
defaults
log global
option httplog
option http-server-close
mode http
option dontlognull
timeout connect 5s
timeout client 20s
timeout server 45s
frontend fe-wp-combined
mode tcp
bind *:31753
tcp-request inspect-delay 2s
tcp-request content accept if HTTP
tcp-request content accept if { req.ssl_hello_type 1 }
use_backend be-wp-recirc-http if HTTP
default_backend be-wp-recirc-https
backend be-wp-recirc-http
mode tcp
server loopback-for-http abns#wp-haproxy-http send-proxy-v2
backend be-wp-recirc-https
mode tcp
server loopback-for-https abns#wp-haproxy-https send-proxy-v2
frontend fe-wp-https
mode http
bind abns#wp-haproxy-https accept-proxy ssl crt /certs/fullkeychain.pem alpn h2,http/1.1
# whatever you need todo for HTTPS traffic
default_backend be-wp-real
frontend fe-wp-http
mode http
bind abns#wp-haproxy-http accept-proxy
# whatever you need todo for HTTP traffic
redirect scheme https code 301 if !{ ssl_fc }
backend be-wp-real
mode http
balance roundrobin
option forwardfor
# Send these request to check health
option httpchk
http-check send meth HEAD uri / ver HTTP/1.1 hdr Host haproxy.local
http-response del-header Server
http-response del-header via
server wp-backend1 proxy-varnish:80 check
http-request set-header x-client-ip %[src]
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
Please help if anyone knows what's happening here - extremely stumped.
nvm.upon further investigation it turned out that I was mixing up tcpflow results.
apparently it was varnish all along that was automatically encoding gzip, after I disabled it - I got br back as expected.

Forward SSL traffic and authentication certificates through HAProxy

I have an nginx from my client where I can POST successfully with:
curl -v --cacert ca.crt --cert client.crt --key client.key -POST https://nginx:8443/api/ -H 'Content-Type: application/json' -H 'cache-control: no-cache' -d#test.json
Now I installed an haproxy in front of nginx and I'm trying to do a POST the same way, unsuccessful:
curl -v --cacert ca.crt --cert client.crt --key client.key -POST http://haproxy:8443/api/ -H 'Content-Type: application/json' -H 'cache-control: no-cache' -d#test.json
Error:
<center>The plain HTTP request was sent to HTTPS port</center>
<hr><center>nginx</center>
Here is my haproxy configuration:
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
defaults
mode tcp
log global
option tcplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
frontend main *:8443
acl url_static path_beg -i /static /images /javascript /stylesheets
acl url_static path_end -i .jpg .gif .png .css .js
use_backend static if url_static
default_backend app
backend static
balance roundrobin
server static 127.0.0.1:8443
backend app
mode tcp
balance roundrobin
server nginx nginx01:8443
I want to forward SSL traffic through HAProxy and pass the certificates for authentication to nginx.
I know it doesn't make any sense to have two LBs but I can't modify nginx and the api server behind, but the clients will be internal.
As you can see at this point I'm able to reach nginx but haproxy doesn't pass the certificates and keys from the request to nginx backend.
Am I missing something? Is this something that I can achieve?
ps: If I'm setting 'ssl verify none' at backend, I'm getting 'No required SSL certificate was sent'.
If I'm setting 'send-proxy' at backend, I'm getting '400 Bad Request' from nginx.
You will need to add the ssl configuration to haproxy and set some headers which will be forwarded to the nginx.
# your other config from above
backend app
mode tcp
balance roundrobin
server nginx nginx01:8443 ssl ca-file <The ca from nginx backend>
the solution implemented was with SS/TLS pass-through from https://www.haproxy.com/documentation/haproxy/deployment-guides/tls-infrastructure/
Setting both frontend and backend to mode tcp I was able to pass the certificates and nginx validate and made the authentication.

Reverse proxy setup on haproxy gives 500; wget on base server & nginx works

I am trying to setup haproxy as a reverse proxy for a server. I am on Centos.
The config goes like this:
global
#log /dev/log local0
#log /dev/log local1 notice
log 127.0.0.1 local2 info
log 127.0.0.1 local2 notice
log 127.0.0.1 local2 debug
chroot /var/lib/haproxy
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
frontend http_front
bind *:801
option forwardfor
stats enable
default_backend http_back
backend http_back
mode http
option httpchk
option forwardfor
http-send-name-header Host
balance roundrobin
server server1 stg-hostserv.com:80
But, if I do a wget against it, I am getting the below error.
# wget http://0.0.0.0:801
--2018-07-16 14:26:24-- http://0.0.0.0:801/
Connecting to 0.0.0.0:801... connected.
HTTP request sent, awaiting response... 500 Internal Server Error
2018-07-16 14:26:24 ERROR 500: Internal Server Error.
haproxy -f /etc/haproxy/haproxy.cfg -d
[WARNING] 197/200148 (13833) : config : frontend 'GLOBAL' has no 'bind' directive. Please declare it as a backend if this was intended.
Available polling systems :
epoll : pref=300, test result OK
poll : pref=200, test result OK
select : pref=150, test result FAILED
Total: 3 (2 usable), will use epoll.
Using epoll() as the polling mechanism.
00000000:http_front.accept(0004)=0006 from [127.0.0.1:60696]
00000000:http_front.clireq[0006:ffffffff]: GET / HTTP/1.1
00000000:http_front.clihdr[0006:ffffffff]: User-Agent: Wget/1.14 (linux-gnu)
00000000:http_front.clihdr[0006:ffffffff]: Accept: */*
00000000:http_front.clihdr[0006:ffffffff]: Host: 0.0.0.0:801
00000000:http_front.clihdr[0006:ffffffff]: Connection: Keep-Alive
00000000:http_back.srvrep[0006:0007]: HTTP/1.1 500 Internal Server Error
00000000:http_back.srvhdr[0006:0007]: Content-Type: text/html
00000000:http_back.srvhdr[0006:0007]: Server: Microsoft-IIS/8.0
00000000:http_back.srvhdr[0006:0007]: X-Powered-By: ASP.NET
00000000:http_back.srvhdr[0006:0007]: Date: Tue, 17 Jul 2018 12:02:00 GMT
00000000:http_back.srvhdr[0006:0007]: Connection: close
00000000:http_back.srvhdr[0006:0007]: Content-Length: 1208
00000001:http_front.clicls[0006:ffffffff]
00000001:http_front.closed[0006:ffffffff]
^C
[root#izp0w3tkx2yr8zhes26ajqz ~]#
I tried different config for the server and consistently hit 500 error. Wget to the base server works without any issues.
I setup nginix to the same thing and it works beautifully. Just haproxy does not seem to work. The customer wants it on haproxy. :)
Can you please advise where I can look at to further debug. Appreciate your assistance.
This update from nuster cache server helped solve the problem:
Does your backend Microsoft-IIS/8.0 check host header? as you set http-send-name-header Host, so request from HAProxy to stg-hostserv.com:80 looks like GET / HTTP/1.1 Host: izp0w3tkx2yr8zhes26ajqz
HAProxy worked when I set:
http-request set-header Host stg-hostserv.com

HAproxy times out(504 error) with large POST bodies

I have 3 nodejs web-servers spun on an ubuntu box and HAproxy to load-balance those servers on the same box. HAproxy listens at port 80(http) and 443(https, with SSL termination). There's no SSL between the HAproxy server and the web-servers.
The POST call to one of the api without SSL, passes through with any value of content-length, but when I try to do the POST call with a content-length greater than 8055 on the HAproxy with SSL connection(port443), HAproxy times out giving a 504 Gateway Timeout error.
Also, if I give an "Expect:100 continue" header to the curl command, the server responds with some delay, which I don't want to exist. Below is how the HAproxy config file looks like:
global
stats socket /var/run/haproxy.sock mode 0777
log 127.0.0.1 local0 info
log 127.0.0.1 local1 info
chroot /usr/share/haproxy
uid nobody
gid nobody
nbproc 1
daemon
maxconn 50000
frontend localnodes:https
bind *:443 ssl crt /etc/ssl/private/443_private_ssl_in.pem no-sslv3
mode http
reqadd X-Forwarded-Proto:\ https
default_backend nodes
timeout client 30000
frontend localnodes-http
bind *:80
mode http
reqadd X-Forwarded-Proto:\ http
default_backend nodes
timeout client 30000
backend nodes
mode http
balance roundrobin
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
log global
timeout connect 3000
timeout server 30000
option httplog
option ssl-hello-chk
option httpchk GET /
http-check expect status 404
server nodejsweb01 127.0.0.1:8000 check
server nodejsweb02 127.0.0.1:8001 check
server nodejsweb03 127.0.0.1:8002 check
I have ensured that the nodejs web-servers behind have no problem, they work fine. I have tried increasing the 'timeout server' period, no effect.
Also tried a solution on this link that tells to give an option ssl ca-file to the backend nodes, as follows:
server nodejsweb01 127.0.0.1:8000 ssl ca-file /etc/ssl/certs/ca.pem check
server nodejsweb02 127.0.0.1:8001 ssl ca-file /etc/ssl/certs/ca.pem check
server nodejsweb03 127.0.0.1:8002 ssl ca-file /etc/ssl/certs/ca.pem check
but after this option HAproxy throws an error saying no servers available at the backend.
Please tell me what am I doing wrong in HAproxy conf file, so that I make the webservers respond successfully with the SSL connection
Try this minimum config:
frontend localnodes
bind *:80
bind *:443 ssl crt /etc/ssl/private/443_private_ssl_in.pem
mode http
default_backend nodes
backend nodes
mode http
option forwardfor
option httplog
server nodejsweb01 127.0.0.1:8000 check
server nodejsweb02 127.0.0.1:8001 check
server nodejsweb03 127.0.0.1:8002 check
I suspect it's those additional options.
It could also be the SSL cert file. Is your PEM file created from a self-signed cert? How is it structured?

HAPROXY reqirep on Host header not forwarding

I have a web server (actually it's a CF environment, but that doesn't matter much) running behind a haproxy version 1.5-dev19 2013/06/17 that accepts requests only for a certain internal domain, let's call it: internal-address.
Meaning, that HTTP requests only work if the host header is suffixed by internal-address, (like: Host: login.internal-address).
Users from the WAN can access this web server by connecting to an external address which has ip forwarding to the internal server.
But when a user accesses the external address, the Host header is suffixed with external-address, and the web server behind the haproxy rejects the request.
I added reqirep entries in to haproxy configuration:
global
log 127.0.0.1 syslog info
daemon
user vcap
group vcap
maxconn 64000
spread-checks 4
defaults
log global
timeout connect 30000ms
timeout client 300000ms
timeout server 300000ms
frontend http-in
mode http
bind :80
option httplog
option forwardfor
reqadd X-Forwarded-Proto:\ http
default_backend http-routers
frontend https-in
mode http
bind :443 ssl crt /var/vcap/jobs/haproxy/config/cert.pem
option httplog
option forwardfor
option http-server-close
reqadd X-Forwarded-Proto:\ https
default_backend http-routers
frontend ssl-in
mode tcp
bind :4443 ssl crt /var/vcap/jobs/haproxy/config/cert.pem
default_backend tcp-routers
backend http-routers
mode http
balance roundrobin
reqirep ^Host:\ uaa.external-address Host:\ uaa.internal-address
reqirep ^Host:\ api.external-address Host:\ api.internal-address
reqirep ^Host:\ external-address:4443 Host:\ loggregator.internal-address:4443
server node0 172.20.0.1:8888 check inter 1000
backend tcp-routers
mode tcp
balance roundrobin
reqirep ^Host:\ external-address:4443 Host:\ loggregator.internal-address:4443
server node0 172.20.0.1:8888 check inter 1000
And every request sent to uaa.external-address or api.external-address is indeed changed and the web server behind the haproxy receives the request as if the Host header is suffixed with internal-address.
But the 3rd rule:
reqirep ^Host:\ external-address:4443 Host:\ loggregator.internal-address:4443
Doesn't work :(
The web server's access log shows the Host header is sent from external-address:4443 , which implies that the haproxy didn't match the Host header correctly and then the web server rejects the request.
The request issued by the client is:
WEBSOCKET REQUEST: [2014-10-01T10:25:07+03:00]
GET /tail/?app=029a1269-67fe-46e2-85f7-e1b0b5d34193 HTTP/1.1
Host: wss://external-address:4443
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: [HIDDEN]
Origin: http://localhost
Authorization: [PRIVATE DATA HIDDEN]
Does anyone know what's wrong with the rule?
EDIT:
I deleted the rules from the backend and created more generic rules in the frontend, and it still doesn't work for websockets:
frontend https-in
mode http
bind :443 ssl crt /var/vcap/jobs/haproxy/config/cert.pem
option httplog
option forwardfor
option http-server-close
reqadd X-Forwarded-Proto:\ https
default_backend http-routers
reqirep ^Host:\ (.*).external-address(.*) Host:\ \1.internal-address\2
frontend ssl-in
mode tcp
bind :4443 ssl crt /var/vcap/jobs/haproxy/config/cert.pem
default_backend tcp-routers
reqirep ^Host:\ (.*).external-address(.*) Host:\ \1.internal-address\2
Thanks in advance.
Which version of HAProxy are you running?
If 1.4, please add 'option http-server-close' into your defaults section.
By default, 1.4 is in tunnel mode, which let HAProxy analyse the first request and response and transfer subsequent requests and responses as payload.
In 1.5, it should work out of the box. HAProxy uses a new mode "http-keep-alive" which allows HAProxy to analyse all the content all the time.
Baptiste