KoolBox Documentation

Troubleshooting & Command Reference

The problems that actually come up on a KoolBox deployment, what causes each one, and the single command that fixes or diagnoses it.

Service, ports and network access

The service will not start

Almost always a database setting. Run sudo koolboxctl status to see what it thinks, then repair the configuration and bring it up:

sudo koolboxctl status
sudo koolboxctl setup && sudo koolboxctl migrate

For the full error:

sudo journalctl -u koolbox -n 50

On RHEL: the console cannot reach its database

On 1.2.8 and earlier, a koolbox-full install on RHEL 9 could leave the service failed with Connectivity: unreachable in koolboxctl status and nothing listening on port 3000 at all — curl: (7) … Connection refused rather than an error page. The cause was PostgreSQL 13's md5 default against the scram-sha-256 those releases wrote into pg_hba.conf.

Fixed from 1.3.0, and upgrading repairs an affected server on its own — it raises the cluster setting, re-hashes the role's password and starts the service:

sudo dnf upgrade koolbox koolbox-full
sudo koolboxctl status                    # expect: reachable / active
If you run setup, always follow it with migrate. On 1.3.x, koolboxctl setup repairs this in place and exits 0 — but it leaves the service failed and does not say so, which looks like the fix did not work. sudo koolboxctl migrate is what starts it. On 1.2.8 itself setup cannot fix it at all: it exits 2 with password left unchanged. Full detail, with transcripts, in RHEL 9 on 1.2.8 and earlier.

Port 3000 is already in use

Change PORT in /etc/koolbox/koolbox.env and restart:

sudo nano /etc/koolbox/koolbox.env
sudo systemctl restart koolbox

I cannot reach the console in a browser

  • Check the service is running: sudo koolboxctl status.
  • Check that HOSTNAME in /etc/koolbox/koolbox.env is 0.0.0.0 and not 127.0.0.1, which only allows local access.
  • Check that port 3000 is open in your cloud provider's security group, and in the host firewall if there is one — sudo ufw status on Debian and Ubuntu, sudo firewall-cmd --list-ports on the RHEL family. Stock cloud images often ship with no host firewall at all (on the RHEL 9.6 image used for verification, firewalld was not even installed), in which case the security group is the only thing that can be blocking you.
If you set up a reverse proxy. HOSTNAME=127.0.0.1 is correct in that case — the proxy reaches the console locally and serves 80/443 itself. See Put the console on a domain with HTTPS.

License, sessions and missing features

Every page redirects me to the License page

The 3-day grace period has ended. Activate a license and everything returns immediately — nothing is deleted while the console is locked.

The Kai assistant is missing from the sidebar

Expected in three cases:

  • The operating mode is set to Air-gapped.
  • The license is not yet activated — including during the grace period.
  • Kai has not been configured.

Check Administration → Settings → Deployment.

I have lost my authenticator app

Use one of the eight recovery codes saved when you enrolled: the 2FA challenge page offers Recovery Code alongside Authenticator and Security Key, and each code works once. Sign in that way and register a new authenticator from My Account.

There is no switch in the console that turns 2FA off. With 2FA enrolled, the My Account dialog offers only Register New Authenticator. If the recovery codes are also gone, this is not something you can clear from the interface — ask Koolify rather than reinstalling, which would not help: the user table is in the database.

“The user needs to sign in again.”

A session outlived the timeout in your security policy. Sign in again. There is deliberately no fallback identity.

Search and document output

Documents come out as DOCX when I asked for PDF

On a brand-new koolbox-full server, restart first. The package manager starts the console while setting up the koolbox package, before LibreOffice has been unpacked, so a fresh single-server install logs LibreOffice not found even though LibreOffice is installed moments later in the same run. sudo systemctl restart koolbox is the whole fix — do not install LibreOffice again. Details in Restart once if you want PDF output.

If a restart does not change it, LibreOffice genuinely is not installed. It is optional, and deliberately not a hard requirement because some distributions do not ship it. Install libreoffice-core and libreoffice-writer to enable PDF and ODT output.

Either way, the service log states which of the two situations you are in at every start:

Expected output
[KoolBox] LibreOffice not found — document generation will output DOCX only (no PDF conversion)

[KoolBox] LibreOffice detected: LibreOffice 24.2.7.2 420(Build:2) — PDF document generation available
koolbox-full includes it. The single-server koolbox-full package installs LibreOffice for you — see Decide which package you need.

Reverse proxy symptoms

nginx returns 502 Bad Gateway, but the console is healthy

On RHEL, Rocky Linux, AlmaLinux and Fedora this is SELinux rather than anything to do with KoolBox. Look in /var/log/nginx/error.log: if it says (13: Permission denied) connecting to 127.0.0.1:3000, nginx is not permitted to open outbound connections, and sudo ausearch -m avc -ts today will show a name_connect denial for dest=3000 — run it as sudo ausearch -m avc -ts recent </dev/null, because with no matching records it waits on your terminal and looks hung. One command fixes it permanently:

sudo setsebool -P httpd_can_network_connect 1

The proxy starts working immediately, with no restart. A genuinely stopped console reads connection refused in that log instead — check it with curl http://127.0.0.1:3000/api/health on the server itself. The full log lines are quoted in Put the console on a domain with HTTPS.

Did you change PORT?. The other way to earn a 502 is to change PORT in /etc/koolbox/koolbox.env and leave the proxy pointing at 3000. koolboxctl status follows the new port automatically, so it will report everything healthy while the proxy keeps knocking on the old one. Update proxy_pass to match and reload nginx.

nginx serves its own welcome page instead of the console

On Debian and Ubuntu, the stock default site is enabled and claims every request that does not match another server_name, so a test by IP address returns the distribution's welcome page and your KoolBox block is never consulted:

sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

Before DNS points at the server, test by asking for the name your block listens for: curl -I -H 'Host: console.example.com' http://127.0.0.1/ should answer 307 with location: /auth/login.

The nginx site commands fail on RHEL

/etc/nginx/sites-available and sites-enabled do not exist on the RHEL family, so tee exits 1 and the symlink step fails with No such file or directory. Write the same server block to /etc/nginx/conf.d/koolbox.conf and skip the symlink entirely — nginx.conf already includes that directory.

AI replies arrive all at once instead of progressively

Your reverse proxy is buffering. Add proxy_buffering off; as shown in the HTTPS setup.

A long AI task ends in a gateway timeout

Raise proxy_read_timeout in your reverse proxy. 600 seconds is a sensible starting point.

Update problems

An update was requested from the console and never started

(Version 1.3.0 and later.) The console itself cannot install anything — it writes a request and a root-owned path unit acts on it. If that unit is not running, the request is never picked up, which is a different situation from the update having failed. Check it and restart it:

systemctl status koolbox-updater.path
sudo systemctl reset-failed koolbox-updater.path && sudo systemctl start koolbox-updater.path

The progress card is stuck, but the update may be done

(Version 1.3.0 and later.) The console's progress card survives its own restart, and usually picks up the result within about 23 seconds — but on one of three applies measured it sat on Installing packages for well over a minute after the update had already completed successfully. Check the outcome from outside the page before you do anything:

sudo koolboxctl status
sudo tail -n 20 /var/log/koolbox/update-*.log

The Update history list on the same page is also authoritative. Take the page's own advice and do not reboot the host: the privileged updater re-executes itself precisely so that it survives the console being replaced underneath it.

A rollback completed but says the update did not complete

The notification for a successful rollback carries the right title and the wrong body: Rolled back to KoolBox 1.3.0 followed by “The update did not complete.” That is a cosmetic product bug. sudo koolboxctl status and the Update history row both report it correctly, and the command's own output ends ✓ KoolBox rolled back to … with Phase : rolled-back.

“This browser cannot generate a staging identifier”

The console's offline upload card refuses to accept files and blames your browser. The browser is almost certainly fine: that card needs a secure context, so it only works over HTTPS or from localhost — and the installer banner tells administrators to use http://<address>:3000, which is not one.

Two ways out, and the second needs no infrastructure at all:

An update was interrupted and the package manager complains

On Debian and Ubuntu, finish the interrupted operation and try again:

sudo dpkg --configure -a
This is a memory problem. It is most likely on a server with less than the recommended memory, where the operating system can terminate the package manager partway through. See Hardware requirements — 4 GB minimum, 8 GB recommended.

Then re-run the update as described in Update from the terminal.

General health check

curl http://127.0.0.1:3000/api/health

This returns the running version, the database schema version and whether the database is connected. It needs no authentication and is safe to use in monitoring — verified: it answers 200 with no session cookie, while an endpoint such as /api/users answers 401.

Expected output
{"status":"ok","version":"1.3.2","schemaVersion":"1.3.2","database":"connected","uptimeSeconds":15}

Two things worth recognizing. version and schemaVersion differing is normal after a rollback — the older code is reading a newer schema on purpose. And a bare HTTP 500 with no JSON at all means the service is up but cannot authenticate to the database; on RHEL that is almost always the password-hash mismatch.

koolboxctl command reference

Everything is done with one command, koolboxctl. Those that change anything need sudo; version is the exception and works without it.

Scroll to see all columns →

The koolboxctl subcommands available on every supported release, and what each one does.
CommandWhat it does
koolboxctl statusVersion, service state (including whether it is enabled at boot), database, health, recent backups
koolboxctl versionVersion numbers only. Needs no sudo
koolboxctl setup [--auto]Create or repair configuration, database user, database and extensions. Safe to re-run, but it will not reset the password of a role that already exists — see the RHEL database mismatch
koolboxctl migrateStart or restart the service so it applies database changes, then wait until it reports ready
koolboxctl backup [file]Back up the database
koolboxctl restore <file> [--yes]Replace the database from a backup. Destructive. It asks you to type the database name — not “yes” — unless you pass --yes. The dump is applied as the unprivileged koolbox account, and one containing psql meta-commands is refused. See what a restore also changes
koolboxctl start / stop / restartControl the service
koolboxctl logsRecent log output (koolboxctl logs -f to follow)
koolboxctl config showPrint the effective configuration, with secrets masked
koolboxctl config --merge-defaultsAppend settings introduced by the installed release to /etc/koolbox/koolbox.env without touching existing values. This is the step an upgrade performs for you
koolboxctl update(1.3.0 and later.) Guided update: checks, shows the release notes, asks, backs up, installs, restarts and verifies. --to X.Y.Z for a named version, --yes to skip the question only — the backup still happens
koolboxctl update --check(1.3.0 and later.) Report only, needs no sudo. Exits 0 up to date, 10 update available, 1 could not check
koolboxctl update --offline <dir|file…>(1.3.0 and later.) Update from staged files with no network — a directory, or the files named individually. Needs the packages plus latest.json and latest.json.sig; the built-in help calls those two optional and they are not
koolboxctl rollback [--to X.Y.Z](1.3.0 and later.) Install an earlier release. Backs up first, and restores software only — never data
koolboxctl helpFull list of commands and options
✗ Unknown command: update. That answer means you are on 1.2.x, where the update and rollback subcommands do not exist yet — nothing is broken. It is also why the upgrade onto 1.3.0 itself has to be done with apt or dnf, as described in Update KoolBox.

Environment variables it reads

Scroll to see all columns →

Environment variables that change koolboxctl behavior.
VariableEffect
KOOLBOX_BACKUP_KEEPHow many backups to retain in the default directory. Default 5
KOOLBOX_READY_TIMEOUTSeconds to wait for the service to report ready before giving up. Default 120
KOOLBOX_UPDATE_TIMEOUTSeconds allowed for each release-manifest download. Default 20, which is the ceiling on how long update --check can take to fail
NO_COLORSet it to anything to turn off colored output — worth using when you are pasting a transcript into a support ticket

Both are read from the environment of the command, so sudo KOOLBOX_READY_TIMEOUT=300 koolboxctl migrate is the way to give a slow or heavily loaded server more time.

What koolboxctl setup does, and does not, do

Run with a terminal attached, setup is a short interview: where PostgreSQL runs, the port, database name and role, then the console's port and bind address, every value pre-filled with what you already have, and a final Apply this configuration? [Y/n]. It then lists exactly what it is about to do before doing it — generate a JWT secret if one is missing, create the role, database and the two search extensions if they do not exist, raise the cluster's password hashing if it is still md5, enable password authentication for that one role on loopback only, and re-key the role if it cannot authenticate with the password in your configuration file. Existing databases, settings and data are never modified, and an external PostgreSQL server is never reconfigured at all — on a managed service or someone else's cluster it only checks and reports.

Run without a terminal — from a script, or with </dev/null — it asks nothing and does the same work, identically to setup --auto, in well under a second. It is safe to re-run as often as you like; on an already-configured server it reports what already exists and exits 0.

setup never starts the service. Its own closing line is nothing is started yet — finish with: sudo koolboxctl migrate, and that is the whole truth: a server can have a perfectly repaired database and a failed service at the same time, with setup having exited 0 and said ✓ Configuration complete. Always follow it with sudo koolboxctl migrate.

koolboxctl help lists every command and option on the release you have installed, which is the version worth trusting over any copy printed here.

The built-in help, verbatim

Captured on 1.3.2. This is the reference worth trusting over anything printed here, because it is the release you actually have:

koolboxctl help
Expected output
koolboxctl — KoolBox Private AI Control Panel administration

Usage: koolboxctl <command> [options]

Installation & upgrades
  setup                 Guided: asks where PostgreSQL runs, its connection
                        details and the console port, then creates/repairs the
                        configuration, database role, database and required
                        PostgreSQL extensions. Safe to re-run.
                        On a local cluster it also reconciles password hashing:
                        password_encryption, the role's stored hash and the
                        pg_hba.conf method are made to agree, and a role that
                        cannot authenticate is re-keyed from koolbox.env.
                        An external server is never reconfigured.
  setup --auto          The same work with no prompts — what the package
                        install scripts run. Exit 2 = configure the database by
                        hand (external PostgreSQL).
  migrate               Start or restart the service so it applies schema and
                        data upgrades, then wait until it reports ready.
  config [show]         Print effective configuration (secrets masked).
  config --merge-defaults
                        Append settings introduced by this release to
                        /etc/koolbox/koolbox.env without touching existing values.

Updates
  update                Guided: check for a release, show the notes, confirm,
                        apply, then verify. Takes a database backup first.
  update --check        Report only. Exit 0 = up to date, 10 = update
                        available, 1 = could not check.
  update --to X.Y.Z [--yes]
                        Install a named version. --yes skips the confirmation
                        only; the backup is always taken.
  update --offline <dir|file…> [--to X.Y.Z] [--yes]
                        Install from .deb/.rpm files already on this host, with
                        latest.json + latest.json.sig if you have them.
  rollback [--to X.Y.Z] [--yes]
                        Reinstall an earlier version. Does not restore the
                        database; without --to, the version of the newest
                        pre-upgrade backup is used.

                        Updates are applied by the privileged runner at
                        /usr/libexec/koolbox/koolbox-update-runner. The release
                        manifest is read from UPDATE_MANIFEST_URL in
                        /etc/koolbox/koolbox.env and its signature must verify
                        before anything is installed.

Operations
  status                Version, service, database and health summary.
  start | stop | restart
  logs [journalctl args]
  version

Data
  backup [file]         pg_dump the application database (gzip). Defaults to
                        /var/lib/koolbox/backups/, keeping the newest 5.
  restore <file> [--yes]
                        Replace the database contents with a backup. Destructive.
                        The dump is applied as the unprivileged koolbox account,
                        and one containing psql meta-commands is refused.

Environment
  KOOLBOX_BACKUP_KEEP   Backups to retain (default 5).
  KOOLBOX_READY_TIMEOUT Seconds to wait for readiness (default 120).
  KOOLBOX_UPDATE_TIMEOUT
                        Seconds allowed for each manifest download (default 20).
  NO_COLOR              Set to disable coloured output.

Documentation: https://koolify.ai
One line of that help text is wrong. update --offline is described as taking the packages “with latest.json + latest.json.sig if you have them”. They are not optional: without both, the update refuses to proceed — after it has already taken a backup. Stage all four files, as Update an isolated server sets out.

Checking the effective configuration

sudo koolboxctl config show
Expected output
PORT=3000
HOSTNAME=0.0.0.0
DB_HOST=localhost
DB_PORT=5432
DB_NAME=koolbox
DB_USER=koolbox
DB_PASSWORD=********
DB_DIALECT=postgres
JWT_SECRET=********
JWT_EXPIRY=24h
NODE_ENV=production
NEXT_TELEMETRY_DISABLED=1
VERBOSE=false
LOG_CLEANUP_HOUR=2
PACKAGES_DIR=/var/lib/koolbox/packages
LICENSE_SERVER_URL=https://www.koolify.ai
PUBLIC_BASE_URL=
ASSISTANT_URL=
ASSISTANT_API_KEY=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
AWS_EC2_METADATA_DISABLED=

The two secrets really are masked rather than merely short — DB_PASSWORD and JWT_SECRET print as ******** against 36- and 64-character values — so this output is safe to paste into a support conversation. Values shown empty are settings this installation is not using.

Useful file locations

Scroll to see all columns →

Where KoolBox keeps its configuration, backups, application files and logs.
PathWhat it is
/etc/koolbox/koolbox.envYour configuration. Never overwritten by an update
/var/lib/koolbox/backups/Database backups
/opt/koolboxThe application. Replaced wholesale by every update. A package removal empties it apart from about 28 KB of image cache
/var/lib/pgsql/dataThe local PostgreSQL data directory on the RHEL family (Debian keeps its own under /var/lib/postgresql). Survives a package removal
/var/log/koolbox/One log per update or rollback performed by koolboxctl update or the console
/var/lib/koolbox/update/staged/Staged offline update batches. Never cleaned up automatically — delete batches you no longer need
journalctl -u koolbox -fLive logs
These paths look missing if you check them without sudo. They belong to root or to the koolbox service user, so an unprivileged ls reports “No such file or directory” for directories that are in fact there. Check them with sudo before concluding something failed to install.

Getting help

When reporting a problem. Include the output of sudo koolboxctl status and the last 50 log lines from sudo journalctl -u koolbox -n 50. It will almost always shorten the conversation.
sudo koolboxctl status
sudo journalctl -u koolbox -n 50

Running KoolBox and Need a Hand?

Tell us what you are seeing — including your koolboxctl status output — and we will work through it with you.