Before we cover how Nginx decides which location block to use to handle requests, let's go over some of the syntax you might see in location block definitions. Location blocks live within server blocks (or other location blocks) and are used to decide how to process the request URI (the part of the request that comes after the domain name or IP address/port).
Location blocks generally take the following form:
The location_match in the above defines what Nginx should check the request URI against. The existence or nonexistence of the modifier in the above example affects the way that the Nginx attempts to match the location block. The modifiers below will cause the associated location block to be interpreted as follows:
(none): If no modifiers are present, the location is interpreted as a prefix match. This means that the location given will be matched against the beginning of the request URI to determine a match.
location /site {
....
}
=: If an equal sign is used, this block will be considered a match if the request URI exactly matches the location given.
location = /page1 {
....
}
~: If a tilde modifier is present, this location will be interpreted as a case-sensitive regular expression match.
location ~ \.(jpe?g|png|gif|ico)$ {
....
}
~:* If a tilde and asterisk modifier is used, the location block will be interpreted as a case-insensitive regular expression match.
location ~* \.(jpe?g|png|gif|ico)$ {
....
}
^~: If a carat and tilde modifier is present, and if this block is selected as the best non-regular expression match, regular expression matching will not take place.
location ^~ /costumes {
....
}
Nginx evaluates the possible location contexts by comparing the request URI to each of the locations. It does this using the following algorithm:
Nginx begins by checking all prefix-based location matches (all location types not involving a regular expression). It checks each location against the complete request URI.
First, Nginx looks for an exact match. If a location block using the = modifier is found to match the request URI exactly, this location block is immediately selected to serve the request.
If no exact (with the = modifier) location block matches are found, Nginx then moves on to evaluating non-exact prefixes. It discovers the longest matching prefix location for the given request URI, which it then evaluates as follows:
If the longest matching prefix location has the ^~ modifier, then Nginx will immediately end its search and select this location to serve the request.
If the longest matching prefix location does not use the ^~ modifier, the match is stored by Nginx for the moment so that the focus of the search can be shifted.
After the longest matching prefix location is determined and stored, Nginx moves on to evaluating the regular expression locations (both case sensitive and insensitive). If there are any regular expression locations within the longest matching prefix location, Nginx will move those to the top of its list of regex locations to check. Nginx then tries to match against the regular expression locations sequentially. The first regular expression location that matches the request URI is immediately selected to serve the request.
If no regular expression locations are found that match the request URI, the previously stored prefix location is selected to serve the request.
It is important to understand that, by default, Nginx will serve regular expression matches in preference to prefix matches. However, it evaluates prefix locations first, allowing for the administer to override this tendency by specifying locations using the = and ^~ modifiers.
It is also important to note that, while prefix locations generally select based on the longest, most specific match, regular expression evaluation is stopped when the first matching location is found. This means that positioning within the configuration has vast implications for regular expression locations.
Create a directory for SSL certificates in /etc/nginx
# mkdir -p /etc/nginx/ssl
cd /etc/nginx/ssl
Generate a certificate
# openssl genrsa -des3 -out server.key 1024
NOTE : You need to give a pass phrase to generate your key between 4 to 8191 characters
Now let us use this key to create a signin certificate request
# openssl req -new -key server.key -out server.csr
Enter pass phrase for server.key:
Country Name (2 letter code) [XX]:IN
State or Province Name (full name) []:AP
Locality Name (eg, city) [Default City]:Hyderabad
Organization Name (eg, company) [Default Company Ltd]:Linux-Library
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:dev02
Email Address []:vmsnivas@gmail.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
NOTE: Leave the extra attributes blank
Now we need to remove the pass phrase for the server.key or else NGINX will prompt for the pass phrase every time you restart it.
We have our certificate ready and all we need to do now is to prepare our server to answer the requests over https on 443 port
For this we need to add a new server section to serve the requests to listen on 443 in our custom config file in /etc/nginx/vhost.d
# vi www.lltest1.ll.conf
server {
listen 443;
root /var/www/html/lltest1;
index index.html index.htm index.php;
server_name www.lltest1.ll lltest1;
ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key
}
Here we are saying NGINX to turn on SSL function for this site and use the certificate and the key provided below.
Verify the configuration
# nginx -t
Reload the NGINX service
# nginx -s reload
Now you can verify your website from any browser. It will shows an error as you are not registered your certificate with neither of the third party certificate providers. But there is no issue as yours is a self signed certificate. You can use proceed unsafe option to go ahead and use your site.
Here while using the default function of loadbalancing with Nginx Upstream directive it uses round-robin method.
Means if we have configured LoadBalancing between 2 nodes then the Nginx will forward traffic to 1 hit to 1 server and the 2nd hit to another and goes on.
If we are clear that one of the 2 machines can handle more load then we can prioritize that host to have the number of consicutive connections through the weight function used along with the server in the upstream directive.
Let us try this for the above Load Balancing concept of Tomcat
OLD
upstream myTomcat {
server dev01.linux-library.ll:8080;
server dev02.linux-library.ll:8081;
}
NEW
upstream myTomcat {
server dev01.linux-library.ll:8080 weight=1;
server dev02.linux-library.ll:8081 weight=2;
}
Means 1 connection will be forwarded to dev01 and 2 connections will be forwarded to dev02.
We are going to have 2 times the load of dev01 coming in dev02
Till now we have seen how to configure a basic webserver for our local host.
Let us now see the process of configuring a custom website.
Either we should have our DNS configured for the site we are looking for or we can put an entry in the /etc/hosts file for the IP which we want to host from.
In my case I want to name my website as www.lltest1.ll, so I am adding an entry for that in the /etc/hosts file
# vi /etc/hosts
192.168.1.110 www.lltest1.ll lltest1.ll
Now I'll create a config file for this website. For this we need to create a config file in the vhost.d directory.
If we name our custom website config files with the name of the site followed by an extension .conf would be easier for us to know which config file corresponds to which site.
# cd /etc/nginx/vhost.d/
# vi www.lltest1.ll.conf
server {
listen 80;
root /var/www/html/lltest1;
index index.html index.htm index.php;
server_name www.lltest1.ll lltest1;
}
In the above case we are giving the alias name of our website. As in nginx we have server_name directive capable to handle both server name and server alias functions.
After creating the config file check for any errors.
# nginx -t
Now let us create the root directory for this site and an index file
# mkdir -p /var/www/html/lltest1
# cd /var/www/html/lltest1
# echo "WELCOME TO LINUX_LIBRARY_TESTING SITE" > index.html
For NGINX the base and main configuration file is /etc/nginx/nginx.conf as it contains all the main and mandatory configs.
Let us add an include statement to pull our customized configs.
We can see the ngin.conf file has an include directive in the http section which will tell the main config to pull the configs from.
By default it will pull the configs from /etc/nginx/conf.d directory.
We'll add an additional include directive to pull our configs from /etc/nginx/vhost.conf in which we are going to have our custom configs. Here we'll remove the server directive and have that in our custom config file.
# cp -prv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.`date +"%Y%m%d"`
# vi /etc/nginx/nginx.conf
include /etc/nginx/vhost.d/*.conf;
If we are hosting multiple websites then we can have our SITE_NAME.d directory in place of vhost.d. This will help us in hosting multiple websites to avoid confusion.
Now let us create a directory named vhost.d and prepare our custom config.
Location of the nginx main config file is /etc/nginx/nginx.conf
Let us know about this configuration file and its options first
worker_processes
This is responsible for machine to know how many workers are available to spawned after getting bounded to an IP / Port.
worker_connections
By default this will be set to 1 but depending on the connections the host can accept we can change it.
Through ulimit -n we can know the max number of connections allowed to a host.
worker_connections 1024;
Buffers This section should be placed in the html section and before the include statement of the nginx config file.
client_body_buffer_size
client_body_buffer_size 10k;
client_header_buffer_size
client_header_buffer_size 1k;
client_max_body_size
client_max_body_size 8m;
large_client_header_buffers
large_client_header_buffers 2 1k;
Timeouts This will tell the server to know the max time to wait after a request has been received from a client. There are 2 types of timeouts.
client_body_timeout This can be set to a max of 12 seconds.
client_body_timeout 12;
client_header_timeout Maintaining the same as the timeout for the body
client_header_timeout 12;
keep_alive_timeout, send_timeout These will let the system know till when a request can be waited and when to send the error if not able to serve the request. If you already have these then you can modify those as per your choice.
keep_alive_timeout 15;
send_timeout 10;
Test your configurations This would always be a good practice to verify your config before restarting the application as you can get to know where you have misconfigured.
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
NGINX is a free, open-source, high-performance HTTP server and reverse proxy, as well as an IMAP/POP3 proxy server. NGINX is known for its high performance, stability, rich feature set, simple configuration, and low resource consumption.
NGINX is one of a handful of servers written to address the C10K problem. Unlike traditional servers, NGINX doesn’t rely on threads to handle requests. Instead it uses a much more scalable event-driven (asynchronous) architecture. This architecture uses small, but more importantly, predictable amounts of memory under load. Even if you don’t expect to handle thousands of simultaneous requests, you can still benefit from NGINX’s high-performance and small memory footprint. NGINX scales in all directions: from the smallest VPS all the way up to large clusters of servers.
Overview of nginx Architecture
Traditional process- or thread-based models of handling concurrent connections involve handling each connection with a separate process or thread, and blocking on network or input/output operations. Depending on the application, it can be very inefficient in terms of memory and CPU consumption. Spawning a separate process or thread requires preparation of a new runtime environment, including allocation of heap and stack memory, and the creation of a new execution context. Additional CPU time is also spent creating these items, which can eventually lead to poor performance due to thread thrashing on excessive context switching. All of these complications manifest themselves in older web server architectures like Apache's. This is a tradeoff between offering a rich set of generally applicable features and optimized usage of server resources.
From the very beginning, nginx was meant to be a specialized tool to achieve more performance, density and economical use of server resources while enabling dynamic growth of a website, so it has followed a different model. It was actually inspired by the ongoing development of advanced event-based mechanisms in a variety of operating systems. What resulted is a modular, event-driven, asynchronous, single-threaded, non-blocking architecture which became the foundation of nginx code.
Nginx uses multiplexing and event notifications heavily, and dedicates specific tasks to separate processes. Connections are processed in a highly efficient run-loop in a limited number of single-threaded processes called workers. Within each worker nginx can handle many thousands of concurrent connections and requests per second.
Now we need to change the configs to change the ports as we know each instance should have some distinct ports to listen on.
[TOMCAT1]
Shutdown Port -> 7005
Web Port -> 7080
Redirect Port -> 7443
AJP Conn. Port -> 7009
[TOMCAT2]
Shutdown Port -> 8005
Web Port -> 8080
Redirect Port -> 8443
AJP Conn. Port -> 8009
Please refer to Basic Clustering to know how to change the ports also to know how can these tomcat instances be run in a clustered environment to balance the load