Setup HTTPs Forward Proxy with HAProxy - https

In HAProxy, I've used option http-proxy to make it work like forward proxy. This seems to be working fine, but for HTTPS traffic that's not possible.
So, is there any option in the HAProxy configuration that allows to proxy the HTTPS traffic just like Squid does ?
I think the problem is that the option https_proxy isn't available.
This configuration works perfectly for HTTP protocol:
frontend http_proxy
bind :3128
option http_proxy
default_backend proxy_server
backend proxy_server
option http_proxy
Note - I've used the certificate with "ssl crt" along with the bind option but that didn't seem to proxy over HTTPS protocol

This is my Haproxy file configuration, it works well for HTTP and HTTPS protocol.
Here's the code :
#-----------------------------------------------------------------------------
# global
#-----------------------------------------------------------------------------
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# Default ciphers to use on SSL-enabled listening sockets.
# For more information, see ciphers(1SSL). This list is from:
# https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
# An alternative list with additional directives can be obtained from
# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
ssl-default-bind-options no-sslv3
# Tuning if required/needed
# tune.ssl.default-dh-param 2048
#-----------------------------------------------------------------------------
# defaults
#-----------------------------------------------------------------------------
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
#-----------------------------------------------------------------------------
# http frontend
#-----------------------------------------------------------------------------
frontend http-in
bind *:80
# Domain redirect, force the 'www' prefix
redirect prefix https://www.domain1.net code 301 if { hdr_beg(host) -i domain1.net }
redirect prefix https://www.domain2.net code 301 if { hdr_beg(host) -i domain2.net }
# Define hosts
acl is-domain1-site hdr(host) -i www.domain1.net
acl is-domain1-blog hdr(host) -i blog.domain1.net
acl is-domain1-wiki hdr(host) -i wiki.domain1.net
acl is-domain2-site hdr(host) -i www.domain2.net
acl is-domain2-blog hdr(host) -i blog.domain2.net
acl is-domain2-wiki hdr(host) -i wiki.domain2.net
# Force https for domain1
redirect scheme https if is-domain1-site !{ ssl_fc }
redirect scheme https if is-domain1-blog !{ ssl_fc }
redirect scheme https if is-domain1-wiki !{ ssl_fc }
# Force https for domain2
redirect scheme https if is-domain2-site !{ ssl_fc }
redirect scheme https if is-domain2-blog !{ ssl_fc }
redirect scheme https if is-domain2-wiki !{ ssl_fc }
# Default backend (parking)
default_backend bk-ct100
#-----------------------------------------------------------------------------
# https frontend
#-----------------------------------------------------------------------------
frontend https-in
bind *:443 ssl crt /etc/ssl/private/
# Domain redirect force www
redirect prefix https://www.domain1.net code 301 if { hdr_beg(host) -i domain1.net }
redirect prefix https://www.domain2.net code 301 if { hdr_beg(host) -i domain2.net }
# Define hosts for domain1
acl is-domain1-site hdr(host) -i www.domain1.net
acl is-domain1-blog hdr(host) -i blog.domain1.net
acl is-domain1-wiki hdr(host) -i wiki.domain1.net
# Define hosts for domain2
acl is-domain2-site hdr(host) -i www.domain2.net
acl is-domain2-blog hdr(host) -i blog.domain2.net
acl is-domain2-wiki hdr(host) -i wiki.domain2.net
# Figure out which backend to use for domain1
use_backend bk-ct101 if is-domain1-site
use_backend bk-ct101 if is-domain1-blog
use_backend bk-ct101 if is-domain1-wiki
# Figure out which backend to use for domain2
use_backend bk-ct102 if is-domain2-site
use_backend bk-ct102 if is-domain2-blog
use_backend bk-ct102 if is-domain2-wiki
# Default backend (parking)
default_backend bk-ct100
#-----------------------------------------------------------------------------
# ct100 backend - parking
#-----------------------------------------------------------------------------
backend bk-ct100
mode http
option forwardfor
server ct100 192.168.100.100:80 check
#-----------------------------------------------------------------------------
# ct101 backend - domain1
#-----------------------------------------------------------------------------
backend bk-ct101
mode http
option forwardfor
server ct101 192.168.100.101:80 check
#-----------------------------------------------------------------------------
# ct102 backend - domain2
#-----------------------------------------------------------------------------
backend bk-ct102
mode http
option forwardfor
server ct102 192.168.100.102:80 check
#-----------------------------------------------------------------------------
# End-Of-File
#-----------------------------------------------------------------------------
In this configuration, I chose to redirect all traffic from HTTP to HTTPS. All of my certificates are stored inside /etc/ssl/private directory. I generated them using CertBot.
You can adapt this file for your needs but it should work :)

Related

Tinyproxy causes login loop with label studio

I'm using tinyproxy as a forward proxy to proxy request to label studio. I can access the app. However, when I try to log in, the app keeps on redirect me back to the login page. What configuration do I have to change?
(notice the /?next=/projects/ redirects to /user/login/)
Current tinyproxy.conf:
##
## tinyproxy.conf -- tinyproxy daemon configuration file
##
## This example tinyproxy.conf file contains example settings
## with explanations in comments. For decriptions of all
## parameters, see the tinproxy.conf(5) manual page.
##
#
# User/Group: This allows you to set the user and group that will be
# used for tinyproxy after the initial binding to the port has been done
# as the root user. Either the user or group name or the UID or GID
# number may be used.
#
User root
Group root
#
# Port: Specify the port which tinyproxy will listen on. Please note
# that should you choose to run on a port lower than 1024 you will need
# to start tinyproxy using root.
#
Port 8888
#
# Listen: If you have multiple interfaces this allows you to bind to
# only one. If this is commented out, tinyproxy will bind to all
# interfaces present.
#
#Listen 192.168.0.1
#
# Bind: This allows you to specify which interface will be used for
# outgoing connections. This is useful for multi-home'd machines where
# you want all traffic to appear outgoing from one particular interface.
#
#Bind 192.168.0.1
#
# BindSame: If enabled, tinyproxy will bind the outgoing connection to the
# ip address of the incoming connection.
#
#BindSame yes
#
# Timeout: The maximum number of seconds of inactivity a connection is
# allowed to have before it is closed by tinyproxy.
#
Timeout 600
#
# ErrorFile: Defines the HTML file to send when a given HTTP error
# occurs. You will probably need to customize the location to your
# particular install. The usual locations to check are:
# /usr/local/share/tinyproxy
# /usr/share/tinyproxy
# /etc/tinyproxy
#
#ErrorFile 404 "/usr/share/tinyproxy/404.html"
#ErrorFile 400 "/usr/share/tinyproxy/400.html"
#ErrorFile 503 "/usr/share/tinyproxy/503.html"
#ErrorFile 403 "/usr/share/tinyproxy/403.html"
#ErrorFile 408 "/usr/share/tinyproxy/408.html"
#
# DefaultErrorFile: The HTML file that gets sent if there is no
# HTML file defined with an ErrorFile keyword for the HTTP error
# that has occured.
#
DefaultErrorFile "/usr/share/tinyproxy/default.html"
#
# StatHost: This configures the host name or IP address that is treated
# as the stat host: Whenever a request for this host is received,
# Tinyproxy will return an internal statistics page instead of
# forwarding the request to that host. The default value of StatHost is
# tinyproxy.stats.
#
#StatHost "tinyproxy.stats"
#
#
# StatFile: The HTML file that gets sent when a request is made
# for the stathost. If this file doesn't exist a basic page is
# hardcoded in tinyproxy.
#
StatFile "/usr/share/tinyproxy/stats.html"
#
# LogFile: Allows you to specify the location where information should
# be logged to. If you would prefer to log to syslog, then disable this
# and enable the Syslog directive. These directives are mutually
# exclusive. If neither Syslog nor LogFile are specified, output goes
# to stdout.
#
#LogFile "/var/log/tinyproxy/tinyproxy.log"
#
# Syslog: Tell tinyproxy to use syslog instead of a logfile. This
# option must not be enabled if the Logfile directive is being used.
# These two directives are mutually exclusive.
#
#Syslog On
#
# LogLevel: Warning
#
# Set the logging level. Allowed settings are:
# Critical (least verbose)
# Error
# Warning
# Notice
# Connect (to log connections without Info's noise)
# Info (most verbose)
#
# The LogLevel logs from the set level and above. For example, if the
# LogLevel was set to Warning, then all log messages from Warning to
# Critical would be output, but Notice and below would be suppressed.
#
LogLevel Info
#
# PidFile: Write the PID of the main tinyproxy thread to this file so it
# can be used for signalling purposes.
# If not specified, no pidfile will be written.
#
#PidFile "/var/run/tinyproxy/tinyproxy.pid"
#
# XTinyproxy: Tell Tinyproxy to include the X-Tinyproxy header, which
# contains the client's IP address.
#
#XTinyproxy Yes
#
# Upstream:
#
# Turns on upstream proxy support.
#
# The upstream rules allow you to selectively route upstream connections
# based on the host/domain of the site being accessed.
#
# Syntax: upstream type (user:pass#)ip:port ("domain")
# Or: upstream none "domain"
# The parts in parens are optional.
# Possible types are http, socks4, socks5, none
#
# For example:
# # connection to test domain goes through testproxy
# upstream http testproxy:8008 ".test.domain.invalid"
# upstream http testproxy:8008 ".our_testbed.example.com"
# upstream http testproxy:8008 "192.168.128.0/255.255.254.0"
#
# # upstream proxy using basic authentication
# upstream http user:pass#testproxy:8008 ".test.domain.invalid"
#
# # no upstream proxy for internal websites and unqualified hosts
# upstream none ".internal.example.com"
# upstream none "www.example.com"
# upstream none "10.0.0.0/8"
# upstream none "192.168.0.0/255.255.254.0"
# upstream none "."
#
# # connection to these boxes go through their DMZ firewalls
# upstream http cust1_firewall:8008 "testbed_for_cust1"
# upstream http cust2_firewall:8008 "testbed_for_cust2"
#
# # default upstream is internet firewall
# upstream http firewall.internal.example.com:80
#
# You may also use SOCKS4/SOCKS5 upstream proxies:
# upstream socks4 127.0.0.1:9050
# upstream socks5 socksproxy:1080
#
# The LAST matching rule wins the route decision. As you can see, you
# can use a host, or a domain:
# name matches host exactly
# .name matches any host in domain "name"
# . matches any host with no domain (in 'empty' domain)
# IP/bits matches network/mask
# IP/mask matches network/mask
#
#Upstream http some.remote.proxy:port
#
# MaxClients: This is the absolute highest number of threads which will
# be created. In other words, only MaxClients number of clients can be
# connected at the same time.
#
# MaxClients 100
#
# Allow: Customization of authorization controls. If there are any
# access control keywords then the default action is to DENY. Otherwise,
# the default action is ALLOW.
#
# The order of the controls are important. All incoming connections are
# tested against the controls based on order.
#
# Allow 127.0.0.1
# Allow ::1
# BasicAuth: HTTP "Basic Authentication" for accessing the proxy.
# If there are any entries specified, access is only granted for authenticated
# users.
#BasicAuth user password
#
# AddHeader: Adds the specified headers to outgoing HTTP requests that
# Tinyproxy makes. Note that this option will not work for HTTPS
# traffic, as Tinyproxy has no control over what headers are exchanged.
#
#AddHeader "X-My-Header" "Powered by Tinyproxy"
#
# ViaProxyName: The "Via" header is required by the HTTP RFC, but using
# the real host name is a security concern. If the following directive
# is enabled, the string supplied will be used as the host name in the
# Via header; otherwise, the server's host name will be used.
#
ViaProxyName "tinyproxy"
#
# DisableViaHeader: When this is set to yes, Tinyproxy does NOT add
# the Via header to the requests. This virtually puts Tinyproxy into
# stealth mode. Note that RFC 2616 requires proxies to set the Via
# header, so by enabling this option, you break compliance.
# Don't disable the Via header unless you know what you are doing...
#
#DisableViaHeader Yes
#
# Filter: This allows you to specify the location of the filter file.
#
#Filter "/etc/tinyproxy/filter"
#
# FilterURLs: Filter based on URLs rather than domains.
#
#FilterURLs On
#
# FilterExtended: Use POSIX Extended regular expressions rather than
# basic.
#
#FilterExtended On
#
# FilterCaseSensitive: Use case sensitive regular expressions.
#
#FilterCaseSensitive On
#
# FilterDefaultDeny: Change the default policy of the filtering system.
# If this directive is commented out, or is set to "No" then the default
# policy is to allow everything which is not specifically denied by the
# filter file.
#
# However, by setting this directive to "Yes" the default policy becomes
# to deny everything which is _not_ specifically allowed by the filter
# file.
#
#FilterDefaultDeny Yes
#
# Anonymous: If an Anonymous keyword is present, then anonymous proxying
# is enabled. The headers listed are allowed through, while all others
# are denied. If no Anonymous keyword is present, then all headers are
# allowed through. You must include quotes around the headers.
#
# Most sites require cookies to be enabled for them to work correctly, so
# you will need to allow Cookies through if you access those sites.
#
#Anonymous "Host"
#Anonymous "Authorization"
#Anonymous "Cookie"
#
# ConnectPort: This is a list of ports allowed by tinyproxy when the
# CONNECT method is used. To disable the CONNECT method altogether, set
# the value to 0. If no ConnectPort line is found, all ports are
# allowed.
#
# The following two ports are used by SSL.
#
#ConnectPort 443
#ConnectPort 563
#
# Configure one or more ReversePath directives to enable reverse proxy
# support. With reverse proxying it's possible to make a number of
# sites appear as if they were part of a single site.
#
# If you uncomment the following two directives and run tinyproxy
# on your own computer at port 8888, you can access Google using
# http://localhost:8888/google/ and Wired News using
# http://localhost:8888/wired/news/. Neither will actually work
# until you uncomment ReverseMagic as they use absolute linking.
#
#ReversePath "/google/" "http://www.google.com/"
#ReversePath "/wired/" "http://www.wired.com/"
#
# When using tinyproxy as a reverse proxy, it is STRONGLY recommended
# that the normal proxy is turned off by uncommenting the next directive.
#
#ReverseOnly Yes
#
# Use a cookie to track reverse proxy mappings. If you need to reverse
# proxy sites which have absolute links you must uncomment this.
#
#ReverseMagic Yes
#
# The URL that's used to access this reverse proxy. The URL is used to
# rewrite HTTP redirects so that they won't escape the proxy. If you
# have a chain of reverse proxies, you'll need to put the outermost
# URL here (the address which the end user types into his/her browser).
#
# If not set then no rewriting occurs.
#
#ReverseBaseURL "http://localhost:8888/"

How to redirect only select subdomains in HAProxy?

I have several domains such as abc.blah.com, xyz.blah.com, 2a.blah.com, 3b.blah.com and many more. In my haproxy.cfg file I would like to handle only a few of the domains and leave the rest to go their intended destination.
For example:
Redirect abc and xyz to different destinations
abc.blah.com == 10.1.1.11
xyz.blah.com == 10.1.1.12
But not 2a.blah.com or 3b.blah.com or *.blah.com. Let them be directed to the actual destination.
That means 2a.blah.com should go to 2a.blah.com
here is the haproxy.cfg
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
contimeout 5000
clitimeout 50000
srvtimeout 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend http-in
bind 0.0.0.0:80
acl xyz hdr(host) -i xyz.blah.com
acl abc hdr(host) -i abc.blah.com
acl default hdr_end(host) -i .blah.com
## figure out which one to use
use_backend xyz_cluster if xyz
use_backend abc_cluster if abc
use_backend direct_forward if default
# send it to xyz.blah.com
backend xyz_cluster
option forwardfor
server node1 10.1.1.12:8080
# send it to "abc.blah.com"
backend abc_cluster
option forwardfor
server node1 10.1.1.11:8080
# handle 2a.blah.com
# handle 3b.blah.com
# handle *.blah.com
# basically forwarding to the source itself
backend direct_forward
option httpclose
option http_proxy
listen stats :9000
mode http
stats enable
stats hide-version
stats realm Haproxy\ Statistics
stats uri /stats
stats auth test:test123
With this configuration, the requests to xyz and abc are routed correctly.
curl -x 10.148.240.78:80 http://xyz.blah.com
Works fine
But requests to 2a.blah.com are throwing 503
curl -x 10.148.240.78:80 http://2a.blah.com
<html><body><h1>503 Service Unavailable</h1>
No server is available to handle this request.
</body></html>
The haproxy log shows the following,
Mar 30 16:48:17 ubuntu-ha-proxy-3289 haproxy[9105]: 10.254.184.246:54533 [30/Mar/2017:16:48:17.793] http-in direct_forward/<NOSRV> 2/-1/-1/-1/2 503 213 - - SC-- 0/0/0/0/0 0/0 "GET http://2a.blah.com HTTP/1.1"
Basically the direct_forward backend needs to be configured to pass the requests to the source domains itself. But it is unclear how it is achieved in haproxy.
Use default_backend <backend> when no "use_backend" rule has been matched.
When doing content-switching between frontend and backends using the
"use_backend" keyword, it is often useful to indicate which backend will be
used when no rule has matched. It generally is the dynamic backend which
will catch all undetermined requests.
frontend http-in
bind 0.0.0.0:80
acl xyz hdr(host) -i xyz.blah.com
acl abc hdr(host) -i abc.blah.com
## figure out which one to use
use_backend xyz_cluster if xyz
use_backend abc_cluster if abc
default_backend direct_forward
Source: https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#default_backend

HAProxy - rewrite path from domain prefix

I would like to rewrite path from the domain prefix. With two cases :
https://prefix.domain.com/path -> https://prefix.domain.com/path/#/prefix
https://prefix.domain.com/path1 -> https://prefix.domain.com/path1/#/prefix/home
I try to rewrite the path with this config. But I can not extract prefix from domain in reqirep. I think that reqrep is only for GET /XXXX HTTP/1.1 string, not full URL.
acl match path_end -i /path
acl match1 path_end -i /path1
use_backend traefik_path if match
use_backend traefik_path1 if match1
default_backend traefik_path
backend traefik_path
reqirep ^([^\ ]*\ /)path \1/path/#/??
balance roundrobin
server traefik 127.0.0.1:8000 check
backend traefik_path1
reqirep ^([^\ ]*\ /)path1 \1/path1/#/??/home
balance roundrobin
server traefik 127.0.0.1:8000 check

Redirect to new domain based on path in Haproxy

Hello and thanks ahead of time for the help.
I have a blog on my old site and I'm trying to 301 redirect all of the posts to their new location on my new site using haproxy. For example, I want https://www.oldsite.com/john-blog/blogpost1 to be 301 redirected to https://www.newsite.com/jill-blog/blogpost1.
https://www.oldsite.com/john-blog => https://www.newsite.com/jill-blog
frontend https
option http-server-close
reqadd X-Forwarded-Proto:\ https
acl is_ob path_sub john-blog
redirect location https://www.newsite.com/jill-blog code 301 if is_ob
I've figure out how to forward traffic for /john-blog but haven't been able to figure out how to do the rewrite so that /john-blog/blogpost1 on the old site 301s to /jill-blog/blogpost1 on the new site.
This is what I was able to come up with:
frontend https
option http-server-close
reqadd X-Forwarded-Proto:\ https
acl old_site hdr(host) -i www.oldsite.com
acl john_blog path_beg /john-blog
acl jill_blog path_beg /jill-blog
reqrep ^([^\ ]*\ /)john-blog(.*) \1jill-blog\2 if old_site john_blog
redirect prefix https://www.newsite.com code 301 if old_site jill_blog
The only downside of this config is that it will also redirect https://www.oldsite.com/jill-blog => https://www.newsite.com/jill-blog. If this is an issue I can try and figure something else out.
How is works
I will follow and example for a request to https://www.oldsite.com/john-blog/blogpost1.
In this example acl old_site would be true, acl john_blog would be true and acl jill_blog would be false.
The reqrep line replaces john-blog with jill-blog only if both the old_site and john_blog acls are true, which for this example is the case. After this line the example url would be https://www.oldsite.com/jill-blog/blogpost1.
At this point acl john_blog is now no longer true but acl jill_blog is as the uri now begins with /jill-blog. acl old_site is still true.
The redirect line is in prefix mode where the redirect location is determined by the provided string with the original uri appended. In this example the provided string is https://www.newsite.com and the uri that gets appended is /jill-blog/blogpost1 resulting in a reditect url of https://www.newsite.com/jill-blog/blogpost1.
Hope that helps.

Block all other url's in HAPROXY

I have a couple of rules defined in HAPROXY
acl want_server_oa path_dir ServerOA
acl serveroa_avail nbsrv(ServerOA) ge 1
use_backend ServerOA if want_server_oa serveroa_avail
acl is_root hdr_dom(host) -i mydomain.com
use_backend domainRoot if is_root
The first 3 rules were setup to route traffic to a certain subdomain
mydomain.com/ServerOA/
And the next 2 rules to route traffic to just
mydomain.com/
This works as expected. However, if I type in
mydomain.com/anypath/
It gives me a tomcat 404. I suspect the second set of rules match and forward traffic to tomcat which then returns a 404.
Based on the documentation, I did try defining some acls for blocking all other paths which didn't quite work (configuration wasn't accepted when starting haproxy).
block unless METH_GET or METH_POST want_server_oa
block unless METH_GET or METH_POST is_root
Any help would be much appreciated.
You must explicitly define the items you allow to be accessible under the root "mydomain.com/" and subfolders then block all others. (Shouldn't be a lot, right?)
acl want_server_oa path_beg /ServerOA
acl allow_html path_reg -i /.*\.html
acl allow_styles path_reg -i /css/.*\.css
block unless METH_GET want_server_oa or METH_POST want_server_oa or METH_GET allow_html or METH_POST allow_html or METH_GET allow_styles or METH_POST allow_styles
Additional note: You can check if your configuration have any errors by using the haproxy -c command. Like so:
haproxy -f /etc/haproxy/haproxy.cfg -c

Resources