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,rsyncand 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.shneeds root: always run it withsudo.- 🛑 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:
- the database — on Oracle, the user/schema; on Firebird, the
.fdbfile; - a user dedicated to NexaOrch, with a password;
- 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: thepublicschema no longer grantsCREATEto every user. Without ownership the user connects, reads — and fails to create the first table. - MySQL / MariaDB —
GRANT ALL PRIVILEGES ON nexaorchdb.* TO 'nexaorchusr'@'%';followed byFLUSH PRIVILEGES;. ⚠️ The first migration runsALTER 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_datawritercover the operations in the table above. - Oracle — there is no “database” to create: you create the user/schema. It needs
CREATE SESSION,CREATE TABLEandCREATE 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 withORA-01950even with every privilege above granted. This is the most common stumble here. - Firebird — the database is a file. Create the
.fdbconnected as the NexaOrch user, so that it owns the database: anyone who is neither the owner norSYSDBAconnects 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:
- PostgreSQL —
psql -h <host> -p 5432 -U nexaorchusr -d nexaorchdb -c "select 1" - MySQL / MariaDB —
mysql -h <host> -P 3306 -u nexaorchusr -p nexaorchdb -e "select 1" - SQL Server —
sqlcmd -S <host>,1433 -U nexaorchusr -P <password> -d nexaorchdb -Q "select 1" - Oracle —
sqlplus nexaorchusr/<password>@<host>:1521/<service-name> - Firebird —
isql-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
uidmappackage providesnewuidmap/newgidmap, which the Worker needs in order to start unprivileged. If thecommand -vabove 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
-
Enforcingis what to expect, and it is the mode the product is prepared for: container volumes are mounted with automatic relabelling. -
PermissiveorDisabledmeans 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-utilsprovidesnewuidmap/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
shadowpackage providesnewuidmap/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/subgidranges 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/stsagentandstsagent_ui_1/stsagent_worker_1. None of that is renamed: anupdatekeeps the names the installation already has, on purpose. This guide uses the NEW names; if your installation is older, readstsagentwherever it saysnexaorch. 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
systemdunit. 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 -dand 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.
- Install — nothing is blocked without a licence.
- Open Settings → Licence and copy the installation code, prefix included.
- Provide that code when purchasing or renewing.
- You get back a
.licfile bound to it: valid on this installation and on no other. - 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 → importaspnetapp.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
Behind a reverse proxy (recommended when there is a DNS name)
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
peeroridentinpg_hba.confthat 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 instancesudo ufw allow from <server-ip> to any port 5432 proto tcp. - Database service, when it is local:
systemctl status postgresql(ormysql,mariadb,firebird). - Local PostgreSQL: by default it listens on
localhostonly. To accept the container, adjustlisten_addressesinpostgresql.confand add the matching line topg_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 withgetsebool -a | grep container_connect, and look atsudo ausearch -m avc -ts recentafter an attempt — adeniedthere points the way. - Database service, when it is local:
systemctl status postgresql(ormariadb).
SUSE Linux Enterprise and openSUSE
- Firewall:
sudo firewall-cmd --list-all— current SUSE versions usefirewalld. Same commands as the block above. - SELinux/AppArmor: SUSE uses AppArmor by default; if it is active for Podman,
sudo aa-statuslists the profiles inenforcemode. - Database service, when it is local:
systemctl status postgresql(ormariadb).
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
uninstalldeletes 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> -pand 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.fdbnamed in the connection string (by default/opt/firebird/data/nexaorchdb.fdb).
⚠️ Before any of them, a backup solves the regret that DROP does not.