to get php-fpm errors in nginx error log you need:
as for nginx: it s enough just basic config
# cat default | grep -v "#"
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name _;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
}
as for php-fpm the main setting is
log_errors = On
basically it s enough. but to be on the safe side i would suggest
to put the following block in php-fpm config(/etc/php/7.0/fpm/php.ini) :
[PHP]
...
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = On
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off
html_errors = On
...
after that all php stack traces will be in
# tail /var/log/nginx/error.log
2023/06/20 23:37:06 [error] 20307#20307: *1 FastCGI sent in stderr: "PHP message: PHP Parse error: syntax error, unexpected '"asd"' (T_CONSTANT_ENCAPSED_STRING) in /var/www/html/php1.php on line 2" while reading response header from upstream, client: 127.0.0.1, server: _, request: "GET /php1.php HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.0-fpm.sock:", host: "localhost"
2023/06/20 23:48:40 [error] 20307#20307: *5 FastCGI sent in stderr: "PHP message: PHP Parse error: syntax error, unexpected '"asd"' (T_CONSTANT_ENCAPSED_STRING) in /var/www/html/php1.php on line 2" while reading response header from upstream, client: 127.0.0.1, server: _, request: "GET /php1.php HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.0-fpm.sock:", host: "localhost"
2023/06/21 00:18:17 [error] 20307#20307: *7 FastCGI sent in stderr: "PHP message: PHP Parse error: syntax error, unexpected '"asd"' (T_CONSTANT_ENCAPSED_STRING) in /var/www/html/php1.php on line 2" while reading response header from upstream, client: 127.0.0.1, server: _, request: "GET /php1.php HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.0-fpm.sock:", host: "localhost:4545"
if you want to see php stack traces not in nginx erorr file but
instead in a separate file you need to add error_log setting
that is
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = On
log_errors = On
error_log = /var/log/php-errors.log
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off
html_errors = On
also very important to create /var/log/php-errors.log manually and set proper
permisssions because php-fpm wont do that and will continue to transfer error
to nginx. so
# touch /var/log/php-errors.log
# chown www-data.www-data /var/log/php-errors.log
# systemctl restart php7.0-fpm
after that nginx error log /var/log/nginx/error.log will be empty
but all php-errors will be in /var/log/php-errors.log
I’ve just installed a nginx+php-fpm server. Everything seems fine except that PHP-FPM never writes error to its log.
fpm.conf
[default]
listen = /var/run/php-fpm/default.sock
listen.allowed_clients = 127.0.0.1
listen.owner = webusr
listen.group = webusr
listen.mode = 0666
user = webusr
group = webusr
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.status_path = /php/fpm/status
ping.path = /php/fpm/ping
request_terminate_timeout = 30s
request_slowlog_timeout = 10s
slowlog = /var/log/php-fpm/default/slow.log
chroot = /var/www/sites/webusr
catch_workers_output = yes
env[HOSTNAME] = mapsvr.mapking.com
php_flag[display_errors] = on
php_admin_value[error_log] = /var/log/php-fpm/default/error.log
php_admin_flag[log_errors] = on
nginx.conf
server
{
listen 80 default_server;
server_name _;
charset utf-8;
access_log /var/log/nginx/access.log rest;
include conf.d/drops.conf.inc;
location /
{
root /var/www/sites/webusr/htdocs;
index index.html index.htm index.php;
}
# pass the PHP scripts to FastCGI server listening on socket
#
location ~ \.php$
{
root /var/www/sites/webusr/htdocs;
include /etc/nginx/fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /htdocs/$fastcgi_script_name;
if (-f $request_filename)
{
fastcgi_pass unix:/var/run/php-fpm/default.sock;
}
}
location = /php/fpm/status
{
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php-fpm/default.sock;
}
location = /php/fpm/ping
{
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php-fpm/default.sock;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html
{
root /usr/share/nginx/html;
}
}
I’ve made an erroneous php script and run, and see error output on the web browser. Also nginx error log states stderr output from fpm with the same message. I’ve check that the user have write (I’ve even tried 777) permission to the appointed log folder. Even the appointed error.log file has be created successfully by php-fpm. However, the log file is always empty, no matter what outrageous error has been made from php script.
What’s going on?
[Found the reason quite a while later]
It was permission. Changed the owner to the sites’s users solved the problem.
asked Dec 30, 2011 at 8:14
eidng8eidng8
2,0772 gold badges13 silver badges11 bronze badges
3
This worked for me:
; Redirect worker stdout and stderr into main error log. If not set, stdout and
; stderr will be redirected to /dev/null according to FastCGI specs.
; Default Value: no
catch_workers_output = yes
Edit:
The file to edit is the file that configure your desired pool.
By default its: /etc/php-fpm.d/www.conf
answered May 11, 2012 at 5:57
michaelbnmichaelbn
7,4033 gold badges33 silver badges46 bronze badges
14
I struggled with this for a long time before finding my php-fpm logs were being written to /var/log/upstart/php5-fpm.log
. It appears to be a bug between how upstart and php-fpm interact. See more here: https://bugs.launchpad.net/ubuntu/+source/php5/+bug/1319595
answered Jan 22, 2015 at 17:31
Code CommanderCode Commander
16.8k8 gold badges64 silver badges65 bronze badges
2
I had a similar issue and had to do the following to the pool.d/www.conf
file
php_admin_value[error_log] = /var/log/fpm-php.www.log
php_admin_flag[log_errors] = on
It still wasn’t writing the log file so I actually had to create it by touch /var/log/fpm-php.www.log
then setting the correct owner sudo chown www-data:www-data /var/log/fpm-php.www.log
.
Once this was done, and php5-fpm restarted, logging was resumed.
ᴍᴇʜᴏᴠ
4,8144 gold badges44 silver badges57 bronze badges
answered Apr 22, 2014 at 15:18
adnansadnans
2,2792 gold badges15 silver badges5 bronze badges
7
There are multiple php config files, but THIS is the one you need to edit:
/etc/php(version)?/fpm/pool.d/www.conf
uncomment the line that says:
catch_workers_output
That will allow PHPs stderr to go to php-fpm’s error log instead of /dev/null.
answered Aug 6, 2012 at 17:05
vectorvector
4874 silver badges6 bronze badges
4
I gathered insights from a bunch of answers here and I present a comprehensive solution:
So, if you setup nginx with php5-fpm and log a message using error_log()
you can see it in /var/log/nginx/error.log
by default.
A problem can arise if you want to log a lot of data (say an array) using error_log(print_r($myArr, true));
. If an array is large enough, it seems that nginx
will truncate your log entry.
To get around this you can configure fpm
(php.net fpm config) to manage logs. Here are the steps to do so.
-
Open
/etc/php5/fpm/pool.d/www.conf
:$ sudo nano /etc/php5/fpm/pool.d/www.conf
-
Uncomment the following two lines by removing
;
at the beginning of the line: (error_log is defined here: php.net);php_admin_value[error_log] = /var/log/fpm-php.www.log
;php_admin_flag[log_errors] = on -
Create
/var/log/fpm-php.www.log
:$ sudo touch /var/log/fpm-php.www.log;
-
Change ownership of
/var/log/fpm-php.www.log
so that php5-fpm can edit it:$ sudo chown vagrant /var/log/fpm-php.www.log
Note:
vagrant
is the user that I need to give ownership to. You can see what user this should be for you by running$ ps aux | grep php.*www
and looking at first column. -
Restart php5-fpm:
$ sudo service php5-fpm restart
Now your logs will be in /var/log/fpm-php.www.log
.
answered Nov 1, 2015 at 18:34
GezimGezim
7,11210 gold badges62 silver badges99 bronze badges
7
There is a bug https://bugs.php.net/bug.php?id=61045 in php-fpm from v5.3.9 and till now (5.3.14 and 5.4.4). Developer promised fix will go live in next release. If you don’t want to wait — use patch on that page and re-build or rollback to 5.3.8.
answered Jun 28, 2012 at 18:03
DrewxDrewx
1511 silver badge2 bronze badges
In your fpm.conf file you haven’t set 2 variable which are only for error logging.
The variables are error_log
(file path of your error log file) and log_level
(error logging level).
; Error log file
; Note: the default prefix is /usr/local/php/var
; Default Value: log/php-fpm.log
error_log = log/php-fpm.log
; Log level
; Possible Values: alert, error, warning, notice, debug
; Default Value: notice
log_level = notice
answered Feb 19, 2012 at 20:18
khizar ansarikhizar ansari
1,4762 gold badges18 silver badges29 bronze badges
1
I’d like to add another tip to the existing answers because they did not solve my problem.
Watch out for the following nginx directive in your php location block:
fastcgi_intercept_errors on;
Removing this line has brought an end to many hours of struggling and pulling hair.
It could be hidden in some included conf directory like /etc/nginx/default.d/php.conf
in my fedora.
answered Mar 4, 2020 at 12:17
ArsylumArsylum
5244 silver badges14 bronze badges
in my case I show that the error log was going to /var/log/php-fpm/www-error.log . so I commented this line in /etc/php-fpm.d/www.conf
php_flag[display_errors] is commented
php_flag[display_errors] = on log will be at /var/log/php-fpm/www-error.log
and as said above I also uncommented this line
catch_workers_output = yes
Now I can see logs in the file specified by nginx.
answered Dec 26, 2015 at 8:35
enRaiserenRaiser
2,6062 gold badges21 silver badges39 bronze badges
In my case php-fpm outputs 500 error without any logging because of missing php-mysql module. I moved joomla installation to another server and forgot about it. So apt-get install php-mysql
and service restart solved it.
I started with trying to fix broken logging without success. Finally with strace
i found fail message after db-related system calls. Though my case is not directly related to op’s question, I hope it could be useful.
answered Apr 22, 2020 at 16:28
user3132194user3132194
2,38123 silver badges17 bronze badges
On alpine 3.15 with php8 i found on /var/log/php8/error.log
/var/log/php8 # cat error.log
16:10:52] NOTICE: fpm is running, pid 14
16:10:52] NOTICE: ready to handle connections
i also have this :
catch_workers_output = yes
answered Oct 4, 2022 at 14:28
uberuber
1143 bronze badges
Check the Owner directory of «PHP-FPM»
You can do:
ls -lah /var/log/php-fpm/
chown -R webusr:webusr /var/log/php-fpm/
chmod -R 777 /var/log/php-fpm/
answered Jul 25, 2017 at 21:11
1
Capture detailed information about errors and request processing in log files, either locally or via syslog.
This article describes how to configure logging of errors and processed requests in NGINX Open Source and NGINX Plus.
Setting Up the Error Log
NGINX writes information about encountered issues of different severity levels to the error log. The error_log directive sets up logging to a particular file, stderr
, or syslog
and specifies the minimal severity level of messages to log. By default, the error log is located at logs/error.log (the absolute path depends on the operating system and installation), and messages from all severity levels above the one specified are logged.
The configuration below changes the minimal severity level of error messages to log from error
to warn
:
error_log logs/error.log warn;
In this case, messages of warn
, error
crit
, alert
, and emerg
levels are logged.
The default setting of the error log works globally. To override it, place the error_log directive in the main
(top-level) configuration context. Settings in the main
context are always inherited by other configuration levels (http
, server
, location
). The error_log
directive can be also specified at the http, stream, server
and location levels and overrides the setting inherited from the higher levels. In case of an error, the message is written to only one error log, the one closest to the level where the error has occurred. However, if several error_log
directives are specified on the same level, the message are written to all specified logs.
Note: The ability to specify multiple
error_log
directives on the same configuration level was added in NGINX Open Source version 1.5.2.
Setting Up the Access Log
NGINX writes information about client requests in the access log right after the request is processed. By default, the access log is located at logs/access.log, and the information is written to the log in the predefined combined format. To override the default setting, use the log_format directive to change the format of logged messages, as well as the access_log directive to specify the location of the log and its format. The log format is defined using variables.
The following examples define the log format that extends the predefined combined format with the value indicating the ratio of gzip compression of the response. The format is then applied to a virtual server that enables compression.
http {
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$gzip_ratio"';
server {
gzip on;
access_log /spool/logs/nginx-access.log compression;
...
}
}
Another example of the log format enables tracking different time values between NGINX and an upstream server that may help to diagnose a problem if your website experience slowdowns. You can use the following variables to log the indicated time values:
$upstream_connect_time
– The time spent on establishing a connection with an upstream server$upstream_header_time
– The time between establishing a connection and receiving the first byte of the response header from the upstream server$upstream_response_time
– The time between establishing a connection and receiving the last byte of the response body from the upstream server$request_time
– The total time spent processing a request
All time values are measured in seconds with millisecond resolution.
http {
log_format upstream_time '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"'
'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';
server {
access_log /spool/logs/nginx-access.log upstream_time;
...
}
}
When reading the resulting time values, keep the following in mind:
- When a request is processed through several servers, the variable contains several values separated by commas
- When there is an internal redirect from one upstream group to another, the values are separated by semicolons
- When a request is unable to reach an upstream server or a full header cannot be received, the variable contains
0
(zero) - In case of internal error while connecting to an upstream or when a reply is taken from the cache, the variable contains
-
(hyphen)
Logging can be optimized by enabling the buffer for log messages and the cache of descriptors of frequently used log files whose names contain variables. To enable buffering use the buffer
parameter of the access_log directive to specify the size of the buffer. The buffered messages are then written to the log file when the next log message does not fit into the buffer as well as in some other cases.
To enable caching of log file descriptors, use the open_log_file_cache directive.
Similar to the error_log
directive, the access_log directive defined on a particular configuration level overrides the settings from the previous levels. When processing of a request is completed, the message is written to the log that is configured on the current level, or inherited from the previous levels. If one level defines multiple access logs, the message is written to all of them.
Enabling Conditional Logging
Conditional logging allows excluding trivial or unimportant log entries from the access log. In NGINX, conditional logging is enabled by the if
parameter to the access_log directive.
This example excludes requests with HTTP status codes 2xx
(Success) and 3xx
(Redirection):
map $status $loggable {
~^[23] 0;
default 1;
}
access_log /path/to/access.log combined if=$loggable;
Usecase: Sampling TLS Parameters
Many clients use TLS versions older than TLS 1.3. Though many ciphers are declared insecure, older implementations still use them; ECC certificates offer greater performance than RSA, but not all clients can accept ECC. Many TLS attacks rely on a “man in the middle” who intercepts the cipher negotiation handshake and forces the client and server to select a less secure cipher. Therefore, it’s important to configure NGINX Plus to not support weak or legacy ciphers, but doing so may exclude legacy clients.
You can evaluate the SSL data obtained from the client and determine what proportion of clients get excluded if support for older SSL protocols and ciphers is removed.
The following configuration example logs the SSL protocol, cipher, and User-Agent
header of any connected TLS client, assuming that each client selects the most recent protocol and most secure ciphers it supports.
In this example, each client is identified by its unique combination of IP address and User-Agent.
-
Define the custom log format
sslparams
that includes the version of the SSL protocol ($ssl_protocol
), ciphers used in the connection ($ssl_cipher
), the client IP address ($remote_addr
), and the value of standardUser Agent
HTTP request field ($http_user_agent
):log_format sslparams '$ssl_protocol $ssl_cipher ' '$remote_addr "$http_user_agent"';
-
Define a key-value storage that will keep the IP address of the client and its User Agent, for example,
clients
:keyval_zone zone=clients:80m timeout=3600s;
-
Create a variable, for example,
$seen
for each unique combination of$remote_addr
andUser-Agent
header:keyval $remote_addr:$http_user_agent $seen zone=clients; server { listen 443 ssl; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; if ($seen = "") { set $seen 1; set $logme 1; } access_log /tmp/sslparams.log sslparams if=$logme; # ... }
-
View the log file generated with this configuration:
TLSv1.2 AES128-SHA 1.1.1.1 "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0" TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 2.2.2.2 "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1" TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0" TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 4.4.4.4 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0" TLSv1 AES128-SHA 5.5.5.5 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0" TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 6.6.6.6 "Mozilla/5.0 (Linux; U; Android 5.0.2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"
-
Process the log file to determine the spread of data:
cat /tmp/sslparams.log | cut -d ' ' -f 2,2 | sort | uniq -c | sort -rn | perl -ane 'printf "%30s %s\n", $F[1], "="x$F[0];'
In this output, low‑volume, less secure ciphers are identified:
ECDHE-RSA-AES128-GCM-SHA256 ========================= ECDHE-RSA-AES256-GCM-SHA384 ======== AES128-SHA ==== ECDHE-RSA-CHACHA20-POLY1305 == ECDHE-RSA-AES256-SHA384 ==
Then you can check the logs to determine which clients are using these ciphers and then make a decision about removing these ciphers from the NGINX Plus configuration.
For more information about sampling requests with NGINX conditional logging see the blog post.
Logging to Syslog
The syslog
utility is a standard for computer message logging and allows collecting log messages from different devices on a single syslog server. In NGINX, logging to syslog is configured with the syslog:
prefix in error_log and access_log directives.
Syslog messages can be sent to a server=
which can be a domain name, an IP address, or a UNIX-domain socket path. A domain name or IP address can be specified with a port to override the default port, 514
. A UNIX-domain socket path can be specified after the unix:
prefix:
error_log syslog:server=unix:/var/log/nginx.sock debug;
access_log syslog:server=[2001:db8::1]:1234,facility=local7,tag=nginx,severity=info;
In the example, NGINX error log messages are written to a UNIX domain socket at the debug
logging level, and the access log is written to a syslog server with an IPv6 address and port 1234
.
The facility=
parameter specifies the type of program that is logging the message. The default value is local7
. Other possible values are: auth
, authpriv
, daemon
, cron
, ftp
, lpr
, kern
, mail
, news
, syslog
, user
, uucp
, local0 ... local7
.
The tag=
parameter applies a custom tag to syslog messages (nginx
in our example).
The severity=
parameter sets the severity level of syslog messages for access log. Possible values in order of increasing severity are: debug
, info
, notice
, warn
, error
(default), crit
, alert
, and emerg
. Messages are logged at the specified level and all more severe levels. In our example, the severity level error
also enables crit
, alert
, and emerg
levels to be logged.
Live Activity Monitoring
NGINX Plus provides a real-time live activity monitoring interface that shows key load and performance metrics of your HTTP and TCP upstream servers. See the Live Activity Monitoring article for more information.
To learn more about NGINX Plus, please visit the Products page.
Last updated on | one reply
PHP-FPM errors are logged by default in the Nginx error log. To view the nginx error log and access log files, we can use tail
to display the last 200 entries.
sudo tail /var/log/nginx/error.log -n 200
Let me know if this helped. Follow me on Twitter, Facebook and YouTube, or 🍊 buy me a smoothie.
1 reply
Leave a reply
Your email address will not be published. Required fields are marked *
Comment *
Name *
Email *
Save my name, email, and website in this browser for the next time I comment.
-
yes, it helped
Reply
In this tutorial, you will learn everything you need to know about logging in
NGINX and how it can help you troubleshoot and quickly resolve any problem you
may encounter on your web server. We will discuss where the logs are stored and
how to access them, how to customize their format, and how to centralize them in
one place with Syslog or a log management service.
Here’s an outline of what you will learn by following through with this tutorial:
- Where NGINX logs are stored and how to access them.
- How to customize the NGINX log format and storage location to fit your needs.
- How to utilize a structured format (such as JSON) for your NGINX logs.
- How to centralize NGINX logs through Syslog or a managed cloud-based service.
Prerequisites
To follow through with this tutorial, you need the following:
- A Linux server that includes a non-root user with
sudo
privileges. We tested
the commands shown in this guide on an Ubuntu 20.04 server. - The
NGINX web server installed
and enabled on your server.
🔭 Want to centralize and monitor your NGINX logs?
Head over to Better Stack and start ingesting
your logs in 5 minutes.
Step 1 — Locating the NGINX log files
NGINX writes logs of all its events in two different log files:
- Access log: this file contains information about incoming requests and
user visits. - Error log: this file contains information about errors encountered while
processing requests, or other diagnostic messages about the web server.
The location of both log files is dependent on the host operating system of the
NGINX web server and the mode of installation. On most Linux distributions, both
files will be found in the /var/log/nginx/
directory as access.log
and
error.log
, respectively.
A typical access log entry might look like the one shown below. It describes an
HTTP GET request to the server for a favicon.ico
file.
217.138.222.101 - - [11/Feb/2022:13:22:11 +0000] "GET /favicon.ico HTTP/1.1" 404 3650 "http://135.181.110.245/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.87 Safari/537.36" "-"
Similarly, an error log entry might look like the one below, which was generated
due to the inability of the server to locate the favicon.ico
file that was
requested above.
2022/02/11 13:12:24 [error] 37839#37839: *7 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 113.31.102.176, server: _, request: "GET /favicon.ico HTTP/1.1", host: "192.168.110.245:80"
In the next section, you’ll see how to view both NGINX log files from the
command line.
Step 2 — Viewing the NGINX log files
Examining the NGINX logs can be done in a variety of ways. One of the most
common methods involves using the tail
command to view logs entries in
real-time:
sudo tail -f /var/log/nginx/access.log
You will observe the following output:
107.189.10.196 - - [14/Feb/2022:03:48:55 +0000] "POST /HNAP1/ HTTP/1.1" 404 134 "-" "Mozila/5.0"
35.162.122.225 - - [14/Feb/2022:04:11:57 +0000] "GET /.env HTTP/1.1" 404 162 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0"
45.61.172.7 - - [14/Feb/2022:04:16:54 +0000] "GET /.env HTTP/1.1" 404 197 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
45.61.172.7 - - [14/Feb/2022:04:16:55 +0000] "POST / HTTP/1.1" 405 568 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
45.137.21.134 - - [14/Feb/2022:04:18:57 +0000] "GET /dispatch.asp HTTP/1.1" 404 134 "-" "Mozilla/5.0 (iPad; CPU OS 7_1_2 like Mac OS X; en-US) AppleWebKit/531.5.2 (KHTML, like Gecko) Version/4.0.5 Mobile/8B116 Safari/6531.5.2"
23.95.100.141 - - [14/Feb/2022:04:42:23 +0000] "HEAD / HTTP/1.0" 200 0 "-" "-"
217.138.222.101 - - [14/Feb/2022:07:38:40 +0000] "GET /icons/ubuntu-logo.png HTTP/1.1" 404 197 "http://168.119.119.25/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.87 Safari/537.36"
217.138.222.101 - - [14/Feb/2022:07:38:42 +0000] "GET /favicon.ico HTTP/1.1" 404 197 "http://168.119.119.25/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.87 Safari/537.36"
217.138.222.101 - - [14/Feb/2022:07:44:02 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.87 Safari/537.36"
217.138.222.101 - - [14/Feb/2022:07:44:02 +0000] "GET /icons/ubuntu-logo.png HTTP/1.1" 404 197 "http://168.119.119.25/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.87 Safari/537.36"
The tail
command prints the last 10 lines from the selected file. The -f
option causes it to continue displaying subsequent lines that are added to the
file in real-time.
To examine the entire contents of an NGINX log file, you can use the cat
command or open it in your text editor:
sudo cat /var/log/nginx/error.log
If you want to filter the lines that contain a specific term, you can use the
grep
command as shown below:
sudo grep "GET /favicon.ico" /var/log/nginx/access.log
The command above will print all the lines that contain GET /favicon.ico
so we
can see how many requests were made for that resource.
Step 3 — Configuring NGINX access logs
The NGINX access log stores data about incoming client requests to the server
which is beneficial when deciphering what users are doing in the application,
and what resources are being requested. In this section, you will learn how to
configure what data is stored in the access log.
One thing to keep in mind while following through with the instructions below is
that you’ll need to restart the nginx
service after modifying the config file
so that the changes can take effect.
sudo systemctl restart nginx
Enabling the access log
The NGINX access Log should be enabled by default. However, if this is not the
case, you can enable it manually in the Nginx configuration file
(/etc/nginx/nginx.conf
) using the access_log
directive within the http
block.
/etc/nginx/nginx.conf
Copied!
http {
access_log /var/log/nginx/access.log;
}
This directive is also applicable in the server
and location
configuration
blocks for a specific website:
/etc/nginx/nginx.conf
Copied!
server {
access_log /var/log/nginx/app1.access.log;
location /app2 {
access_log /var/log/nginx/app2.access.log;
}
}
Disabling the access log
In cases where you’d like to disable the NGINX access log, you can use the
special off
value:
You can also disable the access log on a virtual server or specific URIs by
editing its server
or location
block configuration in the
/etc/nginx/sites-available/
directory:
server {
listen 80;
access_log off;
location ~* \.(woff|jpg|jpeg|png|gif|ico|css|js)$ {
access_log off;
}
}
Logging to multiple access log files
If you’d like to duplicate the access log entries in separate files, you can do
so by repeating the access_log
directive in the main config file or in a
server
block as shown below:
access_log /var/log/nginx/access.log;
access_log /var/log/nginx/combined.log;
Don’t forget to restart the nginx
service afterward:
sudo systemctl restart nginx
Explanation of the default access log format
The access log entries produced using the default configuration will look like
this:
127.0.0.1 alice Alice [07/May/2021:10:44:53 +0200] "GET / HTTP/1.1" 200 396 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4531.93 Safari/537.36"
Here’s a breakdown of the log message above:
127.0.0.1
: the IP address of the client that made the request.alice
: remote log name (name used to log in a user).Alice
: remote username (username of logged-in user).[07/May/2021:10:44:53 +0200]
: date and time of the request."GET / HTTP/1.1"
: request method, path and protocol.200
: the HTTP response code.396
: the size of the response in bytes."-"
: the IP address of the referrer (-
is used when the it is not
available)."Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4531.93 Safari/537.36"
—
detailed user agent information.
Step 4 — Creating a custom log format
Customizing the format of the entries in the access log can be done using the
log_format
directive, and it can be placed in the http
, server
or
location
blocks as needed. Here’s an example of what it could look like:
log_format custom '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"';
This yields a log entry in the following format:
217.138.222.109 - - [14/Feb/2022:10:38:35 +0000] "GET /favicon.ico HTTP/1.1" 404 197 "http://192.168.100.1/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.87 Safari/537.36"
The syntax for configuring an access log format is shown below. First, you need
to specify a nickname for the format that will be used as its identifier, and
then the log format string that represents the details and formatting for each
log message.
log_format <nickname> '<formatting_variables>';
Here’s an explanation of each variable used in the custom
log format shown
above:
$remote_addr
: the IP address of the client$remote_user
: information about the user making the request$time_local
: the server’s date and time.$request
: actual request details like path, method, and protocol.$status
: the response code.$body_bytes_sent
: the size of the response in bytes.$http_referer
: the IP address of the HTTP referrer.$http_user_agent
: detailed user agent information.
You may also use the following variables in your custom log format
(see here for the complete list):
$upstream_connect_time
: the time spent establishing a connection with an
upstream server.$upstream_header_time
: the time between establishing a connection and
receiving the first byte of the response header from the upstream server.$upstream_response_time
: the time between establishing a connection and
receiving the last byte of the response body from the upstream server.$request_time
: the total time spent processing a request.$gzip_ratio
: ration of gzip compression (if gzip is enabled).
After you create a custom log format, you can apply it to a log file by
providing a second parameter to the access_log
directive:
access_log /var/log/nginx/access.log custom;
You can use this feature to log different information in to separate log files.
Create the log formats first:
log_format custom '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer"';
log_format agent "$http_user_agent";
Then, apply them as shown below:
access_log /var/log/nginx/access.log custom;
access_log /var/log/nginx/agent_access.log agent;
This configuration ensures that user agent information for all incoming requests
are logged into a separate access log file.
Step 5 — Formatting your access logs as JSON
A common way to customize NGINX access logs is to format them as JSON. This is
quite straightforward to achieve by combining the log_format
directive with
the escape=json
parameter introduced in Nginx 1.11.8 to escape characters that
are not valid in JSON:
log_format custom_json escape=json
'{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"request":"$request",'
'"status": "$status",'
'"body_bytes_sent":"$body_bytes_sent",'
'"request_time":"$request_time",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent"'
'}';
After applying the custom_json
format to a log file and restarting the nginx
service, you will observe log entries in the following format:
{
"time_local": "14/Feb/2022:11:25:44 +0000",
"remote_addr": "217.138.222.109",
"remote_user": "",
"request": "GET /icons/ubuntu-logo.png HTTP/1.1",
"status": "404",
"body_bytes_sent": "197",
"request_time": "0.000",
"http_referrer": "http://192.168.100.1/",
"http_user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.87 Safari/537.36"
}
Step 6 — Configuring NGINX error logs
Whenever NGINX encounters an error, it stores the event data in the error log so
that it can be referred to later by a system administrator. This section will
describe how to enable and customize the error logs as you see fit.
Enabling the error log
The NGINX error log should be enabled by default. However, if this is not the
case, you can enable it manually in the relevant NGINX configuration file
(either at the http
, server
, or location
levels) using the error_log
directive.
error_log /var/log/nginx/error.log;
The error_log
directive can take two parameters. The first one is the location
of the log file (as shown above), while the second one is optional and sets the
severity level of the log. Events with a lower severity level than set one will
not be logged.
error_log /var/log/nginx/error.log info;
These are the possible levels of severity (from lowest to highest) and their
meaning:
debug
: messages used for debugging.info
: informational messages.notice
: a notable event occurred.warn
: something unexpected happened.error
: something failed.crit
: critical conditions.alert
: errors that require immediate action.emerg
: the system is unusable.
Disabling the error log
The NGINX error log can be disabled by setting the error_log
directive to
off
or by redirecting it to /dev/null
:
error_log off;
error_log /dev/null;
Logging errors into multiple files
As is the case with access logs, you can log errors into multiple files, and you
can use different severity levels too:
error_log /var/log/nginx/error.log info;
error_log /var/log/nginx/emerg_error.log emerg;
This configuration will log every event except those at the debug
level event
to the error.log
file, while emergency events are placed in a separate
emerg_error.log
file.
Step 7 — Sending NGINX logs to Syslog
Apart from logging to a file, it’s also possible to set up NGINX to transport
its logs to the syslog
service especially if you’re already using it for other
system logs. Logging to syslog
is done by specifying the syslog:
prefix to
either the access_log
or error_log
directive:
error_log syslog:server=unix:/var/log/nginx.sock debug;
access_log syslog:server=[127.0.0.1]:1234,facility=local7,tag=nginx,severity=info;
Log messages are sent to a server
which can be specified in terms of a domain
name, IPv4 or IPv6 address or a UNIX-domain socket path.
In the example above, error log messages are sent to a UNIX domain socket at the
debug
logging level, while the access log is written to a syslog
server with
an IPv4 address and port 1234
. The facility=
parameter specifies the type of
program that is logging the message, the tag=
parameter applies a custom tag
to syslog
messages, and the severity=
parameter sets the severity level of
the syslog
entry for access log messages.
For more information on using Syslog to manage your logs, you can check out our
tutorial on viewing and configuring system logs on
Linux.
Step 8 — Centralizing your NGINX logs
In this section, we’ll describe how you can centralize your NGINX logs in a log
management service through Vector, a
high-performance tool for building observability pipelines. This is a crucial
step when administrating multiple servers so that you can monitor all your logs
in one place (you can also centralize your logs with an Rsyslog
server).
The following instructions assume that you’ve signed up for a free
Logtail account and retrieved your source
token. Go ahead and follow the relevant
installation instructions for Vector
for your operating system. For example, on Ubuntu, you may run the following
commands to install the Vector CLI:
curl -1sLf \ 'https://repositories.timber.io/public/vector/cfg/setup/bash.deb.sh' \ | sudo -E bash
After Vector is installed, confirm that it is up and running through
systemctl
:
You should observe that it is active and running:
● vector.service - Vector
Loaded: loaded (/lib/systemd/system/vector.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2022-02-08 10:52:59 UTC; 48s ago
Docs: https://vector.dev
Process: 18586 ExecStartPre=/usr/bin/vector validate (code=exited, status=0/SUCCESS)
Main PID: 18599 (vector)
Tasks: 3 (limit: 2275)
Memory: 6.8M
CGroup: /system.slice/vector.service
└─18599 /usr/bin/vector
Otherwise, go ahead and start it with the command below.
sudo systemctl start vector
Afterward, change into a root shell and append your Logtail vector configuration
for NGINX into the /etc/vector/vector.toml
file using the command below. Don’t
forget to replace the <your_logtail_source_token>
placeholder below with your
source token.
wget -O ->> /etc/vector/vector.toml \
https://logtail.com/vector-toml/nginx/<your_logtail_source_token>
Then restart the vector
service:
sudo systemctl restart vector
You will observe that your NGINX logs will start coming through in Logtail:
Conclusion
In this tutorial, you learned about the different types of logs that the NGINX
web server keeps, where you can find them, how to understand their formatting.
We also discussed how to create your own custom log formats (including a
structured JSON format), and how to log into multiple files at once. Finally, we
demonstrated the process of sending your logs to Syslog or a log management
service so that you can monitor them all in one place.
Thanks for reading, and happy logging!
Article by
Ayooluwa Isaiah
Ayo is the Head of Content at Better Stack. His passion is simplifying and communicating complex technical ideas effectively. His work was featured on several esteemed publications including LWN.net, Digital Ocean, and CSS-Tricks. When he’s not writing or coding, he loves to travel, bike, and play tennis.
Centralize all your logs into one place.
Analyze, correlate and filter logs with SQL.
Create actionable
dashboards.
Share and comment with built-in collaboration.
Got an article suggestion?
Let us know
Next article
How to Get Started with Logging in Node.js
Learn how to start logging with Node.js and go from basics to best practices in no time.
→
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.