Configuring the Nginx Error and Access Logs

Nginx is an open-source, high-performance HTTP and reverse proxy server responsible for handling the load of some of the largest sites on the Internet. When managing NGINX web servers, one of the most frequent tasks you will perform is checking the log files.
Knowing how to configure and read the logs is very useful when troubleshooting server or application issues as they provide detailed debugging information.
Nginx writes records of its events in two types of logs: access logs and error logs. Access logs write information about client requests, and error logs write information about the server and application issues.
This article explains how to configure and read the Nginx access and error logs.
Configuring the Access Log
Whenever a client request is processed, Nginx generates a new event in the access log. Each event record contains a timestamp and includes various information about the client and the requested resource. Access logs can show client IP addresses, requested resources, response statuses, referrers, user agents, and request processing times when those fields are included in the log format.
The access_log directive enables the access log and sets the location of the log file and the format to use:
access_log log_file log_format;Where log_file is the full path to the log file, and log_format is the name of the format to use.
The access log can be enabled in the http, server, or location directive block.
By default, the access log is globally enabled in the http directive inside the main Nginx configuration file:
http {
...
access_log /var/log/nginx/access.log;
...
}For better readability, it is recommended to set a separate access log file for each server block. The access_log directive set in the server directive overrides the one set in the http (higher level) directive:
server {
server_name domain.com;
access_log /var/log/nginx/domain.access.log;
...
}While the access log provides very useful information, it takes disk space and may affect the server performance. If your server is low on resources and you have a busy website, you might want to disable the access log. To do that, set the value of the access_log directive to off:
access_log off;Configuring the Log Format
The log_format directive defines the format of logged messages. It takes the following form and must be placed in the http block:
log_format name [escape=default|json|none] format;Where name is the format name referenced in access_log, and format is a string with embedded Nginx variables.
If no format is specified, Nginx uses the predefined combined format:
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';Common Log Variables
The following variables are most commonly used in log format definitions:
| Variable | Description |
|---|---|
$remote_addr | IP address of the client |
$http_x_forwarded_for | Original client IP when behind a proxy or load balancer |
$remote_user | HTTP authenticated user, or - if not set |
$time_local | Local server time |
$time_iso8601 | Time in ISO 8601 format |
$request | Full request line: method, URI, and protocol |
$status | Response status code |
$body_bytes_sent | Bytes sent to the client, excluding response headers |
$http_referer | Referring URL |
$http_user_agent | Client user agent string |
$request_time | Request processing time in seconds |
$upstream_response_time | Time spent waiting for the upstream server |
Custom Log Format
To define a custom format, add the log_format directive inside the http block, then reference it by name in access_log. The following example extends the combined format with the X-Forwarded-For header, which is useful when Nginx sits behind a load balancer:
http {
log_format custom '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log custom;
}JSON Log Format
For log aggregation with tools like Elasticsearch, Loki, or Datadog, a structured JSON format is often preferred. Use the escape=json parameter to automatically escape special characters in variable values:
http {
log_format json_combined escape=json
'{'
'"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"bytes_sent":$body_bytes_sent,'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"request_time":$request_time'
'}';
access_log /var/log/nginx/access.log json_combined;
}Each log entry will be a valid JSON object on a single line, which log shippers can parse without additional configuration.
Configuring the Error Log
Nginx writes messages about application and general server errors in the error log file. If you are experiencing errors in your web application, the error log is the first place to start for troubleshooting.
The error_log directive enables the error log and sets the location and severity level. It can be set within an http, server, or location block:
error_log log_file log_level;The log_level parameter sets the level of logging. Below are the levels listed by severity (from low to high):
debug— Debugging messages.info— Informational messages.notice— Notices.warn— Warnings.error— Errors while processing a request.crit— Critical issues. Requires a prompt action.alert— Alerts. Action must be taken immediately.emerg— Emergency situation. The system is in an unusable state.
Each log level includes the higher levels. For example, if you set the log level to warn, Nginx will also log the error, crit, alert, and emerg messages.
When the log_level parameter is not specified, it defaults to error.
By default, the error_log directive is defined in the http directive inside the main nginx.conf file:
http {
...
error_log /var/log/nginx/error.log;
...
}As with access logs, it is recommended to set a separate error log file for each server block. For example, to set the domain.com error log to warn:
server {
server_name domain.com;
error_log /var/log/nginx/domain.error.log warn;
...
}Whenever you modify the configuration file, you have to reload the Nginx service for the changes to take effect.
Location of the Log Files
By default on most Linux distributions, access and error logs are located in the /var/log/nginx directory. On Ubuntu
and Debian
, the default paths are:
/var/log/nginx/access.log/var/log/nginx/error.log
Reading and Understanding the Nginx Log Files
You can open and parse the log files using standard commands like cat
, less
, grep
, cut
, awk
, and so on.
Here is an example record from the access log file that uses the default combined Nginx log format:
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"Here is what each field means:
$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 the 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).
Use the tail
command to watch the log file in real time:
tail -f /var/log/nginx/access.logReading the Error Log
Here is an example record from the error log:
2026/03/21 10:42:15 [error] 1234#1234: *7 open() "/var/www/html/favicon.ico" failed (2: No such file or directory), client: 192.168.33.1, server: example.com, request: "GET /favicon.ico HTTP/1.1", host: "example.com"Here is what each field means:
2026/03/21 10:42:15- Timestamp of the event.[error]- Severity level of the message.1234#1234- Nginx process and thread identifier.*7- Connection identifier for the request.open() "/var/www/html/favicon.ico" failed (2: No such file or directory)- The system call that failed and the reported error.client: 192.168.33.1- The client IP address.server: example.com- The server block that handled the request.request: "GET /favicon.ico HTTP/1.1"- The HTTP request line.host: "example.com"- TheHostheader sent by the client.
To watch the error log in real time:
tail -f /var/log/nginx/error.logQuick Reference
| Directive | Description |
|---|---|
access_log /path/to/file | Enable access log at the given path |
access_log /path/to/file format | Enable access log with a named format |
access_log off | Disable the access log |
error_log /path/to/file | Set error log path (default level: error) |
error_log /path/to/file warn | Set error log path and severity level |
log_format name format | Define a custom log format |
log_format name escape=json format | Define a JSON-escaped log format |
Troubleshooting
Nginx cannot write to the log file
Check which user Nginx runs as, then verify that user can write to the log directory. Run ps aux | grep nginx or inspect the user directive in nginx.conf, then use ls -la /var/log/nginx/ to review ownership and permissions before making targeted changes.
Log format changes are not applied
Changes to log_format or access_log directives require a configuration reload. Run nginx -t to validate the configuration first, then reload the service
to apply changes without dropping connections.
Log file grows too large
Log rotation is handled by logrotate on most distributions. The default configuration at /etc/logrotate.d/nginx rotates logs daily and compresses old files. You can adjust the rotation frequency and retention in that file.
FAQ
Where are Nginx log files located?
On most Linux distributions, the default paths are /var/log/nginx/access.log and /var/log/nginx/error.log.
How do I log the real client IP behind a load balancer?
Add $http_x_forwarded_for to your log_format definition. If you use the ngx_http_realip_module, you can also configure the set_real_ip_from and real_ip_header directives to rewrite $remote_addr to the forwarded IP.
Can I write to multiple log files simultaneously?
Yes. Repeat the access_log directive with different file paths and format names. Nginx will write to all of them for each request.
How do I disable the access log for a specific location?
Add access_log off; inside the location block. This overrides the setting inherited from the server or http block for that path only.
Conclusion
Nginx provides a flexible logging system through the access_log, error_log, and log_format directives, giving you full control over what gets recorded and where. For a broader look at managing your Nginx server, see the Nginx commands
guide.
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page