So, you're wrestling with Nginx logs, huh? Been there. In fact, I used to spend way too much time hunting down log files until I finally got smart about it. Let me save you the trouble.
Nginx logs are like the black box flight recorder for your web server. When everything crashes and burns (and it will), those logs are often the only evidence left to figure out what happened. But first, you need to know where to find them.
Where to Find Nginx Logs by Default
On most Linux setups, Nginx logs live in /var/log/nginx/
. Shocking, I know. But here's the breakdown by OS:
Ubuntu/Debian:
/var/log/nginx/access.log
/var/log/nginx/error.log
CentOS/RHEL:
/var/log/nginx/access.log
/var/log/nginx/error.log
FreeBSD:
/var/log/nginx-access.log
/var/log/nginx-error.log
Windows: (Yes, some brave souls run Nginx on Windows)
nginx/logs/access.log
nginx/logs/error.log
Docker Containers:
/var/log/nginx/access.log
/var/log/nginx/error.log
I once spent an entire afternoon debugging an API that was mysteriously failing in production. Turns out Nginx was rejecting the requests with a 413 error because the payload was too large. A simple cat /var/log/nginx/error.log
would have shown me that in seconds. Don't be like me - check the nginx log location first.
Where Are Your Nginx Logs Stored?
Maybe you're on a server someone else set up, and things aren't where they should be. No problem. Here's how to track down your nginx log location:
grep -r "access_log\|error_log" /etc/nginx/
Or go straight to the main config:
cat /etc/nginx/nginx.conf | grep "log"
For virtual hosts:
grep -r "access_log\|error_log" /etc/nginx/sites-available/
One thing I've learned the hard way: logs can be defined at multiple levels. You might have global logs in the main config, plus different logs for each virtual host. It's logs all the way down!
How to Customize Your Log Locations
Once you know where your logs are, you might want to move them. Maybe you want logs organized by project, or you want to store them on a separate partition. Whatever the reason, here's how:
http {
# Global log settings
access_log /path/to/custom/access.log;
error_log /path/to/custom/error.log warn;
server {
# Server-specific log settings (overrides global)
access_log /path/to/site-specific/access.log;
error_log /path/to/site-specific/error.log;
# You can even disable logging for certain locations
location /health-check {
access_log off;
# health checks don't need to fill up your logs
}
}
}
I manage several sites on a single server, and I've found it incredibly helpful to organize logs by project:
access_log /var/log/nginx/projectname-access.log;
error_log /var/log/nginx/projectname-error.log;
This way, when something breaks at 2 AM (and it will), I'm not sifting through logs for a dozen different sites.
Breaking Down Nginx Log Formats
Now that you know the nginx log location, let's talk about what's actually in those logs.
The default access log format (called "combined") looks like this:
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
Which produces entries like:
192.168.1.1 - - [03/Mar/2025:15:42:31 +0000] "GET /api/users HTTP/1.1" 200 1234 "https://example.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
That's fine for basic stuff, but as your site grows, you'll want more info. Here's a custom format I use for performance debugging:
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time $pipe';
access_log /var/log/nginx/detailed-access.log detailed;
That $request_time
field has saved my bacon more times than I can count. When users complain that "the site is slow," you can quickly find out which requests are taking forever.
Practical Techniques for Better Log Analysis
Having logs is one thing. Making sense of them is another. Here are some tricks I use daily:
Find all 500 errors from the last hour:
grep " 5[0-9][0-9] " /var/log/nginx/access.log | grep "$(date -d '1 hour ago' +'%d/%b/%Y:%H')"
Identify slow requests (taking more than 2 seconds):
awk '$NF > 2.0 {print $0}' /var/log/nginx/access.log
Find your top 10 visitors:
cat /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10
See who's hammering a specific URL:
grep "GET /specific-url" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -n
For day-to-day log analysis, I'm a big fan of GoAccess:
goaccess /var/log/nginx/access.log -c
It gives you a real-time dashboard right in your terminal. Much nicer than squinting at raw logs.
How to Handle Log Rotation and Management
Here's something they don't tell you when you're setting up your first server: logs grow. And grow. And grow.
I once got a frantic call at 3 AM because a production server was unresponsive. The culprit? The root partition was 100% full because nobody had set up log rotation. Don't be that person.
Most Linux distributions include logrotate. Here's a sane configuration for your nginx log location:
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
if [ -d /etc/nginx ]; then
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
fi
endscript
}
This rotates logs daily, keeps two weeks of history, and compresses old logs to save space. The kill -USR1
bit tells Nginx to reopen its log files without restarting.
Fixing Common Problems in Nginx Logging
Over the years, I've run into pretty much every possible log-related issue. Here are the greatest hits:
Logs Not Being Written
If you've configured a custom log path but nothing's showing up:
Test if the Nginx user can actually write there:
sudo -u www-data touch /path/to/logs/test.log
Make sure parent directories exist:
sudo mkdir -p /path/to/logs
Check permissions. Nginx runs as www-data or nginx user, and needs write access:
sudo chown -R www-data:www-data /path/to/logs
sudo chmod 755 /path/to/logs
I once spent two hours debugging why logs weren't being written, only to discover that I'd mounted a read-only filesystem at the log path. Don't do that.
Missing Log Entries
Sometimes, you're sure something happened, but it's not in the logs:
- Internal redirects might only log the initial request
- If you've set
access_log off
for certain locations, those requests won't be logged - Nginx buffers log writes, so entries might be delayed
Incorrect Log Format
If your logs look weird:
- Make sure your
log_format
directive comes before anyaccess_log
directives that use it - Check that the format name matches what you're using in
access_log
- Restart Nginx after changing log formats (reload isn't always enough)
Setting Up Advanced Logging in Nginx
Once you've mastered the basics, here are some power-user techniques:
JSON Logging
For easier parsing by log management systems:
log_format json_combined 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"}';
access_log /var/log/nginx/access.log json_combined;
This makes it much easier to ship logs to systems like Elasticsearch or Splunk.
Conditional Logging
Why log everything when you only care about errors?
map $status $loggable {
~^[23] 0;
default 1;
}
access_log /var/log/nginx/error-access.log combined if=$loggable;
This only logs requests that don't return 2xx or 3xx status codes. Your disk will thank you.
Logging to Syslog
For centralized logging:
error_log syslog:server=unix:/dev/log,facility=local7,tag=nginx,severity=info;
access_log syslog:server=unix:/dev/log,facility=local7,tag=nginx,severity=info combined;
This sends logs to syslog, which can forward them to a central log server. Great for multi-server setups.
The Bottom Line
Look, mastering your nginx log location and configuration isn't the sexiest part of web development. But when things go wrong (and they will), you'll be glad you know where to look.
I've been building web applications for over a decade, and I still check the logs first when something breaks. They're often the difference between a quick fix and an all-night debugging session.
Take the time to set up proper logging, rotation, and analysis tools. Your future self, awakened at 3 AM by a production alert, will thank you.