Capacity planning¶
This page helps you size a PKIFactor installation for production and plan its growth. It starts from what was measured on a running appliance, then gives estimates for larger estates. The estimates extrapolate the measurements; check them against your own monitoring after a few weeks in service and adjust.
What was measured¶
Test appliance, version 1.8.50, in daily use for several weeks: about 300 certificates in the inventory (150 managed), a dozen devices, the ACME, EST, CMP and SCEP gateways enabled, Certificate Transparency monitoring and directory synchronization running.
| Resource | Measured |
|---|---|
| Virtual machine | 2 vCPU, 6 GB of memory, 40 GB of disk |
| Memory used by the containers, steady state | about 2 GB in total: backend 630 MB, background worker 200 MB, PostgreSQL 160 MB, each gateway about 60 MB, interface 80 MB, nginx 10 MB |
| Database | 31 MB in total; the certificates table holds about 18 KB per certificate (certificate, chain, request, encrypted private key when PKIFactor generated it) |
Logs and audit trail (pkifactor_audit_logs volume) |
about 3.5 MB per day, of which 150 to 225 KB of audit events (300 to 600 events a day, about 0.4 KB each); the rest is mostly the access log |
| Container images | about 20 GB, half of which can be reclaimed after an upgrade (previous versions) |
Backups (pkifactor_backups volume) |
39 MB for the retained local backups |
Sizing for production¶
| Use | vCPU | Memory | Disk (SSD) |
|---|---|---|---|
| Test or evaluation (the measured appliance) | 2 | 6 GB | 40 GB |
| Production, starting point | 4 | 8 GB | 100 GB |
These values are deliberately generous: the measured appliance uses about a third of its memory in steady state, and production needs room for peaks (a wave of renewals, a network scan, a restore) and for the database cache. Then size the disk on the database, which grows with the number of stored certificates (below), add processors and memory with WEB_WORKERS when the interface and the API are heavily used, and use high availability when continuity matters. For a very large estate, ZetaCert validates the sizing with you.
What makes the installation grow¶
Database¶
Plan about 20 KB per stored certificate. Renewals are stored, not overwritten, so the database grows with the renewal rate:
| Estate | Validity | Renewals a year | Growth a year (estimate) |
|---|---|---|---|
| 10,000 internal certificates | 1 year | 1 | about 200 MB |
| 10,000 public TLS certificates | 200 days (from March 2026) | 2 | about 400 MB |
| 10,000 public TLS certificates | 47 days (from March 2029) | about 8 | about 1.6 GB |
Shorter public validity periods multiply the growth: re-check the disk when your public certificates move to 100 days, then to 47 days. Certificates only discovered (network scan, Certificate Transparency, import) are lighter, as PKIFactor holds no key for them.
Audit trail and logs¶
The audit trail and the technical logs rotate every night and are kept 7 days on the appliance (PKIFACTOR_LOG_RETENTION_DAYS). On the measured appliance this is about 25 MB in total. The volume grows with the traffic, mainly with the number of API and ACME calls. For a longer retention, forward the events to your SIEM (SIEM and syslog) rather than raising the local retention.
Backups¶
A backup is about the size of the database, compressed and encrypted. Plan number of retained backups × database size, and keep a copy off the host (Backup and restore).
Container images¶
Each upgrade brings new images (about 10 GB); the previous ones stay until you remove them. Keep room for two versions (about 20 GB), and reclaim the older one after a successful upgrade with docker image prune -a (it removes only images that no container uses).
Settings for a larger estate¶
| Setting | Default | When to change it |
|---|---|---|
WEB_WORKERS (.env) |
2 | One worker per vCPU of the appliance, up to 6 or 8. It sets the number of processes that serve the interface and the API |
DB_POOL_SIZE / DB_POOL_MAX_OVERFLOW |
8 / 8 | Connections per web worker. Keep (WEB_WORKERS × (DB_POOL_SIZE + DB_POOL_MAX_OVERFLOW)) + background worker below PostgreSQL max_connections (100 by default): 2 workers use up to 52 connections, 4 workers 84, 6 workers 116, which needs a higher max_connections or smaller pools |
WORKER_DB_POOL_SIZE / WORKER_DB_POOL_MAX_OVERFLOW |
10 / 10 | Connections of the background worker (renewals, deployments, scans, Certificate Transparency, synchronization) |
| Renewal threshold of the devices | 30 days | With thousands of certificates renewed by device, spread the renewals: different thresholds per profile or device, and the maintenance hour of the devices |
After any change in .env, restart the services (pkifactor-ctl restart).
What to watch in production¶
| Indicator | Where | Act when |
|---|---|---|
Disk use of /var/lib/docker and /opt/pkifactor |
System monitoring | Above 75 %: reclaim old images, check the backup retention, grow the disk |
Memory of the pkifactor_backend container |
docker stats, system monitoring |
Steadily above 70 % of the host memory: add memory, or reduce WEB_WORKERS |
| State of the background tasks | Oversight workspace, Fleet monitoring > Monitoring | A task late or in error |
| Health endpoints | /health/live, /health/ready (Monitoring) |
degraded or not answering |
| Size of the images and volumes | pkifactor-ctl status (Docker images, Docker volumes) |
Volumes growing faster than the tables above predict |
| Database size | docker exec pkifactor_db psql -U clm_user -d clm_db -c "SELECT pg_size_pretty(pg_database_size('clm_db'))" |
Growth faster than the table above predicts |
| SIEM dead-letter file | siem_deadletter.log in the logs volume |
Not empty for long: the SIEM is unreachable |
See also Requirements and High availability.