21+ years in hosting · Jaipur, India · INR billing with 18% GST · 24/7 email support
Blog · WebJi® India

Apache Log Files Explained: How to Read Access and Error Logs

Quick answer

Apache writes two logs: the access log records one line per request (client IP, time, URL, status code, bytes, referrer, user agent) and the error log records faults such as PHP fatals and config errors. On Ubuntu they sit in /var/log/apache2/, on RHEL-family servers in /var/log/httpd/, and on cPanel under ~/access-logs.

For site owners and VPS admins who need to trace a 500 error, count 404s or spot bots from Apache's raw access and error logs.

✓ In business since 2005
✓ INR + GST billing
✓ 24/7 Email Support — avg reply < 60 min
GuideWebJi®
knowledge
Read time
4 min
Sections
6
Updated
14 Nov 2026
Written by
WebJi® team

What are Apache's access log and error log?

Apache keeps two separate records: the access log writes one line for every request it serves, and the error log records what went wrong while serving them. The access log tells you what happened; the error log tells you why.

Apache access log vs error log at a glance
AttributeAccess logError log
DirectiveCustomLog + LogFormatErrorLog + LogLevel
One entry perRequestEvent (fault, warning, notice)
Typical contentIP, time, URL, status, bytes, referrer, browserModule, severity, PID, client, message
Main useTraffic, 404s, bots, attack patterns500 errors, PHP fatals, config and startup problems

Where are Apache log files stored?

The location depends on who manages the server: cPanel exposes logs inside your home directory, while a self-managed VPS keeps them under /var/log with a distro-specific folder name.

  • cPanel shared hosting: ~/access-logs/ links to the current raw access logs per domain; ~/logs/ holds archived .gz copies if archiving is switched on in Raw Access. The cPanel Errors page shows the most recent 300 error-log entries.
  • Ubuntu and Debian VPS: /var/log/apache2/access.log and /var/log/apache2/error.log; each virtual host may add its own files there.
  • AlmaLinux, Rocky and other RHEL-family VPS: /var/log/httpd/access_log and /var/log/httpd/error_log.
  • Custom virtual hosts: run grep -RiE "CustomLog|ErrorLog" /etc/apache2/ /etc/httpd/ 2>/dev/null to see the paths each site really uses.

PHP can also write its own error_log file inside the site folder, separate from Apache's. The PHP error log guide covers that file, and checking WordPress error logs covers debug.log.

How to read an Apache access log line field by field

Most servers use the "combined" format: seven Common Log Format fields followed by the referrer and the user agent. Apache's default definition is shown first; Debian swaps %b for %O, which counts bytes including headers.

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

203.0.113.9 - - [14/Nov/2026:10:14:02 +0530] "GET /pricing/ HTTP/1.1" 200 18421 "https://www.google.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
Combined log format fields decoded with the example above
TokenFieldExample value
%hClient IP (the proxy's IP if behind Cloudflare or Nginx, unless mod_remoteip is set)203.0.113.9
%lRFC 1413 identity, almost always unused-
%uHTTP-authenticated user-
%tTime the request was received, with offset14/Nov/2026:10:14:02 +0530
"%r"Request line: method, path, protocolGET /pricing/ HTTP/1.1
%>sFinal status after internal redirects200
%bResponse body size in bytes (- when zero)18421
%{Referer}iPage that linked to this URLhttps://www.google.com/
%{User-Agent}iBrowser or bot stringMozilla/5.0 (Windows NT 10.0…)

Read as a sentence: a Windows visitor arriving from Google loaded /pricing/ at 10:14 IST and received 18,421 bytes with status 200.

How to read an Apache 2.4 error log entry

Each Apache 2.4 error entry carries a timestamp, the module and severity, the process ID, the client address and the message, in that order. The severity tells you how serious it is; the message usually names the file at fault.

[Fri Nov 14 10:14:05.418233 2026] [proxy_fcgi:error] [pid 2817] [client 203.0.113.9:51544] AH01071: Got error 'PHP message: PHP Fatal error:  Uncaught Error: Call to undefined function wc_get_product() in /home/shop/public_html/wp-content/themes/store/functions.php:212'

That line shows a PHP-FPM site (hence proxy_fcgi) throwing a fatal error on line 212 of the theme's functions.php, which the visitor saw as a 500 page. With the older mod_php the module tag reads [php:error] or similar instead.

The LogLevel directive filters what is written. The default is warn, so routine "File does not exist" 404 notices, logged at info, never appear in the error log; count 404s from the access log instead.

Apache log commands that answer real questions

A handful of tail, awk and grep one-liners answer most log questions in seconds on any VPS. In the combined format, field 1 is the IP, field 7 the path and field 9 the status. Swap the path for /var/log/httpd/access_log on RHEL-family systems.

# watch errors live while you reproduce a fault
sudo tail -f /var/log/apache2/error.log

# how many of each status code
awk '{print $9}' /var/log/apache2/access.log | sort | uniq -c | sort -rn

# top 20 paths returning 404
awk '$9 == 404 {print $7}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20

# busiest client IPs
awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20

# busiest user agents (bots stand out quickly)
awk -F'"' '{print $6}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -15

# search rotated, compressed logs too
zgrep ' 500 ' /var/log/apache2/access.log*

For a 500 error, take the time and IP from the access line and search the error log for the same second; the matching entry names the script. Repeated 403 lines usually mean a permission or .htaccess deny rule, explained in the 403 Forbidden fix guide. Thousands of POSTs to /wp-login.php or /xmlrpc.php from a few IPs are brute-force attempts worth blocking with Fail2ban.

Apache log rotation and how long logs are kept

Logs are rotated by logrotate or Apache's own rotatelogs, and retention is whatever that configuration says, not a fixed Apache rule. A combined-format line is roughly 150–300 bytes, so a site serving 1,00,000 requests a day adds about 15–30 MB of access log daily.

  • logrotate (Debian/Ubuntu default): /etc/logrotate.d/apache2 rotates daily, keeps 14 compressed copies and reloads Apache afterwards so it reopens the files.
  • rotatelogs (piped logging): CustomLog "|/usr/bin/rotatelogs /var/log/apache2/access.%Y-%m-%d.log 86400" combined starts a new file every 24 hours with no reload. The binary lives in /usr/sbin on RHEL-family systems.
  • cPanel: the host manages rotation; enable "Archive logs" in Raw Access if you want monthly copies kept in ~/logs/.

Tools that turn Apache logs into reports

Use cPanel's Metrics tools when you have no shell, and GoAccess when you have SSH and want a dashboard rather than raw lines.

  • cPanel Metrics: Visitors (last 1,000 hits per domain), Errors, Raw Access download and AWStats, all included with WebJi® Linux hosting.
  • GoAccess: goaccess /var/log/apache2/access.log --log-format=COMBINED -o report.html builds a single HTML report; add --real-time-html for a live view.
  • Plain shell: the one-liners above, which work on any host with SSH and need nothing installed.

If you are weighing Apache against an event-driven server for a busy site, Apache vs Nginx compares how each handles load and logging.

FAQ

Frequently asked questions

Why does every visitor in my access log show the same IP address?

Apache is behind a proxy such as Cloudflare or Nginx, so %h records the proxy. Enable mod_remoteip with RemoteIPHeader X-Forwarded-For (or CF-Connecting-IP) and list the proxy as trusted, and the real client IP appears again.

Can I safely delete a large Apache log file?

Truncate it instead: sudo truncate -s 0 /var/log/apache2/access.log. Deleting with rm leaves Apache writing to the removed file, so the disk space is not freed until a reload. Fix rotation afterwards so the file does not grow back.

How do I make Apache log more detail for one module?

Apache 2.4 accepts per-module levels, for example LogLevel warn rewrite:trace3 to trace mod_rewrite decisions. Reload, reproduce the problem, then set it back, because trace levels write many lines per request.

Do access logs record the time a page took to load?

Not in the combined format. Add %D (microseconds) or %{ms}T (milliseconds) to a custom LogFormat and slow URLs become easy to sort and find.

Checked 14 November 2026 against the Apache HTTP Server 2.4 documentation · Reviewed by the WebJi® team, Jaipur.

WebJi® since 2005

Ready to get started with WebJi®?

Join 12,000+ businesses across India and overseas. INR pricing, 18% GST shown before payment and 24/7 email support in Hindi and English — average first reply under 60 minutes.