Skip to main content

Installation

GEM can be installed on any Debian-based Linux system (Ubuntu, Debian, etc.) using either the remote installer or a local development setup. This includes Windows systems running WSL (Windows Subsystem for Linux). The installer handles system dependencies, database configuration, notifications, and service creation through a web-based installer.

System Requirements

  • OS: Ubuntu 20.04+ or compatible Debian-based Linux distribution (including WSL on Windows)
  • RAM: 2 GB minimum
  • Disk: 10 GB free space
  • Network: Internet connectivity (for package installation)
  • Privileges: Root / sudo access

Quick Install

Install GEM with a single command:

curl -fsSL https://updates.mygem.us/install.sh | sudo sh

This downloads the latest self-extracting installer (.run file), verifies its checksum, and runs it. The installer:

  1. Prompts for an installation directory (default: ~/Apps/GEM)
  2. Installs system dependencies (build tools, PostgreSQL, Node.js 22, FFmpeg, etc.)
  3. Installs npm packages
  4. Launches the installer in a browser

Installation Methods

Remote Installer (Production)

The recommended method for production deployments. The install.sh script served by the update server:

  1. Downloads the latest versioned .run installer
  2. Verifies the MD5 checksum
  3. Makes the installer executable and runs it

The .run file is a self-extracting archive (built with makeself) containing the pre-built GEM application and a setup.sh script.

Local Install (Development)

For development environments where you have the source code:

sudo ./bin/install.sh

This script:

  1. Installs system dependencies via apt-get
  2. Installs or upgrades Node.js to v22
  3. Runs npm install
  4. Launches the installer (bin/install.js)

Installation progress is logged to logs/install.log.

Installer

After dependencies are installed, the installer launches as a local web server and opens in your browser. It walks through six steps:

Step 1: Welcome & Preflight

Displays system requirements and runs automatic preflight checks:

CheckRequirement
Disk space10 GB free
Memory2 GB RAM
Sudo accessRunning as root
PostgreSQLInstalled (or will be)
NetworkInternet connectivity
Architecturex86_64 or ARM
GEM serviceDetects existing installation

Node.js v22 is bundled with the installer, so a system Node install is not required.

If an existing gem.json is found, the installer loads the current configuration and creates a timestamped backup (gem.json.bak.YYYY-MM-DDTHHMMSS).

Step 2: Dependencies

Select which components to install. Each dependency is installed individually with progress tracking:

ComponentDescriptionDefault
PostgreSQLDatabase serverChecked
Node.jsJavaScript runtime (v22)Checked
System Dependenciesbuild-essential, git, mDNS, nmap, arp-scan, FFmpeg, adbChecked
Python & ModulesPython 3, pyatv (Apple TV), lennoxs30api, netaudioUnchecked
Matter (chip-tool)BlueZ, Avahi, and chip-tool for Matter device commissioningUnchecked

Dependencies use two installation mechanisms:

  • [apt] packages are installed via apt install -y with a 5-minute timeout per package
  • [cmd] commands are executed via bash with a 10-minute timeout

Step 3: Database

Configure the PostgreSQL connection. For fresh PostgreSQL installations, the installer can create the database user and database automatically.

Fields:

FieldDefaultDescription
HostlocalhostDatabase server address
Port5432PostgreSQL port
Username(empty)Database user (created if "Create Database" is checked)
Password(empty)Database password (use "Generate" for a random password)
Database Namegem_dbDatabase name

Options:

  • Create Database -- Creates the PostgreSQL user, database, gem schema, all tables, and transfers ownership. Also configures pg_hba.conf for TCP password authentication if needed.
  • Seed Database -- Populates the database with the default theme data (create_theme.sql).
  • Test Connection -- Verifies Sequelize can connect with the provided credentials.

GEM Admin Account:

FieldDefaultDescription
Admin UsernameadminThe login you will use to access the GEM web interface. Recommended to change from the default.
Admin Password(empty)Leave blank to auto-generate a strong password — it is shown on the final screen and nowhere else.

If you set the password manually, it must be at least 12 characters and mix at least three of: lowercase, uppercase, digit, symbol. Click Generate for a strong default that satisfies the rule automatically.

The password you provide here is handed to the GEM server on first boot, used to seed the admin user, and then scrubbed from gem.json (the key is only ever encrypted at rest in the database after that).

Step 4: Notifications (Optional)

Configure email and SMS for system alerts. This step can be skipped and configured later from the admin panel.

Email (SMTP):

  • Host, port, username, password
  • From/to addresses
  • Test button sends a verification email

SMS (Telnyx):

  • From/to phone numbers
  • Telnyx API key
  • Test button sends a verification SMS

Step 5: Server Configuration

SettingDefaultDescription
Location Name(empty)Friendly name for this installation
External URL(empty)Public URL (for remote access / mobile app)
Service Port3000HTTP port for the GEM web interface
Timezone(auto-detected)Server timezone for schedules and logs
Enable SSLOffRun over HTTPS with auto-generated certificates
HTTPS Port8443Port for HTTPS traffic (when SSL enabled)
HTTP Port8080Port for HTTP redirect / CA download (when SSL enabled)
Auto-Regenerate CertsOnRenew certificates on expiry or IP change
Enable REST APIOnAllow external API access
Device AlertsOnSend alerts for device communication failures
Install as ServiceOnCreate a systemd service unit
Start ServiceOnStart GEM immediately after installation

The port field checks whether the chosen port is already in use before proceeding.

Step 6: Complete

Displays an installation summary and provides:

  • The URL to access GEM (e.g., http://localhost:3000/admin/setup)
  • The admin username and password you configured in Step 3 (if the password was auto-generated, it is shown here — copy it now; it is not shown again)
  • Service management command: sudo systemctl status gem

If "Start Service" was selected, the installer installs and starts the systemd service, then exits automatically.

Systemd Service

When "Install as Service" is selected, the installer creates /etc/systemd/system/gem.service:

[Unit]
Description=GEM by Harness Automation
After=network-online.target postgresql.service

[Service]
ExecStart=[dir]/node/bin/node [dir]/server.js
WorkingDirectory=[dir]
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=gem
Environment=NODE_ENV=production PORT=[port]

[Install]
WantedBy=multi-user.target

[dir] and [port] are replaced with the actual installation path and configured port.

Service Commands

# Check status
sudo systemctl status gem

# Start / stop / restart
sudo systemctl start gem
sudo systemctl stop gem
sudo systemctl restart gem

# View logs
sudo journalctl -u gem -f

# Enable / disable auto-start
sudo systemctl enable gem
sudo systemctl disable gem

WSL (Windows Subsystem for Linux)

GEM runs on WSL with Ubuntu or Debian. The installer automatically detects WSL and adapts:

systemd Requirement

The GEM service requires systemd, which is not enabled by default in WSL. If systemd is not active:

  • The installer disables the "Install as Service" and "Start Service" checkboxes
  • You can start GEM manually: ./node/bin/node server.js

To enable systemd in WSL, add to /etc/wsl.conf:

[boot]
systemd=true

Then restart WSL from PowerShell:

wsl --shutdown

After restarting, systemd will be active and the installer can create the GEM service normally.

PostgreSQL on WSL

PostgreSQL installs normally on WSL but may not auto-start. The installer handles this by explicitly starting and enabling PostgreSQL after installation, and checking its status before database operations.

Headless / SSH Installation

When no display server is detected (no DISPLAY or WAYLAND_DISPLAY environment variable), the installer runs in headless mode:

  • The browser is not auto-opened
  • The installer URL is displayed prominently in the terminal with a bordered banner
  • The installer is accessible from any browser on the network

This is useful when installing GEM over SSH on a remote server. Open the displayed URL in a browser on your local machine to complete the installer.

Configuration File

The installer saves all settings to gem.json in the project root. Key sections:

SectionContents
data.connectionPostgreSQL host, port, user, password, database
data.sequelizeSequelize options (dialect, schema, timezone, etc.)
mailSMTP host, port, auth, from/to addresses
smsTelnyx from/to numbers and API key
sslSSL enabled, HTTPS port, HTTP port, auto-regenerate
rest_apiREST API enabled
device_alertsDevice failure alerts enabled
external_urlPublic-facing URL
locationInstallation location name
update_urlUpdate server URL

Resume Support

The install.sh script tracks completed stages in logs/install_state.json. If the install is interrupted (network drop, reboot, crash), re-running install.sh skips already-completed steps:

  • System dependencies
  • Node.js installation
  • npm package installation

The state file is automatically removed after successful completion.

Existing Installation Detection

When the installer detects an existing gem.json:

  1. Creates a timestamped backup of the current config
  2. Loads existing configuration values into the installer fields
  3. Allows reviewing and modifying settings
  4. Supports Save & Exit to save configuration changes without re-running dependency installation

Uninstallation

Remove GEM using the uninstall script:

sudo ./bin/uninstall.sh

This interactively:

  1. Stops and disables the GEM systemd service
  2. Removes the service file and reloads systemd
  3. Optionally drops the PostgreSQL database and user (reads credentials from gem.json)
  4. Optionally removes the GEM application directory

The database is preserved by default unless explicitly confirmed.

Updates

GEM supports over-the-air updates from the update server (updates.mygem.us). The update system:

  1. Check: GEM periodically posts its installation_id to /check_update to see if a new version is available
  2. Download: If an update exists, GEM downloads the encrypted archive (.tar.gz.enc) from /pull_update
  3. Apply: The archive is decrypted and extracted to replace the application files

Updates are encrypted with AES and each version has its own encryption key stored on the update server. Only installations that are registered and enabled on the update server can receive updates.

Installation Registration

Each GEM installation has a unique installation_id (MD5 hash). When a new installation checks for updates:

  1. The update server auto-discovers it and creates a disabled entry
  2. An administrator enables the installation in the update server admin panel
  3. Subsequent update checks succeed and return available versions

Build & Publish Pipeline

For developers building and distributing GEM:

Building an Installer

npm run build:installer

This runs scripts/build-installer.sh which:

  1. Verifies dist/ exists (run npm run build first)
  2. Copies built files to a temp directory
  3. Generates a setup.sh bootstrap script
  4. Packages everything into a self-extracting .run file using makeself
  5. Outputs to install/gem-installer-{version}.run

Publishing an Update

node scripts/publish-update.js
  1. Runs a full build (npm run build)
  2. Creates an encrypted .tar.gz.enc archive of dist/
  3. Uploads to the update server at /push_update with authentication headers

Publishing an Installer

node scripts/publish-installer.js
  1. Runs build:installer to create the .run file
  2. Uploads to the update server at /push_installer with authentication headers

Both publish scripts require update_url and update_key in gem.json.

Troubleshooting

Installer Won't Start

Symptoms: install.sh exits with an error

Causes:

  • Not running as root -- use sudo
  • Not a Debian-based system -- apt-get is required
  • No internet connectivity -- required for package downloads

Database Creation Fails

Symptoms: Step 3 shows an error after clicking "Create Database"

Common Causes:

ErrorSolution
ECONNREFUSEDPostgreSQL is not running. Start it: sudo systemctl start postgresql
pg_hba.conf rejectionThe installer auto-configures this -- try again. Or manually add scram-sha-256 auth for 127.0.0.1/32
permission deniedEnsure the installer is running with sudo
does not existMake sure "Create Database" is checked
password authentication failedUser exists with a different password. The installer will update it if "Create Database" is checked

Connection Lost During Installation

The installer shows a "Connection Lost" modal with automatic reconnection. If the installer process was killed:

  1. Re-run sudo ./bin/install.sh (or the .run installer)
  2. The installer detects the existing gem.json and resumes from where you left off

Forgotten Admin Password

If you've lost the admin password and SMTP isn't configured for the email reset flow, run the recovery script with shell access to the host:

sudo -u gem node bin/reset-admin.js # resets the "admin" account
sudo -u gem node bin/reset-admin.js <username> # resets a named user

The script generates a random 16-character password, prints it to the terminal, and sets the must-change-password flag so you'll be prompted to choose a permanent password on first login. Shell ownership of the host is the security boundary — there is no equivalent network-exposed endpoint.

Service Won't Start

# Check service status and logs
sudo systemctl status gem
sudo journalctl -u gem --no-pager -n 50

Common Causes:

  • Database not running -- sudo systemctl start postgresql
  • Port already in use -- change the port in gem.json and the service file
  • Missing npm packages -- run npm install in the GEM directory