7.3 KiB
Admin Database 0 (0.db
)
This page explains what the Admin Database DB 0
is, why HeroDB uses it, and how to work with it as a developer and end-user. It’s a practical guide covering how databases are created, listed, secured with access keys, and encrypted using per-database secrets.
What is DB 0
?
DB 0
is the control-plane for a HeroDB instance. It stores metadata for all user databases (db_id >= 1
) so the server can:
- Know which databases exist (without scanning the filesystem)
- Enforce access control (public/private with access keys)
- Enforce per-database encryption (whether a given database must be opened encrypted and with which write-only key)
DB 0
itself is always encrypted with the admin secret (the process-level secret provided at startup).
How DB 0
is created and secured
DB 0
lives at<base_dir>/0.db
- It is always encrypted using the
admin secret
provided at process startup (using the--admin-secret <secret>
CLI flag) - Only clients that provide the correct admin secret can
SELECT 0
(see “SELECT
+KEY
” below)
At startup, the server bootstraps DB 0
(initializes counters and structures) if it’s missing.
Metadata stored in DB 0
Keys in DB 0
(internal layout, but useful to understand how things work):
-
admin:next_id
- String counter holding the next id to allocate (initialized to
"1"
)
- String counter holding the next id to allocate (initialized to
-
admin:dbs
- A hash acting as a set of existing database ids
- field = id (as string), value =
"1"
-
meta:db:<id>
- A hash holding db-level metadata
- field
public
="true"
or"false"
(defaults totrue
if missing)
-
meta:db:<id>:keys
- A hash mapping access-key hashes to the string
Permission:created_at_seconds
- Examples:
Read:1713456789
orReadWrite:1713456789
- The plaintext access keys are never stored; only their
SHA-256
hashes are kept
- A hash mapping access-key hashes to the string
-
meta:db:<id>:enc
- A string holding the per-database encryption key used to open
<id>.db
encrypted - This value is write-only from the perspective of the management APIs (it’s set at creation and never returned)
- A string holding the per-database encryption key used to open
-
age:key:<name>
- Base64-encoded X25519 recipient (public encryption key) for named AGE keys
-
age:privkey:<name>
- Base64-encoded X25519 identity (secret encryption key) for named AGE keys
-
age:signpub:<name>
- Base64-encoded Ed25519 verify public key for named AGE keys
-
age:signpriv:<name>
- Base64-encoded Ed25519 signing secret key for named AGE keys
You don’t need to manipulate these keys directly; they’re listed to clarify the model. AGE keys are managed via AGE commands.
Database lifecycle
- Create a database (via JSON-RPC)
- The server allocates an id from
admin:next_id
, registers it inadmin:dbs
, and defaults the database topublic=true
- If you pass an optional
encryption_key
during creation, the server persists it inmeta:db:<id>:enc
. That database will be opened in encrypted mode from then on
- Open and use a database
- Clients select a database over RESP using
SELECT
- Authorization and encryption state are enforced using
DB 0
metadata
- Delete database files
- Removing
<id>.db
removes the physical storage DB 0
remains the source of truth for existence and may be updated by future management methods as the system evolves
Access control model
- Public database (default)
- Anyone can
SELECT <id>
with no key, and will getReadWrite
permission
- Anyone can
- Private database
- You must provide an access key when selecting the database
- The server hashes the provided key with
SHA-256
and checks membership inmeta:db:<id>:keys
- Permissions are
Read
orReadWrite
depending on how the key was added
- Admin
DB 0
- Requires the exact admin secret as the
KEY
argument toSELECT 0
- Permission is
ReadWrite
when the secret matches
- Requires the exact admin secret as the
How to select databases with optional KEY
-
Public DB (no key required)
SELECT <id>
-
Private DB (access key required)
SELECT <id> KEY <plaintext_key>
-
Admin
DB 0
(admin secret required)SELECT 0 KEY <admin_secret>
Examples (using redis-cli
):
# Public database
redis-cli -p $PORT SELECT 1
# → OK
# Private database
redis-cli -p $PORT SELECT 2 KEY my-db2-access-key
# → OK
# Admin DB 0
redis-cli -p $PORT SELECT 0 KEY my-admin-secret
# → OK
Per-database encryption
- At database creation, you can provide an optional per-db encryption key
- If provided, the server persists that key in
DB 0
asmeta:db:<id>:enc
- When you later open the database, the engine checks whether
meta:db:<id>:enc
exists to decide if it must open<id>.db
in encrypted mode - The per-db key is not returned by RPC—it is considered write-only configuration data
Operationally:
- Create with encryption: pass a non-null
encryption_key
to thecreateDatabase
RPC - Open later: simply
SELECT
the database; encryption is transparent to clients
Management via JSON-RPC
You can manage databases using the management RPC (namespaced herodb.*
). Typical operations:
createDatabase(backend, config, encryption_key?)
- Allocates a new id, sets optional encryption key
listDatabases()
- Lists database ids and info (including whether storage is currently encrypted)
getDatabaseInfo(db_id)
- Returns details: backend, encrypted flag, size on disk,
key_count
, timestamps, etc.
- Returns details: backend, encrypted flag, size on disk,
addAccessKey(db_id, key, permissions)
- Adds a
Read
orReadWrite
access key (permissions ="read"
|"readwrite"
)
- Adds a
listAccessKeys(db_id)
- Returns hashes and permissions; you can use these hashes to delete keys
deleteAccessKey(db_id, key_hash)
- Removes a key by its hash
setDatabasePublic(db_id, public)
- Toggles public/private
Copyable JSON examples are provided in the RPC examples documentation.
Typical flows
- Public, unencrypted database
- Create a new database without an encryption key
- Clients can immediately
SELECT <id>
without a key - You can later make it private and add keys if needed
- Private, encrypted database
- Create passing an
encryption_key
- Mark it private (
setDatabasePublic false
) and add access keys - Clients must use
SELECT <id> KEY <plaintext_access_key>
- Storage opens in encrypted mode automatically
Security notes
- Only
SHA-256
hashes of access keys are stored inDB 0
; keep plaintext keys safe on the client side - The per-db encryption key is never exposed via the API after it is set
- The admin secret must be kept secure; anyone with it can
SELECT 0
and perform administrative actions
Troubleshooting
-
ERR invalid access key
when selecting a private db- Ensure you passed the
KEY
argument:SELECT <id> KEY <plaintext_key>
- If you recently added the key, confirm the permissions and that you used the exact plaintext (hash must match)
- Ensure you passed the
-
Database X not found
- The id isn’t registered in
DB 0
(admin:dbs
). Use the management APIs to create or list databases
- The id isn’t registered in
-
Cannot
SELECT 0
- The
KEY
must be the exact admin secret passed at server startup
- The
Reference
- Admin metadata lives in
DB 0
(0.db
) and controls:- Existence:
admin:dbs
- Access:
meta:db:<id>.public
andmeta:db:<id>:keys
- Encryption:
meta:db:<id>:enc
- Existence:
For command examples and management payloads:
- RESP command basics:
docs/basics.md
- Supported commands:
docs/cmds.md
- JSON-RPC examples:
docs/rpc_examples.md