Technical Forum
Ask questions. Discover Answers.
cancel
Showing results for 
Search instead for 
Did you mean: 
Custom Alert Banner

redirect http to https

THE_BLUE
Cirrostratus
Cirrostratus

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 3

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!

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
  }
}

crodriguez
Legacy Employee
Legacy Employee

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.