Skip to content

Virtual hosts and locations

AlexandrGoncharov edited this page Apr 19, 2024 · 15 revisions

Virtual hosts and locations are a way of grouping certain directives that are applied only to requests which satisfy certain criteria. Virtual host is defined as follows:

vhost NAME {
	<directive>;
	...
	<directive>;
}

NAME is a unique identifier of virtual host that may be used to refer it from HTTP scheduler (see Scheduling and Load Balancing).

Location is defined by a string and a match operator that are used to match the string against URL in requests. The syntax is as follows:

location <OP> "<string>" {
	<directive>;
	...
	<directive>;
}

<OP> and <string> are specified the same way as defined in the Caching Policy section.

Multiple virtual hosts and locations may be defined and are processed strictly in the order they are defined in the configuration file. Virtual host directive block can include location directive block.

Caching policy, nonidempotent, headers modification and proxy_pass (see below) directives can be grouped by the vhost and location directives.

Below is an example of virtual host and location directive definition:

cache_bypass suffix ".php";
cache_fulfill suffix ".mp4";

location prefix "/static/" {
	cache_bypass prefix "/static/dynamic_zone/";
	cache_fulfill * *;
	resp_hdr_add Expires "Thu, 15 Apr 2020 20:00:00 GMT"
}

location prefix "/society/" {
	cache_bypass prefix "/society/breaking_news/";
	cache_fulfill suffix ".jpg" ".png";
	cache_fulfill suffix ".css";
	nonidempotent GET prefix "/society/users/";
}

vhost app {
	proxy_pass base;
	location prefix "?" {
		proxy_pass heavy backup=bkp_grp;
		nonidempotent GET prefix "/users/";
		resp_hdr_add Cache-Control "no-cache";
	}
	location prefix "/static/" {
		proxy_pass static;
		cache_fulfill suffix ".jpg" ".png";
		req_hdr_set Host "example3.com";
	}
	cache_fulfill * *;
}

Inheriting Location directives

The directives defined inside of particular virtual host but outside of any specific location are considered the default policy for that virtual host. There is a special virtual host called "default". All virtual host internal directives (specified above) defined outside of any virtual host, are added to the default virtual host implicitly. Also the location directives defined outside of any specific virtual host are considered the policies of default virtual host. The directives defined outside of any specific location and any specific virtual host are belong to default policy of default virtual host and considered the global default policy (location) for all virtual hosts and locations.

When locations are defined in the configuration (in specific or default virtual host), the URL of each request for that virtual host is matched against strings specified in the location directives and using the corresponding match operator. If a matching location is found, then directives for that location are used against the request.

In case there's no matching location, or there's no directive in the location, the directives of that type of default location for current virtual host are used against the request.

E.g. if caching policy directives are defined for some location of request' virtual host, they will be used. If no caching policy directives are found, then caching policy directives of default location of request's virtual host is used. If no caching policy are found in default location of particular virtual host, then caching policy of global default location is used.

Proxy pass

Directive proxy_pass is used in vhost and location directive blocks to specify server groups to which requests for current virtual host and/or location must be sent. The syntax is as follows:

proxy_pass GROUP [backup=BKP_GROUP];

GROUP is the reference to a previously defined 'srv_group'.

BKP_GROUP is the reference to a previously defined backup 'srv_group' (optional parameter). Requests will be sent to backup BKP_GROUP (if specified), if none of the servers in specified GROUP are available.
Example:

location prefix "/society/" {
	proxy_pass heavy backup=bkp_grp;
	...
}
vhost app {
	proxy_pass base;
	location prefix "?" {
		proxy_pass heavy;
		...
	}
	location prefix "/static/" {
		proxy_pass static;
		...
	}
	...
}

Directive proxy_pass is mandatory for virtual host and location directive blocks. For explicit default virtual host directive (and included locations) only proxy_pass directives with default server group is allowed to be specified (it's created automatically if it's missed). For implicit default virtual host - proxy_pass directive is not allowed (since default virtual host must point to default server group).

Local HTTP security limits

HTTP limits (see Frang security limits) also can be grouped by the location directives. If HTTP limit is specified inside location then this limit (instead of globally defined limit) is used against the request of that location. Note, only limits which depend on contents of HTTP request - can be specified inside location directive; directives for these limits are specified here.

Example:

location prefix "?" {
	http_ct_vals "text/html";
	client_body_timeout 50;
	...
}
vhost primary {
	proxy_pass base;
	location prefix "/some_content" {
		proxy_pass base;
		http_uri_len 512;
		...
	}
	location prefix "/static/" {
		proxy_pass static;
		http_methods get head;
		...
	}
	...
}

Virtual hosts listening on different IP addresses and ports

When you have several vhosts and several listen addresses, e.g.

listen 192.168.100.4:443 proto=h2;
listen 192.168.100.6:443 proto=https;

srv_group site1 {
	server 192.168.100.4:8000;
}

vhost site1 {
	proxy_pass ubuntu;
}

srv_group site2 {
	server 1.1.1.1:80;
}

vhost site2 {
	proxy_pass site2;
}

Then both the vhosts (site1 and site2 in this example) will be available on both of the addresses.

If you need to make different vhosts to listen on different addresses and ports, then this can be achieved with adding following HTTPtables rules to the Tempesta FW configuration:

http_chain site1_chain {
	hdr "Host" == "*site1.org" -> site1;
}

http_chain site2_chain {
	hdr "Host" == "*site2.org" -> site2;
}

http_chain {
	mark == 1 -> site1_chain;
	mark == 2 -> site2_chain;
}

Here we use marks from the IP layer to distribute traffic among two HTTP chains for both the sites. The IP marks can be set with iptables:

# iptables -t mangle -A PREROUTING -p tcp -d 192.168.100.4 -j MARK --set-mark 2
# iptables -t mangle -A PREROUTING -p tcp -d 192.168.100.6 -j MARK --set-mark 1

With this configuration site1 will be available on 192.168.100.4 by HTTP/2 only and site2 is only on 192.168.100.6 HTTPS. If you try to make a request to a wrong site on a wrong address

curl -k --connect-to site1.org:443:192.168.100.6:443 https://site1.org

, then curl can't fetch the requested resource and the Tempesta FW log contains

[tempesta fw] Warning: request dropped: cannot find appropriate virtual host: 192.168.100.1
[tempesta fw] 192.168.100.1 "-" "GET / HTTP/1.1" 403 0 "-" "curl/7.74.0"
Clone this wiki locally