diff --git a/pkg/controller/cache.go b/pkg/controller/cache.go
index 2c676cfdb..e55714ad6 100644
--- a/pkg/controller/cache.go
+++ b/pkg/controller/cache.go
@@ -50,6 +50,18 @@ func (c *cache) GetEndpoints(service *api.Service) (*api.Endpoints, error) {
 	return &ep, err
 }
 
+func (c *cache) GetTerminatingPods(service *api.Service) ([]*api.Pod, error) {
+	pods, err := c.listers.Pod.GetTerminatingServicePods(service)
+	if err != nil {
+		return []*api.Pod{}, err
+	}
+	podRef := make([]*api.Pod, len(pods))
+	for i := range pods {
+		podRef[i] = &pods[i]
+	}
+	return podRef, err
+}
+
 func (c *cache) GetPod(podName string) (*api.Pod, error) {
 	sname := strings.Split(podName, "/")
 	if len(sname) != 2 {
diff --git a/pkg/converters/ingress/annotations/backend.go b/pkg/converters/ingress/annotations/backend.go
index f0c8c9791..951f5238a 100644
--- a/pkg/converters/ingress/annotations/backend.go
+++ b/pkg/converters/ingress/annotations/backend.go
@@ -18,6 +18,8 @@ package annotations
 
 import (
 	"fmt"
+	"net"
+	"regexp"
 	"strconv"
 	"strings"
 
@@ -47,7 +49,7 @@ func (c *updater) buildBackendAffinity(d *backData) {
 	}
 	d.backend.Cookie.Name = name
 	d.backend.Cookie.Strategy = strategy
-	d.backend.Cookie.Key = d.ann.CookieKey
+	d.backend.Cookie.Dynamic = d.ann.SessionCookieDynamic
 }
 
 func (c *updater) buildBackendAuthHTTP(d *backData) {
@@ -80,7 +82,14 @@ func (c *updater) buildBackendAuthHTTP(d *backData) {
 			c.logger.Warn("userlist on %v for basic authentication is empty", d.ann.Source)
 		}
 	}
-	d.backend.HreqValidateUserlist(userlist)
+	d.backend.Userlist.Name = userlist.Name
+	realm := "localhost" // HAProxy's backend name would be used if missing
+	if strings.Index(d.ann.AuthRealm, `"`) >= 0 {
+		c.logger.Warn("ignoring auth-realm with quotes on %v", d.ann.Source)
+	} else if d.ann.AuthRealm != "" {
+		realm = d.ann.AuthRealm
+	}
+	d.backend.Userlist.Realm = realm
 }
 
 func (c *updater) buildBackendAuthHTTPExtractUserlist(source, secret, users string) ([]hatypes.User, []error) {
@@ -167,6 +176,10 @@ func (c *updater) buildBackendBlueGreen(d *backData) {
 		deployWeights = append(deployWeights, dw)
 	}
 	for _, ep := range d.backend.Endpoints {
+		if ep.Weight == 0 {
+			// Draining endpoint, remove from blue/green calc
+			continue
+		}
 		hasLabel := false
 		if pod, err := c.cache.GetPod(ep.TargetRef); err == nil {
 			for _, dw := range deployWeights {
@@ -261,3 +274,138 @@ func (c *updater) buildBackendBlueGreen(d *backData) {
 		}
 	}
 }
+
+var (
+	corsOriginRegex  = regexp.MustCompile(`^(https?://[A-Za-z0-9\-\.]*(:[0-9]+)?|\*)?$`)
+	corsMethodsRegex = regexp.MustCompile(`^([A-Za-z]+,?\s?)+$`)
+	corsHeadersRegex = regexp.MustCompile(`^([A-Za-z0-9\-\_]+,?\s?)+$`)
+)
+
+func (c *updater) buildBackendCors(d *backData) {
+	if !d.ann.CorsEnable {
+		return
+	}
+	d.backend.Cors.Enabled = true
+	if d.ann.CorsAllowOrigin != "" && corsOriginRegex.MatchString(d.ann.CorsAllowOrigin) {
+		d.backend.Cors.AllowOrigin = d.ann.CorsAllowOrigin
+	} else {
+		d.backend.Cors.AllowOrigin = "*"
+	}
+	if corsHeadersRegex.MatchString(d.ann.CorsAllowHeaders) {
+		d.backend.Cors.AllowHeaders = d.ann.CorsAllowHeaders
+	} else {
+		d.backend.Cors.AllowHeaders =
+			"DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization"
+	}
+	if corsMethodsRegex.MatchString(d.ann.CorsAllowMethods) {
+		d.backend.Cors.AllowMethods = d.ann.CorsAllowMethods
+	} else {
+		d.backend.Cors.AllowMethods = "GET, PUT, POST, DELETE, PATCH, OPTIONS"
+	}
+	d.backend.Cors.AllowCredentials = d.ann.CorsAllowCredentials
+	if d.ann.CorsMaxAge > 0 {
+		d.backend.Cors.MaxAge = d.ann.CorsMaxAge
+	} else {
+		d.backend.Cors.MaxAge = 86400
+	}
+	if corsHeadersRegex.MatchString(d.ann.CorsExposeHeaders) {
+		d.backend.Cors.ExposeHeaders = d.ann.CorsExposeHeaders
+	}
+}
+
+var (
+	oauthHeaderRegex = regexp.MustCompile(`^[A-Za-z0-9-]+:[A-Za-z0-9-_]+$`)
+)
+
+func (c *updater) buildOAuth(d *backData) {
+	if d.ann.OAuth == "" {
+		return
+	}
+	if d.ann.OAuth != "oauth2_proxy" {
+		c.logger.Warn("ignoring invalid oauth implementation '%s' on %v", d.ann.OAuth, d.ann.Source)
+		return
+	}
+	uriPrefix := "/oauth2"
+	headers := []string{"X-Auth-Request-Email:auth_response_email"}
+	if d.ann.OAuthURIPrefix != "" {
+		uriPrefix = d.ann.OAuthURIPrefix
+	}
+	if d.ann.OAuthHeaders != "" {
+		headers = strings.Split(d.ann.OAuthHeaders, ",")
+	}
+	uriPrefix = strings.TrimRight(uriPrefix, "/")
+	namespace := d.ann.Source.Namespace
+	backend := c.findBackend(namespace, uriPrefix)
+	if backend == nil {
+		c.logger.Error("path '%s' was not found on namespace '%s'", uriPrefix, namespace)
+		return
+	}
+	headersMap := make(map[string]string, len(headers))
+	for _, header := range headers {
+		if len(header) == 0 {
+			continue
+		}
+		if !oauthHeaderRegex.MatchString(header) {
+			c.logger.Warn("invalid header format '%s' on %v", header, d.ann.Source)
+			continue
+		}
+		h := strings.Split(header, ":")
+		headersMap[h[0]] = h[1]
+	}
+	d.backend.OAuth.Impl = d.ann.OAuth
+	d.backend.OAuth.BackendName = backend.ID
+	d.backend.OAuth.URIPrefix = uriPrefix
+	d.backend.OAuth.Headers = headersMap
+}
+
+func (c *updater) findBackend(namespace, uriPrefix string) *hatypes.Backend {
+	for _, host := range c.haproxy.Hosts() {
+		for _, path := range host.Paths {
+			if strings.TrimRight(path.Path, "/") == uriPrefix && path.Backend.Namespace == namespace {
+				return path.Backend
+			}
+		}
+	}
+	return nil
+}
+
+var (
+	rewriteURLRegex = regexp.MustCompile(`^[^"' ]+$`)
+)
+
+func (c *updater) buildRewriteURL(d *backData) {
+	if d.ann.RewriteTarget == "" {
+		return
+	}
+	if !rewriteURLRegex.MatchString(d.ann.RewriteTarget) {
+		c.logger.Warn("rewrite-target does not allow white spaces or single/double quotes on %v", d.ann.Source)
+		return
+	}
+	d.backend.RewriteURL = d.ann.RewriteTarget
+}
+
+func (c *updater) buildWAF(d *backData) {
+	if d.ann.WAF == "" {
+		return
+	}
+	if d.ann.WAF != "modsecurity" {
+		c.logger.Warn("ignoring invalid WAF mode: %s", d.ann.WAF)
+		return
+	}
+	d.backend.WAF = d.ann.WAF
+}
+
+func (c *updater) buildWhitelist(d *backData) {
+	if d.ann.WhitelistSourceRange == "" {
+		return
+	}
+	var cidrlist []string
+	for _, cidr := range strings.Split(d.ann.WhitelistSourceRange, ",") {
+		if _, _, err := net.ParseCIDR(cidr); err != nil {
+			c.logger.Warn("skipping invalid cidr '%s' in whitelist config on %v", cidr, d.ann.Source)
+		} else {
+			cidrlist = append(cidrlist, cidr)
+		}
+	}
+	d.backend.Whitelist = cidrlist
+}
diff --git a/pkg/converters/ingress/annotations/backend_test.go b/pkg/converters/ingress/annotations/backend_test.go
index 681e33679..121617543 100644
--- a/pkg/converters/ingress/annotations/backend_test.go
+++ b/pkg/converters/ingress/annotations/backend_test.go
@@ -18,6 +18,7 @@ package annotations
 
 import (
 	"reflect"
+	"strconv"
 	"strings"
 	"testing"
 
@@ -71,14 +72,14 @@ func TestAffinity(t *testing.T) {
 		},
 		// 6
 		{
-			ann:        types.BackendAnnotations{Affinity: "cookie", SessionCookieStrategy: "prefix"},
-			expCookie:  hatypes.Cookie{Name: "INGRESSCOOKIE", Strategy: "prefix"},
+			ann:        types.BackendAnnotations{Affinity: "cookie", SessionCookieStrategy: "prefix", SessionCookieDynamic: true},
+			expCookie:  hatypes.Cookie{Name: "INGRESSCOOKIE", Strategy: "prefix", Dynamic: true},
 			expLogging: "",
 		},
 		// 7
 		{
-			ann:        types.BackendAnnotations{Affinity: "cookie", CookieKey: "ha"},
-			expCookie:  hatypes.Cookie{Name: "INGRESSCOOKIE", Strategy: "insert", Key: "ha"},
+			ann:        types.BackendAnnotations{Affinity: "cookie", SessionCookieDynamic: false},
+			expCookie:  hatypes.Cookie{Name: "INGRESSCOOKIE", Strategy: "insert", Dynamic: false},
 			expLogging: "",
 		},
 	}
@@ -98,13 +99,12 @@ func TestAffinity(t *testing.T) {
 
 func TestAuthHTTP(t *testing.T) {
 	testCase := []struct {
-		namespace       string
-		ingname         string
-		ann             types.BackendAnnotations
-		secrets         ing_helper.SecretContent
-		expUserlists    []*hatypes.Userlist
-		expHTTPRequests []*hatypes.HTTPRequest
-		expLogging      string
+		namespace    string
+		ingname      string
+		ann          types.BackendAnnotations
+		secrets      ing_helper.SecretContent
+		expUserlists []*hatypes.Userlist
+		expLogging   string
 	}{
 		// 0
 		{
@@ -134,25 +134,32 @@ func TestAuthHTTP(t *testing.T) {
 		},
 		// 5
 		{
-			namespace:       "ns1",
-			ingname:         "i1",
-			ann:             types.BackendAnnotations{AuthType: "basic", AuthSecret: "mypwd"},
-			secrets:         ing_helper.SecretContent{"ns1/mypwd": {"auth": []byte{}}},
-			expUserlists:    []*hatypes.Userlist{&hatypes.Userlist{Name: "ns1_mypwd"}},
-			expHTTPRequests: []*hatypes.HTTPRequest{{}},
-			expLogging:      "WARN userlist on ingress 'ns1/i1' for basic authentication is empty",
+			ann:     types.BackendAnnotations{AuthType: "basic", AuthSecret: "mypwd", AuthRealm: `"a name"`},
+			secrets: ing_helper.SecretContent{"default/mypwd": {"auth": []byte("usr1::clear1")}},
+			expUserlists: []*hatypes.Userlist{&hatypes.Userlist{Name: "default_mypwd", Users: []hatypes.User{
+				{Name: "usr1", Passwd: "clear1", Encrypted: false},
+			}}},
+			expLogging: "WARN ignoring auth-realm with quotes on ingress 'default/ing1'",
 		},
 		// 6
 		{
-			ann:             types.BackendAnnotations{AuthType: "basic", AuthSecret: "basicpwd"},
-			secrets:         ing_helper.SecretContent{"default/basicpwd": {"auth": []byte("fail")}},
-			expUserlists:    []*hatypes.Userlist{&hatypes.Userlist{Name: "default_basicpwd"}},
-			expHTTPRequests: []*hatypes.HTTPRequest{{}},
+			namespace:    "ns1",
+			ingname:      "i1",
+			ann:          types.BackendAnnotations{AuthType: "basic", AuthSecret: "mypwd"},
+			secrets:      ing_helper.SecretContent{"ns1/mypwd": {"auth": []byte{}}},
+			expUserlists: []*hatypes.Userlist{&hatypes.Userlist{Name: "ns1_mypwd"}},
+			expLogging:   "WARN userlist on ingress 'ns1/i1' for basic authentication is empty",
+		},
+		// 7
+		{
+			ann:          types.BackendAnnotations{AuthType: "basic", AuthSecret: "basicpwd"},
+			secrets:      ing_helper.SecretContent{"default/basicpwd": {"auth": []byte("fail")}},
+			expUserlists: []*hatypes.Userlist{&hatypes.Userlist{Name: "default_basicpwd"}},
 			expLogging: `
 WARN ignoring malformed usr/passwd on secret 'default/basicpwd', declared on ingress 'default/ing1': missing password of user 'fail' line 1
 WARN userlist on ingress 'default/ing1' for basic authentication is empty`,
 		},
-		// 7
+		// 8
 		{
 			ann: types.BackendAnnotations{AuthType: "basic", AuthSecret: "basicpwd"},
 			secrets: ing_helper.SecretContent{"default/basicpwd": {"auth": []byte(`
@@ -161,10 +168,9 @@ nopwd`)}},
 			expUserlists: []*hatypes.Userlist{&hatypes.Userlist{Name: "default_basicpwd", Users: []hatypes.User{
 				{Name: "usr1", Passwd: "clearpwd1", Encrypted: false},
 			}}},
-			expHTTPRequests: []*hatypes.HTTPRequest{{}},
-			expLogging:      "WARN ignoring malformed usr/passwd on secret 'default/basicpwd', declared on ingress 'default/ing1': missing password of user 'nopwd' line 3",
+			expLogging: "WARN ignoring malformed usr/passwd on secret 'default/basicpwd', declared on ingress 'default/ing1': missing password of user 'nopwd' line 3",
 		},
-		// 8
+		// 9
 		{
 			ann: types.BackendAnnotations{AuthType: "basic", AuthSecret: "basicpwd"},
 			secrets: ing_helper.SecretContent{"default/basicpwd": {"auth": []byte(`
@@ -172,8 +178,7 @@ usrnopwd1:
 usrnopwd2::
 :encpwd3
 ::clearpwd4`)}},
-			expUserlists:    []*hatypes.Userlist{&hatypes.Userlist{Name: "default_basicpwd"}},
-			expHTTPRequests: []*hatypes.HTTPRequest{{}},
+			expUserlists: []*hatypes.Userlist{&hatypes.Userlist{Name: "default_basicpwd"}},
 			expLogging: `
 WARN ignoring malformed usr/passwd on secret 'default/basicpwd', declared on ingress 'default/ing1': missing password of user 'usrnopwd1' line 2
 WARN ignoring malformed usr/passwd on secret 'default/basicpwd', declared on ingress 'default/ing1': missing password of user 'usrnopwd2' line 3
@@ -181,7 +186,7 @@ WARN ignoring malformed usr/passwd on secret 'default/basicpwd', declared on ing
 WARN ignoring malformed usr/passwd on secret 'default/basicpwd', declared on ingress 'default/ing1': missing username line 5
 WARN userlist on ingress 'default/ing1' for basic authentication is empty`,
 		},
-		// 9
+		// 10
 		{
 			ann: types.BackendAnnotations{AuthType: "basic", AuthSecret: "basicpwd"},
 			secrets: ing_helper.SecretContent{"default/basicpwd": {"auth": []byte(`
@@ -191,8 +196,7 @@ usr2::clearpwd2`)}},
 				{Name: "usr1", Passwd: "encpwd1", Encrypted: true},
 				{Name: "usr2", Passwd: "clearpwd2", Encrypted: false},
 			}}},
-			expHTTPRequests: []*hatypes.HTTPRequest{{}},
-			expLogging:      "",
+			expLogging: "",
 		},
 	}
 
@@ -210,13 +214,9 @@ usr2::clearpwd2`)}},
 		d := c.createBackendData(test.namespace, test.ingname, &test.ann)
 		u.buildBackendAuthHTTP(d)
 		userlists := u.haproxy.Userlists()
-		httpRequests := d.backend.HTTPRequests
 		if len(userlists)+len(test.expUserlists) > 0 && !reflect.DeepEqual(test.expUserlists, userlists) {
 			t.Errorf("userlists config %d differs - expected: %+v - actual: %+v", i, test.expUserlists, userlists)
 		}
-		if len(httpRequests)+len(test.expHTTPRequests) > 0 && !reflect.DeepEqual(test.expHTTPRequests, httpRequests) {
-			t.Errorf("httprequest config %d differs - expected: %+v - actual: %+v", i, test.expHTTPRequests, httpRequests)
-		}
 		c.logger.CompareLogging(test.expLogging)
 		c.teardown()
 	}
@@ -244,11 +244,20 @@ func TestBlueGreen(t *testing.T) {
 		ep := []*hatypes.Endpoint{}
 		if targets != "" {
 			for _, targetRef := range strings.Split(targets, ",") {
+				targetWeight := strings.Split(targetRef, "=")
+				target := targetRef
+				weight := 1
+				if len(targetWeight) == 2 {
+					target = targetWeight[0]
+					if w, err := strconv.ParseInt(targetWeight[1], 10, 0); err == nil {
+						weight = int(w)
+					}
+				}
 				ep = append(ep, &hatypes.Endpoint{
 					IP:        "172.17.0.11",
 					Port:      8080,
-					Weight:    1,
-					TargetRef: targetRef,
+					Weight:    weight,
+					TargetRef: target,
 				})
 			}
 		}
@@ -481,6 +490,13 @@ INFO-V(3) blue/green balance label 'v=3' on ingress 'default/ing1' does not refe
 			expWeights: []int{256, 1, 1, 1, 1},
 			expLogging: "",
 		},
+		// 29
+		{
+			ann:        buildAnn("v=1=50,v=2=50", "deploy"),
+			endpoints:  buildEndpoints("pod0101-01,pod0101-02,pod0102-01,pod0102-02=0"),
+			expWeights: []int{1, 1, 2, 0},
+			expLogging: "",
+		},
 	}
 
 	for i, test := range testCase {
@@ -501,3 +517,239 @@ INFO-V(3) blue/green balance label 'v=3' on ingress 'default/ing1' does not refe
 		c.teardown()
 	}
 }
+
+func TestOAuth(t *testing.T) {
+	testCases := []struct {
+		ann      types.BackendAnnotations
+		backend  string
+		oauthExp hatypes.OAuthConfig
+		logging  string
+	}{
+		// 0
+		{
+			ann:      types.BackendAnnotations{},
+			oauthExp: hatypes.OAuthConfig{},
+		},
+		// 1
+		{
+			ann:     types.BackendAnnotations{OAuth: "none"},
+			logging: "WARN ignoring invalid oauth implementation 'none' on ingress 'default/app'",
+		},
+		// 2
+		{
+			ann:     types.BackendAnnotations{OAuth: "oauth2_proxy"},
+			logging: "ERROR path '/oauth2' was not found on namespace 'default'",
+		},
+		// 3
+		{
+			ann:     types.BackendAnnotations{OAuth: "oauth2_proxy"},
+			backend: "default:back:/oauth2",
+			oauthExp: hatypes.OAuthConfig{
+				Impl:        "oauth2_proxy",
+				BackendName: "default_back_8080",
+				URIPrefix:   "/oauth2",
+				Headers:     map[string]string{"X-Auth-Request-Email": "auth_response_email"},
+			},
+		},
+		// 4
+		{
+			ann:     types.BackendAnnotations{OAuth: "oauth2_proxy", OAuthURIPrefix: "/auth"},
+			backend: "default:back:/auth",
+			oauthExp: hatypes.OAuthConfig{
+				Impl:        "oauth2_proxy",
+				BackendName: "default_back_8080",
+				URIPrefix:   "/auth",
+				Headers:     map[string]string{"X-Auth-Request-Email": "auth_response_email"},
+			},
+		},
+		// 5
+		{
+			ann:     types.BackendAnnotations{OAuth: "oauth2_proxy", OAuthHeaders: "X-Auth-New:attr_from_lua"},
+			backend: "default:back:/oauth2",
+			oauthExp: hatypes.OAuthConfig{
+				Impl:        "oauth2_proxy",
+				BackendName: "default_back_8080",
+				URIPrefix:   "/oauth2",
+				Headers:     map[string]string{"X-Auth-New": "attr_from_lua"},
+			},
+		},
+		// 6
+		{
+			ann:     types.BackendAnnotations{OAuth: "oauth2_proxy", OAuthHeaders: "space before:attr"},
+			backend: "default:back:/oauth2",
+			oauthExp: hatypes.OAuthConfig{
+				Impl:        "oauth2_proxy",
+				BackendName: "default_back_8080",
+				URIPrefix:   "/oauth2",
+				Headers:     map[string]string{},
+			},
+			logging: "WARN invalid header format 'space before:attr' on ingress 'default/app'",
+		},
+		// 7
+		{
+			ann:     types.BackendAnnotations{OAuth: "oauth2_proxy", OAuthHeaders: "no-colon"},
+			backend: "default:back:/oauth2",
+			oauthExp: hatypes.OAuthConfig{
+				Impl:        "oauth2_proxy",
+				BackendName: "default_back_8080",
+				URIPrefix:   "/oauth2",
+				Headers:     map[string]string{},
+			},
+			logging: "WARN invalid header format 'no-colon' on ingress 'default/app'",
+		},
+		// 8
+		{
+			ann:     types.BackendAnnotations{OAuth: "oauth2_proxy", OAuthHeaders: "more:colons:unsupported"},
+			backend: "default:back:/oauth2",
+			oauthExp: hatypes.OAuthConfig{
+				Impl:        "oauth2_proxy",
+				BackendName: "default_back_8080",
+				URIPrefix:   "/oauth2",
+				Headers:     map[string]string{},
+			},
+			logging: "WARN invalid header format 'more:colons:unsupported' on ingress 'default/app'",
+		},
+		// 9
+		{
+			ann: types.BackendAnnotations{
+				OAuth:        "oauth2_proxy",
+				OAuthHeaders: ",,X-Auth-Request-Email:auth_response_email,,X-Auth-New:attr_from_lua,",
+			},
+			backend: "default:back:/oauth2",
+			oauthExp: hatypes.OAuthConfig{
+				Impl:        "oauth2_proxy",
+				BackendName: "default_back_8080",
+				URIPrefix:   "/oauth2",
+				Headers: map[string]string{
+					"X-Auth-Request-Email": "auth_response_email",
+					"X-Auth-New":           "attr_from_lua",
+				},
+			},
+		},
+	}
+	for i, test := range testCases {
+		c := setup(t)
+		d := c.createBackendData("default", "app", &test.ann)
+		if test.backend != "" {
+			b := strings.Split(test.backend, ":")
+			backend := c.haproxy.AcquireBackend(b[0], b[1], "8080")
+			c.haproxy.AcquireHost("app.local").AddPath(backend, b[2])
+		}
+		c.createUpdater().buildOAuth(d)
+		if !reflect.DeepEqual(test.oauthExp, d.backend.OAuth) {
+			t.Errorf("oauth on %d differs - expected: %+v - actual: %+v", i, test.oauthExp, d.backend.OAuth)
+		}
+		c.logger.CompareLogging(test.logging)
+		c.teardown()
+	}
+}
+
+func TestRewriteURL(t *testing.T) {
+	testCases := []struct {
+		input    string
+		expected string
+		logging  string
+	}{
+		// 0
+		{
+			input:    ``,
+			expected: ``,
+		},
+		// 1
+		{
+			input:    `/"/`,
+			expected: ``,
+			logging:  `WARN rewrite-target does not allow white spaces or single/double quotes on ingress 'default/app'`,
+		},
+		// 2
+		{
+			input:    `/app`,
+			expected: `/app`,
+		},
+	}
+
+	for i, test := range testCases {
+		c := setup(t)
+		d := c.createBackendData("default", "app", &types.BackendAnnotations{RewriteTarget: test.input})
+		c.createUpdater().buildRewriteURL(d)
+		if d.backend.RewriteURL != test.expected {
+			t.Errorf("rewrite on %d differs - expected: %v - actual: %v", i, test.expected, d.backend.RewriteURL)
+		}
+		c.logger.CompareLogging(test.logging)
+		c.teardown()
+	}
+}
+
+func TestWAF(t *testing.T) {
+	testCase := []struct {
+		waf      string
+		expected string
+		logging  string
+	}{
+		{
+			waf:      "",
+			expected: "",
+			logging:  "",
+		},
+		{
+			waf:      "none",
+			expected: "",
+			logging:  "WARN ignoring invalid WAF mode: none",
+		},
+		{
+			waf:      "modsecurity",
+			expected: "modsecurity",
+			logging:  "",
+		},
+	}
+	for i, test := range testCase {
+		c := setup(t)
+		d := c.createBackendData("default", "app", &types.BackendAnnotations{WAF: test.waf})
+		c.createUpdater().buildWAF(d)
+		if d.backend.WAF != test.expected {
+			t.Errorf("WAF on %d differs - expected: %v - actual: %v", i, test.expected, d.backend.WAF)
+		}
+		c.logger.CompareLogging(test.logging)
+		c.teardown()
+	}
+}
+
+func TestWhitelist(t *testing.T) {
+	testCase := []struct {
+		cidrlist string
+		expected []string
+		logging  string
+	}{
+		// 0
+		{
+			cidrlist: "10.0.0.0/8,192.168.0.0/16",
+			expected: []string{"10.0.0.0/8", "192.168.0.0/16"},
+		},
+		// 1
+		{
+			cidrlist: "10.0.0.0/8,192.168.0/16",
+			expected: []string{"10.0.0.0/8"},
+			logging:  `WARN skipping invalid cidr '192.168.0/16' in whitelist config on ingress 'default/app'`,
+		},
+		// 2
+		{
+			cidrlist: "10.0.0/8,192.168.0/16",
+			expected: []string{},
+			logging: `
+WARN skipping invalid cidr '10.0.0/8' in whitelist config on ingress 'default/app'
+WARN skipping invalid cidr '192.168.0/16' in whitelist config on ingress 'default/app'`,
+		},
+	}
+	for i, test := range testCase {
+		c := setup(t)
+		d := c.createBackendData("default", "app", &types.BackendAnnotations{WhitelistSourceRange: test.cidrlist})
+		c.createUpdater().buildWhitelist(d)
+		if !reflect.DeepEqual(d.backend.Whitelist, test.expected) {
+			if len(d.backend.Whitelist) > 0 || len(test.expected) > 0 {
+				t.Errorf("whitelist on %d differs - expected: %v - actual: %v", i, test.expected, d.backend.Whitelist)
+			}
+		}
+		c.logger.CompareLogging(test.logging)
+		c.teardown()
+	}
+}
diff --git a/pkg/converters/ingress/annotations/global.go b/pkg/converters/ingress/annotations/global.go
index 92f397bb7..38f6e80e0 100644
--- a/pkg/converters/ingress/annotations/global.go
+++ b/pkg/converters/ingress/annotations/global.go
@@ -18,6 +18,7 @@ package annotations
 
 import (
 	"fmt"
+	"regexp"
 	"strings"
 )
 
@@ -99,6 +100,7 @@ func (c *updater) buildGlobalSSL(d *globalData) {
 	d.global.SSL.DHParam.DefaultMaxSize = d.config.SSLDHDefaultMaxSize
 	d.global.SSL.Engine = d.config.SSLEngine
 	d.global.SSL.ModeAsync = d.config.SSLModeAsync
+	d.global.SSL.HeadersPrefix = d.config.SSLHeadersPrefix
 }
 
 func (c *updater) buildGlobalModSecurity(d *globalData) {
@@ -108,9 +110,26 @@ func (c *updater) buildGlobalModSecurity(d *globalData) {
 	d.global.ModSecurity.Timeout.Processing = d.config.ModsecurityTimeoutProcessing
 }
 
+var (
+	forwardRegex = regexp.MustCompile(`^(add|ignore|ifmissing)$`)
+)
+
+func (c *updater) buildGlobalForwardFor(d *globalData) {
+	if forwardRegex.MatchString(d.config.Forwardfor) {
+		d.global.ForwardFor = d.config.Forwardfor
+	} else {
+		if d.config.Forwardfor != "" {
+			c.logger.Warn("Invalid forwardfor value option on configmap: '%s'. Using 'add' instead", d.config.Forwardfor)
+		}
+		d.global.ForwardFor = "add"
+	}
+}
+
 func (c *updater) buildGlobalCustomConfig(d *globalData) {
 	if d.config.ConfigGlobal != "" {
 		d.global.CustomConfig = strings.Split(strings.TrimRight(d.config.ConfigGlobal, "\n"), "\n")
+	}
+	if d.config.ConfigGlobals.ConfigDefaults != "" {
 		d.global.CustomDefaults = strings.Split(strings.TrimRight(d.config.ConfigGlobals.ConfigDefaults, "\n"), "\n")
 	}
 }
diff --git a/pkg/converters/ingress/annotations/global_test.go b/pkg/converters/ingress/annotations/global_test.go
new file mode 100644
index 000000000..a298e14a9
--- /dev/null
+++ b/pkg/converters/ingress/annotations/global_test.go
@@ -0,0 +1,77 @@
+/*
+Copyright 2019 The HAProxy Ingress Controller Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package annotations
+
+import (
+	"testing"
+
+	"github.com/jcmoraisjr/haproxy-ingress/pkg/converters/ingress/types"
+)
+
+func TestForwardFor(t *testing.T) {
+	testCases := []struct {
+		conf     string
+		expected string
+		logging  string
+	}{
+		// 0
+		{
+			conf:     "",
+			expected: "add",
+			logging:  "",
+		},
+		// 1
+		{
+			conf:     "non",
+			expected: "add",
+			logging:  "WARN Invalid forwardfor value option on configmap: 'non'. Using 'add' instead",
+		},
+		// 2
+		{
+			conf:     "add",
+			expected: "add",
+			logging:  "",
+		},
+		// 3
+		{
+			conf:     "ignore",
+			expected: "ignore",
+			logging:  "",
+		},
+		// 4
+		{
+			conf:     "ifmissing",
+			expected: "ifmissing",
+			logging:  "",
+		},
+	}
+	for i, test := range testCases {
+		c := setup(t)
+		u := c.createUpdater()
+		d := c.createGlobalData(&types.Config{
+			ConfigGlobals: types.ConfigGlobals{
+				Forwardfor: test.conf,
+			},
+		})
+		u.buildGlobalForwardFor(d)
+		if d.global.ForwardFor != test.expected {
+			t.Errorf("ForwardFor differs on %d: expected '%s' but was '%s'", i, test.expected, d.global.ForwardFor)
+		}
+		c.logger.CompareLogging(test.logging)
+		c.teardown()
+	}
+}
diff --git a/pkg/converters/ingress/annotations/host.go b/pkg/converters/ingress/annotations/host.go
index bed6ace48..086adc5e1 100644
--- a/pkg/converters/ingress/annotations/host.go
+++ b/pkg/converters/ingress/annotations/host.go
@@ -29,7 +29,6 @@ func (c *updater) buildHostAuthTLS(d *hostData) {
 		d.host.TLS.CAHash = cafile.SHA1Hash
 		d.host.TLS.CAVerifyOptional = verify == "optional" || verify == "optional_no_ca"
 		d.host.TLS.CAErrorPage = d.ann.AuthTLSErrorPage
-		d.host.TLS.AddCertHeader = d.ann.AuthTLSCertHeader
 	} else {
 		c.logger.Error("error building TLS auth config: %v", err)
 	}
@@ -49,7 +48,7 @@ func (c *updater) buildHostSSLPassthrough(d *hostData) {
 			c.logger.Warn("ignoring path '%s' from '%s': ssl-passthrough only support root path", path.Path, d.ann.Source)
 		}
 	}
-	if d.ann.SSLPassthroughHTTPPort != 0 {
+	if d.ann.SSLPassthroughHTTPPort != "" {
 		httpBackend := c.haproxy.FindBackend(rootPath.Backend.Namespace, rootPath.Backend.Name, d.ann.SSLPassthroughHTTPPort)
 		d.host.HTTPPassthroughBackend = httpBackend
 	}
diff --git a/pkg/converters/ingress/annotations/updater.go b/pkg/converters/ingress/annotations/updater.go
index 700d48e81..fe17be33d 100644
--- a/pkg/converters/ingress/annotations/updater.go
+++ b/pkg/converters/ingress/annotations/updater.go
@@ -73,15 +73,20 @@ func (c *updater) UpdateGlobalConfig(global *hatypes.Global, config *ingtypes.Co
 	global.Syslog.Endpoint = config.SyslogEndpoint
 	global.Syslog.Format = config.SyslogFormat
 	global.Syslog.Tag = config.SyslogTag
+	global.Syslog.HTTPLogFormat = config.HTTPLogFormat
+	global.Syslog.HTTPSLogFormat = config.HTTPSLogFormat
+	global.Syslog.TCPLogFormat = config.TCPLogFormat
 	global.MaxConn = config.MaxConnections
-	global.DrainSupport = config.DrainSupport
-	global.DrainSupportRedispatch = config.DrainSupportRedispatch
+	global.DrainSupport.Drain = config.DrainSupport
+	global.DrainSupport.Redispatch = config.DrainSupportRedispatch
+	global.Cookie.Key = config.CookieKey
 	global.LoadServerState = config.LoadServerState
 	global.StatsSocket = "/var/run/haproxy-stats.sock"
 	c.buildGlobalProc(data)
 	c.buildGlobalTimeout(data)
 	c.buildGlobalSSL(data)
 	c.buildGlobalModSecurity(data)
+	c.buildGlobalForwardFor(data)
 	c.buildGlobalCustomConfig(data)
 }
 
@@ -106,10 +111,20 @@ func (c *updater) UpdateBackendConfig(backend *hatypes.Backend, ann *ingtypes.Ba
 	}
 	// TODO check ModeTCP with HTTP annotations
 	backend.BalanceAlgorithm = ann.BalanceAlgorithm
+	backend.HSTS.Enabled = ann.HSTS
+	backend.HSTS.MaxAge = ann.HSTSMaxAge
+	backend.HSTS.Preload = ann.HSTSPreload
+	backend.HSTS.Subdomains = ann.HSTSIncludeSubdomains
 	backend.MaxConnServer = ann.MaxconnServer
 	backend.ProxyBodySize = ann.ProxyBodySize
 	backend.SSLRedirect = ann.SSLRedirect
+	backend.SSL.AddCertHeader = ann.AuthTLSCertHeader
 	c.buildBackendAffinity(data)
 	c.buildBackendAuthHTTP(data)
 	c.buildBackendBlueGreen(data)
+	c.buildBackendCors(data)
+	c.buildOAuth(data)
+	c.buildRewriteURL(data)
+	c.buildWAF(data)
+	c.buildWhitelist(data)
 }
diff --git a/pkg/converters/ingress/annotations/updater_test.go b/pkg/converters/ingress/annotations/updater_test.go
index 6cde98ace..5ee484716 100644
--- a/pkg/converters/ingress/annotations/updater_test.go
+++ b/pkg/converters/ingress/annotations/updater_test.go
@@ -73,3 +73,10 @@ func (c *testConfig) createBackendData(namespace, name string, ann *types.Backen
 		ann:     ann,
 	}
 }
+
+func (c *testConfig) createGlobalData(config *types.Config) *globalData {
+	return &globalData{
+		global: &hatypes.Global{},
+		config: config,
+	}
+}
diff --git a/pkg/converters/ingress/defaults.go b/pkg/converters/ingress/defaults.go
index bf80b06e6..f7b3e4a1a 100644
--- a/pkg/converters/ingress/defaults.go
+++ b/pkg/converters/ingress/defaults.go
@@ -28,13 +28,14 @@ const (
 func createDefaults() *types.Config {
 	return &types.Config{
 		ConfigDefaults: types.ConfigDefaults{
-			BalanceAlgorithm:      "roundrobin",
-			CookieKey:             "Ingress",
-			HSTS:                  true,
+			BalanceAlgorithm: "roundrobin",
+			CookieKey:        "Ingress",
+			HSTS:             true,
 			HSTSIncludeSubdomains: false,
 			HSTSMaxAge:            "15768000",
 			HSTSPreload:           false,
 			ProxyBodySize:         "",
+			SessionCookieDynamic:  true,
 			SSLRedirect:           true,
 			TimeoutClient:         "50s",
 			TimeoutClientFin:      "50s",
@@ -53,9 +54,9 @@ func createDefaults() *types.Config {
 			BindIPAddrHTTP:               "*",
 			BindIPAddrStats:              "*",
 			BindIPAddrTCP:                "*",
+			ConfigDefaults:               "",
 			ConfigFrontend:               "",
 			ConfigGlobal:                 "",
-			ConfigDefaults:               "",
 			DNSAcceptedPayloadSize:       8192,
 			DNSClusterDomain:             "cluster.local",
 			DNSHoldObsolete:              "0s",
diff --git a/pkg/converters/ingress/helper_test/cachemock.go b/pkg/converters/ingress/helper_test/cachemock.go
index b14139355..11dcc82d9 100644
--- a/pkg/converters/ingress/helper_test/cachemock.go
+++ b/pkg/converters/ingress/helper_test/cachemock.go
@@ -33,6 +33,7 @@ type SecretContent map[string]map[string][]byte
 type CacheMock struct {
 	SvcList       []*api.Service
 	EpList        map[string]*api.Endpoints
+	TermPodList   map[string][]*api.Pod
 	PodList       map[string]*api.Pod
 	SecretTLSPath map[string]string
 	SecretCAPath  map[string]string
@@ -62,6 +63,15 @@ func (c *CacheMock) GetEndpoints(service *api.Service) (*api.Endpoints, error) {
 	return nil, fmt.Errorf("could not find endpoints for service '%s'", serviceName)
 }
 
+// GetTerminatingPods ...
+func (c *CacheMock) GetTerminatingPods(service *api.Service) ([]*api.Pod, error) {
+	serviceName := service.Namespace + "/" + service.Name
+	if pods, found := c.TermPodList[serviceName]; found {
+		return pods, nil
+	}
+	return []*api.Pod{}, nil
+}
+
 // GetPod ...
 func (c *CacheMock) GetPod(podName string) (*api.Pod, error) {
 	if pod, found := c.PodList[podName]; found {
diff --git a/pkg/converters/ingress/ingress.go b/pkg/converters/ingress/ingress.go
index 460d4de4b..d7f1ec152 100644
--- a/pkg/converters/ingress/ingress.go
+++ b/pkg/converters/ingress/ingress.go
@@ -18,10 +18,12 @@ package ingress
 
 import (
 	"fmt"
+	"strconv"
 	"strings"
 
 	api "k8s.io/api/core/v1"
 	extensions "k8s.io/api/extensions/v1beta1"
+	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"github.com/jcmoraisjr/haproxy-ingress/pkg/converters/ingress/annotations"
 	ingtypes "github.com/jcmoraisjr/haproxy-ingress/pkg/converters/ingress/types"
@@ -50,7 +52,7 @@ func NewIngressConverter(options *ingtypes.ConverterOptions, haproxy haproxy.Con
 	}
 	haproxy.ConfigDefaultX509Cert(options.DefaultSSLFile.Filename)
 	if options.DefaultBackend != "" {
-		if backend, err := c.addBackend(options.DefaultBackend, 0, &ingtypes.BackendAnnotations{}); err == nil {
+		if backend, err := c.addBackend(options.DefaultBackend, "", &ingtypes.BackendAnnotations{}); err == nil {
 			haproxy.ConfigDefaultBackend(backend)
 		} else {
 			c.logger.Error("error reading default service: %v", err)
@@ -154,7 +156,7 @@ func (c *converter) syncAnnotations() {
 	}
 }
 
-func (c *converter) addDefaultHostBackend(fullSvcName string, svcPort int, ingFrontAnn *ingtypes.HostAnnotations, ingBackAnn *ingtypes.BackendAnnotations) error {
+func (c *converter) addDefaultHostBackend(fullSvcName, svcPort string, ingFrontAnn *ingtypes.HostAnnotations, ingBackAnn *ingtypes.BackendAnnotations) error {
 	if fr := c.haproxy.FindHost("*"); fr != nil {
 		if fr.FindPath("/") != nil {
 			return fmt.Errorf("path / was already defined on default host")
@@ -182,7 +184,7 @@ func (c *converter) addHost(hostname string, ingAnn *ingtypes.HostAnnotations) *
 	return host
 }
 
-func (c *converter) addBackend(fullSvcName string, svcPort int, ingAnn *ingtypes.BackendAnnotations) (*hatypes.Backend, error) {
+func (c *converter) addBackend(fullSvcName, svcPort string, ingAnn *ingtypes.BackendAnnotations) (*hatypes.Backend, error) {
 	svc, err := c.cache.GetService(fullSvcName)
 	if err != nil {
 		return nil, err
@@ -190,17 +192,20 @@ func (c *converter) addBackend(fullSvcName string, svcPort int, ingAnn *ingtypes
 	ssvcName := strings.Split(fullSvcName, "/")
 	namespace := ssvcName[0]
 	svcName := ssvcName[1]
-	if svcPort == 0 {
+	if svcPort == "" {
 		// if the port wasn't specified, take the first one
 		// from the api.Service object
-		// TODO named port
-		svcPort = svc.Spec.Ports[0].TargetPort.IntValue()
+		svcPort = svc.Spec.Ports[0].TargetPort.String()
 	}
-	backend := c.haproxy.AcquireBackend(namespace, svcName, svcPort)
+	epport := findServicePort(svc, svcPort)
+	if epport.String() == "" {
+		return nil, fmt.Errorf("port not found: '%s'", svcPort)
+	}
+	backend := c.haproxy.AcquireBackend(namespace, svcName, epport.String())
 	ann, found := c.backendAnnotations[backend]
 	if !found {
 		// New backend, configure endpoints and svc annotations
-		if err := c.addEndpoints(svc, svcPort, backend); err != nil {
+		if err := c.addEndpoints(svc, epport, backend); err != nil {
 			c.logger.Error("error adding endpoints of service '%s': %v", fullSvcName, err)
 		}
 		// Initialize with service annotations, giving precedence
@@ -214,17 +219,42 @@ func (c *converter) addBackend(fullSvcName string, svcPort int, ingAnn *ingtypes
 	// Merging Ingress annotations
 	skipped, _ := utils.UpdateStruct(c.globalConfig.ConfigDefaults, ingAnn, ann)
 	if len(skipped) > 0 {
-		c.logger.Info("skipping backend '%s/%s:%d' annotation(s) from %v due to conflict: %v",
+		c.logger.Info("skipping backend '%s/%s:%s' annotation(s) from %v due to conflict: %v",
 			backend.Namespace, backend.Name, backend.Port, ingAnn.Source, skipped)
 	}
 	return backend, nil
 }
 
+func findServicePort(svc *api.Service, servicePort string) intstr.IntOrString {
+	for _, port := range svc.Spec.Ports {
+		if port.Name == servicePort {
+			return port.TargetPort
+		}
+	}
+	for _, port := range svc.Spec.Ports {
+		if port.TargetPort.String() == servicePort {
+			return port.TargetPort
+		}
+	}
+	svcPortNumber, err := strconv.ParseInt(servicePort, 10, 0)
+	if err != nil {
+		return intstr.FromString("")
+	}
+	for _, port := range svc.Spec.Ports {
+		if port.Port == int32(svcPortNumber) {
+			return port.TargetPort
+		}
+	}
+	return intstr.FromString("")
+}
+
 func (c *converter) addHTTPPassthrough(fullSvcName string, ingFrontAnn *ingtypes.HostAnnotations, ingBackAnn *ingtypes.BackendAnnotations) {
 	// a very specific use case of pre-parsing annotations:
 	// need to add a backend if ssl-passthrough-http-port assigned
-	if ingFrontAnn.SSLPassthrough && ingFrontAnn.SSLPassthroughHTTPPort != 0 {
-		c.addBackend(fullSvcName, ingFrontAnn.SSLPassthroughHTTPPort, ingBackAnn)
+	if ingFrontAnn.SSLPassthrough && ingFrontAnn.SSLPassthroughHTTPPort != "" {
+		if _, err := c.addBackend(fullSvcName, ingFrontAnn.SSLPassthroughHTTPPort, ingBackAnn); err != nil {
+			c.logger.Warn("skipping http port config of ssl-passthrough: %v", err)
+		}
 	}
 }
 
@@ -240,23 +270,40 @@ func (c *converter) addTLS(namespace, secretName string) ingtypes.File {
 	return c.options.DefaultSSLFile
 }
 
-func (c *converter) addEndpoints(svc *api.Service, servicePort int, backend *hatypes.Backend) error {
+func (c *converter) addEndpoints(svc *api.Service, svcPort intstr.IntOrString, backend *hatypes.Backend) error {
 	endpoints, err := c.cache.GetEndpoints(svc)
 	if err != nil {
 		return err
 	}
 	// TODO ServiceTypeExternalName
 	// TODO ServiceUpstream - annotation nao documentada
-	// TODO DrainSupport
+	// TODO svcPort.IntValue() doesn't work if svc.targetPort is a pod's named port
 	for _, subset := range endpoints.Subsets {
 		for _, port := range subset.Ports {
-			if int(port.Port) == servicePort && port.Protocol == api.ProtocolTCP {
+			ssport := int(port.Port)
+			if ssport == svcPort.IntValue() && port.Protocol == api.ProtocolTCP {
 				for _, addr := range subset.Addresses {
-					backend.NewEndpoint(addr.IP, servicePort, addr.TargetRef.Namespace+"/"+addr.TargetRef.Name)
+					backend.NewEndpoint(addr.IP, ssport, addr.TargetRef.Namespace+"/"+addr.TargetRef.Name)
+				}
+				if c.globalConfig.DrainSupport {
+					for _, addr := range subset.NotReadyAddresses {
+						ep := backend.NewEndpoint(addr.IP, ssport, addr.TargetRef.Namespace+"/"+addr.TargetRef.Name)
+						ep.Weight = 0
+					}
 				}
 			}
 		}
 	}
+	if c.globalConfig.DrainSupport {
+		pods, err := c.cache.GetTerminatingPods(svc)
+		if err != nil {
+			return err
+		}
+		for _, pod := range pods {
+			ep := backend.NewEndpoint(pod.Status.PodIP, svcPort.IntValue(), pod.Namespace+"/"+pod.Name)
+			ep.Weight = 0
+		}
+	}
 	return nil
 }
 
@@ -282,8 +329,8 @@ func (c *converter) readAnnotations(source *ingtypes.Source, annotations map[str
 	return frontAnn, backAnn
 }
 
-func readServiceNamePort(backend *extensions.IngressBackend) (string, int) {
+func readServiceNamePort(backend *extensions.IngressBackend) (string, string) {
 	serviceName := backend.ServiceName
-	servicePort := backend.ServicePort.IntValue()
+	servicePort := backend.ServicePort.String()
 	return serviceName, servicePort
 }
diff --git a/pkg/converters/ingress/ingress_test.go b/pkg/converters/ingress/ingress_test.go
index d366b58ce..db1fd5f6e 100644
--- a/pkg/converters/ingress/ingress_test.go
+++ b/pkg/converters/ingress/ingress_test.go
@@ -26,6 +26,7 @@ import (
 	extensions "k8s.io/api/extensions/v1beta1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/client-go/kubernetes/scheme"
 
 	ing_helper "github.com/jcmoraisjr/haproxy-ingress/pkg/converters/ingress/helper_test"
@@ -82,6 +83,75 @@ func TestSyncDefaultSvcNotFound(t *testing.T) {
 ERROR error reading default service: service not found: 'system/default'`)
 }
 
+func TestSyncSvcPortNotFound(t *testing.T) {
+	c := setup(t)
+	defer c.teardown()
+
+	c.createSvc1Auto()
+	c.Sync(c.createIng1("default/echo", "echo.example.com", "/", "echo:non"))
+
+	c.compareConfigFront(`
+- hostname: echo.example.com
+  paths: []
+`)
+
+	c.compareConfigBack(`
+- id: _default_backend
+  endpoints:
+  - ip: 172.17.0.99
+    port: 8080
+`)
+
+	c.compareLogging(`
+WARN skipping backend config of ingress 'default/echo': port not found: 'non'
+`)
+}
+
+func TestSyncSvcNamedPort(t *testing.T) {
+	c := setup(t)
+	defer c.teardown()
+
+	c.createSvc1("default/echo", "httpsvc:1001:8080", "172.17.1.101")
+	c.Sync(
+		c.createIng1("default/echo1", "echo1.example.com", "/", "echo:httpsvc"),
+		c.createIng1("default/echo2", "echo2.example.com", "/", "echo:1001"),
+		c.createIng1("default/echo3", "echo3.example.com", "/", "echo:8080"),
+		c.createIng1("default/echo4", "echo4.example.com", "/", "echo:9000"),
+	)
+
+	c.compareConfigFront(`
+- hostname: echo1.example.com
+  paths:
+  - path: /
+    backend: default_echo_8080
+- hostname: echo2.example.com
+  paths:
+  - path: /
+    backend: default_echo_8080
+- hostname: echo3.example.com
+  paths:
+  - path: /
+    backend: default_echo_8080
+- hostname: echo4.example.com
+  paths: []
+`)
+
+	c.compareConfigBack(`
+- id: default_echo_8080
+  endpoints:
+  - ip: 172.17.1.101
+    port: 8080
+- id: _default_backend
+  endpoints:
+  - ip: 172.17.0.99
+    port: 8080
+`)
+
+	c.compareLogging(`
+WARN skipping backend config of ingress 'default/echo4': port not found: '9000'
+`)
+}
+
 func TestSyncSingle(t *testing.T) {
 	c := setup(t)
 	defer c.teardown()
@@ -181,6 +251,50 @@ func TestSyncInvalidEndpoint(t *testing.T) {
 ERROR error adding endpoints of service 'default/echo': could not find endpoints for service 'default/echo'`)
 }
 
+func TestSyncDrainSupport(t *testing.T) {
+	c := setup(t)
+	defer c.teardown()
+
+	svc, ep := c.createSvc1("default/echo", "8080", "172.17.1.101,172.17.1.102")
+	svcName := svc.Namespace + "/" + svc.Name
+	ss := &ep.Subsets[0]
+	addr := ss.Addresses
+	ss.Addresses = []api.EndpointAddress{addr[0]}
+	ss.NotReadyAddresses = []api.EndpointAddress{addr[1]}
+	pod := c.createPod1("default/echo-xxxxx", "172.17.1.103")
+	c.cache.TermPodList[svcName] = []*api.Pod{pod}
+
+	c.SyncDef(
+		map[string]string{"drain-support": "true"},
+		c.createIng1("default/echo", "echo.example.com", "/", "echo:8080"),
+	)
+
+	c.compareConfigFront(`
+- hostname: echo.example.com
+  paths:
+  - path: /
+    backend: default_echo_8080
+`)
+	c.compareConfigBack(`
+- id: default_echo_8080
+  endpoints:
+  - ip: 172.17.1.101
+    port: 8080
+  - ip: 172.17.1.102
+    port: 8080
+    drain: true
+  - ip: 172.17.1.103
+    port: 8080
+    drain: true
+- id: _default_backend
+  endpoints:
+  - ip: 172.17.0.99
+    port: 8080
+`)
+
+	c.compareLogging(``)
+}
+
 func TestSyncRootPathLast(t *testing.T) {
 	c := setup(t)
 	defer c.teardown()
@@ -907,6 +1021,67 @@ func TestSyncAnnBackDefault(t *testing.T) {
 INFO skipping backend 'default/echo5:8080' annotation(s) from ingress 'default/echo5' due to conflict: [balance-algorithm]`)
 }
 
+func TestSyncAnnPassthrough(t *testing.T) {
+	c := setup(t)
+	defer c.teardown()
+
+	svc, ep := c.createSvc1("default/echo", "http:8080", "172.17.1.101")
+	svcPort := api.ServicePort{
+		Name:       "https",
+		Port:       8443,
+		TargetPort: intstr.FromInt(8443),
+	}
+	epPort := api.EndpointPort{
+		Name:     "https",
+		Port:     8443,
+		Protocol: api.ProtocolTCP,
+	}
+	svc.Spec.Ports = append(svc.Spec.Ports, svcPort)
+	ep.Subsets[0].Ports = append(ep.Subsets[0].Ports, epPort)
+	c.Sync(
+		c.createIng1Ann("default/echo1", "echo1.example.com", "/", "echo:8443",
+			map[string]string{
+				"ingress.kubernetes.io/ssl-passthrough":           "true",
+				"ingress.kubernetes.io/ssl-passthrough-http-port": "8080",
+			}),
+		c.createIng1Ann("default/echo2", "echo2.example.com", "/", "echo:8443",
+			map[string]string{
+				"ingress.kubernetes.io/ssl-passthrough":           "true",
+				"ingress.kubernetes.io/ssl-passthrough-http-port": "9000",
+			}),
+	)
+
+	c.compareConfigFront(`
+- hostname: echo1.example.com
+  paths:
+  - path: /
+    backend: default_echo_8443
+- hostname: echo2.example.com
+  paths:
+  - path: /
+    backend: default_echo_8443
+`)
+
+	c.compareConfigBack(`
+- id: default_echo_8080
+  endpoints:
+  - ip: 172.17.1.101
+    port: 8080
+- id: default_echo_8443
+  endpoints:
+  - ip: 172.17.1.101
+    port: 8443
+- id: _default_backend
+  endpoints:
+  - ip: 172.17.0.99
+    port: 8080
+`)
+
+	c.compareLogging(`
+WARN skipping http port config of ssl-passthrough: port not found: '9000'
+`)
+}
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *
  *  BUILDERS
@@ -932,8 +1107,9 @@ func setup(t *testing.T) *testConfig {
 		decode:  scheme.Codecs.UniversalDeserializer().Decode,
 		hconfig: haproxy.CreateInstance(logger, &ha_helper.BindUtilsMock{}, haproxy.InstanceOptions{}).Config(),
 		cache: &ing_helper.CacheMock{
-			SvcList: []*api.Service{},
-			EpList:  map[string]*api.Endpoints{},
+			SvcList:     []*api.Service{},
+			EpList:      map[string]*api.Endpoints{},
+			TermPodList: map[string][]*api.Pod{},
 			SecretTLSPath: map[string]string{
 				"system/ingress-default": "/tls/tls-default.pem",
 			},
@@ -978,24 +1154,30 @@ func (c *testConfig) SyncDef(config map[string]string, ing ...*extensions.Ingres
 	conv.Sync(ing)
 }
 
-func (c *testConfig) createSvc1Auto() *api.Service {
+func (c *testConfig) createSvc1Auto() (*api.Service, *api.Endpoints) {
 	return c.createSvc1("default/echo", "8080", "172.17.0.11")
 }
 
-func (c *testConfig) createSvc1AutoAnn(ann map[string]string) *api.Service {
-	svc := c.createSvc1Auto()
+func (c *testConfig) createSvc1AutoAnn(ann map[string]string) (*api.Service, *api.Endpoints) {
+	svc, ep := c.createSvc1Auto()
 	svc.SetAnnotations(ann)
-	return svc
+	return svc, ep
 }
 
-func (c *testConfig) createSvc1Ann(name, port, endpoints string, ann map[string]string) *api.Service {
-	svc := c.createSvc1(name, port, endpoints)
+func (c *testConfig) createSvc1Ann(name, port, endpoints string, ann map[string]string) (*api.Service, *api.Endpoints) {
+	svc, ep := c.createSvc1(name, port, endpoints)
 	svc.SetAnnotations(ann)
-	return svc
+	return svc, ep
 }
 
-func (c *testConfig) createSvc1(name, port, endpoints string) *api.Service {
+func (c *testConfig) createSvc1(name, port, endpoints string) (*api.Service, *api.Endpoints) {
 	sname := strings.Split(name, "/")
+	sport := strings.Split(port, ":")
+	if len(sport) < 2 {
+		sport = []string{"", port, port}
+	} else if len(sport) < 3 {
+		sport = []string{sport[0], sport[1], sport[1]}
+	}
 
 	svc := c.createObject(`
 apiVersion: v1
@@ -1005,8 +1187,9 @@ metadata:
   namespace: ` + sname[0] + `
 spec:
   ports:
-  - port: ` + port + `
-    targetPort: ` + port).(*api.Service)
+  - name: ` + sport[0] + `
+    port: ` + sport[1] + `
+    targetPort: ` + sport[2]).(*api.Service)
 
 	c.cache.SvcList = append(c.cache.SvcList, svc)
 
@@ -1019,7 +1202,8 @@ metadata:
 subsets:
 - addresses: []
   ports:
-  - port: ` + port + `
+  - name: ` + sport[0] + `
+    port: ` + sport[2] + `
     protocol: TCP`).(*api.Endpoints)
 
 	addr := []api.EndpointAddress{}
@@ -1036,7 +1220,22 @@ subsets:
 	ep.Subsets[0].Addresses = addr
 	c.cache.EpList[name] = ep
 
-	return svc
+	return svc, ep
+}
+
+func (c *testConfig) createPod1(name, ip string) *api.Pod {
+	pname := strings.Split(name, "/")
+
+	pod := c.createObject(`
+apiVersion: v1
+kind: Pod
+metadata:
+  name: ` + pname[1] + `
+  namespace: ` + pname[0] + `
+status:
+  podIP: ` + ip).(*api.Pod)
+
+	return pod
 }
 
 func (c *testConfig) createSecretTLS1(secretName string) {
@@ -1195,8 +1394,9 @@ func (c *testConfig) compareConfigDefaultFront(expected string) {
 
 type (
 	endpointMock struct {
-		IP   string
-		Port int
+		IP    string
+		Port  int
+		Drain bool `yaml:",omitempty"`
 	}
 	backendMock struct {
 		ID               string
@@ -1211,7 +1411,7 @@ func convertBackend(habackends ...*hatypes.Backend) []backendMock {
 	for _, b := range habackends {
 		endpoints := []endpointMock{}
 		for _, e := range b.Endpoints {
-			endpoints = append(endpoints, endpointMock{IP: e.IP, Port: e.Port})
+			endpoints = append(endpoints, endpointMock{IP: e.IP, Port: e.Port, Drain: e.Weight == 0})
 		}
 		backends = append(backends, backendMock{
 			ID:               b.ID,
diff --git a/pkg/converters/ingress/types/annotations.go b/pkg/converters/ingress/types/annotations.go
index 9a4bf0925..2628a0373 100644
--- a/pkg/converters/ingress/types/annotations.go
+++ b/pkg/converters/ingress/types/annotations.go
@@ -20,14 +20,13 @@ package types
 type HostAnnotations struct {
 	Source                 Source `json:"-"`
 	AppRoot                string `json:"app-root"`
-	AuthTLSCertHeader      bool   `json:"auth-tls-cert-header"`
 	AuthTLSErrorPage       string `json:"auth-tls-error-page"`
 	AuthTLSVerifyClient    string `json:"auth-tls-verify-client"`
 	AuthTLSSecret          string `json:"auth-tls-secret"`
 	ServerAlias            string `json:"server-alias"`
 	ServerAliasRegex       string `json:"server-alias-regex"`
 	SSLPassthrough         bool   `json:"ssl-passthrough"`
-	SSLPassthroughHTTPPort int    `json:"ssl-passthrough-http-port"`
+	SSLPassthroughHTTPPort string `json:"ssl-passthrough-http-port"`
 	TimeoutClient          string `json:"timeout-client"`
 	TimeoutClientFin       string `json:"timeout-client-fin"`
 }
@@ -38,18 +37,19 @@ type BackendAnnotations struct {
 	Affinity              string `json:"affinity"`
 	AuthRealm             string `json:"auth-realm"`
 	AuthSecret            string `json:"auth-secret"`
+	AuthTLSCertHeader     bool   `json:"auth-tls-cert-header"`
 	AuthType              string `json:"auth-type"`
 	BalanceAlgorithm      string `json:"balance-algorithm"`
 	BlueGreenBalance      string `json:"blue-green-balance"`
 	BlueGreenDeploy       string `json:"blue-green-deploy"`
 	BlueGreenMode         string `json:"blue-green-mode"`
 	ConfigBackend         string `json:"config-backend"`
-	CookieKey             string `json:"cookie-key"`
 	CorsAllowCredentials  bool   `json:"cors-allow-credentials"`
 	CorsAllowHeaders      string `json:"cors-allow-headers"`
 	CorsAllowMethods      string `json:"cors-allow-methods"`
 	CorsAllowOrigin       string `json:"cors-allow-origin"`
 	CorsEnable            bool   `json:"cors-enable"`
+	CorsExposeHeaders     string `json:"cors-expose-headers"`
 	CorsMaxAge            int    `json:"cors-max-age"`
 	HSTS                  bool   `json:"hsts"`
 	HSTSIncludeSubdomains bool   `json:"hsts-include-subdomains"`
@@ -70,7 +70,7 @@ type BackendAnnotations struct {
 	SecureBackends        bool   `json:"secure-backends"`
 	SecureCrtSecret       string `json:"secure-crt-secret"`
 	SecureVerifyCASecret  string `json:"secure-verify-ca-secret"`
-	SessionCookieDynamic  string `json:"session-cookie-dynamic"`
+	SessionCookieDynamic  bool   `json:"session-cookie-dynamic"`
 	SessionCookieName     string `json:"session-cookie-name"`
 	SessionCookieStrategy string `json:"session-cookie-strategy"`
 	SSLRedirect           bool   `json:"ssl-redirect"`
diff --git a/pkg/converters/ingress/types/config.go b/pkg/converters/ingress/types/config.go
index ab938f92d..a4338a523 100644
--- a/pkg/converters/ingress/types/config.go
+++ b/pkg/converters/ingress/types/config.go
@@ -25,6 +25,7 @@ type ConfigDefaults struct {
 	HSTSMaxAge            string `json:"hsts-max-age"`
 	HSTSPreload           bool   `json:"hsts-preload"`
 	ProxyBodySize         string `json:"proxy-body-size"`
+	SessionCookieDynamic  bool   `json:"session-cookie-dynamic"`
 	SSLRedirect           bool   `json:"ssl-redirect"`
 	TimeoutClient         string `json:"timeout-client"`
 	TimeoutClientFin      string `json:"timeout-client-fin"`
diff --git a/pkg/converters/ingress/types/interfaces.go b/pkg/converters/ingress/types/interfaces.go
index db60ab13f..f2ec1ae90 100644
--- a/pkg/converters/ingress/types/interfaces.go
+++ b/pkg/converters/ingress/types/interfaces.go
@@ -24,6 +24,7 @@ import (
 type Cache interface {
 	GetService(serviceName string) (*api.Service, error)
 	GetEndpoints(service *api.Service) (*api.Endpoints, error)
+	GetTerminatingPods(service *api.Service) ([]*api.Pod, error)
 	GetPod(podName string) (*api.Pod, error)
 	GetTLSSecretPath(secretName string) (File, error)
 	GetCASecretPath(secretName string) (File, error)
diff --git a/pkg/haproxy/config.go b/pkg/haproxy/config.go
index 2add7602d..7911303c2 100644
--- a/pkg/haproxy/config.go
+++ b/pkg/haproxy/config.go
@@ -29,13 +29,14 @@ import (
 type Config interface {
 	AcquireHost(hostname string) *hatypes.Host
 	FindHost(hostname string) *hatypes.Host
-	AcquireBackend(namespace, name string, port int) *hatypes.Backend
-	FindBackend(namespace, name string, port int) *hatypes.Backend
+	AcquireBackend(namespace, name, port string) *hatypes.Backend
+	FindBackend(namespace, name, port string) *hatypes.Backend
 	ConfigDefaultBackend(defaultBackend *hatypes.Backend)
 	ConfigDefaultX509Cert(filename string)
 	AddUserlist(name string, users []hatypes.User) *hatypes.Userlist
 	FindUserlist(name string) *hatypes.Userlist
-	BuildFrontendGroup() (*hatypes.FrontendGroup, error)
+	FrontendGroup() *hatypes.FrontendGroup
+	BuildFrontendGroup() error
 	DefaultHost() *hatypes.Host
 	DefaultBackend() *hatypes.Backend
 	Global() *hatypes.Global
@@ -46,6 +47,7 @@ type Config interface {
 }
 
 type config struct {
+	fgroup          *hatypes.FrontendGroup
 	bindUtils       hatypes.BindUtils
 	mapsTemplate    *template.Config
 	mapsDir         string
@@ -122,7 +124,7 @@ func (c *config) sortBackends() {
 	})
 }
 
-func (c *config) AcquireBackend(namespace, name string, port int) *hatypes.Backend {
+func (c *config) AcquireBackend(namespace, name, port string) *hatypes.Backend {
 	if backend := c.FindBackend(namespace, name, port); backend != nil {
 		return backend
 	}
@@ -132,7 +134,7 @@ func (c *config) AcquireBackend(namespace, name string, port int) *hatypes.Backe
 	return backend
 }
 
-func (c *config) FindBackend(namespace, name string, port int) *hatypes.Backend {
+func (c *config) FindBackend(namespace, name, port string) *hatypes.Backend {
 	for _, b := range c.backends {
 		if b.Namespace == namespace && b.Name == name && b.Port == port {
 			return b
@@ -141,7 +143,7 @@ func (c *config) FindBackend(namespace, name string, port int) *hatypes.Backend
 	return nil
 }
 
-func createBackend(namespace, name string, port int) *hatypes.Backend {
+func createBackend(namespace, name, port string) *hatypes.Backend {
 	return &hatypes.Backend{
 		ID:        buildID(namespace, name, port),
 		Namespace: namespace,
@@ -151,8 +153,8 @@ func createBackend(namespace, name string, port int) *hatypes.Backend {
 	}
 }
 
-func buildID(namespace, name string, port int) string {
-	return fmt.Sprintf("%s_%s_%d", namespace, name, port)
+func buildID(namespace, name, port string) string {
+	return fmt.Sprintf("%s_%s_%s", namespace, name, port)
 }
 
 func (c *config) ConfigDefaultBackend(defaultBackend *hatypes.Backend) {
@@ -187,17 +189,26 @@ func (c *config) FindUserlist(name string) *hatypes.Userlist {
 	return nil
 }
 
-func (c *config) BuildFrontendGroup() (*hatypes.FrontendGroup, error) {
+func (c *config) FrontendGroup() *hatypes.FrontendGroup {
+	return c.fgroup
+}
+
+func (c *config) BuildFrontendGroup() error {
+	// tested thanks to instance_test templating tests
+	// ideas to make a nice test or a nice refactor are welcome
 	if len(c.hosts) == 0 {
-		return nil, fmt.Errorf("cannot create frontends without hosts")
+		return fmt.Errorf("cannot create frontends without hosts")
 	}
 	frontends, sslpassthrough := hatypes.BuildRawFrontends(c.hosts)
+	fgroupMaps := hatypes.CreateMaps()
 	fgroup := &hatypes.FrontendGroup{
 		Frontends:         frontends,
 		HasSSLPassthrough: len(sslpassthrough) > 0,
-		HTTPFrontsMap:     c.mapsDir + "/http-front.map",
-		RedirectMap:       c.mapsDir + "/redirect.map",
-		SSLPassthroughMap: c.mapsDir + "/sslpassthrough.map",
+		Maps:              fgroupMaps,
+		HTTPFrontsMap:     fgroupMaps.AddMap(c.mapsDir + "/_global_http_front.map"),
+		HTTPRootRedirMap:  fgroupMaps.AddMap(c.mapsDir + "/_global_http_root_redir.map"),
+		HTTPSRedirMap:     fgroupMaps.AddMap(c.mapsDir + "/_global_https_redir.map"),
+		SSLPassthroughMap: fgroupMaps.AddMap(c.mapsDir + "/_global_sslpassthrough.map"),
 	}
 	if fgroup.HasTCPProxy() {
 		// More than one HAProxy's frontend or bind, or using ssl-passthrough config,
@@ -205,23 +216,21 @@ func (c *config) BuildFrontendGroup() (*hatypes.FrontendGroup, error) {
 		var i int
 		for _, frontend := range frontends {
 			for _, bind := range frontend.Binds {
-				var bindName string
+				i++
+				bindName := fmt.Sprintf("_socket%03d", i)
 				if len(bind.Hosts) == 1 {
-					bindName = bind.Hosts[0].Hostname
 					bind.TLS.TLSCert = c.defaultX509Cert
 					bind.TLS.TLSCertDir = bind.Hosts[0].TLS.TLSFilename
 				} else {
-					i++
-					bindName = fmt.Sprintf("_socket%03d", i)
 					x509dir, err := c.createCertsDir(bindName, bind.Hosts)
 					if err != nil {
-						return nil, err
+						return err
 					}
 					bind.TLS.TLSCert = c.defaultX509Cert
 					bind.TLS.TLSCertDir = x509dir
 				}
 				bind.Name = bindName
-				bind.Socket = fmt.Sprintf("unix@/var/run/front_%s.sock", bindName)
+				bind.Socket = fmt.Sprintf("unix@/var/run/%s.sock", bindName)
 				bind.AcceptProxy = true
 			}
 		}
@@ -236,7 +245,7 @@ func (c *config) BuildFrontendGroup() (*hatypes.FrontendGroup, error) {
 		} else {
 			x509dir, err := c.createCertsDir(bind.Name, bind.Hosts)
 			if err != nil {
-				return nil, err
+				return err
 			}
 			frontends[0].Binds[0].TLS.TLSCert = c.defaultX509Cert
 			frontends[0].Binds[0].TLS.TLSCertDir = x509dir
@@ -244,141 +253,127 @@ func (c *config) BuildFrontendGroup() (*hatypes.FrontendGroup, error) {
 	}
 	for _, frontend := range frontends {
 		mapsPrefix := c.mapsDir + "/" + frontend.Name
-		frontend.HostBackendsMap = mapsPrefix + "_host.map"
-		frontend.SNIBackendsMap = mapsPrefix + "_sni.map"
-		frontend.TLSInvalidCrtErrorList = mapsPrefix + "_inv_crt.list"
-		frontend.TLSInvalidCrtErrorPagesMap = mapsPrefix + "_inv_crt_redir.map"
-		frontend.TLSNoCrtErrorList = mapsPrefix + "_no_crt.list"
-		frontend.TLSNoCrtErrorPagesMap = mapsPrefix + "_no_crt_redir.map"
-		frontend.VarNamespaceMap = mapsPrefix + "_k8s_ns.map"
+		frontend.Maps = hatypes.CreateMaps()
+		frontend.HostBackendsMap = frontend.Maps.AddMap(mapsPrefix + "_host.map")
+		frontend.RootRedirMap = frontend.Maps.AddMap(mapsPrefix + "_root_redir.map")
+		frontend.SNIBackendsMap = frontend.Maps.AddMap(mapsPrefix + "_sni.map")
+		frontend.TLSInvalidCrtErrorList = frontend.Maps.AddMap(mapsPrefix + "_inv_crt.list")
+		frontend.TLSInvalidCrtErrorPagesMap = frontend.Maps.AddMap(mapsPrefix + "_inv_crt_redir.map")
+		frontend.TLSNoCrtErrorList = frontend.Maps.AddMap(mapsPrefix + "_no_crt.list")
+		frontend.TLSNoCrtErrorPagesMap = frontend.Maps.AddMap(mapsPrefix + "_no_crt_redir.map")
+		frontend.VarNamespaceMap = frontend.Maps.AddMap(mapsPrefix + "_k8s_ns.map")
 		for _, bind := range frontend.Binds {
-			bind.UseServerList = mapsPrefix + "_bind_" + bind.Name + ".list"
+			bind.Maps = hatypes.CreateMaps()
+			bind.UseServerList = bind.Maps.AddMap(c.mapsDir + "/" + bind.Name + ".list")
 		}
 	}
-	type mapEntry struct {
-		Key   string
-		Value string
-	}
-	var sslpassthroughMap []mapEntry
-	var redirectMap []mapEntry
-	var httpFront []mapEntry
+	// Some maps use yes/no answers instead of a list with found/missing keys
+	// This approach avoid overlap:
+	//  1. match with path_beg/map_beg, /path has a feature and a declared /path/sub doesn't have
+	//  2. *.host.domain wildcard/alias/alias-regex has a feature and a declared sub.host.domain doesn't have
 	yesno := map[bool]string{true: "yes", false: "no"}
 	for _, sslpassHost := range sslpassthrough {
 		rootPath := sslpassHost.FindPath("/")
 		if rootPath == nil {
-			return nil, fmt.Errorf("missing root path on host %s", sslpassHost.Hostname)
+			return fmt.Errorf("missing root path on host %s", sslpassHost.Hostname)
 		}
-		sslpassthroughMap = append(sslpassthroughMap, mapEntry{
-			Key:   sslpassHost.Hostname,
-			Value: rootPath.BackendID,
-		})
-		redirectMap = append(redirectMap, mapEntry{
-			Key:   sslpassHost.Hostname + "/",
-			Value: yesno[sslpassHost.HTTPPassthroughBackend == nil],
-		})
+		fgroup.SSLPassthroughMap.AppendHostname(sslpassHost.Hostname, rootPath.BackendID)
+		fgroup.HTTPSRedirMap.AppendHostname(sslpassHost.Hostname+"/", yesno[sslpassHost.HTTPPassthroughBackend == nil])
 		if sslpassHost.HTTPPassthroughBackend != nil {
-			httpFront = append(httpFront, mapEntry{
-				Key:   sslpassHost.Hostname + "/",
-				Value: sslpassHost.HTTPPassthroughBackend.ID,
-			})
-		} else {
-			fgroup.HasRedirectHTTPS = true
+			fgroup.HTTPFrontsMap.AppendHostname(sslpassHost.Hostname+"/", sslpassHost.HTTPPassthroughBackend.ID)
 		}
 	}
 	for _, f := range frontends {
-		var hostBackendsMap []mapEntry
-		var sniBackendsMap []mapEntry
-		var invalidCrtList []mapEntry
-		var invalidCrtMap []mapEntry
-		var noCrtList []mapEntry
-		var noCrtMap []mapEntry
-		var varNamespaceMap []mapEntry
 		for _, host := range f.Hosts {
 			for _, path := range host.Paths {
 				// TODO use only root path if all uri has the same conf
-				redirectMap = append(redirectMap, mapEntry{
-					Key:   host.Hostname + path.Path,
-					Value: yesno[path.Backend.SSLRedirect],
-				})
-				entry := mapEntry{
-					Key:   host.Hostname + path.Path,
-					Value: path.BackendID,
+				fgroup.HTTPSRedirMap.AppendHostname(host.Hostname+path.Path, yesno[path.Backend.SSLRedirect])
+				base := host.Hostname + path.Path
+				var aliasName, aliasRegex string
+				// TODO warn in logs about ignoring alias name due to hostname colision
+				if host.Alias.AliasName != "" && c.FindHost(host.Alias.AliasName) == nil {
+					aliasName = host.Alias.AliasName + path.Path
+				}
+				if host.Alias.AliasRegex != "" {
+					aliasRegex = host.Alias.AliasRegex + path.Path
 				}
+				back := path.BackendID
 				if host.HasTLSAuth() {
-					sniBackendsMap = append(sniBackendsMap, entry)
+					f.SNIBackendsMap.AppendHostname(base, back)
+					f.SNIBackendsMap.AppendAliasName(aliasName, back)
+					f.SNIBackendsMap.AppendAliasRegex(aliasRegex, back)
+					path.Backend.SSL.HasTLSAuth = true
 				} else {
-					hostBackendsMap = append(hostBackendsMap, entry)
+					f.HostBackendsMap.AppendHostname(base, back)
+					f.HostBackendsMap.AppendAliasName(aliasName, back)
+					f.HostBackendsMap.AppendAliasRegex(aliasRegex, back)
 				}
-				if path.Backend.SSLRedirect {
-					fgroup.HasRedirectHTTPS = true
-				} else {
-					httpFront = append(httpFront, entry)
+				if !path.Backend.SSLRedirect {
+					fgroup.HTTPFrontsMap.AppendHostname(base, back)
 				}
+				var ns string
 				if host.VarNamespace {
-					entry.Value = path.Backend.Namespace
+					ns = path.Backend.Namespace
 				} else {
-					entry.Value = "-"
+					ns = "-"
 				}
-				varNamespaceMap = append(varNamespaceMap, entry)
+				f.VarNamespaceMap.AppendHostname(base, ns)
 			}
 			if host.HasTLSAuth() {
-				var entry mapEntry
-				entry.Key = host.Hostname
-				invalidCrtList = append(invalidCrtList, entry)
+				f.TLSInvalidCrtErrorList.AppendHostname(host.Hostname, "")
 				if !host.TLS.CAVerifyOptional {
-					noCrtList = append(noCrtList, entry)
+					f.TLSNoCrtErrorList.AppendHostname(host.Hostname, "")
 				}
-				if host.TLS.CAErrorPage != "" {
-					entry.Value = host.TLS.CAErrorPage
-					invalidCrtMap = append(invalidCrtMap, entry)
+				page := host.TLS.CAErrorPage
+				if page != "" {
+					f.TLSInvalidCrtErrorPagesMap.AppendHostname(host.Hostname, page)
 					if !host.TLS.CAVerifyOptional {
-						noCrtMap = append(noCrtMap, entry)
+						f.TLSNoCrtErrorPagesMap.AppendHostname(host.Hostname, page)
 					}
 				}
 			}
+			// TODO wildcard/alias/alias-regex hostname can overlap
+			// a configured domain which doesn't have rootRedirect
+			if host.RootRedirect != "" {
+				fgroup.HTTPRootRedirMap.AppendHostname(host.Hostname, host.RootRedirect)
+				f.RootRedirMap.AppendHostname(host.Hostname, host.RootRedirect)
+			}
 		}
 		for _, bind := range f.Binds {
-			var useServerList []mapEntry
 			for _, host := range bind.Hosts {
-				useServerList = append(useServerList, mapEntry{Key: host.Hostname})
+				bind.UseServerList.AppendHostname(host.Hostname, "")
 			}
-			if err := c.mapsTemplate.WriteOutput(useServerList, bind.UseServerList); err != nil {
-				return nil, err
-			}
-		}
-		if err := c.mapsTemplate.WriteOutput(hostBackendsMap, f.HostBackendsMap); err != nil {
-			return nil, err
 		}
-		if err := c.mapsTemplate.WriteOutput(sniBackendsMap, f.SNIBackendsMap); err != nil {
-			return nil, err
-		}
-		if err := c.mapsTemplate.WriteOutput(invalidCrtList, f.TLSInvalidCrtErrorList); err != nil {
-			return nil, err
-		}
-		if err := c.mapsTemplate.WriteOutput(invalidCrtMap, f.TLSInvalidCrtErrorPagesMap); err != nil {
-			return nil, err
+	}
+	if err := writeMaps(fgroup.Maps, c.mapsTemplate); err != nil {
+		return err
+	}
+	for _, f := range frontends {
+		if err := writeMaps(f.Maps, c.mapsTemplate); err != nil {
+			return err
 		}
-		if err := c.mapsTemplate.WriteOutput(noCrtList, f.TLSNoCrtErrorList); err != nil {
-			return nil, err
+		for _, bind := range f.Binds {
+			if err := writeMaps(bind.Maps, c.mapsTemplate); err != nil {
+				return err
+			}
 		}
-		if err := c.mapsTemplate.WriteOutput(noCrtMap, f.TLSNoCrtErrorPagesMap); err != nil {
-			return nil, err
+	}
+	c.fgroup = fgroup
+	return nil
+}
+
+func writeMaps(maps *hatypes.HostsMaps, template *template.Config) error {
+	for _, hmap := range maps.Items {
+		if err := template.WriteOutput(hmap.Match, hmap.MatchFile); err != nil {
+			return err
 		}
-		if err := c.mapsTemplate.WriteOutput(varNamespaceMap, f.VarNamespaceMap); err != nil {
-			return nil, err
+		if len(hmap.Regex) > 0 {
+			if err := template.WriteOutput(hmap.Regex, hmap.RegexFile); err != nil {
+				return err
+			}
 		}
 	}
-	if err := c.mapsTemplate.WriteOutput(sslpassthroughMap, fgroup.SSLPassthroughMap); err != nil {
-		return nil, err
-	}
-	if err := c.mapsTemplate.WriteOutput(redirectMap, fgroup.RedirectMap); err != nil {
-		return nil, err
-	}
-	if err := c.mapsTemplate.WriteOutput(httpFront, fgroup.HTTPFrontsMap); err != nil {
-		return nil, err
-	}
-	fgroup.HasHTTPHost = len(httpFront) > 0
-	return fgroup, nil
+	return nil
 }
 
 func (c *config) createCertsDir(bindName string, hosts []*hatypes.Host) (string, error) {
diff --git a/pkg/haproxy/config_test.go b/pkg/haproxy/config_test.go
index dba68dcfe..3beddb4ec 100644
--- a/pkg/haproxy/config_test.go
+++ b/pkg/haproxy/config_test.go
@@ -24,11 +24,11 @@ import (
 
 func TestEmptyFrontend(t *testing.T) {
 	c := createConfig(&ha_helper.BindUtilsMock{}, options{})
-	if _, err := c.BuildFrontendGroup(); err == nil {
+	if err := c.BuildFrontendGroup(); err == nil {
 		t.Error("expected error creating empty frontend")
 	}
 	c.AcquireHost("empty")
-	if _, err := c.BuildFrontendGroup(); err != nil {
+	if err := c.BuildFrontendGroup(); err != nil {
 		t.Errorf("error creating frontends: %v", err)
 	}
 }
@@ -58,11 +58,11 @@ func TestBuildID(t *testing.T) {
 	testCases := []struct {
 		namespace string
 		name      string
-		port      int
+		port      string
 		expected  string
 	}{
 		{
-			"default", "echo", 8080, "default_echo_8080",
+			"default", "echo", "8080", "default_echo_8080",
 		},
 	}
 	for _, test := range testCases {
@@ -86,13 +86,13 @@ func TestEqual(t *testing.T) {
 	if !c1.Equals(c2) {
 		t.Error("c1 and c2 should be equals (default cert)")
 	}
-	b1 := c1.AcquireBackend("d", "app1", 8080)
-	c1.AcquireBackend("d", "app2", 8080)
+	b1 := c1.AcquireBackend("d", "app1", "8080")
+	c1.AcquireBackend("d", "app2", "8080")
 	if c1.Equals(c2) {
 		t.Error("c1 and c2 should not be equals (backends on one side)")
 	}
-	c2.AcquireBackend("d", "app2", 8080)
-	b2 := c2.AcquireBackend("d", "app1", 8080)
+	c2.AcquireBackend("d", "app2", "8080")
+	b2 := c2.AcquireBackend("d", "app1", "8080")
 	if !c1.Equals(c2) {
 		t.Error("c1 and c2 should be equals (with backends)")
 	}
@@ -106,8 +106,8 @@ func TestEqual(t *testing.T) {
 	if !c1.Equals(c2) {
 		t.Error("c1 and c2 should be equals (with hosts)")
 	}
-	_, err1 := c1.BuildFrontendGroup()
-	_, err2 := c2.BuildFrontendGroup()
+	err1 := c1.BuildFrontendGroup()
+	err2 := c2.BuildFrontendGroup()
 	if err1 != nil {
 		t.Errorf("error building c1: %v", err1)
 	}
diff --git a/pkg/haproxy/instance.go b/pkg/haproxy/instance.go
index 6bd5fde55..d0201d278 100644
--- a/pkg/haproxy/instance.go
+++ b/pkg/haproxy/instance.go
@@ -117,6 +117,11 @@ func (i *instance) Update() {
 		i.logger.InfoV(2, "new configuration is empty")
 		return
 	}
+	if err := i.curConfig.BuildFrontendGroup(); err != nil {
+		i.logger.Error("error building configuration group: %v", err)
+		i.clearConfig()
+		return
+	}
 	if i.curConfig.Equals(i.oldConfig) {
 		i.logger.InfoV(2, "old and new configurations match, skipping reload")
 		i.clearConfig()
@@ -141,7 +146,6 @@ func (i *instance) Update() {
 		i.logger.Error("error reloading server:\n%v", err)
 		return
 	}
-	i.clearConfig()
 	i.logger.Info("HAProxy successfully reloaded")
 }
 
@@ -164,8 +168,9 @@ func (i *instance) reload() error {
 	}
 	out, err := exec.Command(i.options.ReloadCmd, i.options.ReloadStrategy, i.options.HAProxyConfigFile).CombinedOutput()
 	if len(out) > 0 {
-		return fmt.Errorf(string(out))
-	} else if err != nil {
+		i.logger.Warn("output from haproxy:\n%v", string(out))
+	}
+	if err != nil {
 		return err
 	}
 	return nil
diff --git a/pkg/haproxy/instance_test.go b/pkg/haproxy/instance_test.go
index a2d17c524..cf11d2dd6 100644
--- a/pkg/haproxy/instance_test.go
+++ b/pkg/haproxy/instance_test.go
@@ -32,6 +32,177 @@ import (
 	"github.com/jcmoraisjr/haproxy-ingress/pkg/types/helper_test"
 )
 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  BACKEND TESTCASES
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+func TestBackends(t *testing.T) {
+	testCases := []struct {
+		doconfig  func(g *hatypes.Global, b *hatypes.Backend)
+		path      []string
+		srvsuffix string
+		expected  string
+	}{
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				b.Cookie.Name = "ingress-controller"
+				b.Cookie.Strategy = "insert"
+			},
+			srvsuffix: "cookie s1",
+			expected: `
+    cookie ingress-controller insert indirect nocache httponly`,
+		},
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				b.Cookie.Name = "Ingress"
+				b.Cookie.Strategy = "prefix"
+				b.Cookie.Dynamic = true
+			},
+			expected: `
+    cookie Ingress prefix dynamic
+    dynamic-cookie-key "Ingress"`,
+		},
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				b.Cors.Enabled = true
+				b.Cors.AllowOrigin = "*"
+				b.Cors.AllowHeaders =
+					"DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization"
+				b.Cors.AllowMethods = "GET, PUT, POST, DELETE, PATCH, OPTIONS"
+				b.Cors.MaxAge = 86400
+			},
+			expected: `
+    http-request use-service lua.send-response if METH_OPTIONS
+    http-response set-status 204 reason "No Content" if METH_OPTIONS
+    http-response set-header Content-Type                 "text/plain" if METH_OPTIONS
+    http-response set-header Content-Length               "0" if METH_OPTIONS
+    http-response set-header Access-Control-Allow-Origin  "*" if METH_OPTIONS
+    http-response set-header Access-Control-Allow-Methods "GET, PUT, POST, DELETE, PATCH, OPTIONS" if METH_OPTIONS
+    http-response set-header Access-Control-Allow-Headers "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization" if METH_OPTIONS
+    http-response set-header Access-Control-Max-Age       "86400" if METH_OPTIONS
+    http-response set-header Access-Control-Allow-Origin  "*"
+    http-response set-header Access-Control-Allow-Methods "GET, PUT, POST, DELETE, PATCH, OPTIONS"
+    http-response set-header Access-Control-Allow-Headers "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization"`,
+		},
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				b.HSTS.Enabled = true
+				b.HSTS.MaxAge = 15768000
+				b.HSTS.Preload = true
+				b.HSTS.Subdomains = true
+			},
+			expected: `
+    http-response set-header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" if { ssl_fc }`,
+		},
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				g.ForwardFor = "add"
+			},
+			expected: `
+    http-request set-header X-Original-Forwarded-For %[hdr(x-forwarded-for)] if { hdr(x-forwarded-for) -m found }
+    http-request del-header x-forwarded-for
+    option forwardfor`,
+		},
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				b.RewriteURL = "/"
+			},
+			path: []string{"/app"},
+			expected: `
+    reqrep ^([^:\ ]*)\ /app/?(.*)$     \1\ /\2`,
+		},
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				b.RewriteURL = "/other"
+			},
+			path: []string{"/app"},
+			expected: `
+    reqrep ^([^:\ ]*)\ /app(.*)$       \1\ /other\2`,
+		},
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				b.RewriteURL = "/other/"
+			},
+			path: []string{"/app", "/app/sub"},
+			expected: `
+    reqrep ^([^:\ ]*)\ /app/sub(.*)$       \1\ /other/\2
+    reqrep ^([^:\ ]*)\ /app(.*)$       \1\ /other/\2`,
+		},
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				b.Whitelist = []string{"10.0.0.0/8", "192.168.0.0/16"}
+			},
+			expected: `
+    http-request deny if !{ src 10.0.0.0/8 192.168.0.0/16 }`,
+		},
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				b.Whitelist = []string{"10.0.0.0/8", "192.168.0.0/16"}
+				b.ModeTCP = true
+			},
+			expected: `
+    tcp-request content reject if !{ src 10.0.0.0/8 192.168.0.0/16 }`,
+		},
+		{
+			doconfig: func(g *hatypes.Global, b *hatypes.Backend) {
+				b.OAuth.Impl = "oauth2_proxy"
+				b.OAuth.BackendName = "system_oauth_4180"
+				b.OAuth.URIPrefix = "/oauth2"
+				b.OAuth.Headers = map[string]string{"X-Auth-Request-Email": "auth_response_email"}
+			},
+			expected: `
+    http-request set-header X-Real-IP %[src]
+    http-request lua.auth-request system_oauth_4180 /oauth2/auth
+    http-request redirect location /oauth2/start?rd=%[path] if !{ path_beg /oauth2/ } !{ var(txn.auth_response_successful) -m bool }
+    http-request set-header X-Auth-Request-Email %[var(txn.auth_response_email)] if { var(txn.auth_response_email) -m found }`,
+		},
+	}
+	for _, test := range testCases {
+		c := setup(t)
+
+		if len(test.path) == 0 {
+			test.path = []string{"/"}
+		}
+		if test.srvsuffix != "" {
+			test.srvsuffix = " " + test.srvsuffix
+		}
+
+		var h *hatypes.Host
+		var b *hatypes.Backend
+
+		b = c.config.AcquireBackend("d1", "app", "8080")
+		b.Endpoints = []*hatypes.Endpoint{endpointS1}
+		h = c.config.AcquireHost("d1.local")
+		for _, p := range test.path {
+			h.AddPath(b, p)
+		}
+		test.doconfig(c.config.Global(), b)
+
+		var mode string
+		if b.ModeTCP {
+			mode = "tcp"
+		} else {
+			mode = "http"
+		}
+
+		c.instance.Update()
+		c.checkConfig(`
+<<global>>
+<<defaults>>
+backend d1_app_8080
+    mode ` + mode + test.expected + `
+    server s1 172.17.0.11:8080 weight 100` + test.srvsuffix + `
+<<backends-default>>
+<<frontends-default>>
+`)
+
+		c.logger.CompareLogging(defaultLogging)
+		c.teardown()
+	}
+}
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *
  *  TEMPLATES
@@ -42,25 +213,36 @@ func TestInstanceEmpty(t *testing.T) {
 	c := setup(t)
 	defer c.teardown()
 
-	template := `
+	c.config.AcquireHost("empty").AddPath(c.config.AcquireBackend("default", "empty", "8080"), "/")
+	c.instance.Update()
+
+	c.checkConfig(`
 global
     daemon
-    quiet
-    stats socket %s level admin expose-fd listeners
-    maxconn 0
+    stats socket /var/run/haproxy.sock level admin expose-fd listeners
+    maxconn 2000
+    hard-stop-after 15m
     lua-load /usr/local/etc/haproxy/lua/send-response.lua
     lua-load /usr/local/etc/haproxy/lua/auth-request.lua
-    tune.ssl.default-dh-param 0
+    ssl-dh-param-file /var/haproxy/tls/dhparam.pem
+    ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256
+    ssl-default-bind-options no-sslv3
 defaults
     log global
-    maxconn 0
+    maxconn 2000
     option redispatch
     option dontlognull
     option http-server-close
     option http-keep-alive
-    timeout client          %s
-    timeout connect         %s
-    timeout server          %s
+    timeout client          50s
+    timeout client-fin      50s
+    timeout connect         5s
+    timeout http-keep-alive 1m
+    timeout http-request    5s
+    timeout queue           5s
+    timeout server          50s
+    timeout server-fin      50s
+    timeout tunnel          1h
 backend default_empty_8080
     mode http
 backend _error404
@@ -75,27 +257,29 @@ backend _error496
     mode http
     errorfile 400 /usr/local/etc/haproxy/errors/496.http
     http-request deny deny_status 400
-frontend _front__http
+frontend _front_http
     mode http
     bind :80
-    http-request set-var(req.backend) base,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/http-front.map,_nomatch)
-    use_backend %%[var(req.backend)] unless { var(req.backend) _nomatch }
+    http-request set-var(req.base) base,regsub(:[0-9]+/,/)
+    http-request redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch) yes }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
+    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
     default_backend _error404
-frontend https-front_empty
+frontend _front001
     mode http
     bind :443 ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem
-    http-request set-var(req.hostbackend) base,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/https-front_empty_host.map,_nomatch)
-    use_backend %%[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
+    http-request set-var(req.hostbackend) base,lower,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front001_host.map,_nomatch)
+    <<tls-del-headers>>
+    use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
     default_backend _error404
-`
-
-	c.config.AcquireHost("empty").AddPath(c.config.AcquireBackend("default", "empty", 8080), "/")
-	c.instance.Update()
-	c.checkConfigFull(fmt.Sprintf(template, "--", "--", "--", "--"))
+`)
 
-	c.checkMap("http-front.map", `
+	c.checkMap("_global_http_front.map", `
 empty/ default_empty_8080`)
-	c.checkMap("https-front_empty_host.map", `
+	c.checkMap("_global_https_redir.map", `
+empty/ no`)
+	c.checkMap("_front001_host.map", `
 empty/ default_empty_8080`)
 
 	c.logger.CompareLogging(defaultLogging)
@@ -105,22 +289,21 @@ func TestInstanceDefaultHost(t *testing.T) {
 	c := setup(t)
 	defer c.teardown()
 
-	c.configGlobal()
-	def := c.config.AcquireBackend("default", "default-backend", 8080)
+	def := c.config.AcquireBackend("default", "default-backend", "8080")
 	def.Endpoints = []*hatypes.Endpoint{endpointS0}
 	c.config.ConfigDefaultBackend(def)
 
 	var h *hatypes.Host
 	var b *hatypes.Backend
 
-	b = c.config.AcquireBackend("d1", "app", 8080)
+	b = c.config.AcquireBackend("d1", "app", "8080")
 	h = c.config.AcquireHost("*")
 	h.AddPath(b, "/")
 	b.SSLRedirect = true
 	b.Endpoints = []*hatypes.Endpoint{endpointS1}
 	h.VarNamespace = true
 
-	b = c.config.AcquireBackend("d2", "app", 8080)
+	b = c.config.AcquireBackend("d2", "app", "8080")
 	h = c.config.AcquireHost("d2.local")
 	h.AddPath(b, "/app")
 	b.SSLRedirect = true
@@ -129,6 +312,8 @@ func TestInstanceDefaultHost(t *testing.T) {
 
 	c.instance.Update()
 	c.checkConfig(`
+<<global>>
+<<defaults>>
 backend d1_app_8080
     mode http
     server s1 172.17.0.11:8080 weight 100
@@ -137,28 +322,39 @@ backend d2_app_8080
     server s1 172.17.0.11:8080 weight 100
 backend _default_backend
     mode http
-    server s0 172.17.0.99:8080 weight 100`, `
-frontend _front__http
+    server s0 172.17.0.99:8080 weight 100
+<<backend-errors>>
+frontend _front_http
     mode http
     bind :80
     http-request set-var(req.base) base,regsub(:[0-9]+/,/)
-    redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/redirect.map,_nomatch) yes }
+    http-request redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch) yes }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
+    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
     use_backend d1_app_8080
-frontend https-front_d2.local
+frontend _front001
     mode http
     bind :443 ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem
-    http-request set-var(txn.namespace) base,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/https-front_d2.local_k8s_ns.map,-)
-    http-request set-var(req.hostbackend) base,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/https-front_d2.local_host.map,_nomatch)
+    http-request set-var(req.base) base,lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.hostbackend) var(req.base),map_beg(/etc/haproxy/maps/_front001_host.map,_nomatch)
+    http-request set-var(txn.namespace) var(req.base),map_beg(/etc/haproxy/maps/_front001_k8s_ns.map,-)
+    <<tls-del-headers>>
     use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
     use_backend d1_app_8080
 `)
 
-	c.checkMap("https-front_d2.local_k8s_ns.map", `
-d2.local/app d2`)
-	c.checkMap("https-front_d2.local_host.map", `
-d2.local/app d2_app_8080`)
-	c.checkMap("redirect.map", `
-d2.local/app yes`)
+	c.checkMap("_global_http_front.map", `
+`)
+	c.checkMap("_global_https_redir.map", `
+d2.local/app yes
+`)
+	c.checkMap("_front001_k8s_ns.map", `
+d2.local/app d2
+`)
+	c.checkMap("_front001_host.map", `
+d2.local/app d2_app_8080
+`)
 
 	c.logger.CompareLogging(defaultLogging)
 }
@@ -167,15 +363,14 @@ func TestInstanceSingleFrontendSingleBind(t *testing.T) {
 	c := setup(t)
 	defer c.teardown()
 
-	c.configGlobal()
-	def := c.config.AcquireBackend("default", "default-backend", 8080)
+	def := c.config.AcquireBackend("default", "default-backend", "8080")
 	def.Endpoints = []*hatypes.Endpoint{endpointS0}
 	c.config.ConfigDefaultBackend(def)
 
 	var h *hatypes.Host
 	var b *hatypes.Backend
 
-	b = c.config.AcquireBackend("d1", "app", 8080)
+	b = c.config.AcquireBackend("d1", "app", "8080")
 	h = c.config.AcquireHost("d1.local")
 	h.AddPath(b, "/")
 	b.SSLRedirect = true
@@ -184,7 +379,7 @@ func TestInstanceSingleFrontendSingleBind(t *testing.T) {
 	h.TLS.TLSFilename = "/var/haproxy/ssl/certs/d1.pem"
 	h.TLS.TLSHash = "1"
 
-	b = c.config.AcquireBackend("d2", "app", 8080)
+	b = c.config.AcquireBackend("d2", "app", "8080")
 	h = c.config.AcquireHost("d2.local")
 	h.AddPath(b, "/app")
 	b.SSLRedirect = true
@@ -194,6 +389,8 @@ func TestInstanceSingleFrontendSingleBind(t *testing.T) {
 
 	c.instance.Update()
 	c.checkConfig(`
+<<global>>
+<<defaults>>
 backend d1_app_8080
     mode http
     server s1 172.17.0.11:8080 weight 100
@@ -202,31 +399,42 @@ backend d2_app_8080
     server s1 172.17.0.11:8080 weight 100
 backend _default_backend
     mode http
-    server s0 172.17.0.99:8080 weight 100`, `
-frontend _front__http
+    server s0 172.17.0.99:8080 weight 100
+<<backend-errors>>
+frontend _front_http
     mode http
     bind :80
     http-request set-var(req.base) base,regsub(:[0-9]+/,/)
-    redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/redirect.map,_nomatch) yes }
+    http-request redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch) yes }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
+    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
     default_backend _default_backend
-frontend _front_001
+frontend _front001
     mode http
     bind :443 ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem crt /var/haproxy/certs/_public
-    http-request set-var(txn.namespace) base,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front_001_k8s_ns.map,-)
-    http-request set-var(req.hostbackend) base,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front_001_host.map,_nomatch)
+    http-request set-var(req.base) base,lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.hostbackend) var(req.base),map_beg(/etc/haproxy/maps/_front001_host.map,_nomatch)
+    http-request set-var(txn.namespace) var(req.base),map_beg(/etc/haproxy/maps/_front001_k8s_ns.map,-)
+    <<tls-del-headers>>
     use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
     default_backend _default_backend
 `)
 
-	c.checkMap("_front_001_k8s_ns.map", `
-d1.local/ d1
-d2.local/app -`)
-	c.checkMap("_front_001_host.map", `
-d1.local/ d1_app_8080
-d2.local/app d2_app_8080`)
-	c.checkMap("redirect.map", `
+	c.checkMap("_global_http_front.map", `
+`)
+	c.checkMap("_global_https_redir.map", `
 d1.local/ yes
-d2.local/app yes`)
+d2.local/app yes
+`)
+	c.checkMap("_front001_host.map", `
+d1.local/ d1_app_8080
+d2.local/app d2_app_8080
+`)
+	c.checkMap("_front001_k8s_ns.map", `
+d1.local/ d1
+d2.local/app -
+`)
 
 	c.checkCerts(`
 certdirs:
@@ -242,19 +450,19 @@ func TestInstanceSingleFrontendTwoBindsCA(t *testing.T) {
 	c := setup(t)
 	defer c.teardown()
 
-	c.configGlobal()
-	def := c.config.AcquireBackend("default", "default-backend", 8080)
+	def := c.config.AcquireBackend("default", "default-backend", "8080")
 	def.Endpoints = []*hatypes.Endpoint{endpointS0}
 	c.config.ConfigDefaultBackend(def)
 
 	var h *hatypes.Host
 	var b *hatypes.Backend
 
-	b = c.config.AcquireBackend("d", "app", 8080)
+	b = c.config.AcquireBackend("d", "app", "8080")
 	h = c.config.AcquireHost("d1.local")
 	h.AddPath(b, "/")
 	b.SSLRedirect = true
 	b.Endpoints = []*hatypes.Endpoint{endpointS1}
+	b.SSL.AddCertHeader = true
 	h.TLS.CAFilename = "/var/haproxy/ssl/ca/d1.local.pem"
 	h.TLS.CAHash = "1"
 	h.TLS.CAErrorPage = "http://d1.local/error.html"
@@ -266,72 +474,96 @@ func TestInstanceSingleFrontendTwoBindsCA(t *testing.T) {
 
 	c.instance.Update()
 	c.checkConfig(`
+<<global>>
+<<defaults>>
 backend d_app_8080
     mode http
+    http-request set-header X-SSL-Client-CN   %{+Q}[ssl_c_s_dn(cn)]
+    http-request set-header X-SSL-Client-DN   %{+Q}[ssl_c_s_dn]
+    http-request set-header X-SSL-Client-SHA1 %{+Q}[ssl_c_sha1,hex]
+    http-request set-header X-SSL-Client-Cert %{+Q}[ssl_c_der,base64]
     server s1 172.17.0.11:8080 weight 100
 backend _default_backend
     mode http
-    server s0 172.17.0.99:8080 weight 100`, `
+    server s0 172.17.0.99:8080 weight 100
+<<backend-errors>>
 listen _front__tls
     mode tcp
     bind :443
     tcp-request inspect-delay 5s
     tcp-request content accept if { req.ssl_hello_type 1 }
-    ## _front_001
-    use-server _server_d1.local if { req.ssl_sni -i -f /etc/haproxy/maps/_front_001_bind_d1.local.list }
-    server _server_d1.local unix@/var/run/front_d1.local.sock send-proxy-v2 weight 0
-    use-server _server_d2.local if { req.ssl_sni -i -f /etc/haproxy/maps/_front_001_bind_d2.local.list }
-    server _server_d2.local unix@/var/run/front_d2.local.sock send-proxy-v2 weight 0
+    ## _front001/_socket001
+    use-server _server_socket001 if { req.ssl_sni -i -f /etc/haproxy/maps/_socket001.list }
+    server _server_socket001 unix@/var/run/_socket001.sock send-proxy-v2 weight 0
+    ## _front001/_socket002
+    use-server _server_socket002 if { req.ssl_sni -i -f /etc/haproxy/maps/_socket002.list }
+    server _server_socket002 unix@/var/run/_socket002.sock send-proxy-v2 weight 0
     # TODO default backend
-frontend _front__http
+frontend _front_http
     mode http
     bind :80
     http-request set-var(req.base) base,regsub(:[0-9]+/,/)
-    redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/redirect.map,_nomatch) yes }
+    http-request redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch) yes }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
+    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
     default_backend _default_backend
-frontend _front_001
+frontend _front001
     mode http
-    bind unix@/var/run/front_d1.local.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem ca-file /var/haproxy/ssl/ca/d1.local.pem verify optional ca-ignore-err all crt-ignore-err all
-    bind unix@/var/run/front_d2.local.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem ca-file /var/haproxy/ssl/ca/d2.local.pem verify optional ca-ignore-err all crt-ignore-err all
-    http-request set-var(req.hostbackend) base,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front_001_host.map,_nomatch)
+    bind unix@/var/run/_socket001.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem ca-file /var/haproxy/ssl/ca/d1.local.pem verify optional ca-ignore-err all crt-ignore-err all
+    bind unix@/var/run/_socket002.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem ca-file /var/haproxy/ssl/ca/d2.local.pem verify optional ca-ignore-err all crt-ignore-err all
+    http-request set-var(req.hostbackend) base,lower,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front001_host.map,_nomatch)
+    <<tls-del-headers>>
     http-request set-header x-ha-base %[ssl_fc_sni]%[path]
-    http-request set-var(req.snibackend) hdr(x-ha-base),regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front_001_sni.map,_nomatch)
-    acl tls-invalid-crt ssl_c_ca_err gt 0
-    acl tls-invalid-crt ssl_c_err gt 0
+    http-request set-var(req.snibackend) hdr(x-ha-base),lower,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front001_sni.map,_nomatch)
     acl tls-has-crt ssl_c_used
-    http-request set-var(req.tls_nocrt_redir) ssl_fc_sni,map(/etc/haproxy/maps/_front_001_no_crt_redir.map,_internal) if !tls-has-crt
-    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni,map(/etc/haproxy/maps/_front_001_inv_crt_redir.map,_internal) if tls-invalid-crt
+    acl tls-need-crt ssl_fc_sni -i -f /etc/haproxy/maps/_front001_no_crt.list
+    acl tls-has-invalid-crt ssl_c_ca_err gt 0
+    acl tls-has-invalid-crt ssl_c_err gt 0
+    acl tls-check-crt ssl_fc_sni -i -f /etc/haproxy/maps/_front001_inv_crt.list
+    http-request set-var(req.tls_nocrt_redir) ssl_fc_sni,lower,map(/etc/haproxy/maps/_front001_no_crt_redir.map,_internal) if !tls-has-crt tls-need-crt
+    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni,lower,map(/etc/haproxy/maps/_front001_inv_crt_redir.map,_internal) if tls-has-invalid-crt tls-check-crt
     http-request redirect location %[var(req.tls_nocrt_redir)] code 303 if { var(req.tls_nocrt_redir) -m found } !{ var(req.tls_nocrt_redir) _internal }
     http-request redirect location %[var(req.tls_invalidcrt_redir)] code 303 if { var(req.tls_invalidcrt_redir) -m found } !{ var(req.tls_invalidcrt_redir) _internal }
-    use_backend _error496 if { var(req.tls_nocrt_redir) _internal } { ssl_fc_sni -i -f /etc/haproxy/maps/_front_001_no_crt.list }
-    use_backend _error495 if { var(req.tls_invalidcrt_redir) _internal } { ssl_fc_sni -i -f /etc/haproxy/maps/_front_001_inv_crt.list }
+    use_backend _error496 if { var(req.tls_nocrt_redir) _internal }
+    use_backend _error495 if { var(req.tls_invalidcrt_redir) _internal }
     use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
     use_backend %[var(req.snibackend)] unless { var(req.snibackend) _nomatch }
     default_backend _default_backend
 `)
 
-	c.checkMap("_front_001_inv_crt_redir.map", `
-d1.local http://d1.local/error.html`)
-	c.checkMap("_front_001_inv_crt.list", `
+	c.checkMap("_socket001.list", `
 d1.local
-d2.local`)
-	c.checkMap("_front_001_no_crt_redir.map", `
-d1.local http://d1.local/error.html`)
-	c.checkMap("_front_001_no_crt.list", `
-d1.local
-d2.local`)
-	c.checkMap("_front_001_host.map", `
 `)
-	c.checkMap("_front_001_sni.map", `
-d1.local/ d_app_8080
-d2.local/ d_app_8080`)
-	c.checkMap("_front_001_bind_d1.local.list", `
-d1.local`)
-	c.checkMap("_front_001_bind_d2.local.list", `
-d2.local`)
-	c.checkMap("redirect.map", `
+	c.checkMap("_socket002.list", `
+d2.local
+`)
+	c.checkMap("_global_http_front.map", `
+`)
+	c.checkMap("_global_https_redir.map", `
 d1.local/ yes
-d2.local/ yes`)
+d2.local/ yes
+`)
+	c.checkMap("_front001_host.map", `
+`)
+	c.checkMap("_front001_sni.map", `
+d1.local/ d_app_8080
+d2.local/ d_app_8080
+`)
+	c.checkMap("_front001_no_crt.list", `
+d1.local
+d2.local
+`)
+	c.checkMap("_front001_inv_crt.list", `
+d1.local
+d2.local
+`)
+	c.checkMap("_front001_no_crt_redir.map", `
+d1.local http://d1.local/error.html
+`)
+	c.checkMap("_front001_inv_crt_redir.map", `
+d1.local http://d1.local/error.html
+`)
 
 	c.logger.CompareLogging(defaultLogging)
 }
@@ -340,18 +572,16 @@ func TestInstanceTwoFrontendsThreeBindsCA(t *testing.T) {
 	c := setup(t)
 	defer c.teardown()
 
-	c.configGlobal()
-	def := c.config.AcquireBackend("default", "default-backend", 8080)
+	def := c.config.AcquireBackend("default", "default-backend", "8080")
 	def.Endpoints = []*hatypes.Endpoint{endpointS0}
 	c.config.ConfigDefaultBackend(def)
 
 	var h *hatypes.Host
 	var b *hatypes.Backend
 
-	b = c.config.AcquireBackend("d", "appca", 8080)
+	b = c.config.AcquireBackend("d", "appca", "8080")
 	h = c.config.AcquireHost("d1.local")
 	h.AddPath(b, "/")
-	b.SSLRedirect = true
 	b.Endpoints = []*hatypes.Endpoint{endpointS1}
 	h.Timeout.Client = "1s"
 	h.TLS.CAFilename = "/var/haproxy/ssl/ca/d1.local.pem"
@@ -378,7 +608,7 @@ func TestInstanceTwoFrontendsThreeBindsCA(t *testing.T) {
 	h.TLS.CAHash = "1"
 	h.TLS.CAErrorPage = "http://d22.local/error.html"
 
-	b = c.config.AcquireBackend("d", "app", 8080)
+	b = c.config.AcquireBackend("d", "app", "8080")
 	h = c.config.AcquireHost("d3.local")
 	h.AddPath(b, "/")
 	b.Endpoints = []*hatypes.Endpoint{endpointS21}
@@ -390,124 +620,148 @@ func TestInstanceTwoFrontendsThreeBindsCA(t *testing.T) {
 
 	c.instance.Update()
 	c.checkConfig(`
+<<global>>
+<<defaults>>
 backend d_app_8080
     mode http
     server s21 172.17.0.121:8080 weight 100
 backend d_appca_8080
     mode http
+    http-request set-header X-SSL-Client-CN   %{+Q}[ssl_c_s_dn(cn)]   if { ssl_fc }
+    http-request set-header X-SSL-Client-DN   %{+Q}[ssl_c_s_dn]       if { ssl_fc }
+    http-request set-header X-SSL-Client-SHA1 %{+Q}[ssl_c_sha1,hex]   if { ssl_fc }
     server s1 172.17.0.11:8080 weight 100
 backend _default_backend
     mode http
-    server s0 172.17.0.99:8080 weight 100`, `
+    server s0 172.17.0.99:8080 weight 100
+<<backend-errors>>
 listen _front__tls
     mode tcp
     bind :443
     tcp-request inspect-delay 5s
     tcp-request content accept if { req.ssl_hello_type 1 }
-    ## _front_001
-    use-server _server__socket001 if { req.ssl_sni -i -f /etc/haproxy/maps/_front_001_bind__socket001.list }
-    server _server__socket001 unix@/var/run/front__socket001.sock send-proxy-v2 weight 0
-    use-server _server__socket002 if { req.ssl_sni -i -f /etc/haproxy/maps/_front_001_bind__socket002.list }
-    server _server__socket002 unix@/var/run/front__socket002.sock send-proxy-v2 weight 0
-    ## https-front_d1.local
-    use-server _server_d1.local if { req.ssl_sni -i -f /etc/haproxy/maps/https-front_d1.local_bind_d1.local.list }
-    server _server_d1.local unix@/var/run/front_d1.local.sock send-proxy-v2 weight 0
+    ## _front001/_socket001
+    use-server _server_socket001 if { req.ssl_sni -i -f /etc/haproxy/maps/_socket001.list }
+    server _server_socket001 unix@/var/run/_socket001.sock send-proxy-v2 weight 0
+    ## _front002/_socket002
+    use-server _server_socket002 if { req.ssl_sni -i -f /etc/haproxy/maps/_socket002.list }
+    server _server_socket002 unix@/var/run/_socket002.sock send-proxy-v2 weight 0
+    ## _front002/_socket003
+    use-server _server_socket003 if { req.ssl_sni -i -f /etc/haproxy/maps/_socket003.list }
+    server _server_socket003 unix@/var/run/_socket003.sock send-proxy-v2 weight 0
     # TODO default backend
-frontend _front__http
+frontend _front_http
     mode http
     bind :80
     http-request set-var(req.base) base,regsub(:[0-9]+/,/)
-    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/http-front.map,_nomatch)
-    redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/redirect.map,_nomatch) yes }
+    http-request redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch) yes }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
     use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
     default_backend _default_backend
-frontend _front_001
+frontend _front001
     mode http
-    bind unix@/var/run/front__socket001.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem crt /var/haproxy/certs/_socket001 ca-file /var/haproxy/ssl/ca/d2.local.pem verify optional ca-ignore-err all crt-ignore-err all
-    bind unix@/var/run/front__socket002.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem
-    timeout client 2s
-    http-request set-var(req.hostbackend) base,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front_001_host.map,_nomatch)
+    bind unix@/var/run/_socket001.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem ca-file /var/haproxy/ssl/ca/d1.local.pem verify optional ca-ignore-err all crt-ignore-err all
+    timeout client 1s
+    http-request set-var(req.hostbackend) base,lower,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front001_host.map,_nomatch)
+    <<tls-del-headers>>
     http-request set-header x-ha-base %[ssl_fc_sni]%[path]
-    http-request set-var(req.snibackend) hdr(x-ha-base),regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front_001_sni.map,_nomatch)
-    acl tls-invalid-crt ssl_c_ca_err gt 0
-    acl tls-invalid-crt ssl_c_err gt 0
-    acl tls-has-crt ssl_c_used
-    http-request set-var(req.tls_nocrt_redir) ssl_fc_sni,map(/etc/haproxy/maps/_front_001_no_crt_redir.map,_internal) if !tls-has-crt
-    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni,map(/etc/haproxy/maps/_front_001_inv_crt_redir.map,_internal) if tls-invalid-crt
-    http-request redirect location %[var(req.tls_nocrt_redir)] code 303 if { var(req.tls_nocrt_redir) -m found } !{ var(req.tls_nocrt_redir) _internal }
+    http-request set-var(req.snibackend) hdr(x-ha-base),lower,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front001_sni.map,_nomatch)
+    acl tls-has-invalid-crt ssl_c_ca_err gt 0
+    acl tls-has-invalid-crt ssl_c_err gt 0
+    acl tls-check-crt ssl_fc_sni -i -f /etc/haproxy/maps/_front001_inv_crt.list
+    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni,lower,map(/etc/haproxy/maps/_front001_inv_crt_redir.map,_internal) if tls-has-invalid-crt tls-check-crt
     http-request redirect location %[var(req.tls_invalidcrt_redir)] code 303 if { var(req.tls_invalidcrt_redir) -m found } !{ var(req.tls_invalidcrt_redir) _internal }
-    use_backend _error496 if { var(req.tls_nocrt_redir) _internal } { ssl_fc_sni -i -f /etc/haproxy/maps/_front_001_no_crt.list }
-    use_backend _error495 if { var(req.tls_invalidcrt_redir) _internal } { ssl_fc_sni -i -f /etc/haproxy/maps/_front_001_inv_crt.list }
+    use_backend _error495 if { var(req.tls_invalidcrt_redir) _internal }
     use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
     use_backend %[var(req.snibackend)] unless { var(req.snibackend) _nomatch }
     default_backend _default_backend
-frontend https-front_d1.local
+frontend _front002
     mode http
-    bind unix@/var/run/front_d1.local.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem ca-file /var/haproxy/ssl/ca/d1.local.pem verify optional ca-ignore-err all crt-ignore-err all
-    timeout client 1s
-    http-request set-var(req.hostbackend) base,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/https-front_d1.local_host.map,_nomatch)
+    bind unix@/var/run/_socket002.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem crt /var/haproxy/certs/_socket002 ca-file /var/haproxy/ssl/ca/d2.local.pem verify optional ca-ignore-err all crt-ignore-err all
+    bind unix@/var/run/_socket003.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem
+    timeout client 2s
+    http-request set-var(req.hostbackend) base,lower,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front002_host.map,_nomatch)
+    <<tls-del-headers>>
     http-request set-header x-ha-base %[ssl_fc_sni]%[path]
-    http-request set-var(req.snibackend) hdr(x-ha-base),regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/https-front_d1.local_sni.map,_nomatch)
-    acl tls-invalid-crt ssl_c_ca_err gt 0
-    acl tls-invalid-crt ssl_c_err gt 0
-    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni,map(/etc/haproxy/maps/https-front_d1.local_inv_crt_redir.map,_internal) if tls-invalid-crt
+    http-request set-var(req.snibackend) hdr(x-ha-base),lower,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front002_sni.map,_nomatch)
+    acl tls-has-crt ssl_c_used
+    acl tls-need-crt ssl_fc_sni -i -f /etc/haproxy/maps/_front002_no_crt.list
+    acl tls-has-invalid-crt ssl_c_ca_err gt 0
+    acl tls-has-invalid-crt ssl_c_err gt 0
+    acl tls-check-crt ssl_fc_sni -i -f /etc/haproxy/maps/_front002_inv_crt.list
+    http-request set-var(req.tls_nocrt_redir) ssl_fc_sni,lower,map(/etc/haproxy/maps/_front002_no_crt_redir.map,_internal) if !tls-has-crt tls-need-crt
+    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni,lower,map(/etc/haproxy/maps/_front002_inv_crt_redir.map,_internal) if tls-has-invalid-crt tls-check-crt
+    http-request redirect location %[var(req.tls_nocrt_redir)] code 303 if { var(req.tls_nocrt_redir) -m found } !{ var(req.tls_nocrt_redir) _internal }
     http-request redirect location %[var(req.tls_invalidcrt_redir)] code 303 if { var(req.tls_invalidcrt_redir) -m found } !{ var(req.tls_invalidcrt_redir) _internal }
-    use_backend _error495 if { var(req.tls_invalidcrt_redir) _internal } { ssl_fc_sni -i -f /etc/haproxy/maps/https-front_d1.local_inv_crt.list }
+    use_backend _error496 if { var(req.tls_nocrt_redir) _internal }
+    use_backend _error495 if { var(req.tls_invalidcrt_redir) _internal }
     use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
     use_backend %[var(req.snibackend)] unless { var(req.snibackend) _nomatch }
     default_backend _default_backend
 `)
 
-	c.checkMap("http-front.map", `
-d3.local/ d_app_8080
-d4.local/ d_app_8080`)
-	c.checkMap("_front_001_inv_crt_redir.map", `
-d21.local http://d21.local/error.html
-d22.local http://d22.local/error.html
+	c.checkMap("_socket001.list", `
+d1.local
 `)
-	c.checkMap("_front_001_inv_crt.list", `
+	c.checkMap("_socket002.list", `
 d21.local
-d22.local`)
-	c.checkMap("_front_001_no_crt_redir.map", `
-d22.local http://d22.local/error.html
+d22.local
 `)
-	c.checkMap("_front_001_no_crt.list", `
-d22.local`)
-	c.checkMap("_front_001_host.map", `
-d3.local/ d_app_8080
-d4.local/ d_app_8080`)
-	c.checkMap("_front_001_sni.map", `
-d21.local/ d_appca_8080
-d22.local/ d_appca_8080`)
-	c.checkMap("_front_001_bind__socket001.list", `
-d21.local
-d22.local`)
-	c.checkMap("_front_001_bind__socket002.list", `
+	c.checkMap("_socket003.list", `
 d3.local
-d4.local`)
-	c.checkMap("https-front_d1.local_inv_crt_redir.map", `
-d1.local http://d1.local/error.html`)
-	c.checkMap("https-front_d1.local_inv_crt.list", `
-d1.local`)
-	c.checkMap("https-front_d1.local_no_crt_redir.map", `
+d4.local
 `)
-	c.checkMap("https-front_d1.local_host.map", `
+	c.checkMap("_global_http_front.map", `
+d1.local/ d_appca_8080
+d21.local/ d_appca_8080
+d22.local/ d_appca_8080
+d3.local/ d_app_8080
+d4.local/ d_app_8080
 `)
-	c.checkMap("https-front_d1.local_sni.map", `
-d1.local/ d_appca_8080`)
-	c.checkMap("https-front_d1.local_bind_d1.local.list", `
-d1.local`)
-	c.checkMap("redirect.map", `
-d21.local/ yes
-d22.local/ yes
+	c.checkMap("_global_https_redir.map", `
+d1.local/ no
+d21.local/ no
+d22.local/ no
 d3.local/ no
 d4.local/ no
-d1.local/ yes
+`)
+	c.checkMap("_front001_host.map", `
+`)
+	c.checkMap("_front001_sni.map", `
+d1.local/ d_appca_8080
+`)
+	c.checkMap("_front001_inv_crt.list", `
+d1.local`)
+	c.checkMap("_front001_inv_crt_redir.map", `
+d1.local http://d1.local/error.html
+`)
+	c.checkMap("_front002_host.map", `
+d3.local/ d_app_8080
+d4.local/ d_app_8080
+`)
+	c.checkMap("_front002_sni.map", `
+d21.local/ d_appca_8080
+d22.local/ d_appca_8080
+`)
+	c.checkMap("_front002_no_crt.list", `
+d22.local
+`)
+	c.checkMap("_front002_inv_crt.list", `
+d21.local
+d22.local
+`)
+	c.checkMap("_front002_no_crt_redir.map", `
+d22.local http://d22.local/error.html
+`)
+	c.checkMap("_front002_inv_crt_redir.map", `
+d21.local http://d21.local/error.html
+d22.local http://d22.local/error.html
 `)
 
 	c.checkCerts(`
 certdirs:
-- dir: /var/haproxy/certs/_socket001
+- dir: /var/haproxy/certs/_socket002
   certs:
   - /var/haproxy/ssl/certs/d.pem`)
 
@@ -518,35 +772,36 @@ func TestInstanceSomePaths(t *testing.T) {
 	c := setup(t)
 	defer c.teardown()
 
-	c.configGlobal()
-	def := c.config.AcquireBackend("default", "default-backend", 8080)
+	def := c.config.AcquireBackend("default", "default-backend", "8080")
 	def.Endpoints = []*hatypes.Endpoint{endpointS0}
 	c.config.ConfigDefaultBackend(def)
 
 	var h *hatypes.Host
 	var b *hatypes.Backend
 
-	b = c.config.AcquireBackend("d", "app0", 8080)
+	b = c.config.AcquireBackend("d", "app0", "8080")
 	h = c.config.AcquireHost("d.local")
 	h.AddPath(b, "/")
 	b.SSLRedirect = true
 	b.Endpoints = []*hatypes.Endpoint{endpointS1}
 
-	b = c.config.AcquireBackend("d", "app1", 8080)
+	b = c.config.AcquireBackend("d", "app1", "8080")
 	h.AddPath(b, "/app")
 	b.SSLRedirect = true
 	b.Endpoints = []*hatypes.Endpoint{endpointS1}
 
-	b = c.config.AcquireBackend("d", "app2", 8080)
+	b = c.config.AcquireBackend("d", "app2", "8080")
 	h.AddPath(b, "/app/sub")
 	b.Endpoints = []*hatypes.Endpoint{endpointS21, endpointS22}
 
-	b = c.config.AcquireBackend("d", "app3", 8080)
+	b = c.config.AcquireBackend("d", "app3", "8080")
 	h.AddPath(b, "/sub")
 	b.Endpoints = []*hatypes.Endpoint{endpointS31, endpointS32, endpointS33}
 
 	c.instance.Update()
 	c.checkConfig(`
+<<global>>
+<<defaults>>
 backend d_app0_8080
     mode http
     server s1 172.17.0.11:8080 weight 100
@@ -564,65 +819,74 @@ backend d_app3_8080
     server s33 172.17.0.133:8080 weight 100
 backend _default_backend
     mode http
-    server s0 172.17.0.99:8080 weight 100`, `
-frontend _front__http
+    server s0 172.17.0.99:8080 weight 100
+<<backend-errors>>
+frontend _front_http
     mode http
     bind :80
     http-request set-var(req.base) base,regsub(:[0-9]+/,/)
-    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/http-front.map,_nomatch)
-    redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/redirect.map,_nomatch) yes }
+    http-request redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch) yes }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
     use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
     default_backend _default_backend
-frontend https-front_d.local
+frontend _front001
     mode http
     bind :443 ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem
-    http-request set-var(req.hostbackend) base,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/https-front_d.local_host.map,_nomatch)
+    http-request set-var(req.hostbackend) base,lower,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front001_host.map,_nomatch)
+    <<tls-del-headers>>
     use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
     default_backend _default_backend
 `)
 
-	c.checkMap("https-front_d.local_host.map", `
+	c.checkMap("_global_http_front.map", `
 d.local/sub d_app3_8080
 d.local/app/sub d_app2_8080
-d.local/app d_app1_8080
-d.local/ d_app0_8080`)
-	c.checkMap("redirect.map", `
+`)
+	c.checkMap("_global_https_redir.map", `
 d.local/sub no
 d.local/app/sub no
 d.local/app yes
-d.local/ yes`)
+d.local/ yes
+`)
+	c.checkMap("_front001_host.map", `
+d.local/sub d_app3_8080
+d.local/app/sub d_app2_8080
+d.local/app d_app1_8080
+d.local/ d_app0_8080
+`)
 
 	c.logger.CompareLogging(defaultLogging)
 }
 
-func TestSSLPassthrough(t *testing.T) {
+func TestInstanceSSLPassthrough(t *testing.T) {
 	c := setup(t)
 	defer c.teardown()
 
-	c.configGlobal()
-
 	var h *hatypes.Host
 	var b *hatypes.Backend
 
-	b = c.config.AcquireBackend("d2", "app", 8080)
+	b = c.config.AcquireBackend("d2", "app", "8080")
 	h = c.config.AcquireHost("d2.local")
 	h.AddPath(b, "/")
 	b.SSLRedirect = true
 	b.Endpoints = []*hatypes.Endpoint{endpointS31}
 	h.SSLPassthrough = true
 
-	b = c.config.AcquireBackend("d3", "app-ssl", 8443)
+	b = c.config.AcquireBackend("d3", "app-ssl", "8443")
 	h = c.config.AcquireHost("d3.local")
 	h.AddPath(b, "/")
 	b.Endpoints = []*hatypes.Endpoint{endpointS41s}
 	h.SSLPassthrough = true
 
-	b = c.config.AcquireBackend("d3", "app-http", 8080)
+	b = c.config.AcquireBackend("d3", "app-http", "8080")
 	b.Endpoints = []*hatypes.Endpoint{endpointS41h}
 	h.HTTPPassthroughBackend = b
 
 	c.instance.Update()
 	c.checkConfig(`
+<<global>>
+<<defaults>>
 backend d2_app_8080
     mode http
     server s31 172.17.0.131:8080 weight 100
@@ -632,40 +896,579 @@ backend d3_app-http_8080
 backend d3_app-ssl_8443
     mode http
     server s41s 172.17.0.141:8443 weight 100
-backend _error404
-    mode http
-    errorfile 400 /usr/local/etc/haproxy/errors/404.http
-    http-request deny deny_status 400`, `
+<<backends-default>>
 listen _front__tls
     mode tcp
     bind :443
     tcp-request inspect-delay 5s
     tcp-request content accept if { req.ssl_hello_type 1 }
     ## ssl-passthrough
-    tcp-request content set-var(req.backend) req.ssl_sni,lower,map(/etc/haproxy/maps/sslpassthrough.map,_nomatch)
+    tcp-request content set-var(req.backend) req.ssl_sni,lower,map(/etc/haproxy/maps/_global_sslpassthrough.map,_nomatch)
     use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
     # TODO default backend
-frontend _front__http
+frontend _front_http
     mode http
     bind :80
     http-request set-var(req.base) base,regsub(:[0-9]+/,/)
-    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/http-front.map,_nomatch)
-    redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/redirect.map,_nomatch) yes }
+    http-request redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch) yes }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
     use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
     default_backend _error404`)
 
-	c.checkMap("sslpassthrough.map", `
+	c.checkMap("_global_sslpassthrough.map", `
 d2.local d2_app_8080
 d3.local d3_app-ssl_8443`)
-	c.checkMap("http-front.map", `
+	c.checkMap("_global_http_front.map", `
 d3.local/ d3_app-http_8080`)
-	c.checkMap("redirect.map", `
+	c.checkMap("_global_https_redir.map", `
 d2.local/ yes
 d3.local/ no`)
 
 	c.logger.CompareLogging(defaultLogging)
 }
 
+func TestInstanceRootRedirect(t *testing.T) {
+	c := setup(t)
+	defer c.teardown()
+
+	var h *hatypes.Host
+	var b *hatypes.Backend
+
+	b = c.config.AcquireBackend("d1", "app", "8080")
+	b.Endpoints = []*hatypes.Endpoint{endpointS1}
+	b.SSLRedirect = false
+	h = c.config.AcquireHost("d1.local")
+	h.AddPath(b, "/")
+	h.RootRedirect = "/app"
+
+	b = c.config.AcquireBackend("d2", "app", "8080")
+	b.Endpoints = []*hatypes.Endpoint{endpointS21}
+	b.SSLRedirect = true
+	h = c.config.AcquireHost("d2.local")
+	h.AddPath(b, "/app1")
+	h.AddPath(b, "/app2")
+	h.RootRedirect = "/app1"
+
+	c.instance.Update()
+
+	c.checkConfig(`
+<<global>>
+<<defaults>>
+backend d1_app_8080
+    mode http
+    server s1 172.17.0.11:8080 weight 100
+backend d2_app_8080
+    mode http
+    server s21 172.17.0.121:8080 weight 100
+<<backends-default>>
+frontend _front_http
+    mode http
+    bind :80
+    http-request set-var(req.base) base,regsub(:[0-9]+/,/)
+    http-request redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch) yes }
+    http-request set-var(req.host) hdr(host),lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.rootredir) var(req.host),map(/etc/haproxy/maps/_global_http_root_redir.map,_nomatch)
+    http-request redirect location %[var(req.rootredir)] if { path / } !{ var(req.rootredir) _nomatch }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
+    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
+    default_backend _error404
+frontend _front001
+    mode http
+    bind :443 ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem
+    http-request set-var(req.hostbackend) base,lower,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front001_host.map,_nomatch)
+    http-request set-var(req.host) hdr(host),lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.rootredir) var(req.host),map(/etc/haproxy/maps/_front001_root_redir.map,_nomatch)
+    http-request redirect location %[var(req.rootredir)] if { path / } !{ var(req.rootredir) _nomatch }
+    <<tls-del-headers>>
+    use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
+    default_backend _error404
+`)
+
+	c.checkMap("_global_http_front.map", `
+d1.local/ d1_app_8080
+`)
+	c.checkMap("_global_https_redir.map", `
+d1.local/ no
+d2.local/app2 yes
+d2.local/app1 yes
+`)
+	c.checkMap("_global_http_root_redir.map", `
+d1.local /app
+d2.local /app1
+`)
+	c.checkMap("_front001_host.map", `
+d1.local/ d1_app_8080
+d2.local/app2 d2_app_8080
+d2.local/app1 d2_app_8080
+`)
+	c.checkMap("_front001_root_redir.map", `
+d1.local /app
+d2.local /app1
+`)
+
+	c.logger.CompareLogging(defaultLogging)
+}
+
+func TestInstanceAlias(t *testing.T) {
+	c := setup(t)
+	defer c.teardown()
+
+	var h *hatypes.Host
+	var b *hatypes.Backend
+
+	b = c.config.AcquireBackend("d1", "app", "8080")
+	b.Endpoints = []*hatypes.Endpoint{endpointS1}
+	h = c.config.AcquireHost("d1.local")
+	h.AddPath(b, "/")
+	h.Alias.AliasName = "*.d1.local"
+
+	b = c.config.AcquireBackend("d2", "app", "8080")
+	b.Endpoints = []*hatypes.Endpoint{endpointS21}
+	h = c.config.AcquireHost("d2.local")
+	h.AddPath(b, "/")
+	h.Alias.AliasName = "sub.d2.local"
+	h.Alias.AliasRegex = "^[a-z]+\\.d2\\.local$"
+
+	b = c.config.AcquireBackend("d3", "app", "8080")
+	b.Endpoints = []*hatypes.Endpoint{endpointS31}
+	h = c.config.AcquireHost("d3.local")
+	h.AddPath(b, "/")
+	h.Alias.AliasRegex = ".*d3\\.local$"
+
+	c.instance.Update()
+	c.checkConfig(`
+<<global>>
+<<defaults>>
+backend d1_app_8080
+    mode http
+    server s1 172.17.0.11:8080 weight 100
+backend d2_app_8080
+    mode http
+    server s21 172.17.0.121:8080 weight 100
+backend d3_app_8080
+    mode http
+    server s31 172.17.0.131:8080 weight 100
+<<backends-default>>
+frontend _front_http
+    mode http
+    bind :80
+    http-request set-var(req.base) base,regsub(:[0-9]+/,/)
+    http-request redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch) yes }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
+    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
+    default_backend _error404
+frontend _front001
+    mode http
+    bind :443 ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem
+    http-request set-var(req.base) base,lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.hostbackend) var(req.base),map_beg(/etc/haproxy/maps/_front001_host.map,_nomatch)
+    http-request set-var(req.hostbackend) var(req.base),map_reg(/etc/haproxy/maps/_front001_host_regex.map,_nomatch) if { var(req.hostbackend) _nomatch }
+    <<tls-del-headers>>
+    use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
+    default_backend _error404
+`)
+
+	c.checkMap("_global_https_redir.map", `
+d1.local/ no
+d2.local/ no
+d3.local/ no
+`)
+	c.checkMap("_global_http_front.map", `
+d1.local/ d1_app_8080
+d2.local/ d2_app_8080
+d3.local/ d3_app_8080
+`)
+	c.checkMap("_front001_host.map", `
+d1.local/ d1_app_8080
+d2.local/ d2_app_8080
+sub.d2.local/ d2_app_8080
+d3.local/ d3_app_8080
+`)
+	c.checkMap("_front001_host_regex.map", `
+^[^.]+\.d1\.local/ d1_app_8080
+^[a-z]+\.d2\.local$/ d2_app_8080
+.*d3\.local$/ d3_app_8080
+`)
+
+	c.logger.CompareLogging(defaultLogging)
+
+}
+
+func TestUserlist(t *testing.T) {
+	type list struct {
+		name  string
+		users []hatypes.User
+	}
+	testCase := []struct {
+		lists    []list
+		listname string
+		realm    string
+		config   string
+	}{
+		{
+			lists: []list{
+				{
+					name: "default_usr",
+					users: []hatypes.User{
+						{Name: "usr1", Passwd: "clear1", Encrypted: false},
+					},
+				},
+			},
+			listname: "default_usr",
+			config: `
+userlist default_usr
+    user usr1 insecure-password clear1`,
+		},
+		{
+			lists: []list{
+				{
+					name: "default_auth",
+					users: []hatypes.User{
+						{Name: "usr1", Passwd: "clear1", Encrypted: false},
+						{Name: "usr2", Passwd: "xxxx", Encrypted: true},
+					},
+				},
+			},
+			listname: "default_auth",
+			realm:    "usrlist",
+			config: `
+userlist default_auth
+    user usr1 insecure-password clear1
+    user usr2 password xxxx`,
+		},
+		{
+			lists: []list{
+				{
+					name: "default_auth1",
+					users: []hatypes.User{
+						{Name: "usr1", Passwd: "clear1", Encrypted: false},
+					},
+				},
+				{
+					name: "default_auth2",
+					users: []hatypes.User{
+						{Name: "usr2", Passwd: "xxxx", Encrypted: true},
+					},
+				},
+			},
+			listname: "default_auth1",
+			realm:    "multi list",
+			config: `
+userlist default_auth1
+    user usr1 insecure-password clear1
+userlist default_auth2
+    user usr2 password xxxx`,
+		},
+	}
+	for _, test := range testCase {
+		c := setup(t)
+
+		var h *hatypes.Host
+		var b *hatypes.Backend
+
+		b = c.config.AcquireBackend("d1", "app", "8080")
+		b.Endpoints = []*hatypes.Endpoint{endpointS1}
+		h = c.config.AcquireHost("d1.local")
+		h.AddPath(b, "/")
+
+		for _, list := range test.lists {
+			c.config.AddUserlist(list.name, list.users)
+		}
+		b.Userlist.Name = test.listname
+		b.Userlist.Realm = test.realm
+
+		var realm string
+		if test.realm != "" {
+			realm = fmt.Sprintf(` realm "%s"`, test.realm)
+		}
+
+		c.instance.Update()
+		c.checkConfig(`
+<<global>>
+<<defaults>>` + test.config + `
+backend d1_app_8080
+    mode http
+    http-request auth` + realm + ` if !{ http_auth(` + test.listname + `) }
+    server s1 172.17.0.11:8080 weight 100
+<<backends-default>>
+<<frontends-default>>
+`)
+		c.logger.CompareLogging(defaultLogging)
+		c.teardown()
+	}
+}
+
+func TestModSecurity(t *testing.T) {
+	testCases := []struct {
+		waf        string
+		endpoints  []string
+		backendExp string
+		modsecExp  string
+	}{
+		{
+			waf:        "modsecurity",
+			endpoints:  []string{},
+			backendExp: ``,
+			modsecExp:  ``,
+		},
+		{
+			waf:        "",
+			endpoints:  []string{"10.0.0.101:12345"},
+			backendExp: ``,
+			modsecExp: `
+    server modsec-spoa0 10.0.0.101:12345`,
+		},
+		{
+			waf:       "modsecurity",
+			endpoints: []string{"10.0.0.101:12345"},
+			backendExp: `
+    filter spoe engine modsecurity config /etc/haproxy/spoe-modsecurity.conf
+    http-request deny if { var(txn.modsec.code) -m int gt 0 }`,
+			modsecExp: `
+    server modsec-spoa0 10.0.0.101:12345`,
+		},
+		{
+			waf:       "modsecurity",
+			endpoints: []string{"10.0.0.101:12345", "10.0.0.102:12345"},
+			backendExp: `
+    filter spoe engine modsecurity config /etc/haproxy/spoe-modsecurity.conf
+    http-request deny if { var(txn.modsec.code) -m int gt 0 }`,
+			modsecExp: `
+    server modsec-spoa0 10.0.0.101:12345
+    server modsec-spoa1 10.0.0.102:12345`,
+		},
+	}
+	for _, test := range testCases {
+		c := setup(t)
+
+		var h *hatypes.Host
+		var b *hatypes.Backend
+
+		b = c.config.AcquireBackend("d1", "app", "8080")
+		b.Endpoints = []*hatypes.Endpoint{endpointS1}
+		b.WAF = test.waf
+		h = c.config.AcquireHost("d1.local")
+		h.AddPath(b, "/")
+		c.config.Global().ModSecurity.Endpoints = test.endpoints
+
+		c.instance.Update()
+
+		var modsec string
+		if test.modsecExp != "" {
+			modsec = `
+backend spoe-modsecurity
+    mode tcp
+    timeout connect 5s
+    timeout server  5s` + test.modsecExp
+		}
+		c.checkConfig(`
+<<global>>
+<<defaults>>
+backend d1_app_8080
+    mode http` + test.backendExp + `
+    server s1 172.17.0.11:8080 weight 100
+<<backends-default>>
+<<frontends-default>>` + modsec)
+
+		c.logger.CompareLogging(defaultLogging)
+		c.teardown()
+	}
+}
+
+func TestInstanceWildcardHostname(t *testing.T) {
+	c := setup(t)
+	defer c.teardown()
+
+	var h *hatypes.Host
+	var b *hatypes.Backend
+
+	b = c.config.AcquireBackend("d1", "app", "8080")
+	b.Endpoints = []*hatypes.Endpoint{endpointS1}
+	b.SSLRedirect = true
+	h = c.config.AcquireHost("d1.local")
+	h.AddPath(b, "/")
+	h = c.config.AcquireHost("*.app.d1.local")
+	h.AddPath(b, "/")
+	h = c.config.AcquireHost("*.sub.d1.local")
+	h.AddPath(b, "/")
+	h.TLS.CAFilename = "/var/haproxy/ssl/ca/d1.local.pem"
+	h.TLS.CAHash = "1"
+	h.TLS.CAVerifyOptional = true
+	h.TLS.CAErrorPage = "http://sub.d1.local/error.html"
+
+	b = c.config.AcquireBackend("d2", "app", "8080")
+	b.Endpoints = []*hatypes.Endpoint{endpointS21}
+	b.SSLRedirect = false
+	h = c.config.AcquireHost("*.d2.local")
+	h.AddPath(b, "/")
+	h.RootRedirect = "/app"
+	h.Timeout.Client = "10s"
+
+	c.instance.Update()
+	c.checkConfig(`
+<<global>>
+<<defaults>>
+backend d1_app_8080
+    mode http
+    http-request set-header X-SSL-Client-CN   %{+Q}[ssl_c_s_dn(cn)]
+    http-request set-header X-SSL-Client-DN   %{+Q}[ssl_c_s_dn]
+    http-request set-header X-SSL-Client-SHA1 %{+Q}[ssl_c_sha1,hex]
+    server s1 172.17.0.11:8080 weight 100
+backend d2_app_8080
+    mode http
+    server s21 172.17.0.121:8080 weight 100
+<<backends-default>>
+listen _front__tls
+    mode tcp
+    bind :443
+    tcp-request inspect-delay 5s
+    tcp-request content accept if { req.ssl_hello_type 1 }
+    ## _front001/_socket001
+    use-server _server_socket001 if { req.ssl_sni -i -f /etc/haproxy/maps/_socket001.list }
+    server _server_socket001 unix@/var/run/_socket001.sock send-proxy-v2 weight 0
+    ## _front001/_socket002
+    use-server _server_socket002 if { req.ssl_sni -i -f /etc/haproxy/maps/_socket002.list }
+    server _server_socket002 unix@/var/run/_socket002.sock send-proxy-v2 weight 0
+    ## _front002/_socket003
+    use-server _server_socket003 if { req.ssl_sni -i -f /etc/haproxy/maps/_socket003.list }
+    server _server_socket003 unix@/var/run/_socket003.sock send-proxy-v2 weight 0
+    ## _front001/_socket001 wildcard
+    use-server _server_socket001_wildcard if { req.ssl_sni -i -m reg -f /etc/haproxy/maps/_socket001_regex.list }
+    server _server_socket001_wildcard unix@/var/run/_socket001.sock send-proxy-v2 weight 0
+    ## _front001/_socket002 wildcard
+    use-server _server_socket002_wildcard if { req.ssl_sni -i -m reg -f /etc/haproxy/maps/_socket002_regex.list }
+    server _server_socket002_wildcard unix@/var/run/_socket002.sock send-proxy-v2 weight 0
+    ## _front002/_socket003 wildcard
+    use-server _server_socket003_wildcard if { req.ssl_sni -i -m reg -f /etc/haproxy/maps/_socket003_regex.list }
+    server _server_socket003_wildcard unix@/var/run/_socket003.sock send-proxy-v2 weight 0
+    # TODO default backend
+frontend _front_http
+    mode http
+    bind :80
+    http-request set-var(req.base) base,regsub(:[0-9]+/,/)
+    http-request set-var(req.redir) var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch)
+    http-request redirect scheme https if { var(req.redir) yes }
+    http-request redirect scheme https if { var(req.redir) _nomatch } { var(req.base),map_reg(/etc/haproxy/maps/_global_https_redir_regex.map,_nomatch) yes }
+    http-request set-var(req.host) hdr(host),lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.rootredir) var(req.host),map(/etc/haproxy/maps/_global_http_root_redir.map,_nomatch)
+    http-request set-var(req.rootredir) var(req.host),map_reg(/etc/haproxy/maps/_global_http_root_redir_regex.map,_nomatch) if { var(req.rootredir) _nomatch }
+    http-request redirect location %[var(req.rootredir)] if { path / } !{ var(req.rootredir) _nomatch }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
+    http-request set-var(req.backend) var(req.base),map_reg(/etc/haproxy/maps/_global_http_front_regex.map,_nomatch) if { var(req.backend) _nomatch }
+    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
+    default_backend _error404
+frontend _front001
+    mode http
+    bind unix@/var/run/_socket001.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem
+    bind unix@/var/run/_socket002.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem ca-file /var/haproxy/ssl/ca/d1.local.pem verify optional ca-ignore-err all crt-ignore-err all
+    http-request set-var(req.base) base,lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.hostbackend) var(req.base),map_beg(/etc/haproxy/maps/_front001_host.map,_nomatch)
+    http-request set-var(req.hostbackend) var(req.base),map_reg(/etc/haproxy/maps/_front001_host_regex.map,_nomatch) if { var(req.hostbackend) _nomatch }
+    <<tls-del-headers>>
+    http-request set-header x-ha-base %[ssl_fc_sni]%[path]
+    http-request set-var(req.snibase) hdr(x-ha-base),lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.snibackend) var(req.snibase),map_beg(/etc/haproxy/maps/_front001_sni.map,_nomatch)
+    http-request set-var(req.snibackend) var(req.snibase),map_reg(/etc/haproxy/maps/_front001_sni_regex.map,_nomatch) if { var(req.snibackend) _nomatch }
+    acl tls-has-invalid-crt ssl_c_ca_err gt 0
+    acl tls-has-invalid-crt ssl_c_err gt 0
+    acl tls-check-crt ssl_fc_sni -i -f /etc/haproxy/maps/_front001_inv_crt.list
+    acl tls-check-crt ssl_fc_sni -i -m reg -f /etc/haproxy/maps/_front001_inv_crt_regex.list
+    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni,lower,map(/etc/haproxy/maps/_front001_inv_crt_redir.map,_internal) if tls-has-invalid-crt tls-check-crt
+    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni,lower,map_reg(/etc/haproxy/maps/_front001_inv_crt_redir_regex.map,_internal) if { var(req.tls_invalidcrt_redir) _internal }
+    http-request redirect location %[var(req.tls_invalidcrt_redir)] code 303 if { var(req.tls_invalidcrt_redir) -m found } !{ var(req.tls_invalidcrt_redir) _internal }
+    use_backend _error495 if { var(req.tls_invalidcrt_redir) _internal }
+    use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
+    use_backend %[var(req.snibackend)] unless { var(req.snibackend) _nomatch }
+    default_backend _error404
+frontend _front002
+    mode http
+    bind unix@/var/run/_socket003.sock accept-proxy ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem
+    timeout client 10s
+    http-request set-var(req.base) base,lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.hostbackend) var(req.base),map_beg(/etc/haproxy/maps/_front002_host.map,_nomatch)
+    http-request set-var(req.hostbackend) var(req.base),map_reg(/etc/haproxy/maps/_front002_host_regex.map,_nomatch) if { var(req.hostbackend) _nomatch }
+    http-request set-var(req.host) hdr(host),lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.rootredir) var(req.host),map(/etc/haproxy/maps/_front002_root_redir.map,_nomatch)
+    http-request set-var(req.rootredir) var(req.host),map_reg(/etc/haproxy/maps/_front002_root_redir_regex.map,_nomatch) if { var(req.rootredir) _nomatch }
+    http-request redirect location %[var(req.rootredir)] if { path / } !{ var(req.rootredir) _nomatch }
+    <<tls-del-headers>>
+    use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
+    default_backend _error404
+`)
+
+	c.checkMap("_socket001.list", `
+d1.local
+`)
+	c.checkMap("_socket002.list", `
+`)
+	c.checkMap("_socket003.list", `
+`)
+	c.checkMap("_socket001_regex.list", `
+^[^.]+\.app\.d1\.local$
+`)
+	c.checkMap("_socket002_regex.list", `
+^[^.]+\.sub\.d1\.local$
+`)
+	c.checkMap("_socket003_regex.list", `
+^[^.]+\.d2\.local$
+`)
+	c.checkMap("_global_http_front.map", `
+`)
+	c.checkMap("_global_http_front_regex.map", `
+^[^.]+\.d2\.local/ d2_app_8080
+`)
+	c.checkMap("_global_https_redir.map", `
+d1.local/ yes
+`)
+	c.checkMap("_global_https_redir_regex.map", `
+^[^.]+\.app\.d1\.local/ yes
+^[^.]+\.sub\.d1\.local/ yes
+^[^.]+\.d2\.local/ no
+`)
+	c.checkMap("_global_http_root_redir.map", `
+`)
+	c.checkMap("_global_http_root_redir_regex.map", `
+^[^.]+\.d2\.local$ /app
+`)
+	c.checkMap("_front001_host.map", `
+d1.local/ d1_app_8080
+`)
+	c.checkMap("_front001_host_regex.map", `
+^[^.]+\.app\.d1\.local/ d1_app_8080
+`)
+	c.checkMap("_front001_sni.map", `
+`)
+	c.checkMap("_front001_sni_regex.map", `
+^[^.]+\.sub\.d1\.local/ d1_app_8080
+`)
+	c.checkMap("_front001_inv_crt.list", `
+`)
+	c.checkMap("_front001_inv_crt_regex.list", `
+^[^.]+\.sub\.d1\.local$
+`)
+	c.checkMap("_front001_inv_crt_redir.map", `
+`)
+	c.checkMap("_front001_inv_crt_redir_regex.map", `
+^[^.]+\.sub\.d1\.local$ http://sub.d1.local/error.html
+`)
+	c.checkMap("_front002_host.map", `
+`)
+	c.checkMap("_front002_host_regex.map", `
+^[^.]+\.d2\.local/ d2_app_8080
+`)
+	c.checkMap("_front002_root_redir.map", `
+`)
+	c.checkMap("_front002_root_redir_regex.map", `
+^[^.]+\.d2\.local$ /app
+`)
+
+	c.logger.CompareLogging(defaultLogging)
+}
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *
  *  BUILDERS
@@ -717,7 +1520,7 @@ func setup(t *testing.T) *testConfig {
 	})
 	instance.curConfig = config
 	config.ConfigDefaultX509Cert("/var/haproxy/ssl/certs/default.pem")
-	return &testConfig{
+	c := &testConfig{
 		t:          t,
 		logger:     logger,
 		bindUtils:  bindUtils,
@@ -726,6 +1529,8 @@ func setup(t *testing.T) *testConfig {
 		tempdir:    tempdir,
 		configfile: configfile,
 	}
+	c.configGlobal()
+	return c
 }
 
 func (c *testConfig) teardown() {
@@ -737,9 +1542,11 @@ func (c *testConfig) teardown() {
 
 func (c *testConfig) configGlobal() {
 	global := c.config.Global()
+	global.Cookie.Key = "Ingress"
 	global.MaxConn = 2000
 	global.SSL.Ciphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256"
 	global.SSL.DHParam.Filename = "/var/haproxy/tls/dhparam.pem"
+	global.SSL.HeadersPrefix = "X-SSL"
 	global.SSL.Options = "no-sslv3"
 	global.StatsSocket = "/var/run/haproxy.sock"
 	global.Timeout.Client = "50s"
@@ -754,45 +1561,6 @@ func (c *testConfig) configGlobal() {
 	global.Timeout.Tunnel = "1h"
 }
 
-var globalConfig = `
-global
-    daemon
-    quiet
-    stats socket /var/run/haproxy.sock level admin expose-fd listeners
-    maxconn 2000
-    hard-stop-after 15m
-    lua-load /usr/local/etc/haproxy/lua/send-response.lua
-    lua-load /usr/local/etc/haproxy/lua/auth-request.lua
-    ssl-dh-param-file /var/haproxy/tls/dhparam.pem
-    ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256
-    ssl-default-bind-options no-sslv3
-defaults
-    log global
-    maxconn 2000
-    option redispatch
-    option dontlognull
-    option http-server-close
-    option http-keep-alive
-    timeout client          50s
-    timeout client-fin      50s
-    timeout connect         5s
-    timeout http-keep-alive 1m
-    timeout http-request    5s
-    timeout queue           5s
-    timeout server          50s
-    timeout server-fin      50s
-    timeout tunnel          1h`
-
-var errorPages = `
-backend _error495
-    mode http
-    errorfile 400 /usr/local/etc/haproxy/errors/495.http
-    http-request deny deny_status 400
-backend _error496
-    mode http
-    errorfile 400 /usr/local/etc/haproxy/errors/496.http
-    http-request deny deny_status 400`
-
 var endpointS0 = &hatypes.Endpoint{
 	Name:   "s0",
 	IP:     "172.17.0.99",
@@ -858,12 +1626,82 @@ func _yamlMarshal(in interface{}) string {
 	return string(out)
 }
 
-func (c *testConfig) checkConfig(backend, frontend string) {
-	c.checkConfigFull(globalConfig + backend + errorPages + frontend)
-}
-
-func (c *testConfig) checkConfigFull(expected string) {
+func (c *testConfig) checkConfig(expected string) {
 	actual := strings.Replace(c.readConfig(c.configfile), c.tempdir, "/etc/haproxy/maps", -1)
+	replace := map[string]string{
+		"<<global>>": `global
+    daemon
+    stats socket /var/run/haproxy.sock level admin expose-fd listeners
+    maxconn 2000
+    hard-stop-after 15m
+    lua-load /usr/local/etc/haproxy/lua/send-response.lua
+    lua-load /usr/local/etc/haproxy/lua/auth-request.lua
+    ssl-dh-param-file /var/haproxy/tls/dhparam.pem
+    ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256
+    ssl-default-bind-options no-sslv3`,
+		"<<defaults>>": `defaults
+    log global
+    maxconn 2000
+    option redispatch
+    option dontlognull
+    option http-server-close
+    option http-keep-alive
+    timeout client          50s
+    timeout client-fin      50s
+    timeout connect         5s
+    timeout http-keep-alive 1m
+    timeout http-request    5s
+    timeout queue           5s
+    timeout server          50s
+    timeout server-fin      50s
+    timeout tunnel          1h`,
+		"<<backend-errors>>": `backend _error495
+    mode http
+    errorfile 400 /usr/local/etc/haproxy/errors/495.http
+    http-request deny deny_status 400
+backend _error496
+    mode http
+    errorfile 400 /usr/local/etc/haproxy/errors/496.http
+    http-request deny deny_status 400`,
+		"<<backends-default>>": `backend _error404
+    mode http
+    errorfile 400 /usr/local/etc/haproxy/errors/404.http
+    http-request deny deny_status 400
+<<backend-errors>>`,
+		"    <<tls-del-headers>>": `    http-request del-header X-SSL-Client-CN
+    http-request del-header X-SSL-Client-DN
+    http-request del-header X-SSL-Client-SHA1
+    http-request del-header X-SSL-Client-Cert`,
+		"<<frontends-default>>": `frontend _front_http
+    mode http
+    bind :80
+    http-request set-var(req.base) base,regsub(:[0-9]+/,/)
+    http-request redirect scheme https if { var(req.base),map_beg(/etc/haproxy/maps/_global_https_redir.map,_nomatch) yes }
+    <<tls-del-headers>>
+    http-request set-var(req.backend) var(req.base),map_beg(/etc/haproxy/maps/_global_http_front.map,_nomatch)
+    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
+    default_backend _error404
+frontend _front001
+    mode http
+    bind :443 ssl alpn h2,http/1.1 crt /var/haproxy/ssl/certs/default.pem
+    http-request set-var(req.hostbackend) base,lower,regsub(:[0-9]+/,/),map_beg(/etc/haproxy/maps/_front001_host.map,_nomatch)
+    <<tls-del-headers>>
+    use_backend %[var(req.hostbackend)] unless { var(req.hostbackend) _nomatch }
+    default_backend _error404`,
+	}
+	for {
+		changed := false
+		for old, new := range replace {
+			after := strings.Replace(expected, old, new, -1)
+			if after != expected {
+				changed = true
+			}
+			expected = after
+		}
+		if !changed {
+			break
+		}
+	}
 	c.compareText("haproxy.cfg", actual, expected)
 }
 
diff --git a/pkg/haproxy/types/backend.go b/pkg/haproxy/types/backend.go
index 6c43850a5..47efa9bc0 100644
--- a/pkg/haproxy/types/backend.go
+++ b/pkg/haproxy/types/backend.go
@@ -37,12 +37,19 @@ func (b *Backend) NewEndpoint(ip string, port int, targetRef string) *Endpoint {
 	return endpoint
 }
 
-// HreqValidateUserlist ...
-func (b *Backend) HreqValidateUserlist(userlist *Userlist) {
-	// TODO implement
-	b.HTTPRequests = append(b.HTTPRequests, &HTTPRequest{})
-}
-
-func (h *HTTPRequest) String() string {
-	return fmt.Sprintf("%+v", *h)
+// AddPath ...
+func (b *Backend) AddPath(path string) {
+	for _, p := range b.Paths {
+		if p == path {
+			// add only unique paths
+			return
+		}
+	}
+	// host's paths that references this backend
+	// used on RewriteURL config
+	b.Paths = append(b.Paths, path)
+	// reverse order in order to avoid overlap of sub-paths
+	sort.Slice(b.Paths, func(i, j int) bool {
+		return b.Paths[i] > b.Paths[j]
+	})
 }
diff --git a/pkg/haproxy/types/backend_test.go b/pkg/haproxy/types/backend_test.go
new file mode 100644
index 000000000..d4bb3063a
--- /dev/null
+++ b/pkg/haproxy/types/backend_test.go
@@ -0,0 +1,63 @@
+/*
+Copyright 2019 The HAProxy Ingress Controller Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package types
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestAddPath(t *testing.T) {
+	testCases := []struct {
+		input    []string
+		expected []string
+	}{
+		{
+			input:    []string{"/"},
+			expected: []string{"/"},
+		},
+		{
+			input:    []string{"/app", "/app"},
+			expected: []string{"/app"},
+		},
+		{
+			input:    []string{"/app", "/root"},
+			expected: []string{"/root", "/app"},
+		},
+		{
+			input:    []string{"/app", "/root", "/root"},
+			expected: []string{"/root", "/app"},
+		},
+		{
+			input:    []string{"/app", "/root", "/app"},
+			expected: []string{"/root", "/app"},
+		},
+		{
+			input:    []string{"/", "/app", "/root"},
+			expected: []string{"/root", "/app", "/"},
+		},
+	}
+	for _, test := range testCases {
+		b := &Backend{}
+		for _, p := range test.input {
+			b.AddPath(p)
+		}
+		if !reflect.DeepEqual(b.Paths, test.expected) {
+			t.Errorf("backend.Paths differs - actual: %v - expected: %v", b.Paths, test.expected)
+		}
+	}
+}
diff --git a/pkg/haproxy/types/frontend.go b/pkg/haproxy/types/frontend.go
index af6460988..891b44939 100644
--- a/pkg/haproxy/types/frontend.go
+++ b/pkg/haproxy/types/frontend.go
@@ -20,8 +20,87 @@ import (
 	"fmt"
 	"reflect"
 	"sort"
+	"strings"
 )
 
+// AppendHostname ...
+func (hm *HostsMap) AppendHostname(base, value string) {
+	// always use case insensitive match
+	base = strings.ToLower(base)
+	isHostnameOnly := !strings.Contains(base, "/")
+	if strings.HasPrefix(base, "*.") {
+		// *.example.local
+		key := "^" + strings.Replace(base, ".", "\\.", -1)
+		key = strings.Replace(key, "*", "[^.]+", 1)
+		if isHostnameOnly {
+			// match eol if only the hostname is provided
+			// if has /path, need to match the begining of the string, a la map_beg() converter
+			key = key + "$"
+		}
+		hm.Regex = append(hm.Regex, &HostsMapEntry{
+			Key:   key,
+			Value: value,
+		})
+	} else {
+		// sub.example.local
+		hm.Match = append(hm.Match, &HostsMapEntry{
+			Key:   base,
+			Value: value,
+		})
+		// Hostnames are already in alphabetical order but Alias are not
+		// Sort only hostname maps which uses ebtree search via map converter
+		if isHostnameOnly {
+			sort.Slice(hm.Match, func(i, j int) bool {
+				return hm.Match[i].Key < hm.Match[j].Key
+			})
+		}
+	}
+}
+
+// AppendAliasName ...
+func (hm *HostsMap) AppendAliasName(base, value string) {
+	if base != "" {
+		hm.AppendHostname(base, value)
+	}
+}
+
+// AppendAliasRegex ...
+func (hm *HostsMap) AppendAliasRegex(base, value string) {
+	if base != "" {
+		hm.Regex = append(hm.Regex, &HostsMapEntry{
+			Key:   base,
+			Value: value,
+		})
+	}
+}
+
+// HasRegex ...
+func (hm *HostsMap) HasRegex() bool {
+	return len(hm.Regex) > 0
+}
+
+// HasHost ...
+func (hm *HostsMap) HasHost() bool {
+	return len(hm.Regex) > 0 || len(hm.Match) > 0
+}
+
+// CreateMaps ...
+func CreateMaps() *HostsMaps {
+	return &HostsMaps{}
+}
+
+// AddMap ...
+func (hm *HostsMaps) AddMap(filename string) *HostsMap {
+	matchFile := filename
+	regexFile := strings.Replace(filename, ".", "_regex.", 1)
+	hmap := &HostsMap{
+		MatchFile: matchFile,
+		RegexFile: regexFile,
+	}
+	hm.Items = append(hm.Items, hmap)
+	return hmap
+}
+
 // HasTCPProxy ...
 func (fg *FrontendGroup) HasTCPProxy() bool {
 	// short-circuit saves:
@@ -63,7 +142,7 @@ func (f *Frontend) HasNoCrtErrorPage() bool {
 // HasTLSMandatory ...
 func (f *Frontend) HasTLSMandatory() bool {
 	for _, host := range f.Hosts {
-		if !host.TLS.CAVerifyOptional {
+		if host.HasTLSAuth() && !host.TLS.CAVerifyOptional {
 			return true
 		}
 	}
@@ -115,12 +194,8 @@ func BuildRawFrontends(hosts []*Host) (frontends []*Frontend, sslpassthrough []*
 	// naming frontends
 	var i int
 	for _, frontend := range frontends {
-		if len(frontend.Hosts) == 1 {
-			frontend.Name = "https-front_" + frontend.Hosts[0].Hostname
-		} else {
-			i++
-			frontend.Name = fmt.Sprintf("_front_%03d", i)
-		}
+		i++
+		frontend.Name = fmt.Sprintf("_front%03d", i)
 	}
 	// sorting frontends
 	sort.Slice(frontends, func(i, j int) bool {
diff --git a/pkg/haproxy/types/frontend_test.go b/pkg/haproxy/types/frontend_test.go
index cd88d713f..5e957a47a 100644
--- a/pkg/haproxy/types/frontend_test.go
+++ b/pkg/haproxy/types/frontend_test.go
@@ -23,6 +23,49 @@ import (
 	yaml "gopkg.in/yaml.v2"
 )
 
+func TestAppendHostname(t *testing.T) {
+	testCases := []struct {
+		hostname      string
+		expectedMatch string
+		expectedRegex string
+	}{
+		// 0
+		{hostname: "Example.Local", expectedMatch: "example.local"},
+		// 1
+		{hostname: "example.local/", expectedMatch: "example.local/"},
+		// 2
+		{hostname: "*.Example.Local", expectedRegex: "^[^.]+\\.example\\.local$"},
+		// 3
+		{hostname: "*.example.local/", expectedRegex: "^[^.]+\\.example\\.local/"},
+		// 4
+		{hostname: "*.example.local/path", expectedRegex: "^[^.]+\\.example\\.local/path"},
+	}
+	for i, test := range testCases {
+		hm := &HostsMap{}
+		hm.AppendHostname(test.hostname, "backend")
+		if test.expectedMatch != "" {
+			if len(hm.Match) != 1 || len(hm.Regex) != 0 {
+				t.Errorf("item %d, expected len(match)==1 and len(regex)==0, but was '%d' and '%d'", i, len(hm.Match), len(hm.Regex))
+				continue
+			}
+			if hm.Match[0].Key != test.expectedMatch {
+				t.Errorf("item %d, expected key '%s', but was '%s'", i, test.hostname, hm.Match[0].Key)
+				continue
+			}
+		} else {
+			//regex
+			if len(hm.Match) != 0 || len(hm.Regex) != 1 {
+				t.Errorf("item %d, expected len(match)==0 and len(regex)==1, but was '%d' and '%d'", i, len(hm.Match), len(hm.Regex))
+				continue
+			}
+			if hm.Regex[0].Key != test.expectedRegex {
+				t.Errorf("item %d, expected key '%s', but was '%s'", i, test.expectedRegex, hm.Regex[0].Key)
+				continue
+			}
+		}
+	}
+}
+
 func TestBuildFrontendEmpty(t *testing.T) {
 	frontends, _ := BuildRawFrontends([]*Host{})
 	if len(frontends) > 0 {
@@ -50,7 +93,7 @@ func TestBuildFrontend(t *testing.T) {
 			hosts: []*Host{h10_1, h10_2},
 			expected: []*Frontend{
 				{
-					Name:    "_front_001",
+					Name:    "_front001",
 					Timeout: timeout10,
 					Hosts:   []*Host{h10_1, h10_2},
 					Binds: []*BindConfig{
@@ -66,7 +109,7 @@ func TestBuildFrontend(t *testing.T) {
 			hosts: []*Host{h10_1, h20_1, h10_2},
 			expected: []*Frontend{
 				{
-					Name:    "_front_001",
+					Name:    "_front001",
 					Timeout: timeout10,
 					Hosts:   []*Host{h10_1, h10_2},
 					Binds: []*BindConfig{
@@ -76,7 +119,7 @@ func TestBuildFrontend(t *testing.T) {
 					},
 				},
 				{
-					Name:    "https-front_h3.local",
+					Name:    "_front002",
 					Timeout: timeout20,
 					Hosts:   []*Host{h20_1},
 					Binds: []*BindConfig{
@@ -92,7 +135,7 @@ func TestBuildFrontend(t *testing.T) {
 			hosts: []*Host{h10CA1_1, h10CA2_1, h10CA2_2},
 			expected: []*Frontend{
 				{
-					Name:    "_front_001",
+					Name:    "_front001",
 					Timeout: timeout10,
 					Hosts:   []*Host{h10CA1_1, h10CA2_1, h10CA2_2},
 					Binds: []*BindConfig{
@@ -113,7 +156,7 @@ func TestBuildFrontend(t *testing.T) {
 			hosts: []*Host{h10_1, h10_2, h10CA2_1, h10CA2_2},
 			expected: []*Frontend{
 				{
-					Name:    "_front_001",
+					Name:    "_front001",
 					Timeout: timeout10,
 					Hosts:   []*Host{h10_1, h10_2, h10CA2_1, h10CA2_2},
 					Binds: []*BindConfig{
diff --git a/pkg/haproxy/types/host.go b/pkg/haproxy/types/host.go
index 6f984f253..5cf7b2ac6 100644
--- a/pkg/haproxy/types/host.go
+++ b/pkg/haproxy/types/host.go
@@ -38,6 +38,8 @@ func (h *Host) AddPath(backend *Backend, path string) {
 		Backend:   backend,
 		BackendID: backend.ID,
 	})
+	backend.AddPath(path)
+	// reverse order in order to avoid overlap of sub-paths
 	sort.Slice(h.Paths, func(i, j int) bool {
 		return h.Paths[i].Path > h.Paths[j].Path
 	})
diff --git a/pkg/haproxy/types/types.go b/pkg/haproxy/types/types.go
index 076341375..7690ed667 100644
--- a/pkg/haproxy/types/types.go
+++ b/pkg/haproxy/types/types.go
@@ -18,18 +18,19 @@ package types
 
 // Global ...
 type Global struct {
-	Procs                  ProcsConfig
-	Syslog                 SyslogConfig
-	MaxConn                int
-	Timeout                TimeoutConfig
-	SSL                    SSLConfig
-	ModSecurity            ModSecurityConfig
-	DrainSupport           bool
-	DrainSupportRedispatch bool
-	LoadServerState        bool
-	StatsSocket            string
-	CustomConfig           []string
-	CustomDefaults         []string
+	Procs           ProcsConfig
+	Syslog          SyslogConfig
+	MaxConn         int
+	Timeout         TimeoutConfig
+	SSL             SSLConfig
+	ModSecurity     ModSecurityConfig
+	Cookie          CookieConfig
+	DrainSupport    DrainConfig
+	ForwardFor      string
+	LoadServerState bool
+	StatsSocket     string
+	CustomConfig    []string
+	CustomDefaults  []string
 }
 
 // ProcsConfig ...
@@ -45,9 +46,12 @@ type ProcsConfig struct {
 
 // SyslogConfig ...
 type SyslogConfig struct {
-	Endpoint string
-	Format   string
-	Tag      string
+	Endpoint       string
+	Format         string
+	HTTPLogFormat  string
+	HTTPSLogFormat string
+	Tag            string
+	TCPLogFormat   string
 }
 
 // TimeoutConfig ...
@@ -59,11 +63,12 @@ type TimeoutConfig struct {
 
 // SSLConfig ...
 type SSLConfig struct {
-	DHParam   DHParamConfig
-	Ciphers   string
-	Options   string
-	Engine    string
-	ModeAsync bool
+	DHParam       DHParamConfig
+	Ciphers       string
+	Options       string
+	Engine        string
+	ModeAsync     bool
+	HeadersPrefix string
 }
 
 // DHParamConfig ...
@@ -78,6 +83,17 @@ type ModSecurityConfig struct {
 	Timeout   ModSecurityTimeoutConfig
 }
 
+// CookieConfig ...
+type CookieConfig struct {
+	Key string
+}
+
+// DrainConfig ...
+type DrainConfig struct {
+	Drain      bool
+	Redispatch bool
+}
+
 // ModSecurityTimeoutConfig ...
 type ModSecurityTimeoutConfig struct {
 	Hello      string
@@ -85,15 +101,36 @@ type ModSecurityTimeoutConfig struct {
 	Processing string
 }
 
+// HostsMapEntry ...
+type HostsMapEntry struct {
+	Key   string
+	Value string
+}
+
+// HostsMap ...
+type HostsMap struct {
+	Match     []*HostsMapEntry
+	MatchFile string
+	Regex     []*HostsMapEntry
+	RegexFile string
+}
+
+// HostsMaps ...
+type HostsMaps struct {
+	Items []*HostsMap
+}
+
 // FrontendGroup ...
 type FrontendGroup struct {
-	Frontends         []*Frontend
-	HasHTTPHost       bool
-	HasRedirectHTTPS  bool
+	Frontends []*Frontend
+	//
 	HasSSLPassthrough bool
-	HTTPFrontsMap     string
-	RedirectMap       string
-	SSLPassthroughMap string
+	//
+	Maps              *HostsMaps
+	HTTPFrontsMap     *HostsMap
+	HTTPRootRedirMap  *HostsMap
+	HTTPSRedirMap     *HostsMap
+	SSLPassthroughMap *HostsMap
 }
 
 // Frontend ...
@@ -102,15 +139,17 @@ type Frontend struct {
 	Binds []*BindConfig
 	Hosts []*Host
 	//
-	ConvertLowercase           bool
-	HostBackendsMap            string
-	SNIBackendsMap             string
-	Timeout                    HostTimeoutConfig
-	TLSInvalidCrtErrorList     string
-	TLSNoCrtErrorList          string
-	TLSInvalidCrtErrorPagesMap string
-	TLSNoCrtErrorPagesMap      string
-	VarNamespaceMap            string
+	Timeout HostTimeoutConfig
+	//
+	Maps                       *HostsMaps
+	HostBackendsMap            *HostsMap
+	RootRedirMap               *HostsMap
+	SNIBackendsMap             *HostsMap
+	TLSInvalidCrtErrorList     *HostsMap
+	TLSInvalidCrtErrorPagesMap *HostsMap
+	TLSNoCrtErrorList          *HostsMap
+	TLSNoCrtErrorPagesMap      *HostsMap
+	VarNamespaceMap            *HostsMap
 }
 
 // BindConfig ...
@@ -119,9 +158,11 @@ type BindConfig struct {
 	Socket string
 	Hosts  []*Host
 	//
-	AcceptProxy   bool
-	TLS           BindTLSConfig
-	UseServerList string
+	AcceptProxy bool
+	TLS         BindTLSConfig
+	//
+	Maps          *HostsMaps
+	UseServerList *HostsMap
 }
 
 // BindTLSConfig ...
@@ -177,7 +218,6 @@ type HostTimeoutConfig struct {
 
 // HostTLSConfig ...
 type HostTLSConfig struct {
-	AddCertHeader    bool
 	CAErrorPage      string
 	CAFilename       string
 	CAHash           string
@@ -191,23 +231,30 @@ type Backend struct {
 	ID        string
 	Namespace string
 	Name      string
-	Port      int
+	Port      string
 	Endpoints []*Endpoint
 	//
 	AgentCheck        AgentCheck
 	BalanceAlgorithm  string
 	Cookie            Cookie
+	Cors              Cors
 	CustomConfig      []string
 	HealthCheck       HealthCheck
-	HTTPRequests      []*HTTPRequest
+	HSTS              HSTS
 	MaxConnServer     int
 	MaxQueueServer    int
 	ModeTCP           bool
+	OAuth             OAuthConfig
+	Paths             []string
 	ProxyBodySize     string
+	RewriteURL        string
 	SendProxyProtocol string
 	SSL               SSLBackendConfig
 	SSLRedirect       bool
 	Timeout           BackendTimeoutConfig
+	Userlist          UserlistConfig
+	WAF               string
+	Whitelist         []string
 }
 
 // Endpoint ...
@@ -237,13 +284,23 @@ type HealthCheck struct {
 	RiseCount string
 }
 
+// OAuthConfig ...
+type OAuthConfig struct {
+	Impl        string
+	BackendName string
+	URIPrefix   string
+	Headers     map[string]string
+}
+
 // SSLBackendConfig ...
 type SSLBackendConfig struct {
-	IsSecure     bool
-	CertFilename string
-	CertHash     string
-	CAFilename   string
-	CAHash       string
+	HasTLSAuth    bool
+	AddCertHeader bool
+	IsSecure      bool
+	CertFilename  string
+	CertHash      string
+	CAFilename    string
+	CAHash        string
 }
 
 // BackendTimeoutConfig ...
@@ -257,15 +314,36 @@ type BackendTimeoutConfig struct {
 	Tunnel      string
 }
 
+type UserlistConfig struct {
+	Name  string
+	Realm string
+}
+
 // Cookie ...
 type Cookie struct {
 	Name     string
 	Strategy string
-	Key      string
+	Dynamic  bool
+}
+
+// Cors ...
+type Cors struct {
+	Enabled bool
+	//
+	AllowCredentials bool
+	AllowHeaders     string
+	AllowMethods     string
+	AllowOrigin      string
+	ExposeHeaders    string
+	MaxAge           int
 }
 
-// HTTPRequest ...
-type HTTPRequest struct {
+// HSTS ...
+type HSTS struct {
+	Enabled    bool
+	MaxAge     int
+	Subdomains bool
+	Preload    bool
 }
 
 // Userlist ...
diff --git a/rootfs/etc/haproxy/modsecurity/spoe-modsecurity.tmpl b/rootfs/etc/haproxy/modsecurity/spoe-modsecurity.tmpl
index 08a1f98e4..2f0fdd405 100644
--- a/rootfs/etc/haproxy/modsecurity/spoe-modsecurity.tmpl
+++ b/rootfs/etc/haproxy/modsecurity/spoe-modsecurity.tmpl
@@ -6,7 +6,7 @@
 # #   This file is automatically updated, do not edit
 # #
 #
-{{- $modsec := .Global.ModSecurity -}}
+{{- $modsec := .Global.ModSecurity }}
 [modsecurity]
 spoe-agent modsecurity-agent
     messages     check-request
@@ -17,4 +17,4 @@ spoe-agent modsecurity-agent
     use-backend  spoe-modsecurity
 spoe-message check-request
     args   unique-id method path query req.ver req.hdrs_bin req.body_size req.body
-    event  on-frontend-http-request
+    event  on-backend-http-request
diff --git a/rootfs/etc/haproxy/template/haproxy.tmpl b/rootfs/etc/haproxy/template/haproxy.tmpl
index baaa02c01..6b0a49c53 100644
--- a/rootfs/etc/haproxy/template/haproxy.tmpl
+++ b/rootfs/etc/haproxy/template/haproxy.tmpl
@@ -7,10 +7,10 @@
 # #
 #
 {{- $cfg := . }}
+{{- $fgroup := $cfg.FrontendGroup }}
 {{- $global := $cfg.Global }}
 global
     daemon
-    quiet
 {{- if gt $global.Procs.Nbproc 1 }}
     nbproc {{ $global.Procs.Nbproc }}
 {{- end }}
@@ -63,11 +63,11 @@ defaults
     load-server-state-from-file global
 {{- end }}
     maxconn {{ $global.MaxConn }}
-{{- if $global.DrainSupport }}
+{{- if $global.DrainSupport.Drain }}
     option persist
-    {{- if $global.DrainSupportRedispatch }}
+{{- if $global.DrainSupport.Redispatch }}
     option redispatch
-    {{- end }}
+{{- end }}
 {{- else }}
     option redispatch
 {{- end }}
@@ -167,16 +167,144 @@ backend {{ $backend.ID }}
     timeout tunnel {{ $timeout.Tunnel }}
 {{- end }}
 
+{{- /*------------------------------------*/}}
+{{- /*              MODE TCP              */}}
+{{- /*------------------------------------*/}}
+{{- if $backend.ModeTCP }}
+
+{{- /*------------------------------------*/}}
+{{- if $backend.Whitelist }}
+    tcp-request content reject if !{ src{{ range $cidr := $backend.Whitelist }} {{ $cidr }}{{ end }} }
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- /*             MODE HTTP              */}}
+{{- /*------------------------------------*/}}
+{{- else }}{{/*** if $backend.ModeTCP ***/}}
+
+{{- /*------------------------------------*/}}
+{{- if $backend.Whitelist }}
+    http-request deny if !{ src{{ range $cidr := $backend.Whitelist }} {{ $cidr }}{{ end }} }
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if $backend.Userlist.Name }}
+    http-request auth
+        {{- if $backend.Userlist.Realm }} realm "{{ $backend.Userlist.Realm }}"{{ end }}
+        {{- "" }} if !{ http_auth({{ $backend.Userlist.Name }}) }
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if and (eq $backend.WAF "modsecurity") $global.ModSecurity.Endpoints }}
+    filter spoe engine modsecurity config /etc/haproxy/spoe-modsecurity.conf
+    http-request deny if { var(txn.modsec.code) -m int gt 0 }
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if $backend.SSL.HasTLSAuth }}
+    http-request set-header {{ $global.SSL.HeadersPrefix }}-Client-CN   %{+Q}[ssl_c_s_dn(cn)]{{ if not $backend.SSLRedirect }}   if { ssl_fc }{{ end }}
+    http-request set-header {{ $global.SSL.HeadersPrefix }}-Client-DN   %{+Q}[ssl_c_s_dn]{{ if not $backend.SSLRedirect }}       if { ssl_fc }{{ end }}
+    http-request set-header {{ $global.SSL.HeadersPrefix }}-Client-SHA1 %{+Q}[ssl_c_sha1,hex]{{ if not $backend.SSLRedirect }}   if { ssl_fc }{{ end }}
+{{- if $backend.SSL.AddCertHeader }}
+    http-request set-header {{ $global.SSL.HeadersPrefix }}-Client-Cert %{+Q}[ssl_c_der,base64]{{ if not $backend.SSLRedirect }} if { ssl_fc }{{ end }}
+{{- end }}
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if $backend.Cors.Enabled }}
+    http-request use-service lua.send-response if METH_OPTIONS
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if eq $global.ForwardFor "add" }}
+    http-request set-header X-Original-Forwarded-For %[hdr(x-forwarded-for)] if { hdr(x-forwarded-for) -m found }
+    http-request del-header x-forwarded-for
+    option forwardfor
+{{- else if eq $global.ForwardFor "ifmissing" }}
+    option forwardfor if-none
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if $backend.OAuth.Impl }}
+{{- $oauth := $backend.OAuth }}
+{{- if eq $oauth.Impl "oauth2_proxy" }}
+    http-request set-header X-Real-IP %[src]
+    http-request lua.auth-request {{ $oauth.BackendName }} {{ $oauth.URIPrefix }}/auth
+    http-request redirect location {{ $oauth.URIPrefix }}/start?rd=%[path] if !{ path_beg {{ $oauth.URIPrefix }}/ } !{ var(txn.auth_response_successful) -m bool }
+{{- range $header, $attr := $oauth.Headers }}
+    http-request set-header {{ $header }} %[var(txn.{{ $attr }})] if { var(txn.{{ $attr }}) -m found }
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if $backend.Cookie.Name }}
+{{- $cookie := $backend.Cookie }}
+    cookie {{ $cookie.Name }} {{ $cookie.Strategy }}
+        {{- if eq $cookie.Strategy "insert" }} indirect nocache httponly{{ end }}
+        {{- if $cookie.Dynamic }} dynamic{{ end }}
+{{- if $cookie.Dynamic }}
+    dynamic-cookie-key "{{ $global.Cookie.Key }}"
+{{- end }}
+{{- end }}
+
 {{- /*------------------------------------*/}}
 {{- range $snippet := $backend.CustomConfig }}
     {{ $snippet }}
 {{- end }}
 
+{{- /*------------------------------------*/}}
+{{- if $backend.RewriteURL }}
+{{- range $path := $backend.Paths }}
+{{- if eq $backend.RewriteURL "/" }}
+    reqrep ^([^:\ ]*)\ {{ $path }}/?(.*)$     \1\ {{ $backend.RewriteURL }}\2
+{{- else }}
+    reqrep ^([^:\ ]*)\ {{ $path }}(.*)$       \1\ {{ $backend.RewriteURL }}{{ if hasSuffix $path "/" }}/{{ end }}\2
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if $backend.HSTS.Enabled }}
+{{- $hsts := $backend.HSTS }}
+    http-response set-header Strict-Transport-Security "max-age={{ $hsts.MaxAge }}
+        {{- if $hsts.Subdomains }}; includeSubDomains{{ end }}
+        {{- if $hsts.Preload }}; preload{{ end }}"
+        {{- if not $backend.SSLRedirect }} if { ssl_fc }{{ end }}
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if $backend.Cors.Enabled }}
+{{- $cors := $backend.Cors }}
+    http-response set-status 204 reason "No Content" if METH_OPTIONS
+    http-response set-header Content-Type                 "text/plain" if METH_OPTIONS
+    http-response set-header Content-Length               "0" if METH_OPTIONS
+    http-response set-header Access-Control-Allow-Origin  "{{ $cors.AllowOrigin }}" if METH_OPTIONS
+    http-response set-header Access-Control-Allow-Methods "{{ $cors.AllowMethods }}" if METH_OPTIONS
+    http-response set-header Access-Control-Allow-Headers "{{ $cors.AllowHeaders }}" if METH_OPTIONS
+{{- if $cors.AllowCredentials }}
+    http-response set-header Access-Control-Allow-Credentials "{{ $cors.AllowCredentials }}" if METH_OPTIONS
+{{- end }}
+    http-response set-header Access-Control-Max-Age       "{{ $cors.MaxAge }}" if METH_OPTIONS
+    http-response set-header Access-Control-Allow-Origin  "{{ $cors.AllowOrigin }}"
+    http-response set-header Access-Control-Allow-Methods "{{ $cors.AllowMethods }}"
+    http-response set-header Access-Control-Allow-Headers "{{ $cors.AllowHeaders }}"
+{{- if $cors.AllowCredentials }}
+    http-response set-header Access-Control-Allow-Credentials "{{ $cors.AllowCredentials }}"
+{{- end }}
+{{- if $cors.ExposeHeaders }}
+    http-response set-header Access-Control-Expose-Headers "{{ $cors.ExposeHeaders }}"
+{{- end }}
+{{- end }}
+
+{{- end }}{{/*** if $backend.ModeTCP ***/}}
+
 {{- /*------------------------------------*/}}
 {{- range $ep := $backend.Endpoints }}
     server {{ $ep.Name }} {{ $ep.IP }}:{{ $ep.Port }}
         {{- if $ep.Disabled }} disabled{{ end }}
         {{- "" }} weight {{ $ep.Weight }}
+        {{- if and (not $backend.ModeTCP) ($backend.Cookie.Name) (not $backend.Cookie.Dynamic) }} cookie {{ $ep.Name }}{{ end }}
         {{- template "backend" map $backend }}
 {{- end }}
 {{- end }}
@@ -235,7 +363,6 @@ backend _error496
 # #   FRONTENDS
 # #
 #
-{{- $fgroup := $cfg.BuildFrontendGroup }}
 {{- $frontends := $fgroup.Frontends }}
 {{- if $fgroup.HasTCPProxy }}
 
@@ -246,21 +373,61 @@ backend _error496
 listen _front__tls
     mode tcp
     bind :443
+
+{{- /*------------------------------------*/}}
+{{- if $global.Syslog.Endpoint }}
+{{- if eq $global.Syslog.HTTPSLogFormat "default" }}
+    option tcplog
+{{- else if $global.Syslog.HTTPSLogFormat }}
+    log-format {{ $global.Syslog.HTTPSLogFormat }}
+{{- else }}
+    no log
+{{- end }}
+{{- end }}
+
+{{- /*------------------------------------*/}}
     tcp-request inspect-delay 5s
     tcp-request content accept if { req.ssl_hello_type 1 }
+
+{{- /*------------------------------------*/}}
 {{- if $fgroup.HasSSLPassthrough }}
     ## ssl-passthrough
-    tcp-request content set-var(req.backend) req.ssl_sni,lower,map({{ $fgroup.SSLPassthroughMap }},_nomatch)
+    tcp-request content set-var(req.backend)
+        {{- "" }} req.ssl_sni,lower,map({{ $fgroup.SSLPassthroughMap.MatchFile }},_nomatch)
+    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- range $frontend := $frontends }}
+{{- range $bind := $frontend.Binds }}
+    ## {{ $frontend.Name }}/{{ $bind.Name }}
+    use-server _server{{ $bind.Name }} if { req.ssl_sni -i -f {{ $bind.UseServerList.MatchFile }} }
+    server _server{{ $bind.Name }} {{ $bind.Socket }} send-proxy-v2 weight 0
+{{- end }}
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if $fgroup.SSLPassthroughMap.HasRegex }}
+    ## ssl-passthrough wildcard
+{{- /*** TODO is map_reg() converter running on every request? ***/}}
+    tcp-request content set-var(req.backend)
+        {{- "" }} req.ssl_sni,lower,map_reg({{ $fgroup.SSLPassthroughMap.RegexFile }},_nomatch)
+        {{- "" }} if { var(req.backend) _nomatch }
+
+{{- /*------------------------------------*/}}
     use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
 {{- end }}
 {{- range $frontend := $frontends }}
-    ## {{ $frontend.Name }}
 {{- range $bind := $frontend.Binds }}
-    use-server _server_{{ $bind.Name }} if
-        {{- "" }} { req.ssl_sni -i -f {{ $bind.UseServerList }} }
-    server _server_{{ $bind.Name }} {{ $bind.Socket }} send-proxy-v2 weight 0
+{{- if $bind.UseServerList.HasRegex }}
+    ## {{ $frontend.Name }}/{{ $bind.Name }} wildcard
+    use-server _server{{ $bind.Name }}_wildcard if { req.ssl_sni -i -m reg -f {{ $bind.UseServerList.RegexFile }} }
+    server _server{{ $bind.Name }}_wildcard {{ $bind.Socket }} send-proxy-v2 weight 0
+{{- end }}
 {{- end }}
 {{- end }}
+
+{{- /*------------------------------------*/}}
     # TODO default backend
 {{- end }}
 
@@ -268,32 +435,59 @@ listen _front__tls
 # #
 #     HTTP frontend
 #
-frontend _front__http
+frontend _front_http
     mode http
     bind :80
 
 {{- /*------------------------------------*/}}
-{{- $hasredirect := $fgroup.HasRedirectHTTPS }}
-{{- $hashttp := $fgroup.HasHTTPHost }}
-{{- if $hasredirect }}
-    http-request set-var(req.base) base,regsub(:[0-9]+/,/)
-{{- if $hashttp }}
-    http-request set-var(req.backend) var(req.base),map_beg({{ $fgroup.HTTPFrontsMap }},_nomatch)
+{{- if $global.Syslog.Endpoint }}
+{{- if $global.Syslog.HTTPLogFormat }}
+    log-format {{ $global.Syslog.HTTPLogFormat }}
+{{- else }}
+    option httplog
+{{- end }}
 {{- end }}
-{{- else if $hashttp }}
-    http-request set-var(req.backend) base,regsub(:[0-9]+/,/),map_beg({{ $fgroup.HTTPFrontsMap }},_nomatch)
+
+{{- /*------------------------------------*/}}
+    http-request set-var(req.base) base,regsub(:[0-9]+/,/)
+
+{{- /*------------------------------------*/}}
+{{- if $fgroup.HTTPSRedirMap.HasRegex }}
+    http-request set-var(req.redir)
+        {{- "" }} var(req.base),map_beg({{ $fgroup.HTTPSRedirMap.MatchFile }},_nomatch)
+    http-request redirect scheme https if { var(req.redir) yes }
+    http-request redirect scheme https if { var(req.redir) _nomatch }
+        {{- "" }} { var(req.base),map_reg({{ $fgroup.HTTPSRedirMap.RegexFile }},_nomatch) yes }
+{{- else }}
+    http-request redirect scheme https if { var(req.base),map_beg({{ $fgroup.HTTPSRedirMap.MatchFile }},_nomatch) yes }
 {{- end }}
 
 {{- /*------------------------------------*/}}
-{{- if $hasredirect }}
-    redirect scheme https if
-        {{- "" }} { var(req.base),map_beg({{ $fgroup.RedirectMap }},_nomatch) yes }
+{{- if $fgroup.HTTPRootRedirMap.HasHost }}
+    http-request set-var(req.host) hdr(host),lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.rootredir)
+        {{- "" }} var(req.host),map({{ $fgroup.HTTPRootRedirMap.MatchFile }},_nomatch)
+{{- if $fgroup.HTTPRootRedirMap.HasRegex }}
+    http-request set-var(req.rootredir)
+        {{- "" }} var(req.host),map_reg({{ $fgroup.HTTPRootRedirMap.RegexFile }},_nomatch) if { var(req.rootredir) _nomatch }
+{{- end }}
+    http-request redirect location %[var(req.rootredir)] if { path / } !{ var(req.rootredir) _nomatch }
 {{- end }}
 
 {{- /*------------------------------------*/}}
-{{- if $hashttp }}
-    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
+    http-request del-header {{ $global.SSL.HeadersPrefix }}-Client-CN
+    http-request del-header {{ $global.SSL.HeadersPrefix }}-Client-DN
+    http-request del-header {{ $global.SSL.HeadersPrefix }}-Client-SHA1
+    http-request del-header {{ $global.SSL.HeadersPrefix }}-Client-Cert
+
+{{- /*------------------------------------*/}}
+    http-request set-var(req.backend) var(req.base),map_beg({{ $fgroup.HTTPFrontsMap.MatchFile }},_nomatch)
+{{- if $fgroup.HTTPFrontsMap.HasRegex }}
+    http-request set-var(req.backend)
+        {{- "" }} var(req.base),map_reg({{ $fgroup.HTTPFrontsMap.RegexFile }},_nomatch)
+        {{- "" }} if { var(req.backend) _nomatch }
 {{- end }}
+    use_backend %[var(req.backend)] unless { var(req.backend) _nomatch }
 
 {{- template "defaultbackend" map $cfg }}
 
@@ -327,41 +521,106 @@ frontend {{ $frontend.Name }}
 {{- if $frontend.Timeout.ClientFin }}
     timeout client-fin {{ $frontend.Timeout.ClientFin }}
 {{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if $global.Syslog.Endpoint }}
+{{- if $global.Syslog.HTTPLogFormat }}
+    log-format {{ $global.Syslog.HTTPLogFormat }}
+{{- else }}
+    option httplog
+{{- end }}
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if or $frontend.HostBackendsMap.HasRegex $frontend.HasVarNamespace }}
+    http-request set-var(req.base) base,lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.hostbackend)
+        {{- "" }} var(req.base),map_beg({{ $frontend.HostBackendsMap.MatchFile }},_nomatch)
+{{- else }}
+    http-request set-var(req.hostbackend) base,lower,regsub(:[0-9]+/,/)
+        {{- "" }},map_beg({{ $frontend.HostBackendsMap.MatchFile }},_nomatch)
+{{- end }}
+{{- if $frontend.HostBackendsMap.HasRegex }}
+    http-request set-var(req.hostbackend)
+        {{- "" }} var(req.base),map_reg({{ $frontend.HostBackendsMap.RegexFile }},_nomatch)
+        {{- "" }} if { var(req.hostbackend) _nomatch }
+{{- end }}
+
+{{- /*------------------------------------*/}}
+{{- if $frontend.RootRedirMap.HasHost }}
+    http-request set-var(req.host) hdr(host),lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.rootredir)
+        {{- "" }} var(req.host),map({{ $frontend.RootRedirMap.MatchFile }},_nomatch)
+{{- if $frontend.RootRedirMap.HasRegex }}
+    http-request set-var(req.rootredir)
+        {{- "" }} var(req.host),map_reg({{ $frontend.RootRedirMap.RegexFile }},_nomatch) if { var(req.rootredir) _nomatch }
+{{- end }}
+    http-request redirect location %[var(req.rootredir)] if { path / } !{ var(req.rootredir) _nomatch }
+{{- end }}
+
+{{- /*------------------------------------*/}}
 {{- if $frontend.HasVarNamespace }}
-    http-request set-var(txn.namespace) base
-        {{- if $frontend.ConvertLowercase }},lower{{ end }}
-        {{- "" }},regsub(:[0-9]+/,/)
-        {{- "" }},map_beg({{ $frontend.VarNamespaceMap }},-)
+    http-request set-var(txn.namespace) 
+        {{- "" }} var(req.base),map_beg({{ $frontend.VarNamespaceMap.MatchFile }},-)
+{{- if $frontend.VarNamespaceMap.HasRegex }}
+    http-request set-var(txn.namespace) 
+        {{- "" }} var(req.base),map_reg({{ $frontend.VarNamespaceMap.RegexFile }},-)
+        {{- "" }} if { var(txn.namespace) - }
+{{- end }}
 {{- end }}
 
 {{- /*------------------------------------*/}}
-    http-request set-var(req.hostbackend) base
-        {{- if $frontend.ConvertLowercase }},lower{{ end }}
-        {{- "" }},regsub(:[0-9]+/,/)
-        {{- "" }},map_beg({{ $frontend.HostBackendsMap }},_nomatch)
+    http-request del-header {{ $global.SSL.HeadersPrefix }}-Client-CN
+    http-request del-header {{ $global.SSL.HeadersPrefix }}-Client-DN
+    http-request del-header {{ $global.SSL.HeadersPrefix }}-Client-SHA1
+    http-request del-header {{ $global.SSL.HeadersPrefix }}-Client-Cert
 
 {{- /*------------------------------------*/}}
 {{- if $frontend.HasTLSAuth }}
-{{- /* missing concat converter, fix after 1.9 */}}
+{{- /*** TODO missing concat converter, fix after 1.9 ***/}}
     http-request set-header x-ha-base %[ssl_fc_sni]%[path]
-    http-request set-var(req.snibackend) hdr(x-ha-base)
-        {{- if $frontend.ConvertLowercase }},lower{{ end }}
-        {{- "" }},regsub(:[0-9]+/,/)
-        {{- "" }},map_beg({{ $frontend.SNIBackendsMap }},_nomatch)
+{{- if $frontend.SNIBackendsMap.HasRegex }}
+    http-request set-var(req.snibase) hdr(x-ha-base),lower,regsub(:[0-9]+/,/)
+    http-request set-var(req.snibackend) var(req.snibase)
+        {{- "" }},map_beg({{ $frontend.SNIBackendsMap.MatchFile }},_nomatch)
+    http-request set-var(req.snibackend) var(req.snibase)
+        {{- "" }},map_reg({{ $frontend.SNIBackendsMap.RegexFile }},_nomatch) if { var(req.snibackend) _nomatch }
+{{- else }}
+    http-request set-var(req.snibackend) hdr(x-ha-base),lower,regsub(:[0-9]+/,/)
+        {{- "" }},map_beg({{ $frontend.SNIBackendsMap.MatchFile }},_nomatch)
+{{- end }}
 {{- $mandatory := $frontend.HasTLSMandatory }}
-    acl tls-invalid-crt ssl_c_ca_err gt 0
-    acl tls-invalid-crt ssl_c_err gt 0
 {{- if $mandatory }}
     acl tls-has-crt ssl_c_used
-    http-request set-var(req.tls_nocrt_redir) ssl_fc_sni
-        {{- if $frontend.ConvertLowercase }},lower{{ end }}
-        {{- "" }},map({{ $frontend.TLSNoCrtErrorPagesMap }},_internal)
-        {{- "" }} if !tls-has-crt
-{{- end }}
-    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni
-        {{- if $frontend.ConvertLowercase }},lower{{ end }}
-        {{- "" }},map({{ $frontend.TLSInvalidCrtErrorPagesMap }},_internal)
-        {{- "" }} if tls-invalid-crt
+    acl tls-need-crt ssl_fc_sni -i -f {{ $frontend.TLSNoCrtErrorList.MatchFile }}
+{{- if $frontend.TLSNoCrtErrorList.HasRegex }}
+    acl tls-need-crt ssl_fc_sni -i -m reg -f {{ $frontend.TLSNoCrtErrorList.RegexFile }}
+{{- end }}
+{{- end }}
+    acl tls-has-invalid-crt ssl_c_ca_err gt 0
+    acl tls-has-invalid-crt ssl_c_err gt 0
+    acl tls-check-crt ssl_fc_sni -i -f {{ $frontend.TLSInvalidCrtErrorList.MatchFile }}
+{{- if $frontend.TLSInvalidCrtErrorList.HasRegex }}
+    acl tls-check-crt ssl_fc_sni -i -m reg -f {{ $frontend.TLSInvalidCrtErrorList.RegexFile }}
+{{- end }}
+{{- if $mandatory }}
+    http-request set-var(req.tls_nocrt_redir) ssl_fc_sni,lower
+        {{- "" }},map({{ $frontend.TLSNoCrtErrorPagesMap.MatchFile }},_internal)
+        {{- "" }} if !tls-has-crt tls-need-crt
+{{- if $frontend.TLSNoCrtErrorPagesMap.HasRegex }}
+    http-request set-var(req.tls_nocrt_redir) ssl_fc_sni,lower
+        {{- "" }},map_reg({{ $frontend.TLSNoCrtErrorPagesMap.RegexFile }},_internal)
+        {{- "" }} if { var(req.tls_nocrt_redir) _internal }
+{{- end }}
+{{- end }}
+    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni,lower
+        {{- "" }},map({{ $frontend.TLSInvalidCrtErrorPagesMap.MatchFile }},_internal)
+        {{- "" }} if tls-has-invalid-crt tls-check-crt
+{{- if $frontend.TLSInvalidCrtErrorPagesMap.HasRegex }}
+    http-request set-var(req.tls_invalidcrt_redir) ssl_fc_sni,lower
+        {{- "" }},map_reg({{ $frontend.TLSInvalidCrtErrorPagesMap.RegexFile }},_internal)
+        {{- "" }} if { var(req.tls_invalidcrt_redir) _internal }
+{{- end }}
 {{- if and $mandatory $frontend.HasNoCrtErrorPage }}
     http-request redirect location %[var(req.tls_nocrt_redir)] code 303 if
         {{- "" }} { var(req.tls_nocrt_redir) -m found } !{ var(req.tls_nocrt_redir) _internal }
@@ -373,11 +632,9 @@ frontend {{ $frontend.Name }}
 {{- if $mandatory }}
     use_backend _error496 if
         {{- "" }} { var(req.tls_nocrt_redir) _internal }
-        {{- "" }} { ssl_fc_sni -i -f {{ $frontend.TLSNoCrtErrorList }} }
 {{- end }}
     use_backend _error495 if
         {{- "" }} { var(req.tls_invalidcrt_redir) _internal }
-        {{- "" }} { ssl_fc_sni -i -f {{ $frontend.TLSInvalidCrtErrorList }} }
 {{- end }}
 
 {{- /*------------------------------------*/}}
@@ -402,4 +659,28 @@ frontend {{ $frontend.Name }}
 {{- else }}
     default_backend _error404
 {{- end }}
+{{- end }}
+
+
+  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# #
+# #   SUPPORT
+# #
+#
+
+{{- if $global.ModSecurity.Endpoints }}
+
+  # # # # # # # # # # # # # # # # # # #
+# #
+#     ModSecurity Agent
+#
+backend spoe-modsecurity
+    mode tcp
+    timeout connect 5s
+    timeout server  5s
+{{- range $i, $endpoint := $global.ModSecurity.Endpoints }}
+    server modsec-spoa{{ $i }} {{ $endpoint }}
+{{- end }}
+
 {{- end }}