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
We can get the catalina logs in $CATALINA_HOME/logs
Here we'll have a catalina.out
We can see some huge info in that log file. If we want to what exactly happens since the start of tomcat then we need to log that into a new file.
By default we have log rotation enabled on this logs.
For now let us stop tomcat and nullify the catalina.out file and then start tomcat to have some new info in the catalina.out
# service tomcat stop
# cd $CATALINA_HOME/logs
# :> catalina.out (or) cat /dev/null > catalina.out
# ll catalina.out
-rw-r----- 1 root root 0 Feb 18 16:19 catalina.out
# service tomcat start
# ll catalina.out
-rw-r----- 1 root root 17341 Feb 18 16:21 catalina.out
We can see the log being written after the start of tomcat.
Now we can notice the instance giving some information about the starting of tomcat, about the configuration for the startup, path of the servlet instance for which the log is responsible for, when the instance and the webapplications have started.
Also as we are not hosting any production applications on it we don't have any other information logged continuously to it as there is no running transaction on it.
And the last line in this log at this moment tells us how much time the tomcat instance has took to startup.
We can see how the issues can be logged in this log file.
As we previously configured another tomcat instance with some different port numbers let us change the config file of the first instance to use the connector port as 8010
Let us stop the tomcat instance, do the above change, start the second instance and then start the first instance.
# cd $CATALINA_HOME
# ./bin/catalina.sh stop
# :> logs/catalina.out
# vi conf/server.xml
Change port 8009 with 8010 and save the config file
We can see 2 tomcat instances running, let us check the catalina.out log for the errors. We will see the following error in the log.
18-Feb-2017 16:39:33.802 SEVERE [main] org.apache.catalina.core.StandardService.initInternal Failed to initialize connector [Connector
[AJP/1.3-8010]]
org.apache.catalina.LifecycleException: Failed to initialize component [Connector[AJP/1.3-8010]]
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:112)
at org.apache.catalina.core.StandardService.initInternal(StandardService.java:549)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:107)
at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:875)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:107)
at org.apache.catalina.startup.Catalina.load(Catalina.java:606)
at org.apache.catalina.startup.Catalina.load(Catalina.java:629)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:311)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:494)
Caused by: org.apache.catalina.LifecycleException: Protocol handler initialization failed
at org.apache.catalina.connector.Connector.initInternal(Connector.java:970)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:107)
... 12 more
Caused by: java.net.BindException: Address already in use
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:433)
at sun.nio.ch.Net.bind(Net.java:425)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:210)
at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:972)
at org.apache.tomcat.util.net.AbstractJsseEndpoint.init(AbstractJsseEndpoint.java:237)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:558)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:968)
... 13 more
Here we need to see the below lines
org.apache.catalina.core.StandardService.initInternal Failed to initialize connector [Connector
[AJP/1.3-8010]]
Caused by: java.net.BindException: Address already in use
This tells us that the application is failed to initialize the AJP Connector Port on 8010 as it is addressed already in use
Now to fix this let us stop tomcat and change the port back to 8009 in the $CATALINA_HOME/conf/server.xml
After this start both the instances and can notice that we don't have any issues in either of the instance
Exception in thread "main" java.lang.NullPointerException
at com.example.myproject.Object1.getValue(Object1.java:16)
at com.example.myproject.Object2.getNumericValue(Object2.java:25)
at com.example.myproject.Object3.main(Object3.java:14)
In this case we need to navigate to the file Object1 and review the method called getValue() to determine what happened
The remaining lines give the further information about how the exception was arrived at.
Most of the times we'll have something different to the above, but the above given can be taken as a basic example of how to find out the issue.
Let us look at the below log once
Exception in thread "main" java.lang.NullPointerException
at com.example.myproject.Object1.getValue(Object1.java:16)
at com.example.myproject.Object2.getNumericValue(Object2.java:25)
at com.example.myproject.Object3.main(Object3.java:14)
Caused by: java.lang.IllegalReferenceException
at com.example.myproject.Object1.getParentValue(Object1.java:22)
This means that we have a NullPointer exception in Object1 at the getValue() method occured as Object1 and getParentValue() method thrown a IllegalReferenceException and this is the initial cause of the problem.
If we have multiple Caused by sections then the lowest is the initial cause of the problem.
Now setting up your Hostname / IP to your server instead of localhost
Open conf/server.xml and edit the following lines to add your Hostname
Find the line starts with Engine and change the value of defaultHost
<Engine name="Catalina" defaultHost="dev02.linux-library.com">
Find the line starts with Host change the value of name to your hostname same as above
<Host name="dev02.linux-library.com" appBase="webapps"
If you want to access the tomcat manager from other than your local machine then you need to allow those IP ranges
To allow IPs to access manager edit webapps/manager/META-INF/context.xml file
NOTE: If you want to access the app from a host of Class-A IP then you should add 10.\d+.\d+.\d+ to the allow directive That should look like below. I have allowed Class-A as well as Class-C ranges