On Debian and Ubuntu, Nginx logs to /var/log/nginx/access.log and error.log, and Apache to /var/log/apache2/access.log and error.log. On RHEL, Rocky and Alma, Apache uses /var/log/httpd/access_log and error_log, with underscores and no extension. In containers built from the official Nginx image, there are no log files at all: everything goes to stdout and stderr, so docker logs is your export.
The web server log is often the first place an intrusion leaves a trace: the scanner sweeping for .env files, the exploit string, the POST to a file that shouldn’t exist. Prime Core has 812 detection rules for web server logs, mapped to 337 MITRE ATT&CK techniques. Among them: exploitation of public-facing apps (T1190), web shells (T1505.003) and vulnerability scanning (T1595.002).
Before you start
Find the real paths. Virtual hosts often log somewhere custom. Ask the server itself:
# Nginx: dump the full effective config and pick out the log directives
sudo nginx -T 2>/dev/null | grep -E 'access_log|error_log'
# Apache
sudo apachectl -S
sudo grep -Ri -E 'CustomLog|ErrorLog' /etc/apache2/ /etc/httpd/ 2>/dev/null
On Debian-based Apache, virtual hosts without their own CustomLog end up in other_vhosts_access.log. People miss that one all the time.
Check whose IP you’re logging. Behind a load balancer, CDN or reverse proxy, every request can appear to come from the proxy. That holds unless the server is set up to log the real client: set_real_ip_from and real_ip_header in Nginx, mod_remoteip in Apache. If every line shows the same few internal IPs, the attacker’s address is only in X-Forwarded-For, if you log it, or in the proxy’s own logs.
Check the format. Both servers default to the “combined” format, but plenty of setups customize it (log_format in Nginx, LogFormat in Apache). Note what yours looks like before uploading.
Permissions. On Debian and Ubuntu these logs are readable by root and the adm group; elsewhere, plan on sudo.
Export from log files
Logs rotate daily or weekly, so include the rotated files. zcat -f reads plain and gzipped files alike:
# Nginx, current and rotated, oldest first
sudo zcat -f $(ls -tr /var/log/nginx/access.log*) > web-03_nginx_access.log
# Apache on RHEL
sudo zcat -f $(ls -tr /var/log/httpd/access_log*) > web-03_httpd_access.lo
For a single day, combined-format timestamps make grep enough:
grep '19/Oct/2026' web-03_nginx_access.log > web-03_access_1019.log
Take the error log as well. Upstream failures, PHP errors and some exploit attempts show up only there.
Export from containers
# Docker: stdout is the access log, stderr the error log
docker logs --since 2026-10-19T00:00:00 --until 2026-10-20T00:00:00 nginx > nginx_access.log 2> nginx_error.log
# Kubernetes
kubectl logs deploy/nginx --since=24h > nginx.log
Container logs disappear with the container unless something collects them. If the pod was replaced, check your cluster’s log collector instead.
What to look for
| Pattern | What it usually means |
|---|---|
| Bursts of 404s for /.env, /.git/config, /wp-login.php, /phpmyadmin | Automated scanning |
| ../, ${jndi:, union select, <script> in the URL | Exploit attempts: traversal, Log4Shell, SQL injection, XSS |
| 200 on a POST to an odd file under an upload directory | Possible web shell; look at what else that IP requested |
| User agents like sqlmap, nikto, nuclei | Tooling that didn’t bother to hide |
| A spike of 5xx right after strange requests | Something broke, possibly because an exploit landed |
Upload, sanitize and review in LogTotal
- Upload. Open logtotal.com and drop in the file.
- Sanitize. [what gets masked: client IPs, hostnames, usernames and tokens in URLs]. Look it over before you continue. Query strings often carry session tokens.
- Review.
When it goes wrong
| Symptom | Likely cause | Fix |
|---|---|---|
| No /var/log/nginx | Custom path, or it runs in a container | nginx -T, or docker logs |
| access.log exists but is empty | Logs go to stdout, or access_log off | Check the config and the container |
| Every request comes from the same IPs | Proxy or load balancer in front; real IP not configured | Use X-Forwarded-For or the proxy’s logs |
| Only the last few days | Rotated files left out | Use the zcat -f command with the * glob |
| Permission denied | Not root, not in adm | sudo |
FAQ
Which matters more, the access log or the error log?
The access log tells you what was requested. The error log tells you what broke. In an exploitation case, you want both, side by side.
What about IIS?
IIS writes W3C logs to C:\inetpub\logs\LogFiles by default. That gets its own guide.