Configuration
GEM's server configuration lives in gem.json at the install root, loaded at startup. The standard installer writes a working gem.json for you; this page explains the settings you're most likely to change.
gem.json holds server bootstrap settings — how to reach the database, which ports to bind, whether HTTPS and the remote tunnel are on. Everything else (devices, zones, users, macros, attributes) is stored in the database and configured through the admin interface, not this file.
Database connection
{
"data": {
"connection": {
"host": "localhost",
"port": 5432,
"user": "gem_user",
"password": "gempass",
"database": "gem_db"
},
"sequelize": {
"dialect": "postgres",
"schema": "gem",
"timezone": "America/Chicago"
}
}
}
connection— how GEM reaches PostgreSQL. The installer creates this database and user; change these values only if you point GEM at a different database.sequelize.schema— GEM keeps all of its tables in thegemschema.sequelize.timezone— set this to the site's local timezone so schedules and history line up with wall-clock time.
Ports and HTTPS
{
"port": 3000,
"ssl": {
"enabled": false,
"port": 8443,
"http_port": 8080,
"auto_regenerate": true
}
}
port— the HTTP port GEM serves on (default3000).ssl.enabled— turn on HTTPS. When enabled, GEM serves HTTPS onssl.portand HTTP onssl.http_port.
Remote access (tunnel)
{
"tunnel": { "enabled": true },
"external_url": "https://your-site.example.com"
}
When the tunnel is enabled, GEM establishes a secure outbound connection for remote access — no inbound firewall ports need to be opened.
You can also turn the tunnel on or off at runtime — without editing gem.json or restarting — by setting a tunnel system attribute (a JSON value such as {"enabled": true} or {"enabled": false}) from the admin System Attributes grid. The attribute overrides the gem.json value and replaces the whole tunnel object, so include every field you need. Live connection status is shown by the Orchestrator Tunnel dashboard widget.
Authentication is always on
There is no configuration that turns authentication off. Every socket event, every REST call and every camera stream connection is checked against a signed-in session, on every deployment, and there is no key you can set to change that.
Earlier versions carried a bypass_auth flag intended for unusual installations. It
did far more than its name suggested — one boolean skipped the session check on every
socket packet, the session-token comparison, session ownership, remote-access
restrictions, the REST surface and the camera stream guard, and marked every incoming
connection as already authenticated. Anything that could reach the controller's port
had full control of the building. It has been removed.
If your gem.json still contains the key it is simply ignored, and the server log
says so once at boot:
ignoring retired config key: bypass_auth - authentication is now always enforced — remove this key from gem.json
Delete the line. If a panel or kiosk was relying on it to skip signing in, give that device its own account — a PIN login on a role scoped to just the UIs it needs is the supported way to run an unattended screen, and unlike the old flag it applies to that one device rather than to everyone who can reach the port.
Real-time connection origins
GEM checks the browser Origin on every real-time (socket) connection so a page on
another site can't open a socket against your controller. Nothing needs configuring
for a normal install — the check accepts any page GEM itself served, which covers
LAN access by IP or hostname, HTTPS, the tunnel hostname, and the mobile apps.
Non-browser clients, which send no origin at all, are unaffected.
One deployment shape needs a hint: a reverse proxy in front of GEM that rewrites the
Host header and doesn't set X-Forwarded-Host. The configured internal_url and
external_url are already accepted, so set those first. For anything else — a kiosk
or dashboard served from a different hostname — list the extra origins:
{
"socket_origins": ["https://kiosk.example.com"]
}
If real-time updates stop working after an upgrade and the server log shows
socket handshake rejected, cross-origin:, the logged origin is the value to add.
As a last resort the check can be turned off entirely with
"socket_origin_check": false, but adding the origin is the better fix.
Camera stream connections
Camera thumbnails and live tiles are delivered over a separate real-time channel, and that channel authenticates every connection against the signed-in session before it will hand over a frame. Nothing needs configuring — the apps and the admin interface present the right credentials automatically.
If camera tiles go black and the server log shows rtsp connection rejected, the
connecting client has no valid session; signing in again is the fix. The check can
be turned off with "rtsp_auth_check": false, but be aware of what that means:
camera frames become available to anything that can reach the controller's port,
including devices on a guest or IoT network. Leave it on.
How cameras are delivered is a separate choice: "rtsp_stream_mode": "video" sends
the camera's own H.264 to the browser instead of decoding it into stills on the
server, which costs the controller far less and gives the camera's real frame rate.
The default stays on stills. See
ONVIF → Stream mode: stills or video.
Camera audio is a separate opt-in again: "rtsp_stream_audio": true carries the
microphone of every video-mode camera through to the browser, where it stays muted
until a viewer presses the speaker button on a tile. It is off by default because it
changes what the system discloses about a room, not because of what it costs — set it
per camera with the stream_audio attribute where only some cameras should carry it.
See ONVIF → Audio.
Notifications
gem.json carries the transport settings for outbound email (mail) and SMS (sms) used by alerts and notification profiles. Configure the recipients and rules themselves in the admin interface under notification profiles.
Updates
{
"update_url": "https://updates.mygem.us",
"update_key": "<your-key>"
}
These control where GEM pulls updates from. The installer sets them; you normally won't touch them.
The Encryption Key (.encryption_key)
GEM encrypts secure attributes (passwords, API keys, private keys) at rest using a key stored in a file named .encryption_key at the install root. It is generated automatically the first time the server starts.
.encryption_key — losing it is unrecoverableThis file is the key to every encrypted attribute in your database. If you lose it, those values cannot be decrypted and must be re-entered by hand.
- Back it up somewhere secure, separately from the database.
- Never commit it to source control (it is git-ignored by default).
- When migrating a system to new hardware, copy
.encryption_keyalong with the database.
GEM exposes secure download/upload of the encryption keys from the admin interface for backup and migration. See Concepts → Secure Attributes.