102

I'm using HAProxy for load balancing and only want my site to support https. Thus, I'd like to redirect all requests on port 80 to port 443.

How would I do this?

Edit: We'd like to redirect to the same url on https, preserving query params. Thus, http://foo.com/bar would redirect to https://foo.com/bar

Jon Chu
  • 1,877
  • 2
  • 20
  • 19

17 Answers17

151

I found this to be the biggest help:

Use HAProxy 1.5 or newer, and simply add the following line to the frontend config:

redirect scheme https code 301 if !{ ssl_fc }
Jay Taylor
  • 13,185
  • 11
  • 60
  • 85
  • 22
    To add to this, from User2966600's answer below, with 301 added, use this to redirect to https for only a specific domain: `redirect scheme https code 301 if { hdr(Host) -i www.mydomain.com } !{ ssl_fc }` – Quentin Skousen Jan 21 '15 at 22:03
  • 1
    That worked. Though it doesn't work without 'code 301'. Thanks for update. – deej Dec 16 '16 at 23:29
  • 7
    An equivalent syntax to the given answer would be like this: `http-request redirect scheme https code 301 if !{ ssl_fc }`. The documentation for [http redirection in ALOHA HAProxy 7.0](https://www.haproxy.com/doc/aloha/7.0/haproxy/http_redirection.html) even mention that "_the syntax of both directives is the same, that said, redirect is now considered as legacy and configurations should move to the http-request redirect form_". I infer, without being completely sure, that the same explanation applies to the newer releases of the open source version of HAProxy. – rodolfojcj May 21 '17 at 18:55
  • Thanks for your reply. Could you expand to explain where must we add this line? In the frontend / backend / default / global / .. ? – realtebo Aug 22 '18 at 23:00
  • I usually place it inside the frontend, but redirects are just a header, so I'd expect a redirect can be triggered up until the response headers have been sent. I'd like to know if it can work in both locations, may have to give it a try. – Jay Taylor Aug 23 '18 at 05:28
  • This is perfect – A X Aug 10 '19 at 20:01
  • 1
    **It's important to note this must be in a separate frontend block.** Many example code online have both binds in the same block, and doing a redirect in a dual binded block will prevent haproxy from starting. – Sami Fouad Sep 24 '20 at 07:44
  • To comlement, the { ssl_fc } is a boolean that returns True if the connections was made over SSL. – RicHincapie Feb 05 '21 at 17:10
  • This (good) answer was burried under five zero scored answers - what's going on? – UpTheCreek Sep 30 '21 at 08:34
69

I don't have enough reputation to comment on a previous answer, so I'm posting a new answer to complement Jay Taylor's answer. Basically his answer will do the redirect, an implicit redirect though, meaning it will issue a 302 (temporary redirect), but since the question informs that the entire website will be served as https, then the appropriate redirect should be a 301 (permanent redirect).

redirect scheme https code 301 if !{ ssl_fc }

It seems a small change, but the impact might be huge depending on the website, with a permanent redirect we are informing the browser that it should no longer look for the http version from the start (avoiding future redirects) - a time saver for https sites. It also helps with SEO, but not dividing the juice of your links.

Marcos Abreu
  • 2,832
  • 22
  • 18
42

To redirect all traffic:

redirect scheme https if !{ ssl_fc }

To redirect a single url (In case of multiple frontend/backend)

redirect scheme https if { hdr(Host) -i www.mydomain.com } !{ ssl_fc }

user2966600
  • 571
  • 4
  • 4
21

The best guaranteed way to redirect everything http to https is:

frontend http-in
   bind *:80
   mode http
   redirect scheme https code 301

This is a little fancier using ‘code 301′, but might as well let the client know it’s permanent. The ‘mode http’ part is not essential with default configuration, but can’t hurt. If you have mode tcp in defaults section (like I did), then it’s necessary.

Maitreya
  • 1,237
  • 11
  • 13
  • You might want to use `http-request redirect scheme https code 301` instead because having the prefix `http-request` allows using `log-format` to affect how this is logged: https://docs.haproxy.org/2.4/configuration.html#4.2-http-request%20redirect – Mikko Rantalainen Jan 30 '23 at 13:03
15

According to http://parsnips.net/haproxy-http-to-https-redirect/ it should be as easy as configuring your haproxy.cfg to contain the follow.

#---------------------------------------------------------------------
# Redirect to secured
#---------------------------------------------------------------------
frontend unsecured *:80
    redirect location https://foo.bar.com

#---------------------------------------------------------------------
# frontend secured
#---------------------------------------------------------------------
frontend  secured *:443
   mode  tcp
   default_backend      app

#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend app
    mode  tcp
    balance roundrobin
    server  app1 127.0.0.1:5001 check
    server  app2 127.0.0.1:5002 check
    server  app3 127.0.0.1:5003 check
    server  app4 127.0.0.1:5004 check
Matthew Brown
  • 1,028
  • 3
  • 11
  • 24
  • 7
    So that would redirect everything to https://foo.bar.com. Ideally though, we'd like http://foo.bar.com/baz to redirect to https://foo.bar.com/baz. We also need query params. – Jon Chu Nov 05 '12 at 22:36
  • @JonChu raises a valid use-case, this is only a partial solution. – Jay Taylor May 13 '13 at 18:09
  • 3
    Instead of using redirect location, try redirect prefix https: //foo.bar.com instead. It should help with the use-case Jon Chu mentions. – xangxiong Oct 23 '13 at 04:22
12

A slight variation of user2966600's solution...

To redirect all except a single URL (In case of multiple frontend/backend):

redirect scheme https if !{ hdr(Host) -i www.mydomain.com } !{ ssl_fc }
Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
Josh Currier
  • 121
  • 1
  • 2
4

Like Jay Taylor said, HAProxy 1.5-dev has the redirect scheme configuration directive, which accomplishes exactly what you need.

However, if you are unable to use 1.5, and if you're up for compiling HAProxy from source, I backported the redirect scheme functionality so it works in 1.4. You can get the patch here: http://marc.info/?l=haproxy&m=138456233430692&w=2

rusty
  • 2,771
  • 1
  • 24
  • 23
3

redirect statement is legacy

use http-request redirect instead

acl http      ssl_fc,not
http-request redirect scheme https if http
Amir Jalali
  • 3,132
  • 4
  • 33
  • 46
2
frontend unsecured *:80
    mode http
    redirect location https://foo.bar.com
sanyi
  • 5,999
  • 2
  • 19
  • 30
1

In newer versions of HAProxy it is recommended to use

http-request redirect scheme https if !{ ssl_fc }

to redirect http traffic to https.

That_Guy
  • 34
  • 5
1

Can be done like this -

  frontend http-in
   bind *:80
   mode http
   redirect scheme https code 301

Any traffic hitting http will redirect to https

chandan
  • 93
  • 1
  • 11
1
  acl host-example hdr(host) -i www.example.com

  # for everything not https
  http-request redirect scheme https code 301 unless { ssl_fc }

  # for anything matching acl
  http-request redirect scheme https code 301 if host-example !{ ssl_fc }
b0bu
  • 1,062
  • 1
  • 9
  • 24
0

If you want to rewrite the url, you have to change your site virtualhost adding this lines:

### Enabling mod_rewrite
Options FollowSymLinks
RewriteEngine on

### Rewrite http:// => https://
RewriteCond %{SERVER_PORT} 80$
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,NC,L]

But, if you want to redirect all your requests on the port 80 to the port 443 of the web servers behind the proxy, you can try this example conf on your haproxy.cfg:

##########
# Global #
##########
global
    maxconn 100
    spread-checks 50
    daemon
    nbproc 4

############
# Defaults #
############
defaults
    maxconn 100
    log global
    mode http
    option dontlognull
    retries 3
    contimeout 60000
    clitimeout 60000
    srvtimeout 60000

#####################
# Frontend: HTTP-IN #
#####################
frontend http-in
    bind *:80
    option logasap
    option httplog
    option httpclose
    log global
    default_backend sslwebserver

#########################
# Backend: SSLWEBSERVER #
#########################
backend sslwebserver
    option httplog
    option forwardfor
    option abortonclose
    log global
    balance roundrobin
    # Server List
    server sslws01 webserver01:443 check
    server sslws02 webserver02:443 check
    server sslws03 webserver03:443 check

I hope this help you

Flat
  • 1,640
  • 1
  • 12
  • 14
0

Why don't you use ACL's to distinguish traffic? on top of my head:

acl go_sslwebserver path bar
use_backend sslwebserver if go_sslwebserver

This goes on top of what Matthew Brown answered.

See the ha docs , search for things like hdr_dom and below to find more ACL options. There are plenty of choices.

Glenn Plas
  • 1,608
  • 15
  • 17
0

Add this into the HAProxy frontend config:

acl http      ssl_fc,not
http-request redirect scheme https if http

HAProxy - Redirecting HTTP Requests

Nick Tsai
  • 3,799
  • 33
  • 36
0

Simply:

frontend incoming_requsts
        bind *:80
        bind *:443 ssl crt *path_to_cert*.**pem**
        **http-request redirect scheme https unless { ssl_fc }**
        default_backend k8s_nodes
0

If you want SSL Termination

# Redirects back on port 443
  frontend http_front
    bind *:80
    mode http
    redirect scheme https code 301 if !{ ssl_fc }
# Forward to backend with SSL         
  frontend myfrontend
    mode tcp
    bind *:443
    default_backend myservers
        
   backend myservers
    mode tcp
    server server1 <SERVER IP >
Aidar Gatin
  • 755
  • 1
  • 7
  • 9