This is a work in progress. Use at your own risk.
The project can be used either as a stand‑alone tool or as a development dependency. Installation differs slightly for each case.
- Install Node.js v22 or later
- Set the
CAPASSenvironment variable before running the setup script - (Optional) environment variables:
CA_VALIDITY_YEARS– number of years the root CA is valid (default5)LOG_FILE- path to a log fileLOG_LEVEL- log level (defaultinfo)AUDIT_LOG_FILE- path to the audit log file
- Install runtime dependencies with
npm install --production - Run
npm run setupto generate the root CA - Start the server with
npm start
- Install all dependencies with
npm install(ornpm ci) - Run
npm run lintto lint the codebase - Execute tests with
npm test - Start the development server with
npm run dev - On Windows you can use
npm run wininstead
-
Copy the configuration example
cp config\defaults.example.json config\defaults.json
-
Edit the configuration to best fit your needs
... "storeDirectory": "./files", // <- This is where your CA and certs will be saved "subject": { "email": { "prompt": "Email address for certificate administrator", "shortName": "E", "default": "something@example.com" // <- Email displayed on certificates }, "organization": { "prompt": "Organization or Company Name", "shortName": "O", "default": "Example Home Lab Industries INC." // <- Organization or Company Name }, "locality": { "prompt": "City or Locality", "shortName": "L", "default": "New York" // <- City or Locality }, "state": { "prompt": "State or Region", "shortName": "ST", "default": "New York" // <- State or Province }, "country": { "prompt": "Country code (eg. US)", "shortName": "C", "default": "US" // <- 2 character Country Code } }, "validDomains": [ "example.com" // <- This is used to validate cert request hostnames not alternate names ], "requireIntermediate": true, // <- Prevents root from issuing leaf certs "defaultIntermediate": "intermediate", // <- Intermediate CA used for server certificates ...
-
Set a CA passphrase in your environment variables and run setup.
- Note: This passphrase only be set once and will be needed to submit future requests
- Note: This will install only production needed dependencies
SET CAPASS=SecretPassphrase && npm run setup
-
Run the server
npm startFor development use:
npm run dev
Windows users can run
npm run winfor development on Windows. -
Submit a post request to the
http://localhost:{{SERVER.PORT}}/newendpoint with the following json body{ "hostname": "certs.example.com", "altNames": [ "certs.example.com", "certs.example.info", "localhost" ], "passphrase": "SecretPassphrase" } -
Submit a request to
http://localhost:{{SERVER.PORT}}/ldapto generate an LDAP server certificate{ "hostname": "ldap.example.com", "altNames": [ "ldap.example.com" ], "passphrase": "SecretPassphrase" } -
All your web certs will be saved to the directory specified in the config in the
newCertsdirectory. Private keys are all in theprivatedirectory. Your Root CA cert is in thecertsfolder and will need to be applied to all machines as a Trusted Root Certificate. If"bundleP12": trueis included in the request body, a PKCS#12 bundle will also be saved asnewCerts/<hostname>.bundle.p12. -
(Optional) Create an intermediate CA by posting to
http://localhost:{{SERVER.PORT}}/intermediateor running:CAPASS=SecretPassphrase node scripts/setup-intermediate.js intermediate-name
This intermediate certificate will be placed under
files/intermediates/and used by default for server certificates ifdefaultIntermediateis set in the configuration. WhenrequireIntermediateistrue, the application refuses to issue leaf certificates with the root key. When a server certificate is issued it is saved alongside a.chain.crtfile containing both the server and intermediate certificates and the HTTP response includes this chain in achainproperty. Present this chain so clients can validate the path using only the trusted root certificate.
This project now includes audit logging for privileged operations (for example: issuing a new CA or intermediate, revoking certificates, and other actions that use the CA private key).
What is logged
- Timestamp and operation type (create, revoke, intermediate, etc.)
- Username/actor or source IP when available (depends on how you authenticate/forward requests)
- Target resource (hostname, intermediate name, certificate fingerprint or serial)
- Outcome (success or failure) and an error message when applicable
- Minimal context required to reproduce the action (request body fields such as hostname and altNames are recorded, but private key material and passphrases are never logged)
How to enable and configure
- The audit logger is wired into the application and audit calls are emitted by the application as part of privileged operations. Audit entries are emitted as JSON objects (one JSON object per line) and include a timestamp.
- By default audit entries are written to the console (stdout) in JSON format. To write audit entries to a dedicated file, set the
AUDIT_LOG_FILEenvironment variable to a filesystem path. - The audit logger uses a file transport (when
AUDIT_LOG_FILEis set) with the following defaults: JSON format with a timestamp, maxsize = 1,048,576 bytes (1 MB) and maxFiles = 5 for simple rotation. - Application logs (info/debug/error) are controlled separately by
LOG_FILEandLOG_LEVEL. SettingLOG_FILEdoes not affect where audit logs are stored.
Environment variables (audit-related)
AUDIT_LOG_FILE– path to the audit log file. When present audit entries are appended to this file (JSON, timestamped). If omitted, audit entries are written to stdout.LOG_FILE– path to the general application log file (separate fromAUDIT_LOG_FILE).LOG_LEVEL– controls the general logger verbosity (default:info). Audit entries use a dedicated audit logger and are emitted regardless ofLOG_LEVEL.
Example audit log entry (JSON, one line per entry)
{"ts":"2025-10-15T12:34:56.789Z","level":"audit","actor":"192.0.2.1","operation":"issue_certificate","target":"example.com","result":"success","serial":"01AB23CD","details":{"altNames":["example.com","www.example.com"],"bundleP12":true}}Notes and best practices
- Sensitive information: The implementation intentionally avoids logging sensitive secrets such as private keys and passphrases. Only operational metadata and request-level context are recorded.
- Rotation & retention: Use your system log rotation or a central log collector (ELK/Opensearch, Splunk, etc.) to rotate and retain audit logs according to your security policy.
- Time synchronization: Ensure your server's clock is synchronized (NTP) so timestamps can be correlated across systems.
- Forwarding logs: If you forward logs to a central collector, make sure transport and storage are protected (TLS, access controls).
- Create intermediate CAs using the setup script or
/intermediateendpoint - Allow more customization regarding certificate types and subjects
- Alert administrator when certificate is about to expire
- Enable admins to auto issue new certificates and send them to the certificate administrator