Contents

Mirrors - Plugixa Activity Log

A log kept only on the site it describes has one weakness: whoever takes over the site can reach it. A mirror answers “where is the copy they cannot take back?”. It sends events off the site as they are written - to a SIEM, a log collector, or a file a log shipper reads.

The Mirrors tab in Settings, listing each mirror with its destination, the events it accepts, how many batches are waiting and its on/off switch

Pro feature. Mirrors are part of Plugixa Activity Log Pro. See the Free vs Pro matrix.

Three kinds of mirror

Settings -> Mirrors -> Add mirror. A site can have up to 20.

Type You give it What is sent
Syslog server Host, port (514 by default) and transport: UDP, TCP or TLS One RFC 5424 message per event, from plugixa-activity-log, with the event code, user and IP address as structured data
HTTPS endpoint (JSON) An https:// URL and an optional bearer token A POST with source, site and an events list, one request per batch
Log file (JSON lines) How many days to keep files (14 by default) One JSON object per line, one file per day

A mirrored event is the whole event: time, code, severity, area, user, role, IP address, the object and the details. That is more than an alert carries, because a mirror is a copy and an alert is a message.

Per-mirror filters

Each mirror has its own filter, so one site can send everything to a file and only the serious events to a SIEM that bills by volume.

Filter Effect
At least this severe Only events of this severity or higher. Any sends all.
Only these areas Only events in these areas. Empty means every area.

Mirror is on pauses a mirror without deleting it.

The queue, and what happens when a receiver is down

Nothing is sent on the request that recorded the events. At the end of that request, the events each mirror accepts are put in a queue, one batch per mirror. WP-Cron delivers them within moments.

When delivery fails:

  1. The batch is retried after 1, 2, 4 and 8 minutes.
  2. That mirror’s later batches are held back meanwhile, so events arrive in the order they happened.
  3. After 5 attempts the batch is dropped and the log records Mirror “…” could not deliver events after 5 attempts (event 9500), at most once an hour per mirror.

The Waiting column shows how many batches a mirror has queued. A number that keeps growing is a receiver that is not answering.

That failure event is the one event never mirrored: a dead receiver would otherwise queue its own failure to itself for ever. Everything else in the plugin’s own trail - settings changes, exports, archiving - is mirrored, because that is exactly what an off-site copy is for.

The test button

Send a test event delivers one event to that mirror straight away, outside the queue, and reports the result: delivered, or the reason it was not. Test before relying on a mirror; a firewall rule is easier to find now than after an incident.

The private-network rule

A mirror is a connection your server opens to an address somebody typed. Left unguarded, that is a way to reach machines behind the site that the internet cannot.

So a destination is refused when it is this machine, a local name (localhost, or a name ending in .localhost, .local or .internal), or a private, loopback, link-local or reserved address. It is checked when you save and again when sending, against what the host name resolves to at that moment.

HTTPS mirrors must use https://, and redirects are not followed. Any 2xx answer counts as success.

The override, for syslog only

Log collectors very often sit on the local network, which the rule above forbids. Allow syslog servers on the private network, on the Mirrors tab, lifts the rule for syslog mirrors.

  • It is off by default. Switch it on only when your collector really is on the LAN.
  • It never applies to HTTPS mirrors. Those stay public-only whatever the setting says.

Where the file mirror writes

wp-content/uploads/plugixa-activity-log/mirror/, in files named after the mirror, a random key and the date, ending in .jsonl. Files older than the mirror’s keep period are deleted.

The folder sits under uploads because that is the one place WordPress guarantees is writable. That also makes it a place a browser could ask for, so it is protected twice:

  • A deny-all .htaccess and an empty index.php block requests and listings.
  • Every file name carries a random key that is fixed per mirror, so a file cannot be guessed.

On Apache the folder is not web-accessible. nginx ignores .htaccess, so there the random file names are the only protection until you do one of two things.

The Health screen tells you which case you are in. Once a file mirror exists, Health shows a File mirror folder check. The site asks its own web server for a harmless test file in the folder and reports what came back:

The check says What it means
Not reachable from the web The web server refused the request. Nothing to do
Reachable from the web The web server served the file, so it would serve the log too. Fix it now
Outside the web root The folder is not under WordPress at all, so no address leads to it
Could not be checked The site could not make a request to itself. Try a file from the folder in a browser

To fix Reachable from the web, either add a rule to the server that denies /wp-content/uploads/plugixa-activity-log/, or move the folder out of reach altogether with one line in wp-config.php:

define( 'PLUGIXA_ACTIVITY_LOG_MIRROR_DIR', '/var/log/my-site/activity' );

The folder must exist or be creatable, and writable by PHP. A folder outside the web root is the only protection that does not depend on how the web server is configured, and it is also where a log shipper usually wants to read from. Developers can set the same thing with the plugixa_activity_log_mirror_directory filter.

Secrets

A bearer token is sent as Authorization: Bearer .... After saving it is shown only as •••• plus its last four characters; leave it as it is to keep the saved token.

Creating, changing or deleting a mirror is recorded in the log (event 9501). Deleting a mirror also drops whatever it still had waiting.

Troubleshooting

Symptom Usual cause
“Addresses on this machine or the private network are refused” The private-network rule. For syslog on a LAN, use the override.
The override is on and an HTTPS mirror is still refused It applies to syslog only, by design.
Waiting keeps growing The receiver is not answering. Use Send a test event for the reason.
Event 9500 A batch failed five times and was dropped. Those events are still in the log.
Nothing arrives on a quiet site Delivery runs through WP-Cron, which needs traffic or a real cron job.
Some events are missing at the receiver The mirror’s severity or area filter excluded them.
The file mirror reports an error The uploads folder is not writable.
A file can be opened in a browser nginx, or any server that ignores .htaccess. Health shows Reachable from the web. Add a deny rule for the folder, or move it with PLUGIXA_ACTIVITY_LOG_MIRROR_DIR.

What to do next

  • Send chosen events to people instead of everything to a machine: Alert Rules PRO.
  • Keep old events searchable on the site: Archive PRO.
  • Check the scheduled jobs: Health.

Quick Links