Nginx Proxy Manager
Nginx Proxy Manager writes each proxy host’s log in its own proxy
format. That format has no request time, upstream time, protocol, remote
user or raw request line, so GeoMetrikks doesn’t tail it live. Only
import-logs reads it, as
Importing NPM’s existing logs describes.
NPM can write a second log next to its own, though, through its
custom nginx configuration
files. Point that second log at the JSON format from
Nginx setup. NPM’s own logs stay as they are.
The /data/... paths below are inside the NPM container. With the usual
./data:/data mount, /data/nginx/custom/http_top.conf is
./data/nginx/custom/http_top.conf on the host.
-
Copy the
log_format geometrikks_jsonblock from Nginx setup into/data/nginx/custom/http_top.conf. NPM includes this file at the top of thehttpblock, before it loads the proxy hosts. If the file already exists, for example with the realip lines from docs/proxy-setup.md, append the block. Define it once. -
Turn the log on. For every proxy host, put this line in
/data/nginx/custom/server_proxy.conf:access_log /data/logs/geometrikks_access.log geometrikks_json;NPM includes that file in every proxy host’s
serverblock, so hosts you add later log there too. To log only some hosts, leaveserver_proxy.confalone and paste the same line into each host’s Advanced tab, under Custom Nginx Configuration. Pick one of the two for a given host. With both, nginx writes every request twice.Keep the JSON in its own file. Pointing it at NPM’s
proxy-host-*_access.logputs two formats in one file. Don’t putaccess_log off;in front of the line either:offcancels everyaccess_logat that level, this one included. -
Check the config and reload nginx inside the NPM container:
Terminal window docker exec <npm-container> sh -c 'nginx -t && nginx -s reload'Open one of your sites, and its requests show up in
data/logs/geometrikks_access.log. -
Point GeoMetrikks at the file in
.env:ACCESS_LOG_DIR=/path/to/npm/data/logsLOGPARSER_LOG_PATHS=/var/log/access/geometrikks_access.logLOGPARSER_LOG_FORMATS=geometrikks-jsonRun
docker compose up -dto recreate the container with the new mount.docker compose restartkeeps the old one.
Every proxy host shares the one file. Each line carries host, so the host
filter still tells them apart. NPM’s logrotate rule matches
/data/logs/*_access.log, so this file rotates weekly along with NPM’s
own logs.
What the log leaves out:
- Cache Assets. On a host with Cache Assets on, NPM serves CSS, JS,
images and fonts from a location that sets
access_log off. Those requests never reach any log, so GeoMetrikks never sees them. NPM adds the same location inside each custom location on that host. Turn Cache Assets off on the hosts where you want that traffic counted. - Other host types.
server_proxy.confcovers proxy hosts only. Redirection hosts, 404 hosts and the default site don’t write to this log. NPM has separate snippet files for redirection and 404 hosts (server_redirect.conf,server_dead.conf), but this setup has only been tested on proxy hosts. TCP and UDP streams are not HTTP and this format doesn’t apply to them. - Visitor address. Behind Cloudflare or another proxy,
$remote_addris that proxy’s address, and the map shows its datacenter. Add the realip lines from docs/proxy-setup.md to the samehttp_top.conf.
Importing NPM’s existing logs
Section titled “Importing NPM’s existing logs”import-logs reads NPM’s own
proxy-host-<id>_access.log files and their rotated copies.
LOGPARSER_LOG_FORMATS=npm fails at startup, so these logs are for
backfill only.
NPM keeps writing its own logs after the JSON log is on, so every request
since then is in both. Pass --before with the time GeoMetrikks started
reading the JSON log, and the import stops there. If you started
GeoMetrikks right after the reload in step 3, that is the first line of
the oldest geometrikks_access.log file on disk:
ls data/logs/geometrikks_access.log*# open the highest-numbered one; zcat -f reads plain and .gz fileszcat -f data/logs/geometrikks_access.log.2.gz | head -n 1# {"client_ip":"...","timestamp":"2026-10-01T14:03:12+02:00",...}GeoMetrikks starts reading a log at its end, so it never ingested what the JSON log wrote before GeoMetrikks started. If GeoMetrikks started later, use the time of the oldest request on the Access Logs page instead, or those requests stay missing.
Import the rotated .gz copies only:
docker compose exec -u geometrikks app sh -c \ 'litestar import-logs --before 2026-10-01T14:03:12+02:00 /var/log/access/proxy-host-*_access.log.*.gz'The sh -c makes the container expand the glob against its own paths.
The current proxy-host-<id>_access.log is left out because it is still
growing: after NPM rotates it, it comes back as .1.gz with a new
checksum, and importing that would add its lines a second time. If the
JSON log is less than a week old, the current files still hold requests
from before the cutoff. Wait for NPM’s next weekly rotation, then import.
NPM’s other access logs import the same way:
redirection-host-<id>_access.logfor redirection hostsdead-host-<id>_access.logfor 404 hostsfallback_http_access.logfor requests that matched no host
default-host_access.log is in nginx’s combined format and imports as
nginx, without host or timings.
Legacy nginx format lists what that format lacks.
NPM rotates these logs weekly and keeps four compressed copies,
proxy-host-<id>_access.log.1.gz to .4.gz. That puts about five weeks of
history on disk, and each rotation deletes the oldest week. Import soon
after turning on the JSON log.
A later run skips the archives it already imported. NPM renumbers them but doesn’t change their content, so their checksums stay the same. If the cutoff turns out to be too early, run the same command with the later one. GeoMetrikks stores each file’s cutoff and imports only the lines in between. An earlier cutoff is refused, because the rows past it are already written.
Imported NPM rows have no response time, upstream time, protocol or remote user. The map, host filter, status codes, URLs, referrers, user agents and bytes are unaffected.