Skip to content

Remote configuration: settings published from the panel

How a configuration published in the Bastrel panel reaches your server, what it is allowed to change by itself, and what always waits for you.

Status: the API side and the resource side are written. Like the licence, this stays inactive in every source and development build: until the release package nothing here changes how Bastrel protects your server. The panel screens to write a configuration come with the panel.

Your local files (config/main.lua, config/modules.lua, config/whitelists.lua) are always the base. The panel can publish a configuration on top, but a panel, an API or a signing key that someone else got hold of must never be able to silence your alerts, lift a calibration, read a secret, or make your server ban people. So the server applies by itself only the timing of the synchronisation; every other change waits for a person with bastrel.admin (or the server console) to read it and accept it.

The server asks the API for its configuration about every 60 seconds (remoteconfig.pollS), and only when:

  • the licence is active (or in its offline grace), and the subscription has the panel configuration (plans Pro and Network); at startup, the stored configuration is used only under the same conditions (a licence that is not disabled, a last token that carries the feature, and the same tenant and server as the stored state; otherwise it is kept aside and your local files apply);
  • remoteconfig.enabled is not false.

Otherwise nothing is requested. Offline, the last valid configuration stays in force, then your local files.

A configuration is taken into account only if all of this is true:

  • the answer is signed by the API and the document is signed with the same key as your licence token;
  • it names your tenant and your server;
  • its hash (the ETag) is the one in the signed document, and the document really has that hash;
  • its signed token has not expired;
  • its version is not older than the newest one already accepted, and it is not larger than 32 KiB;
  • the whole document passes the same checks as your local files. One error, or one new startup warning, refuses all of it: the previous valid state stays, and the console says so once. A refused newer version also cancels the document that was waiting (its hash can no longer be accepted), and a refused answer is not downloaded again until the API publishes something else.

Only the fields listed in config/remote_allowlist.lua, one per line: the timing of the synchronisation itself (uplink.batchS, uplink.bansPollS, uplink.retryS, uplink.retryMaxS, remoteconfig.pollS, remoteconfig.retryMaxS), each inside the bounds of its own check. The rule for this list: a field that could make an alert or a detection quieter never belongs there. You may remove a line (that field then waits for you); adding one is your decision. The intervals of the licence (license.renewS, license.retryS, license.retryMaxS) are not in it and cannot be added: a licence that does not renew before its token expires drops to the local state and forces observe, which would silence your sanctions. They wait for your acceptance like the rest, and even accepted, renewS is refused above one day and retryMaxS above four hours.

Everything else: modes, overrides, thresholds and weights, the content of the lists, the honeypot names, the alert settings. The console tells you once per document:

[bastrel] remote config: 2 change(s) from the panel (version 7) wait for your approval. Run /bas config pending, then /bas config accept <hash>.
  • /bas config pending shows the changes, computed on your server from the document that is waiting (the panel never provides the diff), and its full hash. For a list it shows the items added and removed; a long value is cut with a visible mark (... (+N)) around the first difference; the output is paged (10 lines per page: /bas config pending 2), and /bas config accept is refused until you have displayed every page. The changes that decide what is detected come first (calibration lists, main.mode, sanctions and score thresholds). A list shows N -> M items (-> 0 items in plain words), each item added or removed, and the detection a shortened list cuts when it is known (entities.blacklist and BAS-GE-001, explosions.allowed and BAS-GE-010). Only the fields that differ from your config file are kept. At startup, each accepted field that replaces the value of your file is announced on the console; if you edited that field in your file after accepting, your file wins and the console says so.
  • /bas config accept <hash> accepts that document. The hash must be the full hash of the document waiting now: if a newer version arrived, the old hash is refused and you read the changes again.
  • Both need bastrel.admin or the server console.
  • An accepted configuration takes effect when the resource starts again (restart bastrel). The command says so.

Limit worth knowing: someone with bastrel.admin who is tricked can accept a change they did not read. Read the diff.

A list (honeypots, economy origins, rare items…) has a calibrated flag in your files that says “the owner checked this list on his server”. The panel can never set that flag. If a change alters the content of a calibrated list, accepting it also confirms the calibration of that list, and the command says which ones. If the content was changed and nobody confirmed it (for example the stored state was edited), the list falls back to calibrated = false at startup, with a warning: its rules stay in observe.

These are ignored with a warning, whatever the panel sends; the rest of the document is kept:

  • the calibrated, unverified and localOnly flags;
  • secrets, passwords, tokens, API keys, webhook URLs and the names of convars (any key containing secret, password, token, apikey, api_key, license_key or webhook, or ending in Convar);
  • modules.netevents.ownerCodes and modules.remoteconfig.enabled;
  • modules.logger, modules.discord, main.discord and main.locale: they are read before any remote configuration can exist, so a value would never be applied.

A block is never replaced by an empty value, by a value of another type, or by a table placed under a plain value, and a block marked localOnly is protected as a whole. The checks of every block (commands, bans, pipeline, scan, connection, convars, gameevents, and the startup check) apply to a remote document exactly as to your files.

To keep a whole block local, put localOnly = true in it (in config/main.lua, config/modules.lua, config/whitelists.lua, or in one of their blocks): nothing under it is changed remotely, applied or accepted.

An end of subscription (entitlement.active = false) only stops the cloud functions. It never turns off detection, automatic sanctions or the bans stored on your server.

In the panel, going back to an earlier configuration creates a new version that is a copy of the old one (the history is never rewritten). On your server it arrives like any other version: the fields outside the closed list wait for your acceptance.

config.remote_applied, config.remote_staged (with the diff, 50 lines at most), config.remote_accepted, config.remote_rejected (with the reason: token_bad_signature, token_expired, wrong_owner, etag_mismatch, hash_mismatch, stale_version, version_conflict, invalid_document, invalid_config), config.remote_ignored.

modules.remoteconfig in config/modules.lua: enabled (true), pollS (60, from 30 to 3600), retryMaxS (600, from 30 to 86400).