Forum Discussion

THE_BLUE's avatar
THE_BLUE
Icon for Cirrostratus rankCirrostratus
Aug 05, 2021

redirect http to https

I want to redirect Http to Https, for now I have created 2 VS one with port 443 and port 80 and I have used _sys_https_redirect  

rule ( provided by waf) in VS port 80.. so is there any alternative way instated of creating 2 virtuals?

3 Replies

  • Hi  , yes you can achieve it using single virtual server. For this, you can use port list option where you can add multiple services in a single port list group. In your case, it would be 80 and 443. And This port list group will be mapped on the vServer. With this, single virtual server will listen on multiple ports. Once it is done, with the help of irule, you can manage redirections when request is coming on port 80.

     

    Hope it helps!

  • In general, for security purposes, a virtual server's listening scope, as derived by its destination IP address and port combination (among other things), should be kept as narrow as possible to avoid the possibility of it picking up traffic it is not intended to process.

    Two separate virtual servers, one listening on port 80 and the other listening on port 443, make life easier as only the port 80 virtual needs an iRule or local traffic policy to unconditionally do the redirect. (Local traffic policies generally perform better.) For example, below are my two virtual server definitions, the default pool for the port 443 virtual, and the local traffic policy on the port 80 virtual server. Notice the HTTP virtual server has no default pool (doesn't need one as any traffic to this virtual will be unconditionally redirected by the local traffic policy. Notice the HTTPS virtual server does have a default pool. You don't need a client-ssl and server-ssl profile on the HTTPS virtual server if you don't have any processing that requires visibility into the unencrypted layer 7 payload, such as might be required if using an F5 Advanced WAF application security policy or other iRule or local traffic policy:

    ******* VIRTUAL SERVER LISTENING ON PORT 80 *******
    ltm virtual http_vs_103 {
        creation-time 2021-08-05:13:11:58
        destination 10.10.4.103:http
        ip-protocol tcp
        last-modified-time 2021-08-05:13:11:58
        mask 255.255.255.255
        policies {
            devcentral_test_http_redirect { }
        }
        profiles {
            http { }
            tcp { }
        }
        serverssl-use-sni disabled
        source 0.0.0.0/0
        translate-address enabled
        translate-port enabled
        vs-index 8
    }
     
    ******* LOCAL TRAFFIC POLICY FOR PORT 80 VIRTUAL ********
    ltm policy devcentral_test_http_redirect {
        controls { forwarding }
        last-modified 2021-08-05:13:11:19
        requires { http }
        rules {
            perform_redirect {
                actions {
                    0 {
                        http-reply
                        redirect
                        location "tcl: https://[getfield [HTTP::host] : 1][HTTP::uri]"
                    }
                }
            }
        }
        status published
        strategy first-match
    }
     
    ******* VIRTUAL SERVER LISTENING ON PORT 443 *******
    ltm virtual https_vs_103 {
        creation-time 2021-08-05:13:12:28
        destination 10.10.4.103:https
        ip-protocol tcp
        last-modified-time 2021-08-05:13:12:28
        mask 255.255.255.255
        pool https_pool
        profiles {
            clientssl {
                context clientside
            }
            serverssl {
                context serverside
            }
            tcp { }
        }
        serverssl-use-sni disabled
        source 0.0.0.0/0
        translate-address enabled
        translate-port enabled
        vs-index 9
    }
     
    ******* LOAD BALANCING POOL FOR PORT 443 VIRTUAL *******
    ltm pool https_pool {
        members {
            172.16.20.1:https {
                address 172.16.20.1
            }
            172.16.20.2:https {
                address 172.16.20.2
            }
            172.16.20.3:https {
                address 172.16.20.3
            }
        }
    }

    Mayur's suggestion is good if you want to combine the two ports - 80 (HTTP) and 443 (HTTPS) on one virtual server using a port list that contains two ports: 80 and 443. (Port lists are defined under "Shared Objects" in the BIG-IP system's GUI, also known as the Configuration utility.) But it does make things a little more complex as you will also have to conditionally disable SSL on the connection if it is over port 80. An iRule works better for this. For example:

    ***** IRULE ON SINGLE VIRTUAL LISTENING FOR BOTH 443 AND *) *******
    when CLIENT_ACCEPTED {
        set ssl_on true
        SSL::enable
        if { [TCP::local_port] equals 80 } {
            set ssl_on false
        }
    }
     
    when HTTP_REQUEST {
        if { !$ssl_on } {
            HTTP::respond 301 -version 1.1 Location "https://[HTTP::host][HTTP::uri]" Connection "close"
        }
    }
     
    ******* VIRTUAL SERVER LISTENING ON BOTH 443 AND 80 *******
    ltm virtual http_and_https_vs {
        creation-time 2021-08-05:12:12:31
        ip-protocol tcp
        last-modified-time 2021-08-05:12:29:52
        pool https_pool
        profiles {
            clientssl {
                context clientside
            }
            http { }
            serverssl {
                context serverside
            }
            tcp { }
        }
        rules {
            devcentral_test_http_redirect
        }
        serverssl-use-sni disabled
        traffic-matching-criteria http_and_https_vs_VS_TMC_OBJ
        translate-address enabled
        translate-port enabled
        vs-index 7
    }
     
    ******* TRAFFIC MATCHING CRITERIA FOR SINGLE VIRTUAL SERVER *******
    ltm traffic-matching-criteria http_and_https_vs_VS_TMC_OBJ {
        destination-address-inline 10.10.4.102
        destination-port-list http_and_https
        protocol tcp
        source-address-inline 0.0.0.0
    }
     
    ******* PORT LIST DEFINITION *******
    net port-list /Common/http_and_https {
        ports {
            80 { }
            443 { }
        }
    }

    Finally, in Stephan's suggestion, note that load balancing information, such as LB::server port, is not always available yet at the CLIENT_ACCEPTED and HTTP_REQUEST events, assuming an HTTP-type profile is also assigned to the virtual server. When an HTTP profile is assigned, TCP connection setup on the server-side is delayed until after the first HTTP request is received and whatever conditional logic you have defined for the HTTP_REQUEST event (such as in an iRule or local traffic policy) have run. This allows an iRule or local traffic policy to be involved in selecting the pool, pool member, or node to used during a subsequent load balancing decision. You would also want to check the destination port sent by the client (TCP::local_port) not the destination port of the pool member selected by load balancing (LB::server port), as the latter can be different from the former. For example, the client might connect to the virtual server on port 443 (standard browser behavior when using "https://") but the pool members could be configured with alternate non-standard secure ports, such as 8443 (or whatever the server admin's chose).

    One final note, if you are sure your client's never connect to the virtual server using a URL that directly specifies the port (for example, www.f5trn.com:80/...) you can change the redirects to just "https://[HTTP::host][HTTP::uri]" and ditch the getfield command parts, which causes additional overhead.

  • Alternatively you can use a virtual server with port 0.

    The wildcard of 0 lets the virtual listen on all ports.

    Now you need to differentiate the handling depending on the service port.

    This might be done via LTM policy or by iRule as the following one:

    when CLIENT_ACCEPTED {
      switch [LB::server port] {
        80 {
    	  SSL::disable
    	  return
    	}
        443 {
    	  # some other iRule logic on tcp protocol level
    	}
        default {
    	  reject
    	}
      }
    }
    when HTTP_REQUEST {
      if { [LB::server port] == 80 } {
        HTTP::respond 301 \
          noserver \
          Server "redirector" \
          Location https://[getfield [HTTP::host] ":" 1][HTTP::uri] \
          Date [clock format [clock seconds] -format {%a, %b %d %Y %H:%M:%S GMT} -gmt 1] \
          Connection Close
      } else {
        # some other iRule logic on http protocol level
      }
    }