# How to Set Up the OmniRoute Desktop App on Windows, macOS, and Linux Using Electron

> Easily set up the OmniRoute desktop app on Windows macOS and Linux. This guide explains how to install the Electron-based application with its native system tray and Nextjs server.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-07-04

---

**OmniRoute provides a full-featured Electron-based desktop client that bundles a Next.js server, creates a native system tray interface, and supports Windows, macOS, and Linux through platform-specific installers built with electron-builder.**

The **OmniRoute** repository (`diegosouzapw/OmniRoute`) ships a cross-platform desktop application that wraps a local AI gateway. When you set up the OmniRoute desktop app, you install a self-contained Electron client that automatically manages a Next.js backend, eliminating the need for separate server configuration.

## Architecture Overview

The desktop client follows a three-layer architecture that separates native window management from secure UI communication.

### Main Process

The **main process** ([`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js)) creates the native `BrowserWindow`, manages the system tray, and spawns the Next.js server. It handles **single-instance locking** via `app.requestSingleInstanceLock()` to prevent multiple windows, bootstraps the server using `startNextServer()`, and coordinates auto-updates through `electron-updater`.

### Preload Script

The **preload script** ([`electron/preload.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/preload.js)) runs in a sandboxed context and exposes a minimal API to the React frontend via `window.api.*` methods. This bridges the gap between the main process and renderer without exposing full Node.js capabilities to the UI.

### Package Definition

Build configuration lives in [`electron/package.json`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/package.json), which declares npm scripts including `electron:dev` for hot-reload development and `electron:build` for production binaries. The `electron-builder` configuration targets **Windows** (`nsis`), **macOS** (`dmg`), and **Linux** (`AppImage`).

## Installation Methods

You can install the OmniRoute desktop client either through the global npm CLI or by building directly from source.

### Installing via npm (Recommended)

The quickest way to set up the OmniRoute desktop app uses the packaged CLI, which automatically detects your platform and launches the correct Electron binary.

```bash

# Install globally on Windows, macOS, or Linux

npm install -g omniroute

# Launch the desktop client (opens window + system tray)

omniroute

```

On first launch, the client automatically generates security secrets (`JWT_SECRET`, `STORAGE_ENCRYPTION_KEY`, `API_KEY_SECRET`) if missing and persists them to `DATA_DIR/server.env`.

### Building from Source

For custom builds or development work, clone the repository and use the provided npm scripts:

```bash

# Clone and install dependencies

git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute
npm ci

# Run in development mode with hot-reload and unsafe-eval CSP

npm run electron:dev

# Build production binaries for current platform

npm run electron:build

```

The `electron:build` script produces `omniroute-<version>.exe` (Windows), `OmniRoute-<version>.dmg` (macOS), or `OmniRoute-<version>.AppImage` (Linux) depending on your operating system.

## Platform-Specific Setup

While the core functionality remains identical, each platform handles data persistence, autostart, and window styling differently.

### Windows Setup

On Windows, the NSIS installer creates shortcuts and registers the application in `%APPDATA%\omniroute` for data storage. The installer handles startup shortcuts automatically, and the system tray icon provides access to port configuration and update checks.

### macOS Setup

The macOS build generates a signed `.dmg` that installs to `/Applications`. The app uses a hidden title bar (`titleBarStyle: "hiddenInset"`) for a native look and stores data in `~/Library/Application Support/omniroute`. The `resolveNodeExecutable` helper ensures the bundled Node binary aligns with Electron's version to avoid dock icon duplication.

### Linux Setup

Linux users receive either an `AppImage` or `.deb` package. Data persists to `~/.config/omniroute` (or `$XDG_CONFIG_HOME/omniroute`). The client supports headless launching via `--headless` flag, and autostart integration creates a `.desktop` file in `~/.config/autostart` using the `enableLinuxDesktopAutostart` function.

## How the Desktop Client Works

Understanding the boot sequence helps troubleshoot setup issues and customize configuration.

### Server Bootstrapping and Secrets Generation

When the main process starts, it calls `startNextServer()` to launch the Next.js backend as a child process using the same Node binary as Electron (`resolveNodeExecutable`). The client polls `http://localhost:20128/api/monitoring/health` via `waitForServer()` before displaying the UI, ensuring the dashboard loads only after the server is ready.

### Content Security Policy

The main process enforces CSP via `session.defaultSession.webRequest.onHeadersReceived` to protect against XSS while allowing `unsafe-eval` during development. This security boundary ensures the React UI cannot execute arbitrary code despite running with Node.js integration disabled.

### System Tray and IPC Communication

The system tray persists across restarts and provides quick actions for opening the dashboard, changing ports, and quitting. The preload script exposes methods like `window.api.send('change-port', 3000)` and `window.api.invoke('check-for-updates')`, which trigger corresponding handlers in [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js).

### Auto-Update Mechanism

The `setupAutoUpdater` function configures `electron-updater` to fetch releases from GitHub. Updates download silently and install on application quit, with progress streamed to the renderer via the `update-status` IPC channel.

## Configuration and Customization

After initial setup, you can modify runtime behavior through the tray menu or direct IPC calls.

### Changing the Server Port

To change the port from the default `20128`, use the IPC bridge from the renderer:

```javascript
// Request port change via React UI
window.api.send('change-port', 3000);

```

The main process executes `changePort(3000)`, restarts the Next.js server, updates the tray menu, and broadcasts a `port-changed` event to the UI.

### Enabling Autostart on Linux

Toggle automatic startup programmatically or via the tray:

```javascript
// Enable autostart (creates ~/.config/autostart/omniroute-desktop.desktop)
window.api.invoke('enable-autostart');

```

The underlying `enableLinuxDesktopAutostart` function (lines 11213–11238 in [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js)) writes the desktop entry, while `disableLinuxDesktopAutostart` removes it.

### Checking for Updates Manually

Trigger update checks outside the automatic schedule:

```javascript
// Check for GitHub releases
window.api.invoke('check-for-updates');

```

This fires `electron-updater.checkForUpdates()` and streams status back through the established IPC channel.

## Summary

- **OmniRoute** provides an Electron-based desktop client that bundles a complete Next.js server, eliminating manual server configuration.
- Install via `npm install -g omniroute` for immediate use, or build from source using `npm run electron:build` for custom binaries.
- The **main process** ([`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js)) handles window creation, server lifecycle, and auto-updates, while [`electron/preload.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/preload.js) secures IPC communication.
- Platform-specific installers target Windows (`nsis`), macOS (`dmg`), and Linux (`AppImage`), with data stored in standard OS directories (`%APPDATA%`, `~/Library/Application Support`, `~/.config`).
- The client enforces **single-instance locking**, auto-generates encryption secrets, and polls server health before displaying the UI.
- System tray integration and IPC methods allow runtime configuration of ports, autostart settings, and manual update checks.

## Frequently Asked Questions

### What is the default port for the OmniRoute desktop server?

The desktop client starts the Next.js server on **port 20128** by default. You can change this after initialization through the system tray menu or by sending a `change-port` IPC message from the renderer, which triggers the `changePort()` function in [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js) to restart the server on the new port.

### Where does the OmniRoute desktop app store encryption keys and secrets?

On first launch, the client auto-generates `JWT_SECRET`, `STORAGE_ENCRYPTION_KEY`, and `API_KEY_SECRET` if they do not exist, persisting them to `DATA_DIR/server.env`. This file lives in platform-specific data directories: `%APPDATA%\omniroute` on Windows, `~/Library/Application Support/omniroute` on macOS, and `~/.config/omniroute` on Linux.

### Can I run the desktop client without the graphical interface?

Yes. On **Linux**, you can launch the client in headless mode using the `--headless` flag, which starts the Next.js server and system tray without rendering the BrowserWindow. This is useful for server environments where you need the API gateway but not the dashboard UI.

### How does the application handle automatic updates?

The desktop client uses `electron-updater` configured in [`electron/main.js`](https://github.com/diegosouzapw/OmniRoute/blob/main/electron/main.js) to poll GitHub releases. When an update is available, it downloads in the background and installs automatically when you quit the application. You can also manually trigger checks via the tray menu or the `check-for-updates` IPC channel.