NGINX is the most popular web server in the world, powering close to 35% of all sites according to w2techs. As a popular part of your software stack, it is good to understand its logs. NGINX write two specific types of logs: Error.log and Access.log. This article will dive into each one respectively.
Before you get started, it's best to orient yourself with where things are located. Below are the two most important locations to know as it pertains to logs:
The NGINX access log exist to record the activity of all the visitors to your site. You can use these logs to see what pages are being visited, what files are being requested, where users are coming from, and the list goes on. It also contains sensitive information like the users IP, the date and time of the request, and even the type of application being used to access the site (e.g., Chrome vs Firefox, Mobile vs Desktop). This log is especially helpful when you're trying to better understand your visitor behavior.
By default, all access logs have a standard format are set in the nginx.conf file with the access_log directive. The format looks like this:
access_log log_file log_format;
It is set like this:
By default, NGINX will record all all logs in the combined format, which records the following information:
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
You are not limited to this format, however. A format can be changed by specifying the format you want to use. For example, let's assume you create a custom format and this format is focused on adding the X-Forwarded-For values to the log.
You would create the new log format:
log_format custom '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
Now using the same structure above, you simply add the format type to the end of the configuration file:
access_log /var/log/nginx/access.log custom;
Here is an example of a log entry recorded in an access log file:
192.168.33.1 - - [15/Oct/2019:19:41:46 +0000] "GET / HTTP/1.1" 200 396 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36"
This is how it corresponds to the default log format:
|$remote_addr||192.168.33.1||The IP address of the client making the request.|
|$remote_user||-||HTTP Authenticated User. When the user name is not set, this field shows -.|
|[$time_local]||[15/Oct/2019:19:41:46 +0000]||Local server time.|
|$request||GET / HTTP/1.1||The request type, path and protocol.|
|$status||200||The server response code|
|$body_bytes_sent||396||The size of server response in bytes.|
|$http_referer||-||The URL of the referral.|
|$http_user_agent||Mozilla/5.0 ...||The user agent of the client (web browser).|
The NGINX error log exists to record any issues, glitches, that the application might encounter. Maybe there is an error in a configuration file, or a conflict with a dependency. Maybe the application is forced to reboot, or fails to initialize. This is the log you want to analyze when something goes wrong as it usually contains a bit more detail and can help point you in the right direction. It's also extremely helpful to spend time analyzing the warnings, they can be indicative a problem.
By default, all error logs have a standard format and are set in the nginx.conf with the error_log directive. The format looks like this:
error_log log_file log_level;
It is set like this:
The log starts with the date, time, followed by the criticality of the event (error, warn, crit) and the details of the problem. Watching these logs is critical to understanding your server and detecting problems that might be impacting your users.
2022/05/14 19:55:51 [error] 6689#6689: *16764375 FastCGI sent in stderr: "PHP message: PHP Warning: Division by zero in /var/www/html/my.php on line 438" while reading upstream, client: 10.1.1.1, server: mytest.com, request: "GET /my.php HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.2-fpm.sock:", host: "my.test.com"
In this log, it is categorized as [error], because of a warning from the PHP engine due a division by zero.
Speaking of which, the NGINX error logs provide 8 unique severity levels you should be aware of.
|1. emerg||Emergency messages when your system may be unstable.|
|2. alert||Alert messages of serious issues.|
|3. crit||Critical issues that need to be taken care of immediately.|
|4. error||An error has occurred. Something went wrong while processing a page.|
|5. warn||A warning messages that you should look into it.|
|6. notice||A simple log notice that you can ignore.|
|7. info||Just an information messages that you might want to know.|
|8. debug||Debugging information used to pinpoint the location of error.|
These are the common nginx error logs that you might have on your server:
|FastCGI sent in stderr||Error coming from the FastCGI module (often from your web application).|
|PHP message: PHP Warning||If your web application uses PHP and generates a warning, you may get this type of error. We recommend passing to the developers to investigate and fixing them.|
|2022/05/14 07:08:37 [crit] 6689#6689: *16721837 SSL_do_handshake() failed (SSL: error:1420918C:SSL routines:tls_early_post_process_client_hello:version too low) while SSL handshaking||The SSL_do_handshake happens whenever the client/server can't complete the SSL handshaking or it is ended too soon in the process. It can happen many times on a busy server and is often not a cause for concern.|
By default, NGINX will store all the logs as one log entry on the server, but if you're deploying multiple domains on the same server this is highly impractical. This is why you have an option to configure logs for each domain (both access and errors) and you do this via the VirtualHosts file on the server.
Using the examples, formatting, provided above, this is how your virtual hosts file would look like for unique domains:
error_log /var/log/nginx/domain1.error_log warn;
error_log /var/log/nginx/domain2.error_log debug;
In the example above you see domain1 and domain2 each have their own access and error logs set. You also notice that you have the option to set the severity level for each domain as well (e.g., warn, debug).