Administration and configuration guide for Ultimate Certificate Manager.
UCM stores data in:
- Database --
/opt/ucm/data/ucm.db(SQLite, default) or PostgreSQL viaDATABASE_URL - Data Directory --
/opt/ucm/data/(certificates, keys, backups) - Config --
/etc/ucm/ucm.env(DEB/RPM) or environment variables (Docker) - Logs --
/var/log/ucm/(DEB/RPM) or stdout (Docker)
| Variable | Default | Description |
|---|---|---|
UCM_SECRET_KEY |
(generated) | Session signing key |
UCM_HOST |
0.0.0.0 |
Bind address |
UCM_PORT |
8443 |
HTTPS port |
UCM_DATA_DIR |
/opt/ucm/data |
Data storage |
UCM_LOG_LEVEL |
INFO |
Logging verbosity |
UCM_HTTPS_CERT |
(auto) | Server certificate |
UCM_HTTPS_KEY |
(auto) | Server private key |
DATABASE_URL |
(unset → SQLite) | SQLAlchemy URL. Set to postgresql://user:pass@host:5432/dbname to use PostgreSQL. When unset, UCM uses SQLite at UCM_DATA_DIR/ucm.db. |
# Check status
sudo systemctl status ucm
# Restart service
sudo systemctl restart ucm
# View logs
sudo journalctl -u ucm -f
# Enable on boot
sudo systemctl enable ucmThe service runs as user ucm with restricted permissions (NoNewPrivileges, ProtectSystem=strict).
Logs are rotated automatically via logrotate:
- Location:
/etc/logrotate.d/ucm - Rotation: Daily, 14 copies kept
- Compression: gzip
See LOG_ROTATION.md for details.
UCM auto-generates a self-signed certificate on first run.
Replace with trusted certificate:
- Go to Settings > Security tab
- Select certificate from your CA
- Click Apply HTTPS Certificate
- Restart service:
sudo systemctl restart ucm
Or via files:
sudo cp /path/to/cert.pem /opt/ucm/data/https_cert.pem
sudo cp /path/to/key.pem /opt/ucm/data/https_key.pem
sudo chown ucm:ucm /opt/ucm/data/https_*.pem
sudo systemctl restart ucmConfigure in Settings > Security:
| Setting | Default | Description |
|---|---|---|
| Session Timeout | 24h | Auto-logout after inactivity |
| Max Sessions | 5 | Per-user session limit |
| Require 2FA | No | Force MFA for all users |
UCM enforces 0o700 on its session directory at boot. If the directory is group- or world-readable, the service refuses to start:
RuntimeError: Refusing to boot: session dir <path> has perms 0o755, expected 0o700
Default paths:
| Install method | Path |
|---|---|
| DEB / RPM (systemd) | /var/lib/ucm/sessions/ |
Source / /opt/ucm |
/opt/ucm/data/sessions/ |
| Docker | /app/data/sessions/ (inside container) |
DEB/RPM post-install scripts and the Docker entrypoint already set the right perms. After a manual cp -r or migration that lost ownership:
sudo chown -R ucm:ucm /var/lib/ucm/sessions
sudo chmod 0700 /var/lib/ucm/sessions
sudo systemctl restart ucmThe same recommendation applies to any directory holding TLS keys or HSM PINs (/etc/ucm/, /var/lib/ucm/keys/).
If you terminate TLS on a reverse proxy (Nginx, Traefik, HAProxy, NPM) and forward client info to UCM via headers, declare the proxy CIDR(s) in Settings → Security → Trusted proxies:
security.trusted_proxies = 10.0.0.5/32, 192.168.10.0/24
This affects:
- Audit log IP —
X-Forwarded-Foris honoured only when the request comes from a trusted CIDR; otherwise the directremote_addris used. Spoofed XFF from untrusted networks is ignored. - mTLS / EST / SCEP — proxy-injected
X-SSL-Client-*headers are only accepted from trusted CIDRs. Direct deployments (UCM terminates TLS itself) are unaffected.
Enable/disable in Settings > Security:
- Password -- Standard username/password
- 2FA TOTP -- Time-based one-time password
- WebAuthn -- Hardware security keys
- mTLS -- Client certificate authentication
mTLS client certificates can be enrolled from the Account → mTLS tab. Once enrolled, certificates are fully managed by UCM:
- User Certificates page (
/user-certificates) — Dedicated page to list, export, revoke, and delete all mTLS client certificates - Export — Download as PEM (with key and chain) or PKCS12 (password-protected)
- Revoke — Revoke with reason (key compromise, superseded, etc.)
- RBAC — Viewers see only their own certificates; operators and admins see all
Configure SSO under Settings → SSO. UCM supports three SSO providers:
LDAP / Active Directory:
- Server URL, bind DN, search base, user/group filters
- Group-to-role mapping (map AD groups to UCM roles)
- Test connection before saving
OAuth2 (Azure AD, Google, GitHub):
- Client ID, Client Secret, Authorization/Token/UserInfo URLs
- Callback URL:
https://your-server:8443/api/v2/auth/sso/oauth2/callback - Role claim mapping from token attributes
SAML 2.0:
- IdP Metadata URL or manual XML upload
- Entity ID, ACS URL, certificate configuration
- Attribute mapping for username, email, roles
Important: After configuring SSO, test with a non-admin account first. Keep at least one local admin account as fallback.
Configure SMTP settings under Settings → Email to enable email notifications:
- SMTP Host/Port — Mail server address and port
- Credentials — Username and password (if required)
- Encryption — None, STARTTLS, or SSL/TLS
- From Address — Sender email for all notifications
- Content Type — HTML, Plain Text, or Both
- Alert Recipients — One or more email addresses for expiry alerts
Use the Test button to send a test email and verify connectivity.
Customize the notification email template via the built-in editor:
- Navigate to Settings → Email → Email Template
- Click Edit Template to open the floating editor window
- Switch between HTML and Plain Text tabs
- Edit the template source on the left, see the live preview on the right
- Available variables:
{{title}},{{content}},{{datetime}},{{instance_url}},{{logo}},{{title_color}} - Click Save to apply, or Reset to Default to restore the UCM default template
When SMTP is configured, enable automatic certificate expiry alerts:
- Toggle notifications on/off
- Select warning thresholds (90, 60, 30, 14, 7, 3, 1 days before expiry)
- Check Now triggers an immediate scan of all certificates
Via UI:
- Go to Settings > Backup tab
- Click Create Backup
- Enter encryption password
- Download
.ucmbkpfile
Via command line:
sudo systemctl stop ucm
sudo cp /opt/ucm/data/ucm.db ~/ucm-backup-$(date +%Y%m%d).db
sudo systemctl start ucmVia UI:
- Go to Settings > Backup tab
- Click Restore Backup
- Upload
.ucmbkpfile - Enter encryption password
- All certificates and private keys
- CA hierarchy
- Users and settings
- Audit logs
- Templates
UCM supports two database backends:
- SQLite (default) — zero-config, file-based, suitable for single-node deployments
- PostgreSQL 13+ — recommended for high availability, multi-instance, or when you already operate a managed PG cluster
The active backend is selected by the DATABASE_URL environment variable (or /etc/ucm/ucm.env on DEB/RPM):
- Unset → SQLite at
UCM_DATA_DIR/ucm.db postgresql://user:pass@host:5432/dbname→ PostgreSQL
Settings → Database shows the current backend, size, table count, and exposes:
- Test connection — validate a
DATABASE_URLbefore switching - Switch backend — persist
DATABASE_URLto/etc/ucm/ucm.envand restart (DEB/RPM) - Migrate data — copy all rows from the current backend to the target, then restart
The migration is bidirectional (SQLite ↔ PostgreSQL) and:
- Backs up the source first (
/opt/ucm/data/backups/db_migration/) - Creates the schema on the target via SQLAlchemy
- Disables FK checks during bulk load
- Intersects source/target columns (legacy columns are skipped with a warning)
- Resets PostgreSQL sequences after load
Safety checks (fail fast, source untouched):
- Test connection rejects PostgreSQL servers older than 13 (UCM minimum supported version).
- Migrate refuses if the target already contains UCM data (rows in
users,cas, orcertificates). Reset the target first:- PostgreSQL:
psql ... -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;' - SQLite: delete the target
.dbfile
- PostgreSQL:
- If a migration fails mid-way, the source is untouched and a backup is available under
/opt/ucm/data/backups/db_migration/. Reset the target before retrying.
⚠ Docker installs cannot persist
/etc/ucm/ucm.envfrom inside the container. After running Migrate on Docker, the API returns the target URL — setDATABASE_URLin yourdocker-compose.ymlordocker run -eand restart the container manually.
Admin lockout fix (v2.141). Switching the active backend from PostgreSQL back to SQLite (or vice versa) no longer locks out the admin account. The bcrypt password hash is preserved across the swap and the in-process SQLAlchemy session pool is rebuilt before the next login attempt. Earlier releases could leave a stale connection pool pointing at the old backend, causing
Invalid credentialson first login after the swap.
Backups now backend-aware (v2.141). The Backup action and
/api/v2/system/backupautomatically dispatch topg_dump -Fcwhen PostgreSQL is the active backend (custom format, suitable forpg_restore). SQLite continues to use file-copy snapshots. Restore handles both formats transparently.
Location: /opt/ucm/data/ucm.db
Vacuum database:
sudo systemctl stop ucm
sqlite3 /opt/ucm/data/ucm.db "VACUUM;"
sudo systemctl start ucmExport database:
sqlite3 /opt/ucm/data/ucm.db ".dump" > ucm_dump.sqlUCM supports PostgreSQL 13+ as a drop-in replacement for SQLite. The schema is created automatically on first start.
Recommended PostgreSQL setup:
CREATE USER ucm WITH PASSWORD 'strong-password';
CREATE DATABASE ucm OWNER ucm;
GRANT ALL PRIVILEGES ON DATABASE ucm TO ucm;Activate PostgreSQL (DEB/RPM):
echo 'DATABASE_URL=postgresql://ucm:strong-password@db.example.com:5432/ucm' | sudo tee -a /etc/ucm/ucm.env
sudo systemctl restart ucmActivate PostgreSQL (Docker):
# docker-compose.yml
services:
ucm:
image: neyslim/ultimate-ca-manager:latest
environment:
DATABASE_URL: postgresql://ucm:strong-password@db:5432/ucmBackup PostgreSQL:
pg_dump -U ucm -h db.example.com ucm > ucm-pg-backup.sqlRestore PostgreSQL:
psql -U ucm -h db.example.com ucm < ucm-pg-backup.sqlℹ The
psycopg2-binarydriver is bundled with the DEB/RPM packages and the Docker image. No extra install step is needed.
| Table | Purpose |
|---|---|
users |
User accounts |
certificates |
Certificate records |
certificate_authorities |
CA records |
audit_logs |
Activity audit trail |
settings |
Application settings |
templates |
Certificate templates |
acme_accounts |
ACME client accounts |
scep_requests |
SCEP enrollment requests |
Configure CRL endpoint:
- CRL URL:
https://your-server:8443/crl/<ca-id>.crl - Configure in CA settings > CRL tab
- Set regeneration interval
OCSP responder runs automatically:
- URL:
https://your-server:8443/ocsp - Signing: Uses issuing CA's certificate
- Caching: 5-minute response cache
View ACME accounts and orders in the ACME page, or via API:
curl -k -b cookies.txt https://localhost:8443/api/v2/acme/accountsView pending SCEP requests in the SCEP page, or via API:
curl -k -b cookies.txt https://localhost:8443/api/v2/scep/requests?status=pendingEST (RFC 7030) is configured under Operations → EST:
- Enable EST and select the issuing CA
- Authentication — Configure client authentication (HTTP Basic or TLS mutual auth)
- Endpoint —
https://your-server:8443/.well-known/est/ - Operations — Simple enroll, re-enroll, CA certs distribution
- Monitor EST requests in the Operations page
Configure certificate discovery under Operations → Discovery:
- Scan Profiles — Create profiles with target hosts/CIDR ranges, port lists, and scan options
- Scheduling — Enable scheduled scans with configurable intervals
- Results — View discovered certificates, filter by status, expiry, issuer
- Quick Scan — One-off scans without creating a profile
- SNI support — Enable SNI for virtual host scanning
Admin reset:
- Go to Users page
- Select user
- Click Reset Password
- Set temporary password
- User must change on next login
| Role | Certificates | CAs | Users | Settings |
|---|---|---|---|---|
| Admin | Full | Full | Full | Full |
| Operator | Full | Full | Read | Read |
| Auditor | Read | Read | None | None |
| Viewer | Read (limited) | Read | None | None |
Users can create API keys for automation:
- Go to Account > API Keys
- Click Generate Key
- Copy key (shown only once)
- Use in
X-API-Keyheader
curl -k https://localhost:8443/api/health
# Or remotely: curl -k https://your-server-fqdn:8443/api/healthKey metrics to monitor:
- Certificate expiration dates
- CA validity periods
- Disk space for data directory
- Database size
All actions are logged:
- Go to Audit page
- Filter by action, user, date
- Export CSV for compliance
UCM includes a full report scheduler that can automatically generate and email reports on a recurring basis.
Prerequisite: Email delivery must be configured first. Go to Settings > Email and configure your SMTP server before enabling scheduled reports.
| Report Type | Description |
|---|---|
expiring_certificates |
Certificates expiring within N days |
revoked_certificates |
All revoked certificates with reason and date |
ca_hierarchy |
CA tree with issued certificate counts |
audit_summary |
Audit log activity grouped by action type |
compliance_status |
Policy compliance across all certificates |
certificate_inventory |
Full certificate inventory with metadata |
- Go to Reports page
- Click the schedule icon next to any report type
- Configure:
- Enabled — Toggle schedule on/off
- Frequency —
daily,weekly, ormonthly - Time — Execution time in
HH:MMformat (24-hour, server timezone) - Day of Week — For weekly:
0(Monday) through6(Sunday) - Day of Month — For monthly:
1through28 - Format — Output format:
csv,json, orpdf - Recipients — Email addresses to receive the report (max 50)
- Click Save
A weekly expiring certificates report sent every Monday at 8 AM:
Report Type: Expiring Certificates
Frequency: Weekly
Time: 08:00
Day of Week: Monday
Format: CSV
Recipients: admin@example.com, security@example.com
Before relying on a schedule, send a test report:
- Configure the schedule as desired
- Click Send Test on the report row
- A one-time report is generated and emailed to all configured recipients
- Verify the email arrives and the content is correct
- Reports not sending — Check SMTP configuration in Settings > Email
- Empty reports — Verify the report type has data (e.g., no expiring certs if all are valid)
- Wrong timezone — Report time uses server timezone; check system clock
- Recipient limit — Maximum 50 email addresses per report schedule
See UPGRADE.md for version-specific migration steps.
# Check logs
sudo journalctl -u ucm -n 100
# Check permissions
ls -la /opt/ucm/data/
sudo chown -R ucm:ucm /opt/ucm/data/
# Check port
sudo netstat -tlpn | grep 8443# Find locking process
fuser /opt/ucm/data/ucm.db
# Stop service and fix
sudo systemctl stop ucm
sqlite3 /opt/ucm/data/ucm.db "PRAGMA integrity_check;"
sudo systemctl start ucm