Documentation · Reference
Security and operations
How to run Pyrite on a local network, how the engine protects apps and data, and which checks are the responsibility of the people who build and approve apps.
01 /Use one address for the portal and apps
Single sign-on uses the engine’s session cookie. The browser associates cookies with the server’s hostname regardless of port. To share a session, open the portal and all apps using the same hostname or IP address.
For example, if you open the portal at http://192.168.1.20:8080/ and an app at http://server-app:8101/, the browser treats them as different hosts and the app asks you to sign in again. Choose one form of the address and use it everywhere, including bookmarks, links and emails. The addresses in this example are fictitious.
If each app has its own name (Network rules), whoever opens an app without being signed in goes through the portal, writes the password once and comes back to the app by itself: no cookie is valid for the whole domain. With name and port nothing changes (see Sign-in: one sign-in, wrong attempts, the console).
02 /Firewall and ports
- On first startup, Windows Security asks whether to allow
pyrite.exeon the network. Select “Private networks” and allow access. Windows asks again for each new program folder or executable, for example if you move the program to another folder. The old firewall rule stays in place until you remove it. - Other PCs need to reach the engine’s port (usually 8080) and the public app ports specified in their manifests.
- Pyrite reads the state of the Windows firewall and can create its own rule: installing the service creates it, the command
pyrite.exe firewall status | open | closemanages it, and Network rules have a “Windows firewall” box (see The Windows firewall). - Internal app ports (the public port plus 1000) respond only to the engine on the server. Keep them closed to the network.
- If you use a firewall other than Windows Firewall, open the same ports to the internal network only.
03 /Internal network only
Without a certificate the engine uses HTTP, so passwords and data travel across the local network in cleartext. You can enable HTTPS on the Certificates page. One certificate covers the engine and all app ports. You can use your company CA, a .pfx or .pem file, or an internal CA created by Pyrite. You can also have Let’s Encrypt (with the Cloudflare DNS or with port 443) and more than one certificate: see HTTPS and certificates. Some apps can be opened to the internet (Network rules), but only with HTTPS on, one app at a time and only for non-sensitive data. The console is never reachable from the internet.
04 /Central administration
- Administrator access goes through the engine console. Opening
/_/on an app port redirects to that app’s Data tab in the console. App ports reject administrative API calls. - Each app has a technical administrator with a random password that no one knows. Only the engine uses this account.
- There is also no direct sign-in to the engine’s PocketBase dashboard. The
/_/path leads to the console, and the engine’s superuser is a service account with a random password that is never written down. The executable does not include PocketBase’ssuperusercommand. - A console Owner can therefore open every app, while an Admin can open the apps they manage. Grant Owner access to a small number of people and protect their accounts with long passwords.
- PocketBase normally allows open registration. The engine directory disables it. The administrator adds people to the directory.
05 /The console and access levels
- Only Owners and Admins can enter the console, using their directory accounts. Anyone at User level stops at the sign-in page.
- Every console operation uses one rules table specifying the required access level and app scope. Operations absent from the table are denied.
- Console keys are held only in the engine’s memory and sent in a request header. They are never sent in a cookie. A console session closes by itself after 30 minutes without use (the time is changed in Network rules, from 5 minutes to 12 hours) and never lasts more than 12 hours from the sign-in. Restarting the engine invalidates all keys (see The console closes by itself).
- On every request, the engine rechecks the user. Disabling the account, changing its password or level, or removing access to an app invalidates the person’s keys.
- There are four levels: Owner, People Admin, App Admin and User. The People Admin manages the people and groups of their unit and does not see the apps; the App Admin manages their apps and does not see the people. Whoever was an Admin before stays “Admin (as in 0.7.5)”: they work only on their own apps and on people at User level, with the same limits as before. Whoever manages without being an Owner does not see the Owners: where one would appear they read “Owner”, with no email. Directory searches through relations are refused to them (see The console and the levels).
- Units keep the customers apart on one engine: what belongs to another unit “does not exist” for whoever does not manage it, and the engine decides it, not the page (see More customers on one engine: units).
- Two-factor authentication is a six-digit code from the phone, after email and password, for the console and for the portal. Five wrong codes in 15 minutes stop the code of that person for 15 minutes. An Owner can remove it from someone who lost the phone (see Two-factor authentication).
- The last active Owner cannot be deleted, disabled or moved to another level.
- Apps uploaded by an Admin remain stopped until an Owner approves them.
- The Advanced pages (PocketBase settings, SQL console and, if the administrator has created its own collections, the data registry) are available only to Owners. Changes there affect the engine registry directly without the validation performed by Pyrite’s pages. Collections managed by Pyrite (people, groups, grants, apps, portal home, engine settings and analytics) are hidden from the data registry. Their native PocketBase APIs return 403 to console requests except for the operations Pyrite’s pages use. Collection imports do not modify these collections. The “Superuser IPs” list cannot be viewed or changed from the console. “Impersonate” is disabled for everyone.
Importing people and groups from Excel on the People page respects access levels. An Admin can add only User-level accounts, only to groups they can edit, and with grants only to apps they manage. Other apps appear nonexistent to that Admin. Nobody can import an Owner. The import adds entries only and is applied in full or rolled back. Temporary passwords appear only in a file available for a single download within ten minutes. They are excluded from events, responses and notes.
Smart import on the Import tab writes directly to the app database with server privileges, outside the app’s API rules and routes. If an app relies on routes or hooks to maintain consistency (for example, movements, history or status), use app.json field import.consoleCollections to list only the collections where console import and undo are permitted. Set it to [] to permit none. If the field is omitted, the tab warns that all collections are visible. The two-stage import is atomic, with limits of 50,000 rows and 60 seconds of writes. “Undo” reverses the whole import, unless other records reference the imported ones or imported records have since changed. Imports from app pages require a recipe approved by the administrator (toolAccess) and observe its row limits. JSON files are limited to 128 MB per file and 16 MB per item.
06 /Access and sessions
- Every request to an app requiring sign-in passes through the engine, which checks the session and access grant. Revoking access takes effect immediately.
- The engine’s session cookie never reaches an app. Before forwarding any request, the engine strips all its own cookies except the language cookie, even on the ports of public apps.
- The app token must belong to the same person as the portal session. Otherwise the engine rejects the request.
- In apps requiring sign-in, identity fields are locked. Email, name and password come from the directory. Apps cannot change them or create users. No one can change their own role.
- State-changing requests that use the portal session, including portal sign-in and uploads from “Import preview”, are accepted only from the engine’s pages. An app page on another port cannot initiate them on someone’s behalf.
- The engine counts the wrong passwords for each real address, also behind a tunnel. From the internet 5 errors in 15 minutes block that address, and 10 errors on the same email block that email for one hour; from the local network you can always sign in. The console has its own count. The thresholds are changed in Network rules (see Sign-in).
07 /App isolation
Each database-backed app runs in its own process with its own data. The engine enforces three additional boundaries.
- A separate key for each app. The engine communicates with each app using its own unique key. The app receives the key at startup and immediately removes it from the environment so that app scripts cannot read it.
- Restricted internal port. An app’s internal port accepts only requests from the engine with the correct key. Another app or program on the same server cannot use that port to bypass the gateway.
- Confined scripts. App scripts (hooks and migrations) cannot start programs or terminate the process. They can read only files in the app folder and write only to its data folder,
state. Theapp.jsonmanifest, code inrelease, and logs are read-only to scripts. An app therefore cannot change its own access settings, roles or tools. The database cannot be used to read or write files outside the folder, either. Paths through symbolic links or Windows junctions inside the app folder are rejected even if the link points back into the folder. The only exception is thestatefolder itself. The administrator can relocate it to another drive using a junction (see Data, backups and disk space).
Engine tools called by app scripts, including import, operate within the same boundaries. They access files in that app’s folder and its own database.
An app cannot call the engine (console, portal) nor another app of the same server: it gets a refusal (403) and an event appears in the console. The limit, stated plainly: the fence greatly reduces what a script can do, but it is a defense inside the program. The script runs in the same process of the engine of that app, with the same Windows user. The full guarantee, one Windows user for each app, is not in this version: see What an app can do.
Outbound network
A fourth boundary controls calls that app scripts make outside the server. Scripts can reach only addresses declared in the app.json manifest’s network field (allow for HTTPS, or allowHttp to permit HTTP for internal systems that lack HTTPS). With no network declaration they can reach no addresses. The engine also verifies the actual address after DNS resolution. An exact hostname may resolve to an internal server. Wildcards are limited to public addresses. Each app’s Outbound network tab offers Block and Warn modes. Warn allows all calls and counts those that would have been blocked. Apps start in Block mode. The AI page shows calls to AI models and their costs.
Slow routes
The engine waits up to 4 minutes and 50 seconds for an app script route to respond. On timeout it returns a 504 with an explanation. If the app closes the connection without responding, even abruptly, it returns a 502. An app that is stopped or restarting returns the usual 503. The engine never retries a request it has already sent. Check the outcome before retrying because the route may have completed its work. Both 504 and 502 leave a warning in the engine history. The engine reuses connections to apps to avoid spurious “unavailable” messages under load.
08 /Limits of engine protection
The engine controls who can enter an app and enforces its isolation. The remaining protections depend on the app and whoever approves it.
- The app’s PocketBase API rules and code determine what a person can view and change. Hiding a button leaves the underlying data accessible unless server-side rules protect it. Before opening an app to users, test it with a low-privilege role and confirm that it exposes only the intended data. The agent standard defines mandatory rules and checks.
- An app’s code controls its own data. An incorrect hook can delete or change its records. Read the delivery notes and check the hooks before enabling a new app.
- An import from the Import tab writes directly to the app database. Field validation applies. Automatic app rules triggered when someone adds a record through an app page do not run.
- In Warn mode the outbound network blocks nothing. The same applies to conflicting edits (two people editing the same record simultaneously) when the manifest sets
"concurrency": "warn". The engine only counts what it would block: protection requires Block mode and"strict". See theapp.jsonmanifest. - On Windows the memory limit in the manifest is advisory. An app may exceed it.
- “Upload app” validates ZIP package size, paths, links, the manifest, ports and folders. In this alpha the scores shown for “Security check” and “Standard compatibility” are only indicative. They do not examine the code or constitute a security review. The engine installs the app in a stopped state so the administrator can review it first. An Admin’s upload must also be approved by an Owner before it can start.
- Apps with public access are available to anyone on the network. Use them only for material anyone may read. Hiding an app tile on the portal home page does not restrict access to the app.
- Units separate people, groups and apps for the engine, but the scripts of the apps of all the units run on the same computer. Do not upload scripts written by someone you do not trust counting only on the fence (see What an app can do).
09 /Credentials and passwords
- Create the first Owner on the first-start page. This page opens from any computer of the network, never from the internet, and only until an Owner exists. It asks for a code that Pyrite prints on the server, so nobody else on the network can take the engine before you. After that, it redirects to the console. Protect Owner accounts with long passwords.
- Initial passwords generated through “Import from apps” are shown once. Deliver them in person or through a private channel.
- User passwords must meet the engine’s rules for uppercase and lowercase letters, a number, a special character and the minimum length set in Engine settings. Anyone receiving a password from the administrator must change it on first sign-in. Everyone can change their own password through the portal. The administrator resets forgotten passwords for Admins and Users. An Owner can reset either level, and an Admin can reset passwords for people at User level.
- Owners who forget their password can reset it by email if engine mail is configured and the application address is correct. The single-use link opens the engine’s reset page and expires after 30 minutes. An Owner can also use
pyrite.exe owner reset EMAILon the server. Theowner createcommand on that server creates an Owner. Anyone able to run commands on the server can therefore obtain console access, so secure the server itself.
10 /Data, backups and disk space
- App data is stored in
apps\<id>\statefor each app. Engine data is incontrol\pb_data. Protect these folders. - To move an app’s data to another drive, replace
apps\<id>\statewith a Windows junction (mklink /J) pointing to the new location outsideapps. Stop the app, copystateto the new location, remove the original folder, create the junction and restart the app. Scripts, import, backup and restore will keep working. The exception applies only tostateitself. Scripts and import reject links further down (such as onstate\pb_data) or elsewhere in the app folder. Before archiving this app, restorestateto its original location. Archiving does not copy the junction and stops with “copy failed”, leaving the app stopped with its data intact. - Backups stay on the engine drive. To protect them, enable “Copy backups to a network folder” in Engine settings. Each day the engine copies them to a NAS or another drive and verifies each file with SHA-256. Alternatively, download copies regularly and store them elsewhere.
- Allow disk space for safety copies created during restores (the engine retains the last three per app), registry backups created before updates (
pre_migrazione_<data>.zip), engine update restore points undercontrol\aggiornamenti, and apps inarchivio. Theritorno_<data>folders incontrol\aggiornamenticontain personal data and app data written after an update. The engine never removes them. Delete them manually when no longer needed. Certificate keys are incontrol\certificati, accessible only to SYSTEM, Administrators and the engine account. Backups exclude these keys. - Files uploaded to “Import preview” are stored in
control\tmp_import. The limit is 100 MB per file and ten files per person. The engine deletes them two hours after their last use. - The engine removes metrics after 30 days. Engine events are in the history (
control\storico), which nobody deletes from the console: it lasts one year by default and an Owner can lengthen it up to ten years, but not shorten it (see The engine history).