-
Notifications
You must be signed in to change notification settings - Fork 8
Database Backend
Version: 2.142+
UCM supports two database backends:
| Backend | Default | Use case |
|---|---|---|
| SQLite | ✅ yes | Single-node, simple, zero-config |
| PostgreSQL | opt-in | HA, multi-instance, larger PKIs, backups |
The backend is selected at runtime via the DATABASE_URL environment variable. When unset, UCM uses the bundled SQLite database at ${UCM_DATA_DIR}/ucm.db.
DATABASE_URL |
Backend |
|---|---|
| (unset) | SQLite (default) |
sqlite:///opt/ucm/data/ucm.db |
SQLite (explicit) |
postgresql+psycopg2://user:pass@host:5432/ucm |
PostgreSQL |
postgresql://user:pass@host:5432/ucm |
PostgreSQL (driver auto) |
-
PostgreSQL ≥ 13 (older versions are explicitly rejected by
Test connection) - A pre-existing empty database and a user with
CREATEprivileges on it - Network reachability from UCM to the PostgreSQL server (port 5432 by default)
The psycopg2-binary driver is bundled in DEB, RPM and Docker images.
Admin lockout fix (v2.141) — switching the active backend from PostgreSQL back to SQLite no longer locks out the admin account. The bcrypt password hash from the SQLite source-of-truth is preserved across the swap and the in-process SQLAlchemy session pool is rebuilt before the next login attempt. Previously the swap could leave a stale connection pool pointing at the old backend, causing the next admin login to fail with
Invalid credentials.
The Settings → Database section shows:
-
Active backend —
sqliteorpostgresql -
Database size — file size (SQLite) or
pg_database_size(PG) - Table count — non-system tables
- Migration version — current schema version
Three actions are available:
Validates a DATABASE_URL before applying it. For PostgreSQL, this also reads server_version_num and rejects servers older than version 13 with a clear error message.
Persists DATABASE_URL to /etc/ucm/ucm.env (DEB/RPM only) and restarts the service. No data is migrated — switching to an empty PG points UCM at an empty schema, which UCM will create on next start.
Docker: the container cannot persist
/etc/ucm/ucm.env. SetDATABASE_URLin yourdocker-compose.ymlordocker run -eand restart the container.
Copies all data from the current backend to a target DATABASE_URL. The migration is bidirectional — both SQLite → PostgreSQL and PostgreSQL → SQLite are supported and verified end-to-end (47 tables, 3800+ rows).
-
Pre-flight emptiness check — the target is probed before any write. If
users,casorcertificatesalready contain rows, migration is refused with HTTP 409 and a cleanup hint:-
PostgreSQL target:
psql -d ucm -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;' - SQLite target: delete the target file
-
PostgreSQL target:
- Source backup first — UCM creates a full backup of the current database before any migration.
- Source untouched on failure — if the migration fails mid-way, the source backend is unchanged. The error message points to the backup location.
-
PostgreSQL ≥ 13 enforcement — applied to the target during
Test connection.
- Schema is created on the target via SQLAlchemy
create_all()(no manual SQL). - Foreign key checks are temporarily disabled during bulk load:
- PostgreSQL:
SET session_replication_role = 'replica' - SQLite:
PRAGMA foreign_keys = OFF
- PostgreSQL:
- Source/target columns are intersected to handle legacy schema drift.
-
memoryviewand JSON values are normalized across drivers. - PostgreSQL sequences are reset to the max existing ID after load.
- The
_migrationsbookkeeping table is created on the target if missing.
Leave DATABASE_URL unset. UCM uses ${UCM_DATA_DIR}/ucm.db. Use the standard backup tooling.
- Provision an empty PG database (
CREATE DATABASE ucm OWNER ucm;). - On a freshly installed UCM: set
DATABASE_URLand start — the schema is created automatically. - On an existing SQLite UCM: use Settings → Database → Migrate data to copy SQLite → PG, then Switch backend.
- Point all UCM instances at the same
DATABASE_URL.
Same workflow in the other direction — set DATABASE_URL to the SQLite URL, run Migrate data, then switch.
The standard Settings → Backup workflow operates on the active backend — backups taken while running on PostgreSQL contain PG data, restore must be performed against a compatible PG schema. Use platform-native tools (pg_dump / pg_restore) if you want a portable snapshot independent of UCM.
Upgrade your PostgreSQL server. UCM does not support PG < 13 due to JSON/sequence behaviour.
Either the target was already used or a previous migration partially populated it. Reset the target as suggested in the error message and retry.
Check the application logs at /var/log/ucm/ucm.log. The source database is untouched — fix the target (drop schema, fix permissions, etc.) and retry. Restore the source from the backup created at the start of the migration if anything looks off.
Edit your docker-compose.yml:
services:
ucm:
environment:
DATABASE_URL: postgresql+psycopg2://ucm:secret@db:5432/ucmThen docker compose up -d.
- Configuration — full environment variable reference
- Installation Guide — DEB / RPM / Docker setup
- Backup-Restore — database backup workflow