1. Before you start
You need one machine and one key. That is the whole list.
The machine
- One server that can already reach your database — PostgreSQL, SQL Server, MySQL or Oracle — on your own network. It does not have to be the database server itself, and it should not be someone's laptop — this is a service that runs all day.
-
Outbound HTTPS to
api.sonela.aion port 443. If the machine can browse the web, it can run the gateway. No inbound port, no VPN, no tunnel. - Windows Server / Windows 10 or later (x64), or a 64-bit Linux with glibc (Ubuntu 20.04+, Debian 11+, RHEL 8+ and their relatives). No runtime to install: the download is one self-contained file and carries its own.
-
On Linux only: the system's international components package,
libicu. Every ordinary desktop or server install already has it — the exception is a stripped-down container or minimal image, where it is one command (apt-get install -y libicu-devon Debian/Ubuntu, which ship only versionedlibicupackages;dnf install -y libicuon RHEL and relatives). Without it the gateway stops immediately; section 8 shows exactly what that looks like. - About 100 MB of free disk. The file is smaller than that; it unpacks itself into a temporary folder the first time it runs.
On Oracle: the read-only login
Oracle Database 19c or newer connects through the gateway only, version 2.2.0 or later.
Sonela reads the tables of the login's current schema, and a read-only login owns none,
so ask your DBA for a login that holds SELECT on the application's tables
and a logon trigger that makes the application's schema its current one:
CREATE USER sonela_reader IDENTIFIED BY "…";
GRANT CREATE SESSION TO sonela_reader;
GRANT SELECT ON app.orders TO sonela_reader; -- one grant per table Sonela may read
CREATE OR REPLACE TRIGGER sonela_reader_schema
AFTER LOGON ON sonela_reader.SCHEMA
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET CURRENT_SCHEMA = APP';
END;
Sonela reads tables only, never views, and refuses an administrator login (SYS or SYSDBA), whose sessions a read-only transaction does not bind.
The key
In Sonela, open Data sources and add one in Sonela Gateway
mode (or move an existing guidance-only source onto that rung). The moment it is
created, the dashboard shows a key beginning ck_ — once.
Sonela stores only a hash of it, so it cannot be shown again. The same panel then walks
you through the rest of this guide in five steps: pick the platform, take the download,
type your database connection string, and it builds a setup script with all three of the
settings below already in it — assembled in your browser and sent nowhere. Everything
here is what that script does, for doing it by hand or for when a step goes wrong.
2. Download and verify it
Take the file for the server's platform from the download panel in your dashboard, or from the gateway page. Each build publishes its SHA-256 next to it. Check it before you run anything — it is the one step that proves the file you have is the file we published.
Windows
Paste the SHA-256 from the download panel into the first line, then run both. PowerShell prints hashes in capitals and ours are lower case, so let the comparison handle it rather than reading 64 characters yourself:
$published = 'paste-the-sha-256-from-the-download-panel'
(Get-FileHash -Algorithm SHA256 .\sonela-gateway-win-x64.exe).Hash -eq $published.Trim().ToUpper()
It must print True. Anything else, see the warning below.
Linux
Paste the SHA-256 from the download panel in place of the placeholder:
echo 'paste-the-sha-256-from-the-download-panel sonela-gateway-linux-x64' | sha256sum -c -
It must print sonela-gateway-linux-x64: OK. Note the two
spaces before the file name — that is the format sha256sum
expects. Every build also publishes that same line as a file, at the download's own URL
with .sha256 on the end, so
curl -O <download-url>.sha256 && sha256sum -c
sonela-gateway-linux-x64.sha256 does the whole check without pasting anything.
Only once it says OK:
chmod +x sonela-gateway-linux-x64
./sonela-gateway-linux-x64 --version
--version prints the build and the protocol versions it speaks. It is the
fastest proof that the file downloaded intact and runs on this machine, and it is the
first thing support will ask for.
What the signature means on Windows
If the download panel showed a signature line for the file you took, the executable is code-signed: right-click it, choose Properties → Digital Signatures, and Windows will name Sonela as the publisher. If the panel said the build is not signed, then it is not, and Windows will say so too — twice. Your browser may refuse the download before you ever see the file, and Windows shows “Windows protected your PC” the first time you run it. Both are expected on an unsigned build and neither means anything is wrong with the file; section 8 walks through exactly what each one looks like and what to click.
Either way, the SHA-256 is the check that matters. A signature tells you who published a file; the hash tells you that the exact bytes on your disk are the exact bytes we built. If the hash does not match, do not run the file — delete it and download it again.
3. The three settings
The gateway is configured entirely through environment variables. There is no config file by design: this runs on your machine, and putting your database sign-in into a file on your disk should be your decision, not our default.
| Variable | What it is |
|---|---|
SONELA_GATEWAY_KEY |
Required. The ck_… key from the dashboard. Shown
once, when it is minted. Lost it? Rotate the key on the data source in the
dashboard and install the new one (section 6).
|
SONELA_DB_CONNECTION |
Required. The connection string for your own database. PostgreSQL:
Host=localhost;Port=5432;Database=app;Username=app_reader;Password=….
SQL Server:
Server=localhost,1433;Database=app;User Id=app_reader;Password=…;TrustServerCertificate=True
— keep TrustServerCertificate=True unless the server has a CA-issued
certificate, because the driver encrypts by default and refuses a self-signed one
without it. MySQL:
Server=localhost;Port=3306;Database=app;User ID=app_reader;Password=….
Oracle: User Id=app_reader;Password=…;Data Source=localhost:1521/APP,
with gateway 2.2.0 or later. Use a read-only login. It is used only to open connections from this
machine and never leaves it.
|
SONELA_DB_DIALECT |
Optional. Which engine that connection string dials: postgres (the
default), sqlserver, mysql or oracle. Must match the data source's engine in the
Sonela dashboard — a mismatch fails safely with a message naming this variable.
|
SONELA_URL |
Optional. Where to poll. Defaults to https://api.sonela.ai; leave
it unset unless you have been told otherwise.
|
The setup script the dashboard's key panel builds writes all three of these for you, with your key already in place. If you are setting them by hand instead, copy the key from that panel rather than typing it — a mistyped key is the most common first failure, and the gateway will not start on it.
Try it in the foreground first
Before making it a service, run it once in a terminal with the two required values set. You should see, within a second or two:
[09:14:22] polling https://api.sonela.ai for work
That line means it is connected and waiting for questions. Press Ctrl+C to stop it — that is the normal way this program ends, and it exits cleanly.
4. Run it as a service
The gateway should come back on its own after a reboot. Neither recipe below needs any third-party tool.
Windows — a scheduled task at startup
sc.exe create is the usual answer and it is the wrong one here: it expects a
program written to be a Windows service, and this is a console application. Rather than
ship a wrapper you would have to trust, the honest no-extra-software route on Windows is
a scheduled task that runs at boot as SYSTEM and restarts if it stops.
Put the executable somewhere permanent, then, in an elevated PowerShell:
New-Item -ItemType Directory -Force "C:\Program Files\Sonela Gateway" | Out-Null
Move-Item .\sonela-gateway-win-x64.exe "C:\Program Files\Sonela Gateway\" -Force
# Machine-wide values, so the task sees them at boot with nobody logged in.
[Environment]::SetEnvironmentVariable('SONELA_GATEWAY_KEY', 'ck_…', 'Machine')
[Environment]::SetEnvironmentVariable(
'SONELA_DB_CONNECTION',
'Host=localhost;Port=5432;Database=app;Username=app_reader;Password=…',
'Machine')
# SQL Server? Use its connection-string form from the table above, and add:
# [Environment]::SetEnvironmentVariable('SONELA_DB_DIALECT', 'sqlserver', 'Machine')
$action = New-ScheduledTaskAction `
-Execute 'C:\Program Files\Sonela Gateway\sonela-gateway-win-x64.exe'
$trigger = New-ScheduledTaskTrigger -AtStartup
$principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet `
-RestartCount 999 -RestartInterval (New-TimeSpan -Minutes 1) `
-ExecutionTimeLimit ([TimeSpan]::Zero) -MultipleInstances IgnoreNew
Register-ScheduledTask -TaskName 'Sonela Gateway' `
-Action $action -Trigger $trigger -Principal $principal -Settings $settings
Start-ScheduledTask -TaskName 'Sonela Gateway'
Machine-wide variables are readable by every account on this
machine. Not administrators only: the registry key they live in
(HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment) grants
BUILTIN\Users read, and every process started afterwards inherits them in
its environment. That is the trade for not writing a settings file. Keep the database
login read-only, and treat this machine as one that holds a database sign-in every user
of it can read — because it does. On Linux the equivalent file is root-only
(below); Windows has no equivalent without a wrapper service.
The task writes nothing to a log file of its own. To see what the gateway is saying, run it in the foreground once (section 3) — the messages are identical.
Linux — a systemd unit
Put the values in a file only root can read:
sudo install -m 0755 sonela-gateway-linux-x64 /usr/local/bin/sonela-gateway
sudo useradd --system --no-create-home --shell /usr/sbin/nologin sonela
sudo tee /etc/sonela-gateway.env >/dev/null <<'EOF'
SONELA_GATEWAY_KEY=ck_…
SONELA_DB_CONNECTION=Host=localhost;Port=5432;Database=app;Username=app_reader;Password=…
EOF
# SQL Server? Use its connection-string form from the table above, and add a line:
# SONELA_DB_DIALECT=sqlserver
sudo chown root:root /etc/sonela-gateway.env
sudo chmod 0600 /etc/sonela-gateway.env
Then the unit:
sudo tee /etc/systemd/system/sonela-gateway.service >/dev/null <<'EOF'
[Unit]
Description=Sonela Gateway
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=sonela
EnvironmentFile=/etc/sonela-gateway.env
ExecStart=/usr/local/bin/sonela-gateway
Restart=always
RestartSec=10
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now sonela-gateway
sudo systemctl status sonela-gateway
systemd reads EnvironmentFile as root before dropping to the
sonela user, so the file stays unreadable by the account the gateway runs
as. Follow the log with:
journalctl -u sonela-gateway -f
5. Confirm it connected
Two places agree, and it is worth checking both the first time.
-
On the server. The log's first line is
polling https://api.sonela.ai for work. That is the whole success signal — the gateway is quiet when idle, on purpose, so an empty log after that line means "connected, nothing to do", not "stuck". - In Sonela. On Data sources, the gateway source shows a green Gateway connected badge. It reports on every poll, so the badge turns green within about half a minute of starting.
| Badge | Meaning |
|---|---|
| Gateway connected | Heard from in the last 2 minutes. This is the normal state. |
| Last seen n min ago | Quiet for between 2 minutes and an hour. Brief amber after a restart is expected; amber that stays is worth looking at. |
| Gateway offline | Not heard from for over an hour, or never. Start at section 8. |
Once it is connected, run Introspect on the data source. The gateway reads your schema from inside your network and drafts a manifest for you to review and approve. From version 1.5.0 it also reads the foreign keys between your tables and the comments your database keeps on them, unless comments are switched off on the data source; every comment is listed on the review screen before the assistant reads it. Nothing is read from your tables until you approve it.
6. Rotating the key
Every gateway data source card in the dashboard carries a Rotate gateway
key button. Pressing it mints a fresh ck_… key and kills the old
one at that instant — Sonela stores only the key's SHA-256 hash, so there is
nothing on our side to read back or re-issue; rotation is always a new key, shown
exactly once, like the first one was.
Rotation is an outage you schedule. There is no grace period with two live keys: within about half a minute of the click, the running gateway's next poll is refused, it logs that the platform no longer recognises its key, and it exits. It stays down until you install the new key and restart it:
- In the dashboard, open the data source and press Rotate gateway key.
Copy the new
ck_…key from the one-time sheet. - Update
SONELA_GATEWAY_KEYon the server with the new value. - Restart the gateway —
Restart-ScheduledTask -TaskName 'Sonela Gateway'orsudo systemctl restart sonela-gateway.
Nothing else changes: the approved schema, the widget keys and the data source itself
all stay exactly as they were — rotation replaces the credential, not the setup.
Treat the ck_… key like any other secret: if it may have been seen by
someone who should not have it, rotate it.
7. Stopping and removing it
Ctrl+C in the foreground, or:
# Windows
Stop-ScheduledTask -TaskName 'Sonela Gateway'
Unregister-ScheduledTask -TaskName 'Sonela Gateway' -Confirm:$false
[Environment]::SetEnvironmentVariable('SONELA_GATEWAY_KEY', $null, 'Machine')
[Environment]::SetEnvironmentVariable('SONELA_DB_CONNECTION', $null, 'Machine')
[Environment]::SetEnvironmentVariable('SONELA_DB_DIALECT', $null, 'Machine')
Remove-Item "C:\Program Files\Sonela Gateway" -Recurse -Force
# Linux
sudo systemctl disable --now sonela-gateway
sudo rm /etc/systemd/system/sonela-gateway.service /etc/sonela-gateway.env /usr/local/bin/sonela-gateway
sudo systemctl daemon-reload
Stopping the gateway is complete on your side: nothing of it remains running, and the only thing it ever held — your database sign-in — was in the environment you have just cleared. In Sonela the data source stays where it is and simply reads Gateway offline; a question routed to it answers that the database is unreachable rather than guessing.
8. When it does not work
It refuses to start and lists what is missing
The gateway cannot start. Missing configuration:
SONELA_GATEWAY_KEY - The gateway key (ck_...). It is shown exactly once, …
SONELA_DB_CONNECTION - The connection string of YOUR database. …
Exactly what it says: one or both required values are not visible to the process. The
usual cause is that they were set in a terminal but the service starts without one — on
Windows they must be Machine variables, on Linux they must be in the
unit's EnvironmentFile. Run --help for the full list.
On Linux, it exits at once mentioning ICU
Process terminated. Couldn't find a valid ICU package installed on the system.
Please install libicu using your package manager and try again.
The machine is missing libicu, the system package .NET uses for language
and text handling. This is a minimal image or a stripped-down container, not a normal
server install. Install it and start the gateway again:
# Debian / Ubuntu — there is no package called plain "libicu" here; the
# versions are numbered (libicu72, libicu74, …) and this one resolves on all of them
sudo apt-get update && sudo apt-get install -y libicu-dev
# RHEL / Rocky / Alma
sudo dnf install -y libicu
Nothing else changes — the file you downloaded, your key and your settings all stay as they are.
“the platform does not recognize this gateway key”
[09:14:22] the platform does not recognize this gateway key; check SONELA_GATEWAY_KEY …
The key is wrong, or it belongs to a data source that no longer exists. The gateway
stops here rather than retrying, deliberately: polling forever on a bad
key would hide a paste error behind a service that looks like it is running. Copy the key
again from the dashboard's paste-ready block — the whole value, including
ck_, with no trailing space — and restart. If the key was lost, section 6.
“platform unreachable”
[09:14:22] platform unreachable (…); retrying with backoff up to 60 s
It cannot reach api.sonela.ai. It keeps retrying and recovers on its own,
logging platform connection restored when it does. This line is printed
once per outage, not once per attempt — so silence after it means still
trying, not fixed.
Usually outbound filtering. Confirm from that machine:
# Windows
Test-NetConnection api.sonela.ai -Port 443
# Linux
curl -sS -o /dev/null -w '%{http_code}\n' https://api.sonela.ai/health
If that fails, the machine needs outbound HTTPS to api.sonela.ai on port
443 — an allow-list entry on the proxy or firewall. Nothing inbound is ever required.
Questions come back with a database error
If the gateway is connected but a question answers with a message from your database —
authentication failed, relation does not exist, connection refused — that is your
database talking, passed through word for word rather than replaced with something
vaguer. The gateway is fine and keeps polling; the fix is in the database login or in
what it is allowed to read. Check that the login in SONELA_DB_CONNECTION can
connect from this machine and can read the tables you approved.
Introspection logs “could not be read” or “too large to send whole”
[09:14:22] job … (introspect): foreign keys could not be read; sending the columns without them
[09:14:22] job … (introspect): database notes could not be read; sending the columns without them
[09:14:22] job … (introspect): the schema is too large to send whole; database notes were left out
Introspection still succeeds with every column; the assistant just does not see those extras. The first two mean the database refused to list its foreign keys or its comments to this login, or took longer than 10 seconds to. The third means the result was past the size Sonela accepts, so the comments were dropped first, then the foreign keys, and never a column. The review screen says what this version could not read, so approving it is an informed choice rather than a surprise.
“update the Sonela Gateway”
Sonela sent work in a newer format than this build understands, and the gateway refused
it rather than guessing at it. Its own log says
refused: the job speaks protocol … — update the Sonela Gateway. Download the
current build, replace the file, restart the service. Your key and settings do not
change.
Windows warns about the download, or blocks it
Expected on an unsigned build, and it happens at two different moments. Neither is a statement about this file: both are statements about a file Windows has not seen enough copies of yet. Check the SHA-256 first (section 2) — a hash that matches is a stronger statement about the bytes on your disk than either warning is.
In the browser, while downloading. Edge says the file “isn't commonly downloaded”, or “was blocked because it could harm your device”; Chrome says “isn't commonly downloaded. Make sure you trust…”. The file is usually already on disk, quarantined, rather than never fetched:
- Edge — open the downloads flyout, click the … on the item, choose Keep, then Show more → Keep anyway.
- Chrome — open the downloads bar or page and choose Keep.
At first run. SmartScreen shows “Windows protected your PC” and names an unknown publisher: More info → Run anyway.
Both disappear once we code-sign the Windows build. Until then the download panel says plainly that the build is not signed, and never claims otherwise.
9. What the gateway never does
-
It never sends, logs or echoes back the values in
SONELA_DB_CONNECTION. They are used to open connections from that machine and nothing else. - Its log records job ids, what kind of job it was, how long it took and whether it succeeded — and connection state changes. Never your key, never your settings, never the SQL, never a row of data. Support reads that log over your shoulder, and it is written to be safe to show.
- It accepts no inbound connections. It is a client, and there is no port on it to reach.
- It runs only read-only queries. Every statement is validated as a single read-only SELECT over the schema you approved and rewritten to add the filters you declared — your tenant column, where several organisations share the database, and your soft-delete column — on your machine, before it reaches your database. It is then executed in a READ ONLY transaction with a three-second statement timeout and a 500-row cap.