Intermediate · 10 min · practise every command in the built-in terminal

Reading the Logs

nginx writes a line to /var/log/nginx/access.log for every request, and to error.log when something goes wrong. They belong to the group adm — and you're in it, so no sudo needed.

tail -n 5 /var/log/nginx/access.log

One line, field by field

203.0.113.42 - - [17/Oct/2026:14:02:11 +0200] "GET /about.html HTTP/1.1" 200 2348 "-" "Mozilla/5.0 …"
Field (awk)HereMeaning
$1203.0.113.42who asked (the visitor's IP)
$4[17/Oct/2026:14:02:11when
$6 $7"GET /about.htmlwhat they asked for
$9200the answer's status
$102348bytes sent
last part"Mozilla/5.0 …"the browser or bot

Questions the log answers

# Who visits the most?
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -3

# How did the server answer?
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c

# Which pages are missing?
awk '$9 == 404 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

# Which search engines came by?
grep -i bot /var/log/nginx/access.log

Requests for /wp-login.php, /.env or /phpmyadmin/ on a site that has none of them are scanners looking for weak spots — every public server sees them.

The error log

tail /var/log/nginx/error.log

It says why: No such file or directory behind a 404, Permission denied behind a 403, connect() failed when a backend is down.

💡 tail -f /var/log/nginx/access.log follows the log live (Ctrl+C to stop). Old logs are rotated daily by logrotate: access.log.1, then compressed access.log.2.gz — read those with zcat.

Practice tasks

  1. Show the last 5 requests to the server
  2. Find the IP address that sent the most requests
  3. List the pages that were not found (404)
  4. Find the requests made by search engine bots
  5. Read why requests failed, in the error log

Commands in this lesson

Web Server (nginx)