Documentation

GeoIP Analytics

Import local GeoIP data, backfill analytics rows, understand Unknown locations, and maintain DB-IP City Lite attribution.

Source: GEOIP_ANALYTICS.md

DesertCMS analytics store page views locally. Runtime page-view collection does not call an external geolocation API.

Visitor locations come from the local SQLite table analytics_geoip_ranges. If that table is empty, the dashboard reports GeoIP as not imported and location rows show Unknown.

What Analytics Stores

When analytics are enabled, DesertCMS stores:

  • path
  • referrer
  • timestamp
  • HMAC-hashed IP
  • HMAC-hashed user agent
  • raw IP address when analytics_store_raw_ip = 1
  • country code, country, region, and city when a local GeoIP match is available

The country flag shown in admin analytics is derived from the stored two-letter country code.

DB-IP City Lite

For a launch-ready free city database, run:

doas su -m _desertcms -c 'env DESERTCMS_CONFIG=/etc/desertcms.conf perl /usr/local/www/desertcms/bin/desertcms-maint.pl geoip-refresh-dbip-lite'

That downloads the current monthly DB-IP City Lite CSV, imports city/state/country ranges locally, and backfills existing analytics rows.

On small VPS deployments, use observed-only mode first:

doas su -m _desertcms -c 'env DESERTCMS_CONFIG=/etc/desertcms.conf perl /usr/local/www/desertcms/bin/desertcms-maint.pl geoip-refresh-dbip-lite --observed-only'

Observed-only mode imports only ranges that match IPs already present in analytics. It is faster and lighter, but new visitor IPs outside those ranges will remain Unknown until the next refresh or a full import.

DB-IP Lite requires attribution where results are displayed. The admin dashboard adds DB-IP attribution automatically when DB-IP metadata is imported.

Custom CSV Or TSV

Simple files can use either of these shapes:

network,country,region,city
203.0.113.0/24,US,California,Los Angeles
start_ip,end_ip,country,region,city
203.0.113.0,203.0.113.255,US,California,Los Angeles

Import and backfill:

doas su -m _desertcms -c 'env DESERTCMS_CONFIG=/etc/desertcms.conf perl /usr/local/www/desertcms/bin/desertcms-maint.pl geoip-import /var/desertcms/geoip.tsv'
doas su -m _desertcms -c 'env DESERTCMS_CONFIG=/etc/desertcms.conf perl /usr/local/www/desertcms/bin/desertcms-maint.pl geoip-backfill'

Use --append when adding a second range file, such as IPv6 ranges after IPv4 ranges.

GeoLite2-Style CSV

For GeoLite2-style city exports, pass both blocks and locations files:

doas su -m _desertcms -c 'env DESERTCMS_CONFIG=/etc/desertcms.conf perl /usr/local/www/desertcms/bin/desertcms-maint.pl geoip-import --blocks /var/desertcms/GeoLite2-City-Blocks-IPv4.csv --locations /var/desertcms/GeoLite2-City-Locations-en.csv'
doas su -m _desertcms -c 'env DESERTCMS_CONFIG=/etc/desertcms.conf perl /usr/local/www/desertcms/bin/desertcms-maint.pl geoip-import --append --blocks /var/desertcms/GeoLite2-City-Blocks-IPv6.csv --locations /var/desertcms/GeoLite2-City-Locations-en.csv'
doas su -m _desertcms -c 'env DESERTCMS_CONFIG=/etc/desertcms.conf perl /usr/local/www/desertcms/bin/desertcms-maint.pl geoip-backfill'

Troubleshooting Unknown Locations

If analytics still show Unknown:

  • Confirm analytics_store_raw_ip = 1; backfill needs stored IP addresses.
  • Confirm the dashboard GeoIP status shows a nonzero range count.
  • Confirm the import source matches the visitor IP family. IPv4-only imports will not resolve IPv6 visitors.
  • Run geoip-backfill after importing ranges.
  • Use the full DB-IP import instead of observed-only if new visitors are outside observed ranges.
  • Ignore private/local IPs. DesertCMS labels private addresses as Local when backfilled, but public visitor geolocation depends on public IP ranges.

Check import status from SQLite:

doas su -m _desertcms -c 'sqlite3 /var/desertcms/desertcms.sqlite "select count(*) from analytics_geoip_ranges; select key,value from analytics_geoip_meta;"'

Backfill a limited number of recent unresolved rows while testing:

doas su -m _desertcms -c 'env DESERTCMS_CONFIG=/etc/desertcms.conf perl /usr/local/www/desertcms/bin/desertcms-maint.pl geoip-backfill --limit 100'