Skip to content

Installation

From the package to the first login.

This is the same guide that ships inside the .tar.gz, here in browsable form. Installing is extracting and running sudo ./manage.sh install — the rest of this page is what to do when the case is not the simple one.

STSDATA NexaOrch installation guide

The stsagent-bundle-<version>.tar.gz package contains the application already compiled, as ready container images, plus the manage.sh script, which covers both a fresh install and the update of an existing one. There is no source code inside and nothing is compiled on the server.

What is in the package

Item What it is for
images/ UI and Worker images, loaded by Podman
manage.sh The installer and updater — run it with sudo
tools-bin/ Operations tools, already compiled (installer, connection switch, provider migration, password reset). All reachable through manage.sh; you never need to call the binaries directly
docker-compose.prod.yml, version.txt The container definition and this package’s version
agent-windows/ This version’s Windows Automation Agent installer. manage.sh leaves it in /opt/nexaorch/agent-windows/, and the administrator copies it from there to the Windows server — never downloads it through a browser. The procedure is in the administrator manual, Workers section

Prerequisites

  • A 64-bit Linux server with bash, curl, rsync and Podman (podman + podman compose). The install command differs by distribution — see the next section.
  • Distributions covered by this guide: Debian and Ubuntu; RHEL, Fedora, Rocky Linux and AlmaLinux; SUSE Linux Enterprise and openSUSE.
  • No .NET on the server — no SDK, no runtime. The application runs inside the images, and the operations tools are self-contained.
  • Disk space: the package is around 1.2 GB and extracting it takes as much again. Leave ~3 GB free in the folder where you extract it.
  • manage.sh needs root: always run it with sudo.
  • 🛑 A database that already exists, with its own user and password — the installer creates neither, and read and write is not enough: NexaOrch applies the migrations on its own on the first start. See The database: what to prepare first.

The database: what to prepare first

🛑 The installer creates neither the database nor the user. It asks for the connection details of a database that already exists. If the database is going to run in a container too, bring it up separately first (via Podman, for instance) and point the installer at it.

Before running manage.sh install, prepare three things:

  1. the database — on Oracle, the user/schema; on Firebird, the .fdb file;
  2. a user dedicated to NexaOrch, with a password;
  3. that user’s privileges on that database.

Why read and write is not enough

On the first start, and on every update, NexaOrch applies the database migrations on its own. It is not optional and there is no button for it: that is the step that creates and evolves the schema. These are the operations it runs, taken from the product’s own migrations:

operation when it shows up
CREATE TABLE, DROP TABLE creating the schema and removing tables the product dropped
ADD COLUMN, DROP COLUMN, ALTER COLUMN schema evolution between versions
RENAME TABLE, RENAME COLUMN renames
CREATE INDEX, DROP INDEX indexes
ADD FOREIGN KEY, DROP FOREIGN KEY referential integrity
SELECT, INSERT, UPDATE, DELETE normal product use

⚠️ A user with only SELECT/INSERT/UPDATE/DELETE installs and then breaks on the first start. The error comes from inside the migration and names the object it tried to create — not the privilege that was missing.

The privilege, by vendor

Replace nexaorchdb and nexaorchusr with the names you are going to use. Run these as the database administrator, before installing.

  • PostgreSQL — the simplest path is for the user to own the database: CREATE DATABASE nexaorchdb OWNER nexaorchusr; (or, if the database already exists, ALTER DATABASE nexaorchdb OWNER TO nexaorchusr;). ⚠️ On PostgreSQL 15 and newer this stopped being a detail: the public schema no longer grants CREATE to every user. Without ownership the user connects, reads — and fails to create the first table.
  • MySQL / MariaDBGRANT ALL PRIVILEGES ON nexaorchdb.* TO 'nexaorchusr'@'%'; followed by FLUSH PRIVILEGES;. ⚠️ The first migration runs ALTER DATABASE … CHARACTER SET utf8mb4, which is a privilege on the database, not on a table. A grant built out of table-level verbs alone passes the connection test and fails on the first migration.
  • SQL Server — create the login and the database user, then grant db_owner; if you prefer to split it, db_ddladmin + db_datareader + db_datawriter cover the operations in the table above.
  • Oracle — there is no “database” to create: you create the user/schema. It needs CREATE SESSION, CREATE TABLE and CREATE SEQUENCE (primary keys are identity columns, and on Oracle those are backed by an internal sequence) — and a tablespace quota: ALTER USER nexaorchusr QUOTA UNLIMITED ON users;. 🛑 Without the quota, creating the first table fails with ORA-01950 even with every privilege above granted. This is the most common stumble here.
  • Firebird — the database is a file. Create the .fdb connected as the NexaOrch user, so that it owns the database: anyone who is neither the owner nor SYSDBA connects and reads, but cannot change metadata — and a migration is a metadata change.

Check before installing, not during

Test the connection from the server where NexaOrch will run, with the database’s native client and with the same user and password you will give the installer:

  • PostgreSQLpsql -h <host> -p 5432 -U nexaorchusr -d nexaorchdb -c "select 1"
  • MySQL / MariaDBmysql -h <host> -P 3306 -u nexaorchusr -p nexaorchdb -e "select 1"
  • SQL Serversqlcmd -S <host>,1433 -U nexaorchusr -P <password> -d nexaorchdb -Q "select 1"
  • Oraclesqlplus nexaorchusr/<password>@<host>:1521/<service-name>
  • Firebirdisql-fb -u nexaorchusr -p <password> <host>/3050:/path/nexaorchdb.fdb

⚠️ On Oracle the installer’s “Database” field is the service name, not a catalog name as with the other vendors. It is the same value that goes after the slash in the command above.

💡 The test above proves credentials and reachability. It does not prove DDL privilege — for that, CREATE TABLE nexaorch_test (id INT); DROP TABLE nexaorch_test; with the same user answers in two commands what the migration would only answer on the first start.

💡 The installer runs that DDL test on its own, as the sixth step of its database check, and drops the table right after. Doing it here is about finding out beforehand, without having to get that far with the whole wizard already answered.

Prerequisites by distribution

Go straight to the block for your distribution family; you do not need to read the others. Each block has the install command, the check that it is ready and what to confirm before moving on.

⚠️ Run the check before continuing. A prerequisite that is silently missing shows up three steps later, with an error that never mentions the step that was skipped.

Debian, Ubuntu and derivatives

sudo apt update
sudo apt install podman podman-compose uidmap

Confirm it is ready:

podman --version
podman compose version
command -v newuidmap newgidmap
  • SELinux: not applicable — this family uses AppArmor.
  • Rootless: the uidmap package provides newuidmap/newgidmap, which the Worker needs in order to start unprivileged. If the command -v above does not print both paths, the container will not start.
  • Firewall (ufw): open the port the screen will be reached on. The defaults are 8081 (HTTPS) and 8080 (HTTP); if you pick different ones during installation, open those — they are host ports, and they can be changed.

RHEL, Fedora, Rocky Linux and AlmaLinux

This block covers the whole family: if you are on Rocky Linux or AlmaLinux, this is yours.

sudo dnf install podman podman-compose shadow-utils

⚠️ On RHEL, Rocky and Alma, podman-compose is often not in the base repository. If the command above cannot find it, enable EPEL and try again:

sudo dnf install epel-release

Confirm it is ready:

podman --version
podman compose version
command -v newuidmap newgidmap

🛑 SELinux — check before moving on. Only this family ships with SELinux enabled by default:

getenforce
  • Enforcing is what to expect, and it is the mode the product is prepared for: container volumes are mounted with automatic relabelling.

  • Permissive or Disabled means SELinux is blocking nothing. The install works — but if you are testing the product, a result like that invalidates the relabelling check: the test would pass even if there were a defect there.

  • Rootless: shadow-utils provides newuidmap/newgidmap.

  • Firewall (firewalld): open the port the screen will be reached on. The defaults are 8081 (HTTPS) and 8080 (HTTP); if you pick different ones during installation, open those — they are host ports, and they can be changed.

SUSE Linux Enterprise and openSUSE

sudo zypper install podman podman-compose shadow

Confirm it is ready:

podman --version
podman compose version
command -v newuidmap newgidmap
  • SELinux: not applicable in the default setup — this family uses AppArmor.
  • Rootless: the shadow package provides newuidmap/newgidmap.
  • Firewall (firewalld): open the port the screen will be reached on. The defaults are 8081 (HTTPS) and 8080 (HTTP); if you pick different ones during installation, open those — they are host ports, and they can be changed.

What this guide does not do. It states what NexaOrch needs to exist on the machine and how to check that it does. Configuring the firewall, creating accounts or tuning subuid/subgid ranges in depth is server administration, and stays with whoever runs the server.

Fresh install

Use this path if the server does not yet have a NexaOrch installation.

Extract the package anywhere — it does not have to be the final location, because the installation goes to /opt/nexaorch:

⚠️ A server that already has an installation older than this version keeps the previous names. Up to this version, the service account, the folder and the containers were called stsagent, /opt/stsagent and stsagent_ui_1 / stsagent_worker_1. None of that is renamed: an update keeps the names the installation already has, on purpose. This guide uses the NEW names; if your installation is older, read stsagent wherever it says nexaorch. To check without guessing: sudo ./manage.sh runtime-names.

tar -xzf stsagent-bundle-<version>.tar.gz
cd stsagent-bundle-<version>

Run the installer:

sudo ./manage.sh install

The wizard asks for everything still missing to get the system running:

  • Database — the connection details of an existing database (host, port, name, user, password). The wizard does not bring up a new database for you: if you also want to run the database in a container, bring it up yourself (for example via Podman) before running the installer, and point it there.
  • Administrator account — password generated automatically or typed in. There is no default password: either you set it here, or the system asks for it on first access to the screen (see First access).
  • Company, email notifications (SMTP), execution and AI integration (Ollama) — the same sections as the Settings screen, written to the database before the first login.
  • Host folders — Worker data, public downloads, SSH keys, file transfer and backups.
  • Start on reboot — optionally, a systemd unit. See Starting on its own after a reboot.

At the end, two containers (ui and worker) come up via podman compose, all isolated under a dedicated service account — nexaorch by default, and not the user who ran the command.

When the installation finishes, there is nothing left to run: the containers are already up and the last line on screen carries the access address. In particular, do not call podman compose by hand — on the server it does not work with your user’s environment, for the reason the Talking to compose without manage.sh section, at the end of this guide, explains.

HTTPS certificate

This package ships no certificate. On a fresh install, manage.sh generates a self-signed one on the server itself, with a random password: every installation ends up with its own key, and nothing secret travels through the downloads page, which is public.

It is enough to bring the system up and check that everything responds. It is not a production certificate, and the browser will warn about it. To replace it with your own, without reinstalling:

sudo ./manage.sh set-certificate --pfx my-certificate.pfx --password PASSWORD
sudo ./manage.sh set-certificate --crt mine.crt --key mine.key
sudo ./manage.sh set-certificate --self-signed --hosts 10.0.0.180,nexaorch.local

Reinstalling on top: the password of the certificate that is already there

On a reinstall, the certificate already on the server is not replaced: the installation reuses the file and the password that are there, without asking anything.

It only asks “Password for the existing certificate” when the password kept in the .env does not open the file — the case of someone who swapped the .pfx by hand without updating the .env. That password was not chosen by you: it is random, generated by the previous installation, and it lives in the installation’s .env.

sudo grep HTTPS_CERT_PASSWORD /opt/nexaorch/.env

If nobody has that password, ask to replace the certificate: the installation generates a new self-signed one right there on the server, carrying this machine’s IP and name in the SAN field — file and password written together — and runs to the end.

If the installation is already running, the same thing is solved without reinstalling anything:

sudo /opt/nexaorch/manage.sh set-certificate --self-signed --hosts 10.0.0.180,nexaorch.local

Update

Use this path if the server already has an installation running and you want to bring it to this version.

Copy the package to the server and extract it:

tar -xzf stsagent-bundle-<version>.tar.gz
cd stsagent-bundle-<version>

Run the update from inside the extracted folder — that is where this version’s images come from:

sudo ./manage.sh update

The update does not ask the database, SMTP, company, execution and Ollama questions again, does not touch databases already provisioned, and preserves .env, the certificate and the Worker’s data folders. It only loads the new images and recreates the containers. Pending database migrations run on their own when the UI boots.

Going back to the previous version

Before recreating the containers, the script tags the images currently in use as :previous. If the new version does not come up correctly:

sudo /opt/nexaorch/manage.sh rollback

Returns to the previous images, without needing the old package.

Starting on its own after a reboot

The installation offers to write a systemd unit that brings the containers up at boot. If you declined at the time and changed your mind, or want to turn it off later, there is no need to edit /etc/systemd/system by hand:

sudo /opt/nexaorch/manage.sh enable-boot
sudo /opt/nexaorch/manage.sh disable-boot

Why this matters more than it looks. The unit records which services this host starts. Without that, it would run a plain compose up -d and start every service in the file — including the UI on a host that should only run the Worker, taking ports that belong to something else there. The deploy always respected the service selection; it was the boot that did not, and the problem only surfaced after a reboot, far from the change that caused it.

Worker-only host

A server can run only the Automation Agent, without the Portal — the usual arrangement when execution has to happen near a database or a file share, and the Portal lives elsewhere.

That selection is recorded on the host itself, in STS_SERVICES inside the installation’s .env. This is what keeps a manual call (up, rollback, switch-connection) aware that the host has no UI — before, every manual invocation fell back to the “ui worker” default and went looking for an image that was never shipped there.

Installation licence

NexaOrch is licensed per installation. There is no per-Agent code: the package licenses all of them.

Concept What it is
Installation licence A .lic file stating what this installation bought. It is not typed anywhere — it is imported in Settings → Licence
Agents included How many Automation Agents the purchased package includes. It comes inside the .lic itself, signed

How to obtain the .lic file

This installation’s code is not supplied by you: NexaOrch generates it the first time it comes up and shows it in Settings → Licence, in a format like LIC-FQCH-EGS0-J2GC-GSHQ.

Installations created before August 2026 show the same code with the NEXA- prefix, and keep it forever — there is nothing to update. The prefix is part of the code: always copy what the screen shows, in full. LIC-ABCD-… and NEXA-ABCD-… are different installations.

  1. Install — nothing is blocked without a licence.
  2. Open Settings → Licence and copy the installation code, prefix included.
  3. Provide that code when purchasing or renewing.
  4. You get back a .lic file bound to it: valid on this installation and on no other.
  5. Import the file on the same screen. No reinstall, nothing to stop.

manage.sh install asks nothing about licensing. Installing without a licence is the normal path — it is how evaluations, proofs of concept and labs work.

The Agents license themselves

The .lic states how many Agents you bought, and they take the slots in the order they arrive, with no configuration on each server. Import the licence and the Agents that already exist become compliant immediately. An Agent installed later takes a free slot on its own, within the first minute it comes up.

Need one more Agent: there is no standalone Agent licence. You buy the extension and receive a new .lic for this same installation, now with more Agents included. Import it on the same screen — buying, renewing and extending are the same gesture.

When there is no slot left: while no licence has been imported, nothing happens. With a licence in place, an Agent beyond the included number takes no new work; runs already in progress finish normally and the other Agents are unaffected. Validation happens on your own server — NexaOrch never needs internet to check a licence.

Evaluation and restricted mode

A fresh installation starts with 15 days of evaluation, with the complete product: nothing is cut during the trial, because a crippled product cannot be evaluated. The on-screen notice starts from day 10.

Situation What happens
Trial running Complete product. Notice on screen from day 10
Trial expired Restricted mode from day 16 — the trial has no grace period
Licence expired 7 days of grace before restricted mode
No licence ever imported Nothing is blocked

The 7-day grace exists for an operational reason: NexaOrch runs overnight loads. A licence expiring at midnight with an immediate cut-off means a load that does not run, with nobody awake to import a file — and the customer finds out at 8am with an empty BI, on precisely the day they were renewing.

In restricted mode writes are denied and the interface becomes read-only. Processes, history and connections stay where they are; importing the licence unlocks it immediately.

Installations that already existed before the trial regime do not enter evaluation: their creation date is empty, and empty means “no trial”, not “trial starting now”. The regime applies to those born under it.

Publishing: direct or behind a reverse proxy

NexaOrch works both ways, chosen by configuration and switchable later, without reinstalling.

Direct mode (default)

The system serves HTTPS itself, with the certificate at /opt/nexaorch/https/aspnetapp.pfx. Access is by IP.

The installation generates that certificate with this machine’s IP and name already in the SAN field — that is, the address matches. The browser still warns, because it is self-signed: nobody but the server itself recognises the issuer. These are different things, and only the second one remains:

  • Wrong address → solved by the installation, or reissue with --hosts
  • Unknown issuer → solved by importing the certificate

If the server changes IP or name, reissue:

sudo /opt/nexaorch/manage.sh set-certificate --self-signed
sudo /opt/nexaorch/manage.sh set-certificate --self-signed --hosts 10.0.0.180,nexaorch.local

Removing the browser warning

The installation leaves the public certificate at /opt/nexaorch/https/aspnetapp.crt. Distribute that file — it holds no private key; do not send the .pfx — and import it as a trusted authority on the machines that use the system.

  • Windows, machine by machine: certlm.msc → Trusted Root Certification Authorities → Certificates → import aspnetapp.crt.
  • Windows, the whole domain at once (recommended where there is AD): Group Policy → Computer Configuration → Policies → Windows Settings → Security Settings → Public Key Policies → Trusted Root Certification Authorities → Import.
  • Firefox uses its own store: Settings → Privacy & Security → Certificates → View Certificates → Authorities → Import.

If you have a corporate CA, issuing through it is the better path — domain machines already trust that CA, and there is nothing to distribute:

sudo /opt/nexaorch/manage.sh set-certificate --pfx /path/cert.pfx --password '<password>'
sudo /opt/nexaorch/manage.sh set-certificate --crt /path/cert.crt --key /path/cert.key

An nginx terminates TLS with a certificate issued for the name and forwards HTTP to NexaOrch. It is the arrangement that removes the browser warning without installing anything on users’ machines — a public CA certificate only ever exists for a name, never for a private IP.

sudo /opt/nexaorch/manage.sh set-proxy-mode --proxy 10.0.0.5
sudo /opt/nexaorch/manage.sh set-proxy-mode --proxy 10.0.1.0/24
sudo /opt/nexaorch/manage.sh set-proxy-mode --proxy off

The IP you provide is the proxy’s. Without it the system ignores the X-Forwarded-* headers, and the result is a redirect loop and a login that never completes. In this mode the system listens on HTTP only, on 8080.

The leg between the proxy and the system is in clear text. When nginx is on another server, that leg crosses the network — and the authentication cookie travels in it. It is the same arrangement used by Gitea, pgAdmin and most applications behind a proxy, and it is acceptable when both sit on the same trusted network. Two measures are not optional: open port 8080 in the firewall only to the proxy’s IP, and keep proxy and system on the same VLAN, never with the internet or a guest network in between.

An example configuration — the three marked settings are requirements of this system, not formality:

server {
    listen 443 ssl;
    server_name nexaorch.customer.com;

    ssl_certificate     /etc/letsencrypt/live/nexaorch.customer.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/nexaorch.customer.com/privkey.pem;

    # package import accepts 11 MB; the nginx default is 1 MB
    client_max_body_size 12m;

    location / {
        proxy_pass http://10.0.0.180:8080;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        # without this line: redirect loop
        proxy_set_header X-Forwarded-Proto $scheme;
        # without this line (or with a short value): "the screen froze" on the preview screens — see below
        proxy_read_timeout 300s;
    }

    location /downloads/ {
        proxy_pass http://10.0.0.180:8080;
        # the public page serves the ~1.2 GB package
        proxy_buffering off;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

🛑 The proxy timeout and the preview screens (the screen that “freezes”)

The proxy_read_timeout in the example above is not a formality: four screens ask the server to open a connection to a third-party database and read from it before answering. On a large table — many rows and, above all, many columns — that easily exceeds the 60 seconds nginx waits by default.

The routes, by name:

button, on screen route
Read source fields (DataSync panel) POST /SharedCommands/Edit?handler=TestSourceExtract
Preview DataSync source and target POST /SharedCommands/Edit?handler=PreviewDataSyncSource and ...=PreviewDataSyncTarget
Test target (tries CREATE/DROP on a probe table) POST /SharedCommands/Edit?handler=TestDestDdl
Test a SQL command or step POST /SharedCommands/Edit?handler=TestCommandSql and POST /Jobs/Step/...?handler=TestStepSql

⚠️ Creating a location for those routes will not work. The ?handler= is a query string, and an nginx location matches the path only — which is why the setting goes in location /, as in the example, and applies to the whole system. If you would rather scope it, the smallest workable scope is per page (/SharedCommands/Edit and /Jobs/Step), never per handler.

What happens without it — and this is what you need to recognise later. Nginx gives up before the system answers and returns its own 504 error page. The screen expected JSON, gets HTML, and what the operator sees is something like:

SyntaxError: Unexpected token '<', "<html> <h"... is not valid JSON

🛑 Nothing in that message points at the proxy. Operators report “the screen froze” or “a JavaScript error”, and the problem gets hunted in the system, the database, the browser — never in nginx. If you see that error only on the preview screens and only with large tables, this setting is the suspect, and the confirmation is in the nginx error.log (upstream timed out).

300s is a starting point, not a measurement. If reading the source legitimately takes longer, the number goes up; if you would rather the operator fails fast, it goes down — but then previewing a large table stops working, and that is the trade being made.

⚠️ Installations already running. The line entered this guide after most existing installations were configured — the file running today may not have it. Check the location / of your server block, add the line if it is missing, and reload with nginx -t && systemctl reload nginx. Nothing in the system needs restarting.

First access

When the installation is done through the wizard (manage.sh install), the administrator account and the company details are written there, and you go straight to the sign-in screen.

A database that did not go through the wizard — for example, pointing the application at a new database with switch-connection, or restoring a backup into a clean one — opens at first access: the screen itself asks for the administrator password (if there is no user yet) and then for the company details. At the end it shows this installation’s code, which is what you give STSDATA to license it. The same code is always available under Settings › Licence.

Filling in the company details is mandatory: that step is what gives the installation its identity.

When the database connection fails

This applies to every distribution. The per-family blocks further down carry only what differs: firewall, SELinux and service name.

💡 Start from what the installer already answered

If the failure happened during the installation, do not start by testing by hand: the installer has already run the diagnostic and written it all down. It checks the database in six steps — the name resolves, the port accepts TCP, the server completes the protocol, the credentials are accepted, the database is reachable, and the user can create and drop a table:

  [OK]      host 'db.example.local' resolves (10.0.0.7)
  [OK]      port 5432 accepts TCP
  [FAILED]  credentials accepted for user 'nexaorchusr'
            no pg_hba.conf entry for host "10.0.0.7", user "nexaorchusr"
            -> PostgreSQL refused this origin (pg_hba.conf), not the password. ...
  [SKIPPED] database 'nexaorchdb' is reachable
  • the step that fails states the cause and what to check; the ones after it come out as [SKIPPED], never blank;
  • it writes a log file and prints the path on screen, including when everything passes. ⚠️ That log never contains the password, nor its length;
  • 🛑 it prints which operating-system user is connecting. The installer runs as the service account, not as the user who typed the command — and with peer or ident in pg_hba.conf that is the name the database sees. That is why “it works in DBeaver” can be true while the installer fails.

Two actions answer without changing anything, and they are where any check should start:

sudo ./manage.sh runtime-names   # service account, folder and container prefix this host uses
sudo ./manage.sh pg-hba-path     # where pg_hba.conf is (it asks the server first)

The rest of this section covers what the installer does not reach: what happens after it finishes, and the manual test, when you want to separate “the database refuses” from “NexaOrch refuses”.

🛑 Is the database “on the same server”? Then localhost will not do

NexaOrch runs inside a container. In there, localhost is the container itself — not the server. Pointing the connection string at localhost with the database installed on the host gives “connection refused” even with the database up and the credentials right, and it is the most common mistake in this installation.

Instead of localhost, use:

  • host.containers.internal, on the Podman versions that publish it; or
  • the server’s IP on the network (the same one you would use from another machine).

💡 Confirm with sudo ./manage.sh logs ui --lines 50 right after bringing it up: the connection error shows there, with the host it actually tried.

The four outcomes, and what each one means

Test from the server with the native client (commands in The database: what to prepare first). What comes back tells you where the problem is:

what happens what it is where to look
the name does not resolve DNS or /etc/hosts use the IP to confirm
connection refused, or it hangs until the timeout port closed, service down, or the localhost above firewall and service — see your distribution’s block
authentication fails user, password, or the origin host is not accepted on MySQL, the 'user'@'host' in the grant; on PostgreSQL, pg_hba.conf
it connects, but the install fails afterwards credentials fine and privilege missing the privileges section above

⚠️ The fourth one does not look like a connection problem. The connection worked; what was missing was CREATE TABLE. If the connection test passes and the installation breaks right after, start there.

💡 Where pg_hba.conf lives — ask the server, not the distribution

The path changes by family, and any list goes out of date. PostgreSQL itself answers:

sudo -u postgres psql -tAc 'SHOW hba_file'

The paths by family, for when the server is not up:

family where pg_hba.conf usually is
Debian, Ubuntu /etc/postgresql/<version>/main/pg_hba.conf
RHEL, Fedora, Rocky, Alma /var/lib/pgsql/data/pg_hba.conf
SUSE, openSUSE /var/lib/pgsql/data/pg_hba.conf

💡 The installer tries to open that file for the Podman network on its own, and says on screen what it did. If it cannot find the file, it says so instead of staying silent — and sudo ./manage.sh pg-hba-path shows where it looked.

Debian, Ubuntu and derivatives

  • Firewall: sudo ufw status. If it is active, open the database port to the server — for instance sudo ufw allow from <server-ip> to any port 5432 proto tcp.
  • Database service, when it is local: systemctl status postgresql (or mysql, mariadb, firebird).
  • Local PostgreSQL: by default it listens on localhost only. To accept the container, adjust listen_addresses in postgresql.conf and add the matching line to pg_hba.conf.

RHEL, Fedora, Rocky Linux and AlmaLinux

  • Firewall: sudo firewall-cmd --list-all. To open a port: sudo firewall-cmd --add-port=5432/tcp --permanent && sudo firewall-cmd --reload.
  • SELinux: with SELinux enforcing, a container reaching out to a host service can be denied. Check with getsebool -a | grep container_connect, and look at sudo ausearch -m avc -ts recent after an attempt — a denied there points the way.
  • Database service, when it is local: systemctl status postgresql (or mariadb).

SUSE Linux Enterprise and openSUSE

  • Firewall: sudo firewall-cmd --list-all — current SUSE versions use firewalld. Same commands as the block above.
  • SELinux/AppArmor: SUSE uses AppArmor by default; if it is active for Podman, sudo aa-status lists the profiles in enforce mode.
  • Database service, when it is local: systemctl status postgresql (or mariadb).

If none of the above explains it

Collect these outputs before opening a ticket — together they answer nearly every question support would ask:

sudo ./manage.sh version
sudo ./manage.sh logs ui --lines 200

⚠️ Do not paste output from podman commands run by hand: compose echoes the whole podman run line, with the database password and the certificate password in clear text. manage.sh filters it; a bare command does not.

Lost the administrator password

The system has no “forgot my password”, and there is no way to create a new administrator in a database that already has users. If the only administrator loses the password — or gets locked out by failed attempts — the way back is this command, on the server itself:

sudo /opt/nexaorch/manage.sh reset-password --list
sudo /opt/nexaorch/manage.sh reset-password --user admin
sudo /opt/nexaorch/manage.sh reset-password --user admin --password 'NewPassword@2026'
Form What it does
--list Lists the users, with roles and who is locked out
--user <name> Without --password, only shows the situation: nothing is changed
--user + --password Resets the password and unlocks the account

The new password needs at least 10 characters and at least one that is neither a letter nor a digit — the same rule as the users screen. If it does not pass, the command refuses and changes nothing.

Omitting --password makes the command ask in the terminal, without echoing what you type. Prefer that form: whatever goes on the command line is visible to other users of the machine, through ps.

On reset, that user’s open sessions drop. An inactive user still cannot log in even with the new password — reactivate them on the users screen. A user in the Recycle Bin has to be restored first; the command says so when that is the case.

Other commands

sudo /opt/nexaorch/manage.sh version     # installed version and container state
sudo /opt/nexaorch/manage.sh logs ui     # UI container log
sudo /opt/nexaorch/manage.sh logs worker # Worker container log
sudo /opt/nexaorch/manage.sh up          # (re)start the containers already loaded
sudo /opt/nexaorch/manage.sh down        # STOP the installation (does not uninstall)
sudo /opt/nexaorch/manage.sh down worker # stop only the Worker (the UI stays up)

Stopping the installation

sudo /opt/nexaorch/manage.sh down          # stop everything
sudo /opt/nexaorch/manage.sh down worker   # stop only the Worker
sudo /opt/nexaorch/manage.sh down ui       # stop only the UI

down stops; it does not uninstall. No volume and no data are removed — to remove the installation there is uninstall. At the end, the command lists what is still up.

When automatic boot is enabled, a down with no argument stops through the systemd unit rather than around it, so systemd does not keep thinking the application is up. Stopping a single service does not touch the unit — after a reboot it comes back (use disable-boot if that is not what you want).

Talking to compose without manage.sh

If you need to call podman compose directly, it will not work with your own user’s environment: this server has the Docker compose plugin installed, and the command tries a socket the service account does not expose, failing with failed to connect to the docker API at unix:///run/user/<uid>/podman/podman.sock. The correct invocation is:

sudo -u nexaorch env \
  XDG_RUNTIME_DIR=/run/user/$(id -u nexaorch) \
  HOME=/opt/nexaorch \
  PODMAN_COMPOSE_PROVIDER=podman-compose \
  podman compose -p nexaorch -f /opt/nexaorch/docker-compose.prod.yml ps

manage.sh already does exactly this internally — prefer it whenever there is a ready command.

Moving the database

sudo /opt/nexaorch/manage.sh switch-connection --provider <P> --connection '<string>'

Points the installation at another database. It migrates no data — use it when the database is still the same one, but its IP, port or password changed.

Migrating to another database vendor

sudo /opt/nexaorch/manage.sh migrate-provider

Copies this installation’s data to another database (for example, Firebird → PostgreSQL). Interactive: it asks for source and target, and the source is only read, never altered.

It stops the containers before copying and leaves them stopped at the end — with the Automation Agent running, the source would be a moving target, and a run starting after its table was copied would never reach the destination.

It does not repoint the installation. When it finishes, run switch-connection to start using the new database, or up to go back to today’s one.

Removing the installation

sudo /opt/nexaorch/manage.sh uninstall

Removes this installation: containers, images, the network and the service account, in that order — reversing it locks the machine. And it asks before removing a data folder that sits outside the installation directory.

🛑 The database is NOT touched. Nothing in uninstall deletes data: Job definitions, execution history, connections, encrypted credentials and users all stay where they are. The command itself says so on screen, before asking for confirmation.

That is what you want in most cases — reinstalling on top finds everything again. If you really do want to discard the data, that is a separate step, at the end of this guide: Removing the database as well.


Adjust the paths if STS_INSTALL_DIR was customised in the original installation.

Removing the database as well

This section sits outside the installation sequence on purpose, and nothing here is needed in order to remove the product: uninstall has already done that and did not touch the database. Read this part only if the decision is to discard the data.

🛑 There is no going back

Dropping the database is the most destructive action related to this product. There is no undo and no recycle bin. What is lost:

  • the Job definitions and their steps — all the work of whoever built the automations;
  • the execution history, with logs and statistics;
  • the connections and the encrypted credentials;
  • the users, roles and permissions;
  • the imported licence and this installation’s identity.

⚠️ One detail that often catches people: the user the application connects with usually cannot create databases. Whoever drops it generally cannot recreate it alone — they will need someone with administrative privileges on the database server. Confirm that beforehand, not after.

The command, by provider

The commands below are in plain text rather than in a code block, on purpose: they must not be copied in the same run as the installation commands. Type yours, replacing <database-name> with the real name — which is in DEFAULT_CONNECTION_STRING, in the installation’s .env file, before you remove the installation.

  • MySQL / MariaDB — connect with mysql -u <admin> -p and run: DROP DATABASE <database-name>;
  • PostgreSQL — connect with psql -U <admin> and run: DROP DATABASE <database-name>;
  • SQL Server — connect with sqlcmd -S <host> -U <admin> and run: DROP DATABASE <database-name>;
  • Oracle — you do not drop a “database”: you remove the user/schema, with DROP USER <user> CASCADE; run by someone with DBA privileges.
  • Firebird — there is no remote DROP DATABASE: the database is a file. Stop the service and delete the .fdb named in the connection string (by default /opt/firebird/data/nexaorchdb.fdb).

⚠️ Before any of them, a backup solves the regret that DROP does not.