Detailed Apache logging turns vague 4xx and 5xx responses, TLS handshake failures, reverse-proxy timeouts, and rewrite loops into request-level evidence. Raising the log detail lets you see what Apache decided, which module made the decision, and which client request triggered it.
Apache splits diagnostics between the error log and one or more access logs. The LogLevel directive controls how much goes into the error log and supports module-scoped overrides such as ssl:info or rewrite:trace3, while LogFormat and CustomLog control which request fields are written to access logs and where those records are stored.
Verbose logging should be treated as a temporary troubleshooting mode on busy systems because it increases disk writes and can capture sensitive data in URLs, headers, or cookies. The commands below assume a Debian or Ubuntu layout under /etc/apache2/ with the apache2 systemd unit; RHEL-family systems typically use /etc/httpd/ and the httpd service name instead.
Steps to configure verbose Apache logging:
- List the configuration files that the running Apache instance loads.
$ sudo apache2ctl -t -D DUMP_INCLUDES Included configuration files: (*) /etc/apache2/apache2.conf (146) /etc/apache2/mods-enabled/access_compat.load (146) /etc/apache2/mods-enabled/alias.load (146) /etc/apache2/mods-enabled/auth_basic.load ##### snipped ##### (225) /etc/apache2/sites-enabled/000-default.conf (225) /etc/apache2/sites-enabled/default-ssl.confSome hosts also print the AH00558 server-name warning before the include list. That warning does not prevent the command from showing the active configuration tree.
Related: Location for Apache configuration
- Find the active LogLevel directive in the main server config.
$ sudo grep --recursive --line-number --extended-regexp '^[[:space:]]*LogLevel' /etc/apache2/ /etc/apache2/apache2.conf:143:LogLevel warn
- Find the current LogFormat and CustomLog definitions before adding a verbose variant.
$ sudo grep --recursive --line-number --extended-regexp '^[[:space:]]*(LogFormat|CustomLog)[[:space:]]' /etc/apache2/ /etc/apache2/apache2.conf:212:LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined /etc/apache2/apache2.conf:213:LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined ##### snipped ##### /etc/apache2/sites-available/000-default.conf:21: CustomLog ${APACHE_LOG_DIR}/access.log combined - List the loaded modules before choosing module-specific log levels.
$ sudo apache2ctl -M | grep -E 'rewrite|ssl|logio' logio_module (static) rewrite_module (shared) ssl_module (shared)
Only add module:level tokens for modules that are actually loaded. If the module you want to trace is missing, enable it first.
- Open the main Apache configuration file.
$ sudoedit /etc/apache2/apache2.conf
- Set a conservative default LogLevel and raise detail only for the module you are troubleshooting.
LogLevel warn ssl:info rewrite:trace3
warn keeps routine noise low, info restores lower-priority messages such as core:info for missing-file diagnostics, and trace1 through trace8 are the most verbose per-module levels.
trace levels can generate large volumes of output on busy servers and should be left enabled only for the shortest possible troubleshooting window.
- Add a dedicated verbose access-log format in /etc/apache2/apache2.conf.
LogFormat "%v:%p %a %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\" \"%{Host}i\"" verbose_timingThis format adds the canonical vhost and port (%v:%p), the client IP (%a), response bytes (%b), request time in microseconds (%D), and selected request headers without replacing your existing standard format.
Verbose formats can expose internal hostnames, query strings, or sensitive headers if you add too many fields, so avoid logging secrets such as authentication tokens or session cookies.
- Add a second CustomLog line inside the affected VirtualHost so the default access log stays in place.
<VirtualHost *:80> ServerName logs.example.net CustomLog ${APACHE_LOG_DIR}/access.log combined CustomLog ${APACHE_LOG_DIR}/access_verbose.log verbose_timing </VirtualHost>Writing to a separate access_verbose.log file keeps the normal access log stable for parsers and dashboards while you collect the extra detail.
- Validate the updated Apache configuration before reloading the service.
$ sudo apache2ctl configtest Syntax OK
Some hosts print the AH00558 server-name warning before Syntax OK. Fixing that warning is optional for logging changes.
Related: How to test Apache configuration
- Reload the running Apache service to apply the new logging settings.
$ sudo systemctl reload apache2
Use sudo systemctl reload httpd on most RHEL-family systems.
- Follow the error log in a second terminal.
$ sudo timeout 1 tail --follow=name --lines=20 /var/log/apache2/error.log [Thu Apr 09 04:19:08.752189 2026] [ssl:info] [pid 3462:tid 281473257799712] AH01883: Init: Initialized OpenSSL library [Thu Apr 09 04:19:08.752436 2026] [ssl:info] [pid 3462:tid 281473257799712] AH01887: Init: Initializing (virtual) servers for SSL [Thu Apr 09 04:19:08.752448 2026] [ssl:info] [pid 3462:tid 281473257799712] AH01914: Configuring server logs.example.net:443 for SSL protocol ##### snipped #####
The exact messages depend on the module you raised. For missing-file 404 diagnostics in Apache 2.4, a temporary LogLevel warn core:info is often enough.
- Send a request through the vhost that should appear in the verbose access log.
$ curl --head --header "Host: logs.example.net" http://127.0.0.1/ HTTP/1.1 200 OK Date: Thu, 09 Apr 2026 04:19:10 GMT Server: Apache/2.4.58 (Ubuntu) Last-Modified: Thu, 09 Apr 2026 04:19:05 GMT ETag: "29af-64eff5129f6b0" Accept-Ranges: bytes Content-Length: 10671 Vary: Accept-Encoding
If 127.0.0.1 does not hit the same virtual host locally, use the site hostname directly or add a Host header that matches the vhost you changed.
- Confirm that the verbose access log is collecting the extra fields you added.
$ sudo tail --lines=1 /var/log/apache2/access_verbose.log logs.example.net:80 127.0.0.1 - - [09/Apr/2026:04:19:10 +0000] "HEAD / HTTP/1.1" 200 - 1133 "-" "curl/8.5.0" "logs.example.net"
The leading logs.example.net:80 field comes from %v:%p, the dash after 200 comes from %b because a HEAD request sends no response body, and 1133 is the request time from %D in microseconds.
- Restore the normal logging level after you capture the evidence you need.
LogLevel warn
Remove the temporary CustomLog ${APACHE_LOG_DIR}/access_verbose.log verbose_timing line as well if you only needed the extra log during a debugging session.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
