Skip to content
Pages in Releases

Noust 3.3 changelog

What changed in 3.3.

Reference Updated View as Markdown

Changes since Noust 3.2.1. Upgrade notes are in UPGRADING-3.3.md; the databases area is described in databases.md.

3.3 shows the databases a server really has. Until 3.2 the Databases area only saw engines installed on the host, so a database in a Docker container (most of them, on the servers this release was measured against) did not exist for Noust; an engine that refused Noust's account was shown as an engine with nothing in it; and an application was linked to a database only if Noust had written its connection string. None of that changes anything on the server by itself: what is new is what Noust sees and says, and the actions it offers.

Databases in containers (item 67)

  • Instances. A database server is now either the host's engine (as before) or a container Noust finds on its own: the official images of PostgreSQL, MySQL, MariaDB, Redis, Valkey and MongoDB and their common derivatives (PostGIS, TimescaleDB, pgvector, Bitnami). Each one is named by a key that stays the same when the container is recreated: postgresql@<project>.<service> for a Compose service, postgresql@<container> otherwise.
  • The same code as the host. Listing databases, users and tables, sizes, the data browser, read-only queries, dumps, restores, backup policies and links all work on an instance: the engine's own client runs inside the container through docker exec. The container's passwords are read inside the container and never reach the host's process list; the ones Noust holds itself travel in the environment of the docker process.
  • Whose it is. A container's databases belong to the application its Compose project is (the project label against the application's project or name), so a stack's Postgres and Redis show as its application's.
  • What differs. Start, stop and restart act on the container. Installing, uninstalling and configuring do not exist for an instance: the image decides the engine, and Noust says so. When only the application's own account is available (no root password in the container's environment), the instance is marked as limited access.
  • Every --engine option of noust db takes an instance key, and noust db engines lists the containers after the host's engines.

An engine that does not let Noust in says so (item 68)

  • A listing that failed used to come back empty: a MySQL that asked root for a password showed as a server with no databases and no users, and its tracked databases as gone. Now the engine's own answer is shown, verbatim, with the fix above it, and the tracked databases of an engine that could not be read are marked "not verified" instead of missing.
  • For MySQL/MariaDB and Redis the fix is in the console: store the account Noust signs in with (PUT /api/databases/engines/{engine}/credentials, sudo mode, audited as db.credentials.set). The engine is asked first, and nothing is saved if it refuses. noust db config goes through the same check, and --password alone asks for the password without echo, so it never reaches the shell history or the process list.
  • PostgreSQL and MongoDB do not sign in with a stored password; their message says what Noust needs instead (peer authentication for postgres, the administrator Noust created).
  • Noust reads each application's environment and finds the databases it names: connection URLs (DATABASE_URL, REDIS_URL, Prisma, Laravel, JDBC, driver suffixes) and the DB_* and REDIS_* sets. A reference resolves to one engine: by port on this machine (a container's published port included), by service name inside the application's Compose project, never by guessing between two. Nothing of the application runs, no password is kept or shown, and a .env that leads outside the application's tree is not read.
  • The databases list shows those applications as detected beside the database. "Record the link" makes one a link without touching the application (POST .../links/detected, audited as db.link.record), one at a time and only when the operator asks: an application's .env is written by whoever deploys it, so what it names is a claim. A database another application owns is refused, an existing link is never overwritten, and the recorded link carries no account, so a later password rotation never writes the new password into an application that merely named the account. noust db adopt tracks databases and records no links.

Counts (item 70)

MySQL counts tables in its listing; Redis reports keys rather than tables; a count the listing does not know is shown as unknown, never as 0.

Engines: versions and settings (item 71)

  • Choose what to install. PostgreSQL 14 to 18 (from the PostgreSQL project's repository, or the distribution's when it is the one asked for), MariaDB 10.11, 11.4 or 11.8 (from MariaDB's repository) or the distribution's, MySQL from the distribution, Redis or Valkey, MongoDB 7.0 or 8.0, as far as each upstream publishes for the server's release. Every upstream signing key is pinned by fingerprint and checked before apt trusts it, MongoDB's included. MySQL and MariaDB, and Redis and Valkey, cannot be installed beside each other, a check the install itself makes. Only the pinned primary key is written to apt's keyring (exported from a throwaway keyring, so a file that also carries another key or a secret key is refused); a leftover source for another release (mongodb-org-7.0.list under an 8.0 install) is refused with the file to remove; a source Noust added is removed again when apt-get update then fails; apt-get install runs with --no-remove; and the version that ends up running is compared with the one asked for. Installing needs sudo mode in the API, as removing does. GET /api/databases/engines/catalog and noust db catalog say what this server can install; noust db install postgresql --version 17.
  • Settings. A closed set per engine (connections, memory, listen addresses, slow-query logging, time zone...) with the current value, a recommendation for this server's memory and cores, and whether it needs a restart: noust db settings <engine> [KEY=VALUE ...], the console's Settings page, GET/PUT /api/databases/engines/{engine}/settings (sudo mode, audited as db.settings.change). Values go into Noust's own include file, never the distribution's; each change is checked with the engine's own tool, applied (reload, restart or at runtime, as the setting needs), and put back with the engine's journal in the error if the engine does not come back. Opening an engine beyond the loopback asks for confirmation, and the ens-medium profile refuses it; removing a listen setting counts as opening it unless what the engine falls back to is known to be the loopback, and the live value is read back after the change. A Redis maxmemory below what it already uses, appendonly no and save off ask for confirmation too (confirm in the API, which answers confirmation_required with every warning; confirm_exposure is still honoured), memory settings are capped at 90% of the RAM, and Redis writes a snapshot before any restart Noust makes. Changes to one engine are serialised, a symlinked configuration file or directory is refused, every PostgreSQL step targets the same cluster (several online clusters are refused), a slow start that is still loading is waited for, and the previous files are put back whatever interrupts the change.

Exposure without false alarms (item 72)

  • A port Docker publishes that the DOCKER-USER chain refuses on the public interface is shown as closed by the firewall, not exposed; an IPv6 publication on a server without an IPv6 route likewise. The database exposure check reads the chain with the same code as the server's security check.
  • An image that only mentions a database in its name (zabbix/zabbix-server-mysql) is no longer taken for one: there is one reader of images, which compares the repository name. A container of an image that reader does not know (a registry other than Docker Hub, an image id, supabase/postgres) is still reported when it publishes a database's own port.
  • A rule in DOCKER-USER that jumps to another chain before the drop leaves the port exposed: where the packet goes is not proven closed.

Compose stacks running outside their unit (item 73)

A Compose application whose unit is stopped while its containers run (started by hand with docker compose up -d) used to show as stopped and raise "the unit is not running" while it served. It is now its own state, "Running outside Noust" (amber), in noust list, the console, the overview and the fleet summary; the monitor says once (app.outside_unit) that a reboot would not bring it back. noust app reclaim <domain> (and the button on the application's page, POST /api/apps/{domain}/reclaim, sudo mode, audited as apps.reclaim) enables and starts the unit after the same docker compose up --dry-run rehearsal adoption uses; if that rehearsal would recreate a container it refuses unless --accept-recreate is given.

Fixes

  • A Redis container counts as installed even when the host has no redis-cli.
  • A container's MongoDB archive is restored into the database asked for: the archive says which database it holds and mongorestore renames it (--nsFrom/--nsTo), so restoring "as a new database" or testing a dump never touches the original. Container archives pass verification.
  • A container's log masks the passwords in it (generated root passwords, the container's secret variables, passwords in logged statements) and needs databases.manage.
  • One .env that is not UTF-8 no longer breaks the databases list; a .env is opened once, without following links, and at most 1 MiB of it is read.
  • Changing only the password of an engine's stored account is tested with the stored user, as it is saved.

3.3.1

  • Sudo mode lasts while you work. Confirming it's you opens sudo mode for 15 minutes, and every action that needs it extends that again, up to 2 hours from the confirmation and never past the session. An account with a second factor confirms with one: a code from its authenticator, a backup code or a passkey; the password is not asked again. The windows and the password are settings (auth.sudo.idle_minutes, auth.sudo.max_minutes, auth.sudo.require_password); the ens-medium profile keeps the password and at most 10 and 30 minutes. The confirmation dialog says how long it lasts.
  • A pending SSH or firewall change says whether it is proven. The banner watches for the new SSH login that proves the way in still works, names it when it arrives (who, from where, when) and only then offers Keep; before, Keep answered "No new SSH login since the change". Undoing no longer shows that error left over from an earlier Keep. The window before a change undoes itself is 5 minutes instead of 2. noust server security pending shows the same.
  • Refusing root logins works for Ubuntu and Debian administrators (issue #14). A sudoers rule separated by a tab, which is how Debian and Ubuntu ship %sudo, was not read, so a member of sudo was "an account that cannot use sudo" and the fix was refused. Sudoers is now read as sudo reads it (aliases, host and runas lists, negation, Defaults scopes, includes); a rule that does not run every command as root no longer counts as a way to root.
  • Install hints name this server's package manager (issue #12): apt on Debian and Ubuntu, dnf on Fedora and RHEL, zypper on openSUSE, all three only when Noust cannot tell.
  • Every "how to fix" names a command that exists (issue #13). The failed-units finding pointed at noust server units --failed; it now opens the services list filtered to the failed units (noust service list --all --state failed, GET /api/services?state=failed). A test checks every command and route Noust suggests; it found and fixed ten more.
  • noust web start without root says so (issue #11) instead of ending in a traceback.
  • The engines page no longer contradicts itself. The server's own engines are now listed under "On this server" when engines in containers are listed below them, and a server engine that is not installed but runs in a container says so beside its state ("Not installed", "1 in a container"). GET /api/databases/engines reports each engine's engine_type, so a client never splits an instance key.
  • A container's missing password or authorization is only a warning when something can reach it. A Redis or MongoDB in a container is judged by what Docker publishes of its port: on its Docker networks only it is the image's default and is not reported; published on the server's loopback it names the address and says any process on the server can reach it; published on any other address it says anything that reaches that port can. MongoDB containers are now asked whether they enforce authorization, and their fix is the compose file's (MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD, which take effect on an empty data volume) rather than /etc/mongod.conf. The servers' own Redis and MongoDB keep their warnings.
  • Every page of the console shows that it is loading. The Databases list drew its header over a blank area until the list, the backup policies and the open ports had all answered; it now keeps its filters and a table of placeholder rows from the first frame, and says nothing about the databases (no "No databases yet", no count) before it knows them. The rows wait at most a second for the notice above them: the open-port check can take seconds and no longer holds them back. The same gap is closed on a service's page, the unit file, the table of tables, the connection tab, the logs (a pane still waiting for its first lines draws the shape of lines and is marked busy), the servers count of Settings > Central, and on the figures, cards and sections that were placeholders a screen reader could not tell from content. A route that keeps the console waiting more than a second (the session, a page's code) now shows a skeleton in the page's place instead of leaving the previous page, or nothing, on screen. A test opens every route of the console against a server that never answers and refuses a page that shows nothing, a placeholder a screen reader cannot hear, or an empty state, so a new page cannot ship without its loading state.

Something on this page is wrong or unclear? Report it on GitHub.

Help, contributing and the project’s policies are under Project.

Search the documentation

Type to search every page.

↑ ↓ to move, Enter to open, Esc to close