A site on another server

Same snippet, no agent, no log shipping - and an honest account of what the allowlist does not stop.

The beacon works on a host this Loghound installation has no access log for. Paste the same snippet. Nothing else is installed there: no agent, no log shipping, no second Loghound.

<script src="https://loghound.example.com/b.js?v=1" defer></script>

This is how a hosted search page at search.example.com, running on a different machine from the one Loghound is on, appears in the same panel as everything else.

01 · Two modes, and the server decides which
MERGE — A LOG SOURCE HERE COVERS THE HOSTNAMElog linewins on factsbeaconwins on timeONE SESSIONplanes: log and beaconSTANDALONE — NO LOG SOURCE HERE COVERS ITbeacon onlycreates the sessionMARKEDone planeTRANSPORT FIELDS: ABSENTNot zero. A zero is a measurement, andfive rules that read them are silencedCoverage is derived from evidence: has thisinstallation ingested log lines for that hostname.

Figure 1 — the two modes. You do not declare which applies. Configuration says what somebody intended; evidence says what is true, and only the second is safe to act on.

Whether a host is already covered is derived from whether this installation has actually ingested log lines for that hostname in the last seven days. Asking you to state the mode in a second place would guarantee the two drifted the first time a site moved.

02 · Permission: the hostname allowlist
'beacon' => [
    'allowed_hosts' => ['search.example.com', 'shop.example.com'],
],

Empty by default, so an installation that says nothing behaves exactly as it did before this existed. A beacon from a hostname that is not on the list keeps the ordinary behaviour precisely: a fresh provisional session id, a staged row, merge only, no session created, and no hostname and no search term recorded anywhere.

Being on the list buys three things and nothing else:

  1. Its beacons may create a session when no log source covers the host.
  2. Its reported hostname is recorded, so it sits in the Virtual host dimension beside hosts that came from a log line and filters identically.
  3. Search terms from it are kept.

How a listed host is told apart from the open internet

Three facts have to agree, and the collector checks all three:

  • What the page says it is. Entirely attacker-chosen, so on its own it is worth nothing.
  • What the browser says it is — the Origin header. A user agent sets this on every cross-origin request and page script cannot change it: a page on another domain cannot make a browser send somebody else’s origin. This is the fact that makes the first one worth reading. They are required to agree, and a disagreement is refused rather than reconciled. A request with no Origin is refused for this purpose too, because the beacon is cross-origin by construction and a browser running it always sends one.
  • What you said — the hostname is on the list.
03 · What this does NOT stop
The allowlist is a permission, not an authentication, and this documentation is not going to imply otherwise

Origin binds browsers. Anything that is not a browser — curl, a script, a load generator — sends whatever headers it is told to. So somebody who knows a hostname is on your list can fabricate sessions attributed to it. They can make up dwell times, invent visitors, and report a human as headless automation.

What bounds that:

  • It reaches only the hostnames you listed. It cannot touch another host’s data and it cannot invent a hostname you did not name.
  • It reads nothing. The collector answers 204 with an empty body to every request, success or failure, so it is not an oracle for anything.
  • It cannot reach the log-backed planes. A forged beacon cannot create a log line, a status code, a byte count or a reverse DNS result, and it cannot alter a session that has those — the merge never overwrites a fact the log supplied.
  • Rate limits apply per address, per session and per hostname, so a listed host is not a way around the limiter.

This is the same exposure every client-side analytics product carries — they all accept a beacon whose only claim to authenticity is a site identifier visible in the page source. Loghound’s answer is not to pretend the problem is solved. It is to mark what the evidence actually is.

04 · A beacon-only session is marked, and never claims a log fact

A standalone session has no transport plane: no status code, no bytes, no server timing, no conditional-request behaviour, no inter-request rhythm, no reverse DNS from a log line. Two guarantees, and both are needed.

  • On the document. None of those fields is written. Not zero — absent. A zero in any of them is a measurement, and an asset ratio of zero reads as “this client fetched only markup”, which is a bot signal, about a visitor whose asset fetching was never observable from here.
  • In the ruleset. Five rules are silenced: no JS on HTML, no sub-resources, no conditional requests, single page under ten seconds, and periodic timing. Without that, the absent counters would be read back as the zeros PHP hands out — and a zero in those fields is not a neutral value, it is an accusation. The silencing makes that a guarantee rather than a coincidence: the no-sub-resources rule, for instance, also requires that an HTML 200 was served, which a beacon-only session has no record of, so it could not fire anyway — but relying on a second rule’s precondition to save you is exactly the kind of thing that stops being true after a refactor. The no-interaction rule is deliberately not silenced, because it reads the beacon’s own interaction count, which a beacon-only session has.

The session carries a planes value — log only, log and beacon, or beacon only — as a facetable dimension, plus a reason code worth no points, present so the verdict explains itself. The vocabulary page lists all three values.

Asking for sessions that have a transport plane is “none of beacon only”, not “log only”

The field is newer than the product, so every session indexed before it existed has no value for it — and every one of those came from a log. The negation includes that history; the positive form would silently exclude all of it. The None of operator is what spells it.

05 · When a standalone host later gains a log source

You add the vhost, or move the site onto the Loghound machine. From that moment both planes describe the same visit, and this produces one session, not two:

  1. The coverage check flips as soon as hits appear for that hostname, so nothing new is promoted to standalone.
  2. Beacons for a visit already in flight are claimed by the log-backed session through the client key — the mechanism that has always existed for a beacon arriving before its log line.
  3. Any provisional standalone document already published for those rows is deleted by id before the run indexes anything. Deleting first means a failure leaves a gap, never a double count.

History is untouched. A session that really was beacon-only when it happened stays beacon-only, because a reconfiguration today is not evidence about last week.

Loghound is open source and MIT licensed. Questions about the Opensolr half — the account, the indexes, the plan — go to opensolr.com/contact; questions about the software itself belong on GitHub.

Loghound Documentation