Setup — Portal Configuration Reference
Setup is the Administrator-only configuration area of the portal (setup.php). It replaced the old approach of editing one very large config.php: almost every setting is now entered in a browser, checked live, and stored in the portal_settings database table.
This document describes how Setup works as built. For installing the portal, see QuickStart.md (the minimum to reach sign-in) and Install.md (everything outside the portal).
Where to find it
Administration → Setup, inside the Administration submenu of the nav drawer. It is visible to Administrators only (the Administrator tier in USERLEVEL_LABELS; Grid Staff do not see it).
The page has tabs across the top (setup.php?section=…). Each tab shows a status badge — for example Not configured, Check cron or Check paths — so the tab bar doubles as a progress overview. Nothing forces an order, and nothing blocks the rest of the portal while Setup is incomplete: unconfigured features simply degrade (placeholder images and tiles, “RemoteAdmin is not configured” messages) rather than failing.
What is still in config.php
Only settings that cannot sensibly live in the database:
| Setting | Why it stays |
|---|---|
PORTAL_BASE_URL | A wrong value gets baked into emails and shared links already sent, and can’t be fixed afterwards. |
DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASS, DB_CHARSET | Needed to open the database in the first place. |
USERLEVEL_LABELS (and its helper functions) | The numeric keys are relied on throughout the code, including the check that gates access to Setup itself. Editing them through a web form risks locking administrators out. |
Pre-login checks
Before sign-in is possible, the public pages run startup checks (includes/preflight.php): config.php loads, the required constants are set (not sample values), the database opens, and the portal’s database user has the minimum grants for sign-in (UserAccounts, portal_sessions, portal_settings). A failure shows a generic “This portal isn’t ready yet” page; the real reason is logged on a line starting SVPortal preflight:. Setup’s Database tab then covers everything beyond that minimum. See QuickStart.md and Install.md.
The tabs
| Tab | Contents |
|---|---|
| Database | Live checks of the connection, access to the OpenSim tables, and grants on the portal_ tables, with a green “Database OK” banner when all four checks pass. Also the ALLOW_OS_DATABASE_WRITES master switch. |
| ROBUST | ROBUST_HOST, private and public ports, public host, and the derived login, asset and map-tile URLs; a live “does ROBUST respond” check; a collapsed “Additional information” section showing the matching Robust.ini values; a security note about the private port. |
| RemoteAdmin & Cron | REMOTEADMIN_HOST, password and enable switch; a region scan that tests RemoteAdmin against each region; a collapsed box showing the [RemoteAdmin] section each simulator needs (key access_password); the crontab lines using the portal’s real cron/ path; per-job “has it run” status; and an OAR backup path check (default or not-a-directory shows a red message on the OAR job and a Check cron badge). A “Setting up the cron jobs” help section stays open until a job has confirmed running. |
| Identity | GRID_NAME, display name, subtitle, email “from” name. A GRID_NAME of “This Grid”, “My Grid” or “Your Grid Name” counts as a placeholder (red warning, Not configured badge). |
| Estates | The region-level and estate-level feature flags (ENABLE_*). Each flag shows a badge (Grants OK, Grants needed, Needs OS Database Writes), a ✓/✗ line per table and privilege it needs, and — when something is missing — the exact GRANT statements with your database and user filled in. The badge is advice and does not block the switch. The user-management, partnership and clear-presence flags show the same way on the General tab. |
| File Settings | Every upload, OAR and asset-cache folder, size limit and timeout, plus TINYMCE_PATH. Four collapsible groups, a one-line description per setting, live ✓/✗ folder checks (run as the web server user), and “How to set this up” guides with commands pre-filled from the saved values. Badge Check paths while the OAR path is still the default. |
| General | Email/SMTP, password policy, session and timeout settings, display and feature toggles, world map tuning, in-world notification settings (grid robot, relay access code), and the remaining miscellaneous settings. |
How saving works
There are two control types, and they behave differently on purpose:
- Sliding switches save instantly, with no Save button — the Display & Feature Toggles group, the default-theme dropdown, and the feature-flag and OS-write switches (which reload the page so their grant checks refresh).
- Plain checkboxes are saved by the form’s Save button. Any form containing checkboxes carries a note saying so (RemoteAdmin, Email, Password Policy, Everything Else).
Status is computed live
There is no stored “configured” flag to fall out of date. Each tab’s status comes from the saved values themselves:
- Empty or null → not configured.
- Still equal to a shipped placeholder value (for example
grid.yourgrid.example, or aGRID_NAMEof “This Grid”) → not configured. The list of placeholder values is kept in one place (includes/settings_data.php) so it can’t drift from the sample defaults. - Otherwise → configured. This does not mean reachable; a configured-but-unreachable ROBUST host is a runtime condition, and the live checks report it separately.
It corrects itself the moment a field is fixed. Checklist lines are worded to state what is true in either state (“Database: connected” / “Database: not connected”), so a ✗ says what is wrong rather than just describing the passing case.
Secrets
Values such as REMOTEADMIN_PASSWORD, SMTP_PASSWORD and INWORLD_RELAY_ACCESS_CODE are stored readable in portal_settings, because the portal has to send them on to other services. Each secret field shows a status line (saved / none / still the sample value) rather than the value.
Reveal… lets an Administrator see a saved secret. It asks for the administrator’s own portal password, then shows the value in a dialog that closes itself after 60 seconds. Five wrong passwords lock Reveal out for that session for five minutes. Each reveal and each failed attempt is written to portal_log (setup_secret_revealed / setup_secret_reveal_failed) naming only the setting, never the value; if portal_log can’t be written, it is recorded in the PHP error log instead and Reveal still works. Reveal covers those three settings only, not DB_PASS.
Storage
All Setup settings live in one key/value table, portal_settings (setting_name, setting_value), with setting_name matching the old config.php constant name exactly. A new setting needs no schema change, just a new row. Array-valued settings (for example STARTER_AVATARS) are JSON-encoded in the same column.
The database is the source of truth: once a value has a row, config.php is no longer consulted for it. Code reads settings through the get_effective_…() getters in includes/settings_data.php, which fall back to a safe default when no row exists.
Upgrading an existing portal
Two routes bring existing config.php values into the database:
- Automatic, per setting. Each getter copies the value from
config.phpthe first time it is needed and no row exists. Opening a Setup tab renders every field on it, so a tab visit imports all of that tab’s settings at once. importsettings.php, deliberate and complete (recommended). Run once from a shell, before first opening Setup:sudo php importsettings.phpfrompublic/. It imports every migrated setting, prints a diff, backs upconfig.phpto the folder abovepublic/and comments out the migrateddefine()lines. It needs root, or any user with write access toconfig.phpand to that parent folder; without that the import still completes and only the trim is skipped. SeeInstall.mdfor details.
Placeholder values are imported too, on purpose: a copied-over YourRemoteAdminPassword is correctly shown as “not configured” rather than the import inventing a configured state.
Why Setup does not edit OpenSim’s ini files
Rewriting an operator’s live OpenSim.ini or Robust.HG.ini was ruled out: a bug could break a production region for the audience least equipped to recover it. Instead Setup shows the exact snippet each section needs, built from the operator’s own saved values, says which file and section it belongs in, and which process to restart (a region restart and a ROBUST restart are different actions with different impact). The operator pastes it by hand.
Not implemented
- Forced first stop. An earlier design had Administrators land on Setup → ROBUST with a dismissible modal while ROBUST was unconfigured. This was not built; the tab badges serve as the prompt.
- Automatic restarts from Setup after a section is saved.
- Editing OpenSim ini files (see above).
