Recently, I faced the challenge of configuring the Apache and Haproxy service on the same server. The best solution would be haproxy working in http mode, but in this case I intended to use a proxy on the same port for services that require the TCP mode. Moreover, Let's Encrypt configuration on Apache was more accessible. The biggest problem was transferring the client's IP from Haproxy to Apache, while Haproxy was working in TCP mode. Due to the fact that all traffic was encrypted between the user and Apache.
Problem:
In the initial configuration, I saw the IP address of the proxy server in the Apache logs.
Solution 1:
Use mode tcp and proxy_http plugin.
1. Haproxy
Before the entire operation, make sure you have "tcplog" enabled.
defaults
log global
mode tcp
option tcplog
balance roundrobin
retries 3
option dontlognull
We will start the actual configuration by editing the /etc/haproxy/haproxy.cfg file in which we will set our TCP mode and select our backend.
frontend https
bind <my_external_ip_adress>:443
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
default_backend local-server
Then you should also add the TCP mode and the "send-proxy-v2" flag to our backend.
backend local-server
option redispatch
mode tcp
option ssl-hello-chk
server apache1 apache1:443 check send-proxy-v2
After all, we restart our haproxy service.
systemctl restart haproxy
2. Apache
Then in the /etc/apache2/apache2.conf file we add the ProxyProtocol option and change the default LogFormat.
ProxyProtocol On
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%a %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
We must enable apache proxy_http plugin too.
a2enmod proxy_http
After all, we restart our apache2 service.
systemctl restart apache2
Solution 2
If you can't use send-proxy-v2, use http mode.
1. Haproxy
Create a haproxy configuration like this:
defaults
log global
log 127.0.0.1 local0 err
mode http
option httplog
frontend http-in
bind <my_external_ip_adress>:80
option http-server-close
option forwardfor except 127.0.0.1/8
default_backend local-server
frontend https-in
bind <my_external_ip_adress>:443
option http-server-close
option forwardfor except 127.0.0.1/8
http-request add-header X-Forwarded-Proto https
http-request add-header X-Forwarded-For %[src]
default_backend local-server
backend local-server
balance roundrobin
server apache1 apache1:80 weight 1 maxconn 512 check inter 10s rise 2 fall 2
2. Apache:
In apache itself you will only have to change the log format:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy
SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
CustomLog "logs/access_log" combined env=!forwarded
CustomLog "logs/access_log" proxy env=forwarded
3. Testing
Now we can go to our logs and check if we received an ip instead of a proxy ip, the user's address.
tail -f /var/log/apache2/*.log
Now we get:
==> /var/log/apache2/kamdev.access.log <==
84.0.37.0 - - [01/Jul/2024:21:08:49 +0200] "GET / HTTP/1.1" 200 8654 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"
Komentarze