Rewrite Host Header to Server Name

Problem this snippet solves:

On each HTTP request, the selected pool member IP address is looked up against a datagroup and the corresponding hostname is inserted in the HTTP host header.

The iRule expects one string type datagroup to be defined: ip_to_host_dg

If you're using a version lower than 10.0, see the second example. For versions lower than 9.4.4, change the class reference in the second iRule from ip_to_host_dg to $::ip_to_host_dg.

Code :

# Name : host_header_rewrite_rule
#
# HTTP host header rewrite rule
#
# BIG-IP LTM
#   Tested on version 11.1.0 (but should work on 10.x or 11.x)
#
# Version: 1.1 - Initial version tested
#
# Description:
#
# On each HTTP request, the selected pool member IP address is looked up against a datagroup and the corresponding hostname
#   is replaced in the HTTP host header.
#
# Configuration requirements:
#
# 1. This iRule expects a string datagroup named ip_to_host_dg to be defined with the following format:
#
#ltm data-group internal ip_to_host_dg {
#    records {
#        1.1.1.1 {
#            data host1.example.com
#        }
#        1.1.1.2 {
#            data host2.example.com
#        }
#        1.1.1.5 {
#            data host3.example.com
#        }
#    }
#    type string
#}
#
# 2. Each pool member must be configured and any time the pool membership changes, this data group must be updated.
#
when HTTP_REQUEST_SEND {

   # Log debug messages to /var/log/ltm? 1=yes, 0=no.
   set host_debug 1

   # Need to force the host header replacement and HTTP:: commands into the clientside context
   #  as the HTTP_REQUEST_SEND event is in the serverside context
   clientside {

      if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: [HTTP::method] request to [HTTP::host][HTTP::uri]"}

      # Look up the selected server IP in the datagroup to get the host header value
      set host_header_value [class match -value [IP::server_addr] equals ip_to_host_dg]

      if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Looked up [IP::server_addr], found: $host_header_value."}

      # Check if the lookup returned a value
      if {$host_header_value ne ""}{
   
         # Replace the host header value
         HTTP::header replace Host $host_header_value
         if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Replaced Host header with $host_header_value."}
      }
   }
}

# v9.x

# Name : host_header_rewrite_rule (v9.x)
#
# HTTP host header rewrite rule
#
# BIG-IP LTM
#   Tested on version 9.4.8
#
# Version: 1.0 - Initial version tested
#
# Description:
#
# On each HTTP request, the selected pool member IP address is looked up against a datagroup and the corresponding hostname
#   is replaced in the HTTP host header.
#
# Configuration requirements:
#
# 1. This iRule expects a string datagroup named ip_to_host_dg to be defined with the following format:
#
#   pool member IP |  host header to insert
#   ---------------|-------------------
#   1.1.1.1        |  host1.example.com
#   1.1.1.2        |  host2.example.com
#   1.1.1.5        |  host3.example.com
#
# 2. Each pool member must be configured and any time the pool membership changes, this datagroup must be updated.
#
when HTTP_REQUEST_SEND {

   # Log debug messages to /var/log/ltm? 1=yes, 0=no.
   set host_debug 1

   # Need to force the host header replacement and HTTP:: commands into the clientside context
   #  as the HTTP_REQUEST_SEND event is in the serverside context
   clientside {

      if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: New [HTTP::method] request to [HTTP::host][HTTP::uri]"}

      # Look up the selected server IP in the datagroup to get the host header value
      set host_header_value [findclass [LB::server addr] ip_to_host_dg " "]

      if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Looked up [LB::server addr], found: $host_header_value."}

      # Check if the lookup returned a value
      if {$host_header_value ne ""}{
   
         # Replace the host header value
         HTTP::header replace Host $host_header_value
         if {$host_debug}{log local0. "[IP::client_addr]:[TCP::client_port]: Replaced Host header with $host_header_value."}
      }
   }
}
Published Mar 18, 2015
Version 1.0
  • Hey, I used the code above and it worked perfectly when I wanted to replace the hostheader from www.abc.com to "site1" for pool member 1 and "site2" for pool member 2. However the webpage has been hosted on site1/reports and site2/reports. When I enter in my browser http://www.abc.com/reports my url address change to http://site1/reports(it get redirected). How can I fix this? in other words when I enter http://www.abc.com/reports below happens. For Node member 1: Hostheader=site1 uri=site1/reports For Node member 2: Hostheader=site1 uri=site2/reports However we need to have this uri change being transparent from the user perspective. Thanks, Peyman
  • Hi paymon, maybe a bit late (2018 *cough*) but here are some ideas.

     

    1. You could configure your AppServer that its sending relative redirects and no absolute ones.
    2. Configure your AppServer to accept "X-Forwarded-Host"-Headers
    3. Create an iRule with a "HTTP_RESONSE"-Event wich is scanning for redirects and modify the Location-Header

    Have a nice day.