Where does Apache log traffic that hits the server IP directly (bypassing the VHost domain)?

image

Hi everyone,

I am trying to track down a malicious IP scanning my server, but I cannot find its entries anywhere in my standard logs.

I can see the IP (193.32.204.199) actively making requests in real-time on my Apache mod_status dashboard. The requests look like this:
GET /public/.git/config HTTP/1.1

However, the attacker is hitting the server IP directly (xxx.xxx.xxx.73) instead of using my website’s domain name. Because of this, the traffic is completely missing from my domain’s custom access logs.

I have already tried checking /var/log/apache2/access.log (and running grep for the IP across /var/log/), but nothing shows up.

Where does Apache route and save log files for raw, direct-to-IP traffic that completely bypasses the configured Virtual Hosts domain?

Thanks for any help!

image

You’re on the right track. Here’s the complete procedure, with a few details added to avoid common pitfalls.

Why the traffic is missing

Your IP is being accessed directly (via IP, not domain), so Nginx routes it to the default server block, which is configured with:

access_log off;
error_log /dev/null;

That’s why nothing shows up in your domain logs. The request never reaches a domain vhost.

In HestiaCP, the default vhost is defined in:

/etc/nginx/conf.d/<YOUR_PUBLIC_IP>.conf

Full default vhost config (before)

This is what the file typically looks like. Note the access_log off; and error_log /dev/null; in both server blocks:

server {
        listen <YOUR_PUBLIC_IP>:80 default_server;
        server_name _;
        access_log off;
        error_log /dev/null;

        location / {
                proxy_pass http://<YOUR_PUBLIC_IP>:8080;
   }
}

server {
        listen <YOUR_PUBLIC_IP>:443 default_server ssl;
        server_name _;
        access_log off;
        error_log /dev/null;

        ssl_certificate     /usr/local/hestia/ssl/certificate.crt;
        ssl_certificate_key /usr/local/hestia/ssl/certificate.key;

        return 301 http://$host$request_uri;

        location / {
                root /var/www/document_errors/;
        }

        location /error/ {
                alias /var/www/document_errors/;
        }
}

Full default vhost config (after — with logging enabled)

Change the access_log and error_log lines in both server blocks:

server {
        listen <YOUR_PUBLIC_IP>:80 default_server;
        server_name _;
        access_log /var/log/apache2/domains/default_access.log combined;
        error_log  /var/log/apache2/domains/default_error.log error;

        location / {
                proxy_pass http://<YOUR_PUBLIC_IP>:8080;
   }
}

server {
        listen <YOUR_PUBLIC_IP>:443 default_server ssl;
        server_name _;
        access_log /var/log/apache2/domains/default_access.log combined;
        error_log  /var/log/apache2/domains/default_error.log error;

        ssl_certificate     /usr/local/hestia/ssl/certificate.crt;
        ssl_certificate_key /usr/local/hestia/ssl/certificate.key;

        return 301 http://$host$request_uri;

        location / {
                root /var/www/document_errors/;
        }

        location /error/ {
                alias /var/www/document_errors/;
        }
}

Note: In HestiaCP, Nginx and Apache share the /var/log/apache2/domains/ directory, so this path is correct.

ls -ld /var/log/apache2/domains/

Step 1 — Back up the config

cp /etc/nginx/conf.d/<YOUR_PUBLIC_IP>.conf /etc/nginx/conf.d/<YOUR_PUBLIC_IP>.conf.bak

Step 2 — Enable logging on the default vhost

Edit:

vi /etc/nginx/conf.d/<YOUR_PUBLIC_IP>.conf

Apply the “after” version shown above.

Step 3 — Test and reload

nginx -t && systemctl reload nginx

Only reload if nginx -t reports syntax is ok and test is successful.

Step 4 — Watch the traffic

tail -f /var/log/apache2/domains/default_access.log

To filter for the malicious IP:

tail -f /var/log/apache2/domains/default_access.log | grep 193.32.204.199

You can also watch the error log:

tail -f /var/log/apache2/domains/default_error.log

Step 5 — Restore when done

Once you’ve captured enough, restore the backup:

cp /etc/nginx/conf.d/<YOUR_PUBLIC_IP>.conf.bak /etc/nginx/conf.d/<YOUR_PUBLIC_IP>.conf
nginx -t && systemctl reload nginx

This puts access_log off; and error_log /dev/null; back, so the log doesn’t grow indefinitely from scanner noise.

Optional — Block the IP at the firewall

If you just want it gone, you can drop it at the firewall level instead of logging:

# nftables
nft add rule inet filter input ip saddr 193.32.204.199 drop

# or iptables
iptables -I INPUT -s 193.32.204.199 -j DROP

For repeated scanners, fail2ban is a better long-term solution.

Summary

  • IP-direct traffic goes to the default vhost, which has logging disabled.
  • Temporarily enable access_log / error_log there.
  • nginx -t && systemctl reload nginx
  • tail -f the new log to catch the scanner.
  • Restore the backup when done.

Thanks a bunch :folded_hands:.

I intend to keep the logging on permanently.

  1. Is there any risk to that? And will this change be overwritten when hestiacp is updated?

  2. I currently use crowdsec to block malicious IPs and it works well. But I doesn’t work when the IP is accessed directly.

You’re welcome!

1. Is there any risk in keeping logging on permanently?

The main risk is disk usage, not stability. The default vhost catches all unmatched traffic — scanners, bots, random IP hits — which can be very noisy. Depending on your exposure, that log can grow fast.

Mitigations:

  • Logrotate: make sure a rotation rule covers the new log. You can add one under /etc/logrotate.d/ or extend HestiaCP’s existing rule to include default_access.log / default_error.log.
  • Compress + keep limited copies: e.g. daily rotation, keep 7–14 days, compress old ones.
  • Monitor size: a quick du -h /var/log/apache2/domains/default_* once in a while.
  • Optionally log only errors: if the access log gets too noisy, you can keep only error_log on and leave access_log off.

Performance-wise, logging itself is negligible unless you’re under heavy scanning, in which case disk I/O and space are the real concerns.

2. Will this be overwritten on HestiaCP update?

Possibly, yes. Files under /etc/nginx/conf.d/ — including the <PUBLIC_IP>.conf default vhost — are generated and managed by HestiaCP. When HestiaCP rebuilds the web config (on update, or when you run its rebuild commands), it may regenerate this file and revert your changes.

Ways to make it survive:

  • Check whether HestiaCP has a hook/template for the default vhost. HestiaCP uses templates under /usr/local/hestia/data/templates/web/nginx/. If the default vhost is built from a template, edit the template, not just the generated file — then rebuilds will keep your change.
  • Keep the backup (<PUBLIC_IP>.conf.bak) and re-apply after updates.
  • Use a separate include: some setups let you drop a custom .conf that HestiaCP won’t overwrite. Whether that works depends on how the default vhost is assembled — worth checking with hestia docs or the file’s header comments.
  • After each HestiaCP update, verify the file still has your logging lines.

So: short term it works, but don’t assume it’s permanent — either hook into the template or re-apply after updates.

3. CrowdSec doesn’t catch direct-IP access

That’s consistent with what you’re seeing: CrowdSec reads the Nginx/Apache logs. If IP-direct traffic goes to the default vhost with access_log off, CrowdSec never sees it, so it can’t act.

To make CrowdSec work for direct-IP traffic, you need the traffic to be logged somewhere CrowdSec reads. Two approaches:

  1. Keep the default vhost logging on (what you’re doing), and make sure CrowdSec’s Nginx/Apache parser is pointed at that log file. Then CrowdSec can parse and ban those IPs.
  2. Block at the firewall/bouncer level: CrowdSec’s firewall bouncer can drop IPs before they reach Nginx, but it still needs a detection source — which again means logs, or a scenario that watches for direct-IP hits.

So enabling logging on the default vhost is actually the right move to feed CrowdSec. Just make sure:

  • CrowdSec’s acquisition config (/etc/crowdsec/acquis.yaml or similar) includes the new log path.
  • The Nginx/Apache parser matches the log format (combined).

Once that’s in place, CrowdSec should start seeing and banning direct-IP scanners too.

Thanks for the information on crowdsec.
Surprisingly the malicious IP is already in the crowdsec community blocklist. However, it keeps hitting my server through the direct IP. Does this mean the direct IP address is not protected?