Settings, limits and exposure
An engine's settings and limits on the host, making a database public on purpose, and the ports open beyond the machine.
Part of Databases.
Settings
noust db settings postgresql # current, recommended, restart needed
noust db settings postgresql shared_buffers=2GB work_mem=64MB
noust db settings mysql max_connections=default # back to the engine's own defaultEach engine has a closed set of settings. They are written to Noust's own file
(conf.d/90-noust.conf for PostgreSQL, 99-noust.cnf for MySQL and MariaDB,
/etc/redis/noust.conf for Redis and Valkey, and MongoDB's YAML), checked with the engine's own
tool, applied, and put back if the engine does not come back, or if the change is interrupted half
way. One change per engine runs at a time. A slow start (a large Redis data set loading, MySQL
recovering after a crash) is waited for up to 15 minutes while the engine says it is still
starting, rather than rolled back.
A change that costs something is refused until it is confirmed (--yes, or confirm in the API,
whose refusal lists every warning in warnings); nothing is written before that:
- listening beyond the loopback, including removing a listen setting (
listen_addresses=default) when what the engine falls back to is not known to be the loopback. Under theens-mediumprofile it is refused outright, and an engine that turns out to listen beyond the loopback once it restarts is put back on its previous settings; - a Redis
maxmemorybelow what Redis holds now: withnoevictionwrites start failing, with any other policy keys are dropped at once; appendonly noorsave offon Redis.
Redis writes a snapshot (BGSAVE, waited for) before Noust restarts it, and the restart does not
happen when the snapshot fails. Cache sizes (shared_buffers, innodb_buffer_pool_size,
maxmemory) stop at 90% of the server's memory. A configuration file or directory that is a
symbolic link is refused: Noust writes as root, and the engine's own account owns some of those
directories. On a server with several PostgreSQL clusters running, Noust does not guess which one
to configure and says so; every step targets the one cluster by name.
Resource limits of an engine on the host
An application has limits behind the health gate and an instance has them from the day it is made
(noust db instance limits). The engine the distribution installed on the host can be held to the
same four, so one runaway query does not take the memory of every application beside it:
noust db limits postgresql # what Noust sets, what systemd holds, what the kernel enforces
noust db limits postgresql --memory 4g --cpus 2 # memory, processors
noust db limits postgresql --swap 0 --tasks 4096 # no swap; processes and threads
noust db limits postgresql --remove cpus # take one awayThey are written to a systemd drop-in of Noust's own beside the engine's unit
(/etc/systemd/system/<unit>.service.d/90-noust-limits.conf: MemoryMax=, CPUQuota=,
MemorySwapMax=, TasksMax=), never to the distribution's unit file. daemon-reload makes systemd
write them into the running service's cgroup, so the engine is not restarted and no connection
is dropped. A limit is then proved twice instead of assumed: systemd is asked what it holds for the
unit, and the kernel's cgroup files are read for what it will enforce. A limit systemd accepts and
the kernel ignores (a cgroup v1 host, or memory accounting off) is reported as such. If systemd
does not hold the limit as written (another drop-in sets it later), refuses the reload, or the
engine stops answering, the previous drop-in is put back, systemd reloads it again, and the error
carries the engine's journal verbatim.
A memory limit is a promise the kernel keeps by killing the engine's process when it is exceeded;
for a database that is a crash and a recovery. Set it well above the engine's cache settings
(shared_buffers, innodb_buffer_pool_size, maxmemory); one below what the engine uses now is
refused until it is confirmed (--yes, or confirm in the API). The least memory accepted is what
the engine needs to start, and nothing above the server's own memory or processors is.
The limits belong to the unit, not to a database: every database of the engine shares them. An
engine in a container has its own (noust db instance limits). The console shows the same form
under an engine's settings, and GET/PUT /api/databases/engines/{engine}/limits is the API
(sudo mode to change, audited as db.limits.change).
Making a database public, on purpose
A database is private: its engine listens on the loopback and noust db connect-info prints the SSH
tunnel to reach it. For a desktop client on your own computer there is a deliberate, reversible action:
noust db public open shop -e postgresql --from 203.0.113.7 --access read-write # asks first
noust db public list
noust db public show shop -e postgresql --reveal # the connection, with the password
noust db public close shop -e postgresql # undoes all of itOpening does four things, in this order, each recorded so it can be undone, and undoes the earlier ones when a later one fails:
- A proxy on the public port you choose (
--port, 1024 to 65535; a free one next to the engine's is suggested), on the address you choose (--bind, every IPv4 address by default): a systemd socket and a service runningsystemd-socket-proxyd(noust-dbexpose-<engine>-<port>), forwarding to the engine's loopback port. The engine is not reconfigured and not restarted, nothing already connected notices, and it keeps listening on the loopback only. - An account of its own for that database,
<database>_remote, with the access you chose (--access owner|read-write|read-only, owner by default) on that database alone. Applications' accounts and passwords are never the ones given out. The password is shown once and kept as a secret (show --reveal, sudo mode, shows it again). - TLS required of that account where the engine can: PostgreSQL refuses it without (one marked
hostnossl ... rejectline above every other inpg_hba.conf, checked by PostgreSQL before it is reloaded and put back if it refuses it), MySQL and MariaDB refuse it without (REQUIRE SSLon the account). Redis and MongoDB cannot do that for one account, so for them TLS is optional only when you say so (--allow-plaintext): the password and the data then cross the network in clear. - The firewall, through the one firewall manager (ufw or firewalld): an allow rule for the port from
each
--fromaddress or network, or from anyone when none is given. With no firewall that Noust changes, or an inactive one, the warnings say that nothing limits who reaches the port.
Everything it will do, and what you accept by going ahead (anyone who can reach the port can try the
account's password; a Redis account reaches every key), is printed first and asked about (--yes;
confirm in the API). It is refused whatever you confirm under the ens-medium profile, for an engine in a
container Noust did not make (its compose file publishes its ports), for Redis without a password and
MongoDB without authorization (a public port in front of them would be an open door), and for a port that
is taken.
An instance Noust runs is public the same way, because Noust publishes it on 127.0.0.1 itself: the
proxy forwards to that port (noust-dbexpose-postgresql.pg16-<port>, ordered after the instance's
unit, as the host engine's is) and the instance stays private. What differs is TLS: no
account inside an instance can be made to require it, so PostgreSQL and the other engines whose image
has TLS off are opened only with --allow-plaintext, and the plan says so first.
close removes what the record says was made and nothing else: the firewall rule only if Noust added it
(an identical rule of yours is left), the units, the TLS line and the account. One step that cannot be
done now (the engine is stopped) leaves the record closing and is named; running close again
finishes it. The API is GET /api/databases/public, POST .../public/plan, POST .../public (sudo mode),
GET .../public/{engine}/{database}, POST .../reveal (sudo mode) and DELETE .../public/{engine}/{database}
(sudo mode).
Exposure
noust db exposure lists database ports reachable from the network. A port Docker publishes that
the DOCKER-USER chain refuses on the public interface is reported as closed by the firewall, not
as open.