GuidesDatabasesEverywhere5 min read

DatabasesEverywhere configuration

Configure node identity, API exposure, allowed database images, host safety reserves, quota enforcement, storage paths, and backup policy before accepting customer instances.

Identity and secrets

The main configuration starts with values generated and stored by the panel:

yaml
remote: https://panel.example.com
uuid: node-db-1
token_id: node-db-1-primary
token: replace-with-at-least-32-random-bytes
jwt_signing_key: replace-with-a-different-32-byte-random-key

token authenticates panel API requests. jwt_signing_key signs WebSocket and temporary-download credentials. Each secret must contain at least 32 random bytes, must be different, and must never be committed.

The configuration administration API cannot change uuid, token_id, token, jwt_signing_key, or the external FuseQuota helper path and digest. Change those boundaries directly on the host.

API listener and trusted hosts

Keep the API on loopback when a local reverse proxy terminates HTTPS:

yaml
api:
  host: 127.0.0.1
  port: 8090
  trusted_hosts:
    - node-api.example.com

The request Host must match remote, a concrete api.host, or an entry in api.trusted_hosts. If a browser sends an Origin, it is checked separately against the allow-list derived from remote.

To expose the native HTTPS server directly, use a non-loopback host and enable TLS:

yaml
api:
  host: 0.0.0.0
  port: 8443
  ssl:
    enabled: true
    certificate: /etc/letsencrypt/live/node.example.com/fullchain.pem
    key: /etc/letsencrypt/live/node.example.com/privkey.pem

Cleartext non-loopback API binds are rejected. Database gateways can bind publicly without TLS, but they log a warning because credentials, queries, and results can be intercepted. Enable each gateway's native TLS whenever traffic crosses an untrusted network.

Container runtime

Docker is the default:

yaml
daemon:
  engine: docker
  socket_path: /var/run/docker.sock

Podman can use /run/podman/podman.sock for rootful operation or /run/user/<uid>/podman/podman.sock for rootless operation. Do not switch an occupied node between runtimes.

Database networking is intentionally not configurable. Every instance uses network_mode=none and a private Unix socket.

Database images

Use explicit version tags or digests. Bare image references and latest are rejected:

yaml
images:
  postgres: "postgres:18.4"
  redis: "redis:8.8.0"
  mariadb: "mariadb:12.3.2"
  mysql: "mysql:8.4"
  mongodb: "mongo:8.3.4"
  clickhouse: "clickhouse/clickhouse-server:26.4.4.38"
  qdrant: "qdrant/qdrant:v1.18.2"
  allowed:
    postgres: ["postgres:18.4"]
    redis: ["redis:8.8.0"]
    mariadb: ["mariadb:12.3.2"]
    mysql: ["mysql:8.4"]
    mongodb: ["mongo:8.3.4", "mongo:7.0.37"]
    clickhouse: ["clickhouse/clickhouse-server:26.4.4.38"]
    qdrant: ["qdrant/qdrant:v1.18.2"]

The configured default is always implicitly allowed. Keep every additional allow-list entry reviewed and administrator-controlled.

MySQL uses the official mysql:8.4 LTS image because the credential gateway depends on a compatibility authentication plugin removed from MySQL 9.x.

MongoDB 8.x has a known incompatibility with Linux kernel 6.19 and newer. If MongoDB fails on such a host, select the known-compatible mongo:7.0.37 image for MongoDB only.

Capacity reserves

Keep memory and disk headroom outside the database allocation pool:

yaml
allocation:
  max_memory_mib: null
  max_disk_mib: null
  reserved_memory_mib: 512
  reserved_disk_mib: 2048

When a maximum is null, DatabasesEverywhere uses detected physical capacity minus the reserve. An explicit maximum can shrink the pool but cannot override the reserve.

New instances and memory or disk increases are rejected if projected allocations exceed the pool or current host availability would fall inside the reserve. Decreases are always allowed. Stopped and failed instances remain allocated until deletion.

CPU is a scheduling signal and per-instance runtime limit, but not a node admission reserve because CPU contention slows workloads without making the host unbootable.

Disk enforcement

Disk mode is detected on every daemon boot from the filesystem backing paths.volumes:

  • Btrfs uses qgroups.
  • ZFS uses refquotas.
  • Project-quota-enabled XFS, ext4, and f2fs use native project quotas.
  • Other supported filesystems use FuseQuota.

There is no manual disk.mode switch and no unenforced fallback.

Use the disk section to configure the bundled helper and native project ID range:

yaml
disk:
  fuse_quota_binary: embedded
  fuse_quota_binary_sha256: ""
  fuse_quota_rescan_interval_seconds: 150
  project_id_base: 200000

Reserve a bounded range of up to 1,000,000 consecutive project IDs starting at project_id_base exclusively for DatabasesEverywhere. XFS mode rejects conflicting /etc/projects or /etc/projid entries instead of replacing them.

Official release binaries contain the matching verified FuseQuota helper. A source build for another architecture must point to a trusted, root-owned helper and provide its lowercase SHA-256 digest.

The systemd unit uses KillMode=process so healthy FuseQuota helpers and mounts can survive a normal daemon restart. After a host reboot or stale helper, the daemon repairs only the affected instance.

Storage paths

The recommended layout is:

yaml
paths:
  data: /var/lib/dbev
  metadata: /var/lib/dbev/metadata
  volumes: /var/lib/dbev/volumes
  backups: /var/lib/dbev/backups
  sockets: /run/dbev/sockets
  locks: /run/dbev/locks
  logs: /var/log/dbev
  artifacts: /var/lib/dbev/artifacts
  exports: /var/lib/dbev/artifacts/exports
  imports: /var/lib/dbev/artifacts/imports
  fuse: /var/lib/dbev/fuse
  tmp: /var/lib/dbev/tmp

Every existing ancestor is checked before creation and after hardening. It must be a real directory, be owned by root or the daemon user, and not be writable by group or others. A root-owned sticky directory such as /tmp is allowed.

The daemon and mutating maintenance commands share an exclusive lock under paths.locks. Stop the service before migrations, metadata resets, or development cleanup.

Move an existing path layout

Stop managed containers and the service before migrating:

bash
sudo systemctl stop databases-everywhere
sudo dbev migrate-paths --dry-run
sudo dbev migrate-paths
sudo systemctl start databases-everywhere

sudo dbev --move-new-config is an alias. Live data is not moved unless the operator explicitly adds --force.

Automatic backups

Enable a daily schedule, per-instance retention, and bounded catalog previews:

yaml
backups:
  enabled: true
  interval_minutes: 1440
  run_on_startup: false
  retention_keep_latest_per_instance: 7
  retention_max_age_days: 30
  storage:
    driver: local
  browsing:
    enabled: true
    max_objects: 256
    max_preview_objects: 32
    preview_rows_per_object: 10
    max_row_bytes: 4096
    max_catalog_bytes: 1048576

The storage driver can be local, s3, or kopia. Retention is applied per instance through the selected driver. Changing the driver selects a different inventory and does not migrate previous backups.

Row previews contain database content and need the same encryption and access policy as the backup. Set preview_rows_per_object: 0 to keep schema browsing without captured rows.

See Data operations and backups for S3, Kopia, restore, and temporary-download flows.

Apply and verify changes

Validate the file before restarting:

bash
sudo dbev --config /etc/databases-everywhere/config.yml check-config
sudo dbev --setup
sudo systemctl restart databases-everywhere

Most listener, TLS, path, image, and runtime changes require a restart. PATCH /api/system/config writes a merged configuration patch but returns restart_required: true rather than restarting the node automatically.