SQL storage
Persistent state for lindir lives in PostgreSQL or MySQL/MariaDB. Development can use memory://.
Choice at deploy time
| Config | Value |
|---|---|
dbEngine |
postgres (default) or mysql / mariadb |
dbDsn |
Connection URL, or memory:// for local/dev without a DB |
PostgreSQL example
{
"dbEngine": "postgres",
"dbDsn": "postgresql://lindir:YOUR_PASSWORD@127.0.0.1:5432/lindir"
}
Also accepted: postgres://... or libpq keywords host=... user=... password=... dbname=... port=....
CREATE USER lindir WITH PASSWORD 'YOUR_PASSWORD';
CREATE DATABASE lindir OWNER lindir;
Requires libpq at link/runtime (postgresql-libs / libpq).
MySQL / MariaDB example
{
"dbEngine": "mysql",
"dbDsn": "mysql://lindir:YOUR_PASSWORD@127.0.0.1:3306/lindir"
}
Also accepted: mariadb://... or mysql-native form host=127.0.0.1;port=3306;user=lindir;pwd=...;db=lindir.
Create the database and user before starting lindir:
CREATE DATABASE lindir CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'lindir'@'%' IDENTIFIED BY 'YOUR_PASSWORD';
GRANT ALL PRIVILEGES ON lindir.* TO 'lindir'@'%';
FLUSH PRIVILEGES;
MySQL / MariaDB: max_allowed_packet
Fleet inventory and vulnerability feed caches (Arch AVG, Debian DSA list, Ubuntu/OSV
JSON) are large. mysql-native sends big parameters with COM_STMT_SEND_LONG_DATA,
but MariaDB/MySQL still enforce max_allowed_packet on the whole value (not per
chunk). Defaults (often 16 MiB) are too small; Lindir does not change this at
runtime (max_allowed_packet is GLOBAL-only / read-only as SESSION on current MariaDB).
Set 64 MiB (or higher) on the database server before using Vulns Refresh or large inventory syncs:
- Create a server config snippet (path varies by distro):
# /etc/my.cnf.d/lindir.cnf (MariaDB on many RPM/Arch layouts)
# /etc/mysql/mariadb.conf.d/99-lindir.cnf (Debian/Ubuntu MariaDB)
[mysqld]
max_allowed_packet = 64M
- Restart the database:
sudo systemctl restart mariadb
# or: sudo systemctl restart mysqld
- Confirm:
SHOW VARIABLES LIKE 'max_allowed_packet';
-- Value should be >= 67108864
Optional one-shot until the next restart (needs a privileged DB account):
SET GLOBAL max_allowed_packet = 67108864;
If you see errors similar to Parameter … longer than ‘max_allowed_packet’ bytes during vuln feed refresh, raise this setting and retry.
After a MariaDB major upgrade, run sudo mariadb-upgrade -u root -p if the server
reports Column count of mysql.proc is wrong (error 1558).
MySQL / MariaDB: nullable timestamps
MariaDB in strict mode rejects empty string for TIMESTAMP NULL / DATETIME NULL
(Incorrect datetime value: ''). Repos must bind the SQL_NULL sentinel from
lindir.storage.database for “no value yet” fields such as last_used_at,
started_at, finished_at, retired_at, locked_until. Do not pass D null
or "" for those parameters — the MySQL driver turns those into non-null ''.
Driver status
| Engine | Status |
|---|---|
memory:// |
SQL subset for unit tests / offline dev |
| PostgreSQL | Implemented via dpq2 (libpq); ? → $n rewrite |
| MySQL/MariaDB | Implemented via mysql-native |
Schema
Versioned SQL under sql/migrations/. Migrations run automatically on server start.
| Migration | Adds |
|---|---|
001–003 |
Core IdM (users, groups, hosts, policy, POSIX) |
002 / tokens |
Auth tokens + audit |
004–006 |
OIDC + WebAuthn |
007 |
WireGuard peers |
008–010 |
Fleet labels/inventory/queries + packages + reboot fields |
011_ops_qol |
Account policy, enroll tokens, host last_seen_at, user lockout/must-change |
012_fleet_energy |
Energy policies + host/label targets |
Empty string → SQL NULL handling for MySQL is intentional in repos (timestamps / optional fields).
