Skip to content
OneviumDocs
On this page

Remote gateway: Docker, HTTPS, and private management

Build from a matching package and configure persistent storage, HTTPS, SSH pairing, and restart/rollback checks.

When a remote gateway is useful#

Use a server-hosted gateway when you need a fixed HTTPS address or must accept business events while the computer is offline. The assistant still executes on its designated Onevium device. The gateway does not make an offline computer run; queued work has a deadline.

Interface screenshots use isolated example data; captions identify empty tokens and unsaved drafts. Follow the connection checks below to verify your deployment.

Prerequisite: obtain a matching deployment package#

Before continuing, have:

  • The complete deployment source package matching the desktop version, including server/gateway/Dockerfile, compose.example.yml, and the protocol/workers files referenced by the Dockerfile.
  • Working Docker Engine and Compose v2, server SSH access, a domain, and valid TLS certificates.
  • A dedicated persistent directory and a server account authorized to manage it.
  • A working Onevium installation and model connection.

If the package is unavailable, obtain it from the maintainer first. This guide does not invent a public image or require ordinary users to clone a private repository. The image name below is a local tag built on your server.

Run Docker commands from the package root on the server. Run the SSH forwarding command on the computer hosting Onevium.

Use origins for gateway settings: the gateway address, ONEVIUM_GATEWAY_PUBLIC_URL, and GATEWAY_URL in API examples contain only scheme, host, and optional port. If the interface shows https://gateway.example.com/api/v1 as the API address, use https://gateway.example.com for those values, removing /api/v1. The private management address is likewise only http://127.0.0.1:8430, without a management path.

Step 1: save remote mode and export the device public key#

In Onevium, open Channels → External Access → External access settings → Connection:

  1. Choose Remote gateway under Gateway location.
  2. Enter the planned https://gateway.example.com gateway address without /api/v1.
  3. Expand Advanced remote settings and choose Private connection via SSH. You can enter http://127.0.0.1:8430 as the planned private address and leave the token empty initially.
  4. Save first. Changing mode pauses external access; only then select Export device identity.
  5. Upload onevium-device-public.json to the server over a verified SSH connection.

Enter the remote gateway HTTPS address; the connection change takes effect after saving.

The file contains owner_id, device_id, and public_key, not a private key. Do not generate a substitute private key for the desktop executor. Export does not mean the device is paired, a listener is enabled, or a service is published.

Step 2: build a local image#

From the matching package root:

bash
docker build -f server/gateway/Dockerfile \
  -t onevium-gateway:preview-c2409f75f .

The Dockerfile uses Node 24.15.0 and builds dependencies inside the image. Do not rebuild native dependencies in the active desktop installation. A successful build produces an image, not a running deployment.

Prepare a new dedicated data directory. Check UID/GID using the server account that will also own SSH management access:

bash
id -u
id -g

This example uses /srv/onevium-gateway. Verify it is not another service's directory before creating it with the appropriate permissions:

bash
sudo install -d -m 700 -o "$(id -u)" -g "$(id -g)" /srv/onevium-gateway

Do not reinitialize or change ownership of an existing deployment. SQLite storage needs local/block storage with working file locks, not a shared multi-host database volume.

Step 3: configure Compose and environment variables#

Create gateway.env in the package root. Replace UID/GID with the preceding output, and use the real domain and paths:

dotenv
GATEWAY_UID=1000
GATEWAY_GID=1000
ONEVIUM_GATEWAY_IMAGE=onevium-gateway:preview-c2409f75f
ONEVIUM_GATEWAY_DATA_PATH=/srv/onevium-gateway
ONEVIUM_GATEWAY_PUBLIC_URL=https://gateway.example.com
ONEVIUM_GATEWAY_ENABLED=1
ONEVIUM_GATEWAY_ACCEPTING_REQUESTS=0
ONEVIUM_GATEWAY_CALLBACK_HOSTS=
VariablePurpose
GATEWAY_UID/GIDMatch container file access with the SSH management account
ONEVIUM_GATEWAY_DATA_PATHPersistent host directory mounted at /data
ONEVIUM_GATEWAY_PUBLIC_URLPublic HTTPS origin and expected public Host
ONEVIUM_GATEWAY_ENABLED=1Explicitly start the server listener
ONEVIUM_GATEWAY_ACCEPTING_REQUESTS=0Reject new work during setup while retaining management and existing-query paths
ONEVIUM_GATEWAY_CALLBACK_HOSTSComma-separated exact callback hostnames; empty blocks all callbacks

The supplied Compose file maps container 0.0.0.0:8420 to host 127.0.0.1:8420. Do not expose port 8420 directly to the public network.

The base Compose file does not forward the admission switch or callback allowlist. Create gateway.override.yml:

yaml
services:
  gateway:
    image: "${ONEVIUM_GATEWAY_IMAGE:?Set the local image tag}"
    environment:
      ONEVIUM_GATEWAY_ENABLED: "${ONEVIUM_GATEWAY_ENABLED:-1}"
      ONEVIUM_GATEWAY_ACCEPTING_REQUESTS: "${ONEVIUM_GATEWAY_ACCEPTING_REQUESTS:-0}"
      ONEVIUM_GATEWAY_CALLBACK_HOSTS: "${ONEVIUM_GATEWAY_CALLBACK_HOSTS:-}"

Do not skip this: adding unreferenced values to gateway.env does not automatically pass them into a container. Validate the merged configuration:

bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml config --quiet

Step 4: initialize identity and start with admission paused#

Replace the public-key mount with its real absolute server path:

bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml run --rm --no-deps --pull never \
  -v /srv/onevium-device-public.json:/device-public.json:ro \
  gateway init --identity-file /device-public.json

Expect Gateway identity initialized. No listener started. Initialization writes identity once. If the file already exists, inspect the existing deployment instead of deleting configuration to retry. Compose run runs a one-off initialization here without publishing the service ports.

Start the gateway:

bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml up -d --no-build --pull never gateway

Check private management and logs:

bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml exec -T gateway node dist/cli.cjs manage --path state
bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml logs --tail 50 gateway

The expected checks are management-state JSON and a startup log containing status: listening and public_management: false. These are checks to perform, not observations already made on your deployment.

Step 5: configure public HTTPS reverse proxying#

This example assumes Nginx is installed and running on the same server as the gateway. Add this server block to your site configuration and replace the domain and valid certificate paths:

nginx
server {
    listen 443 ssl;
    server_name gateway.example.com;
    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;
    client_max_body_size 20m;

    location / {
        proxy_pass http://127.0.0.1:8420;
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600s;
        proxy_buffering off;
    }
}

Check syntax first and reload only after it passes. If validation fails, fix the configuration before reloading:

bash
sudo nginx -t
sudo nginx -s reload

Preserve the public Host, forward WebSocket upgrade headers, and disable buffering for SSE. The official Nginx WebSocket guide explains explicit forwarding of upgrade headers.

This configuration is for the remote Docker gateway. Do not substitute the built-in gateway's loopback Host rule, and never proxy Onevium's original web/management port.

From an authorized client, check:

bash
curl -sS -o /dev/null -w '%{http_code}\n' \
  https://gateway.example.com/api/v1/management/state

Expect 404. Management is not public. Direct browser-script business requests carrying Origin are also rejected; call from your backend.

Step 6: establish private SSH management and pair#

The management socket is /data/control/gateway.sock inside the container, corresponding to /srv/onevium-gateway/control/gateway.sock on the host. The directory is mode 700; socket and control token are mode 600.

Retrieve the control token in a trusted server terminal:

bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml exec -T gateway node dist/cli.cjs management-token

The output is a sensitive private management token. Paste it only into Onevium's matching password field, not into URLs, source code, or log screenshots.

On the Onevium computer, open and retain this forwarding connection:

bash
ssh -o ExitOnForwardFailure=yes -N \
  -L 127.0.0.1:8430:/srv/onevium-gateway/control/gateway.sock \
  gateway-user@YOUR_SERVER

Use a verified SSH host and key; do not disable host checking. The SSH user needs permission to access the host socket. The local endpoint explicitly binds loopback. The OpenSSH manual documents local-port forwarding to a remote Unix socket.

Return to Onevium's advanced remote settings:

FieldExample
Gateway addresshttps://gateway.example.com
Management connectionPrivate connection via SSH
Private management addresshttp://127.0.0.1:8430
Private management tokenThe retrieved control-token

Private management detail: enter the address and token, save, then pair. The token is empty and the draft is unsaved in this example.

Save, then select Pair this device. Expect a paired confirmation. If it fails, inspect SSH and private management rather than switching to public /management. A public URL alone cannot manage a self-hosted gateway.

Step 7: publish, allow admission, and make a real call#

  1. In remote mode, create or select an application and configure its assistant and project capabilities.
  2. Run capability checks and publish the service after they pass. See external access.
  3. Change ONEVIUM_GATEWAY_ACCEPTING_REQUESTS to 1 in server gateway.env, then rerun the preceding up -d --no-build --pull never gateway command to apply the environment.
  4. Select Enable external access on the Onevium application page and confirm connectivity.
  5. Use the application's key and authenticated subject to request a test reply. Save the admission receipt and query the actual Run result.

A 202, running container, or paired device alone is not a completed end-to-end check. Follow the same run_id to a real terminal state and the correct backend result. See conversations for API/SSE examples and authentication for credentials.

For callbacks, add exact hostnames to server ONEVIUM_GATEWAY_CALLBACK_HOSTS, reapply Compose, then configure a callback. Only public HTTPS/443 destinations are accepted; empty lists, private networks, and localhost do not bypass restrictions. See Webhooks and callbacks.

Verify restart recovery#

Stop test submissions and let existing runs reach terminal states, or complete necessary reconciliation, before restarting:

bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml restart gateway

Use restart for the same configuration. After changing environment or image, use this guide's up command to recreate the container. Mounted storage is retained; see the official up reference.

Check that:

  • Private management remains readable and application/device identity is unchanged.
  • The original App Key still reads old runs and conversations.
  • Completed attachments still download with matching contents.
  • Reconnection does not replay work that started but has an unknown outcome.

Unknown outcomes can remain in reconciling, pending_sync, or similar states until confirmed. An online server can accept and queue work within deadlines, but cannot make a sleeping computer execute it.

Pause, back up, and roll back#

  1. Pause the business sender and inspect active runs; confirm outcomes or record unresolved items.
  2. Set ONEVIUM_GATEWAY_ACCEPTING_REQUESTS=0, reapply Compose, and verify that new work receives 503 while old results remain readable.
  3. Pause external access in Onevium. For a consistent backup, stop the gateway and copy the entire persistent directory to a new restricted backup location.
bash
docker compose --env-file gateway.env -p onevium-gateway \
  -f server/gateway/compose.example.yml -f gateway.override.yml stop gateway

Include identity configuration, databases and companion files, private control credentials, and attachments. Do not copy only a live SQLite file, use down -v, or delete /data as a rollback procedure.

Before reverting an image, confirm compatibility with the data format. If unknown, remain paused and obtain a compatible build or matching snapshot from the maintainer. An older snapshot may omit executions and callbacks that happened afterward; reconcile them rather than replaying business side effects. After recovery, keep admission at 0 until identity, old data, and connections are checked.

Common failures#

SymptomFirst checks
Build cannot find filesComplete matching package and package-root build context
Init reports an existing fileExisting initialization; do not overwrite owner/device identity
Container exits after startupEnabled flag, server-config.json, directory permissions, logs
Correct address returns 403PUBLIC_URL versus Host, proxy Host preservation, unexpected Origin
502 or dropped WSSHost listener, TLS proxy, Upgrade headers, timeouts
Private management 401/unreachablecontrol-token, live SSH forwarding, loopback address, socket UID/GID
Pair action disabledSaved settings, pending edits, configured private address and token
202 without completionOnline Onevium device, published capabilities, approvals, run state
Environment changes ignoredOverride forwarding and an up/recreate rather than restart alone
Data missing after restartChanged DATA_PATH or a different volume; do not hide it by initializing again

Next steps and acceptance boundary#

Retain the image tag, deployment configuration, and backup location. Record real API, model execution, SSH, TLS, SSE, callback, and restart checks. Until then, describe the state as “deployment awaiting acceptance,” not “production live.”

Continue with authentication, business conversations, and Webhooks and callbacks.