SPORK ACME Server Guide
v0.5.2 | 2,855 tests | 0 warnings | 0 audit vulnerabilities | 17/17 CI jobs green | FIPS 140-3 default
SPORK ACME Server is a standalone, RFC 8555-compliant certificate authority that works with certbot, acme.sh, and any ACME client out of the box. It includes a built-in micro-CA, interactive setup wizard, admin dashboard, and FIPS 140-3 mode.
Download
Download the installer and run the setup wizard:
# Download the installer
curl -fSL -o spork-acme-installer \
https://rayketcham.com/CRLs/sp0rk/static/spork-acme-server-0.5.2-linux-x86_64-installer
# Make executable
chmod +x spork-acme-installer
# Verify integrity (optional)
./spork-acme-installer --verify
# Run the interactive setup wizard (requires root)
sudo ./spork-acme-installer
/opt/spork-acme/bin/, and launches the interactive setup wizard.
Runs on any Linux x86_64 system (Rocky 8+, Ubuntu 18.04+, Debian 10+, Alpine 3.12+). No glibc or OpenSSL required.
System Requirements
| Requirement | Details |
|---|---|
| Architecture | x86_64 (amd64) |
| Operating System | Linux (any distribution with kernel 4.x+) |
| RAM | 256 MB minimum, 512 MB recommended |
| Disk | 100 MB for binary + 1 GB for CA data |
| Network | Port 6446 (ACME/HTTPS, configurable) |
| Dependencies | None — statically linked against musl libc |
Setup Wizard
The setup wizard runs automatically on first launch. It generates a complete CA hierarchy, TLS certificates, systemd service, and starts the ACME server.
sudo ./spork-acme-installer
The following screenshots show each step of the wizard.
SPORK ACME Server - Interactive Setup
Verifying binary integrity...
✓ Binary verified
╔════════════════════════════════════════════════════════╗
║ ║
║ SPORK ACME Server ║
║ Interactive Setup ║
║ v0.5.2 ║
║ ║
╚════════════════════════════════════════════════════════╝
Welcome! This wizard will set up a complete ACME server
with its own Certificate Authority in just a few steps.
What you'll get:
• RFC 8555 compliant ACME server
• Automatic TLS certificate issuance
• Post-quantum cryptography ready
• No external dependencies
Press Enter to continue...
CERTIFICATE SUBSCRIBER AGREEMENT & TERMS OF SERVICE
════════════════════════════════════════════════
Version 1.0-alpha | Effective: February 2025
ALPHA SOFTWARE NOTICE
This CA is alpha software. It is provided for testing,
evaluation, and educational purposes only. SPORK CA is
NOT publicly trusted. No WebTrust, ETSI, or other audit
has been performed.
SPORK ACME is licensed under the Business Source License
1.1 (BSL). Licensor: QuantumNexum LLC
Allowed: Non-production use
Production: Requires a commercial license
Contact: licensing@quantumnexum.com
On 2130-01-01, this software converts to Apache License 2.0.
Type "I ACCEPT" to agree to these terms:
> I ACCEPT
CA DEPLOYMENT TYPE
══════════════════
Select deployment type:
> Standalone 2-Tier (Root CA → ACME) - Simplest setup
Standalone 3-Tier (Root → Issuing → ACME) - Production recommended
Windows CA Integration
Import existing CA (PFX/PKCS#12 file)
Architecture:
┌─────────────────────┐
│ Root CA │ (signs end-entity certs)
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ ACME Server │ (this server)
└─────────────────────┘
FIPS 140-3 MODE
═══════════════
This binary uses aws-lc-rs (NIST Certificate #4816)
for all cryptographic operations.
FIPS On restricts algorithms to FIPS-approved set:
ECDSA P-256/P-384, RSA ≥3072, RSA-PSS ≥3072
FIPS Off allows all algorithms (Ed25519, RSA-2048, PQC):
Crypto backend is still FIPS-certified, but algorithm
policy restrictions are relaxed.
Select:
> FIPS On - FIPS-approved algorithms only (Recommended)
FIPS Off - All algorithms available (Ed25519, RSA-2048, PQC)
CRYPTOGRAPHIC ALGORITHM
═══════════════════════
FIPS Mode: On — showing FIPS-approved algorithms only
Select signing algorithm:
> ECDSA P-256 - Fast, widely compatible (FIPS ✓) (Recommended)
ECDSA P-384 - Higher security margin (FIPS ✓)
RSA 3072 SHA-384 - CNSA 1.0, IIS/Windows native (FIPS ✓)
RSA 4096 - Maximum RSA security (FIPS ✓)
CA IDENTITY
═══════════
Domain name (optional, press Enter to skip): quantumnexus.com
→ DC=example, DC=com
Organization (O): Acme Corporation
Org Unit (OU) (optional, comma-separated): Engineering, Security
Full DN (without CN):
DC=example, DC=com, O=Acme Corporation, OU=Engineering, OU=Security
Root CA Common Name [Acme Corporation Root CA]: Acme Root CA
Is this correct? [Y/n] Y
SERVER CONFIGURATION
════════════════════
External hostname (domain name or IP clients will use)
[acme.quantumnexus.com]: acme.quantumnexus.com
ACME server port [6446]: 6446
Tip: Bind to 0.0.0.0 to listen on all network interfaces.
Bind address [0.0.0.0]: 0.0.0.0
Installation directory [/opt/spork-acme]: /opt/spork-acme
REVIEW CONFIGURATION
════════════════════
[1] Deployment: Standalone 2-Tier
[2] FIPS Mode: On
[3] Algorithm: ecdsa-p256
[4] Subject DN: DC=example, DC=com, O=Acme Corporation
[5] Root CA DN: CN=Acme Root CA, DC=example, DC=com, O=Acme Corporation
[6] External URL: https://acme.quantumnexus.com:6446
[7] Bind Address: 0.0.0.0:6446
[8] Install Path: /opt/spork-acme
Optional Features:
[T] Trust CA: Yes
[U] Admin UI: Yes (at /admin)
[P] Proxy: No
What would you like to do?
> Proceed with setup
Edit a field
Cancel
SETTING UP...
════════════
[1/12] Creating data directory...
✓ /opt/spork-acme
[2/12] Setting up encrypted key storage...
✓ Encrypted lockbox created (AES-256-GCM + Argon2id)
[3/12] Initializing Certificate Authority...
✓ Root CA initialized (ecdsa-p256)
→ Certificate: /opt/spork-acme/ca/root.crt
[4/12] Generating TLS server certificate...
✓ TLS certificate issued
→ Certificate: /opt/spork-acme/tls/server.crt
[5/12] Generating SuperAdmin certificate...
✓ SuperAdmin PFX generated
╔══════════════════════════════════════════════════════╗
║ SAVE THESE CREDENTIALS NOW - SHOWN ONLY ONCE! ║
╘══════════════════════════════════════════════════════╝
PFX Password: xK9pL2mN4qR7sT8vW1yZ3aB5cD6eF8gH
Recovery Code: ACME-2025-RECOVER-XXXXX
[6/12] Configuring ACME server...
✓ ACME configuration saved
[7/12] Installing binary...
✓ Binary installed to /opt/spork-acme/bin/spork-acme
[8/12] Installing systemd service...
✓ Created /etc/systemd/system/spork-acme.service
✓ Enabled spork-acme.service
✓ Enabled spork-acme-crl.timer (CRL every 6h)
[9/12] Installing CA certificate to system trust store...
✓ CA added to system trust store
[10/12] Configuring web server proxy...
— Skipped (no proxy selected)
[11/12] Generating CRL...
✓ CRL generated (7-day lifetime)
[12/12] Final checks...
✓ All components initialized
╔══════════════════════════════════════════════════════╗
║ ✓ SETUP COMPLETE! ║
╚══════════════════════════════════════════════════════╝
Your SPORK ACME server is ready!
Installation Summary
───────────────────────────────────────────────────────
Install Path: /opt/spork-acme
Service: systemd (spork-acme.service)
Binary: /opt/spork-acme/bin/spork-acme
External URL: https://acme.quantumnexus.com:6446
Admin Dashboard: https://acme.quantumnexus.com:6446/admin
Getting Started
───────────────────────────────────────────────────────
1. Start the service:
$ systemctl start spork-acme.service
2. Check status:
$ systemctl status spork-acme.service
3. Test with certbot:
$ certbot certonly \
--server https://acme.quantumnexus.com:6446/directory \
--standalone --agree-tos -d test.quantumnexus.com
4. Access admin dashboard:
https://acme.quantumnexus.com:6446/admin
Deployment Types
| Option | Description | Recommended |
|---|---|---|
| 2-tier | Root CA + Issuing CA (root stays offline) | Yes, for testing |
| 3-tier | Root + Policy CA + Issuing CA | Enterprise production |
| Subordinate | Subordinate to Windows CA (CSR export/import) | AD-integrated environments |
| WinRM Bridge | Direct subordination via WinRM to Windows CA | Automated AD environments |
| Import PFX | Import existing CA from PFX/PKCS#12 file | Migration from existing CA |
Algorithm Selection
| Algorithm | Type | Notes |
|---|---|---|
| ECDSA P-256 | Classical | Default. Fastest, broadest compatibility. FIPS-approved. |
| ECDSA P-384 | Classical | Higher security margin. FIPS-approved. |
| RSA 3072 / 4096 | Classical | Legacy compatibility. FIPS-approved (≥3072). |
| ML-DSA-65 | Post-Quantum | NIST FIPS 204. Requires PQC-aware clients. |
| ML-DSA-65 + ECDSA P-256 | Hybrid | Composite signature. Best of both worlds. |
| ML-DSA-87 + ECDSA P-384 | Hybrid | Maximum security for both classical and PQC. |
| SLH-DSA-SHA2-128s | Post-Quantum | Hash-based, conservative security assumptions. |
--no-default-features --features ceremony.
DN Builder
The setup wizard includes an interactive Distinguished Name builder for configuring your CA subject. It supports multi-level attributes with editing and reordering.
| Attribute | Description | Example |
|---|---|---|
| CN (Common Name) | CA display name | QuantumNexus Issuing CA |
| O (Organization) | Organization name (removable) | QuantumNexus Inc |
| OU (Org Unit) | Multi-level OU support | IT Security, PKI Operations |
| C (Country) | 2-letter ISO code | US |
| ST (State) | State or province | California |
| L (Locality) | City | San Francisco |
| DC (Domain Component) | Auto-parsed from domain | DC=example,DC=com |
The builder provides a review screen showing the full DN preview:
Subject DN: CN=QuantumNexus Issuing CA, OU=PKI Operations, O=QuantumNexus Inc, C=US
[1] Edit attributes
[2] Reorder attributes
[3] Remove an attribute
[4] Accept and continue
Bind Address & Ports
| Setting | Default | Description |
|---|---|---|
| Bind address | 0.0.0.0 | IP to listen on (127.0.0.1 for localhost-only) |
| ACME port | 6446 | HTTPS port for ACME protocol and admin UI |
| External URL | Auto-detected | Public URL clients use to reach this server |
The wizard also prompts for:
- Lockbox passphrase — encrypts all CA private keys (AES-256-GCM + Argon2id)
- Systemd service — install and enable
spork-acme.service - System trust store — optionally add CA cert to OS trust store
FIPS Mode
The official SPORK ACME binary ships with FIPS 140-3 enabled by default. All cryptographic operations use aws-lc-rs (NIST Certificate #4816) as the backend. No special build steps, flags, or separate downloads are needed — one binary, FIPS by default.
Setup Wizard Toggle
During setup, the wizard asks you to choose FIPS mode:
FIPS 140-3 MODE
═══════════════
This binary uses aws-lc-rs (NIST Certificate #4816)
for all cryptographic operations.
> FIPS On - FIPS-approved algorithms only (Recommended)
FIPS Off - All algorithms available (Ed25519, RSA-2048, PQC)
- FIPS On (default): Only FIPS-approved algorithms shown in algorithm selection (ECDSA P-256/P-384, RSA ≥3072)
- FIPS Off: All algorithms available including Ed25519, RSA-2048, and PQC. The crypto backend is still aws-lc-rs (FIPS-certified) — only the algorithm policy is relaxed.
FIPS Algorithm Matrix
| Algorithm | FIPS Status | Notes |
|---|---|---|
| ECDSA P-256 | Approved | Recommended default |
| ECDSA P-384 | Approved | Higher security margin |
| RSA ≥3072 | Approved | RSA-2048 rejected |
| RSA-PSS ≥3072 | Approved | |
| Ed25519 | Not approved | Available with FIPS Off |
| RSA-2048 | Not approved | Available with FIPS Off |
| ML-DSA-* | Approved (FIPS 204) | Requires PQC feature flag |
| SLH-DSA-* | Approved (FIPS 205) | Requires PQC feature flag |
Verifying FIPS Mode
# Check if binary was built with FIPS
./spork-acme --version
# Output includes "fips" in feature list
# Server logs show FIPS status at startup
sudo journalctl -u spork-acme | grep -i fips
Domain Policy
SPORK ACME Server uses a deny-by-default domain policy. All certificate
requests are rejected unless the requested domain matches an --allow-domain pattern.
Configuration
# Allow all domains (universal wildcard)
sudo spork-acme -s /opt/spork-acme --allow-domain "**"
# Allow a specific domain and all subdomains
sudo spork-acme -s /opt/spork-acme --allow-domain "**.quantumnexus.com"
# Allow only single-level subdomains
sudo spork-acme -s /opt/spork-acme --allow-domain "*.quantumnexus.com"
# Allow an exact domain
sudo spork-acme -s /opt/spork-acme --allow-domain "server1.quantumnexus.com"
# Multiple patterns (repeat the flag)
sudo spork-acme -s /opt/spork-acme \
--allow-domain "**.internal.corp" \
--allow-domain "*.lab.local"
Wildcard Patterns
| Pattern | Matches | Does Not Match |
|---|---|---|
** | Everything | — |
**.quantumnexus.com | a.quantumnexus.com, b.c.quantumnexus.com | quantumnexus.com |
*.quantumnexus.com | a.quantumnexus.com | b.c.quantumnexus.com |
server1.quantumnexus.com | server1.quantumnexus.com | server2.quantumnexus.com |
Policy File (domain-policy.toml)
In addition to CLI flags, you can define domain policy in a TOML file. The wizard auto-generates this file during setup. You can also create it manually:
# /opt/spork-acme/domain-policy.toml
[policy]
mode = "deny-by-default" # or "allow-by-default"
[[allow]]
pattern = "*.quantumnexus.com"
[[allow]]
pattern = "quantumnexus.com"
[[deny]]
pattern = "*.evil.com"
Load the policy file with --domain-policy-file:
spork-acme -s /opt/spork-acme \
--domain-policy-file /opt/spork-acme/domain-policy.toml
CLI flags (--allow-domain, --deny-domain) are additive with the policy file.
Deny rules always take precedence over allow rules. Domain policy applies to all protocols: ACME, EST, and SCEP.
--allow-domain or a policy file, the server
will reject all certificate requests. During the setup wizard, you are prompted to configure
allowed domains. Use --allow-domain "**" for testing environments.
Rate Limiting
SPORK ACME includes built-in rate limiting to protect against abuse:
| Limit | Default |
|---|---|
| Per-IP requests | 600/minute |
| Per-account requests | 300/minute |
To disable rate limiting (for testing or behind a load balancer that handles its own limits):
spork-acme -s /opt/spork-acme --no-rate-limit
Health & Metrics Endpoints
/health
Returns JSON with server health status including CA status, signer health, CRL age, and uptime:
curl -sk https://localhost:6446/health | jq
/metrics
Prometheus-format metrics endpoint with certificate, order, challenge, and account counters. Requires authentication (admin credentials or mTLS).
curl -sk https://localhost:6446/metrics
Service Management
The setup wizard installs two systemd units:
| Unit | Purpose |
|---|---|
spork-acme.service | Main ACME server process |
spork-acme-crl.timer | Periodic CRL regeneration (every 6 hours, 7-day validity) |
Common Commands
# Check server status
sudo systemctl status spork-acme
# Start / stop / restart
sudo systemctl start spork-acme
sudo systemctl stop spork-acme
sudo systemctl restart spork-acme
# Enable at boot
sudo systemctl enable spork-acme
# View live logs
sudo journalctl -u spork-acme -f
# View CRL timer status
sudo systemctl list-timers spork-acme-crl.timer
Management Menu
Running the installer again (or the installed binary) with an existing installation presents a management menu:
sudo /opt/spork-acme/bin/spork-acme
SPORK ACME Server v0.5.2
Existing installation detected at /opt/spork-acme/
1) Configure - Web UI, TLS certificates, proxy settings
2) Backup - Create/restore encrypted backups, scheduling
3) Security - Audit, hardening, permissions, user management
4) Upgrade - Upgrade binary with full backup
5) Status - Service health and configuration review
6) Uninstall - Clean removal with optional backup
Select an option [1-6]:
Server Mode (No Systemd)
Run the server directly in the foreground for debugging:
sudo SPORK_LOCKBOX_PASSPHRASE="your-passphrase" \
spork-acme -s /opt/spork-acme
Admin Dashboard
The admin portal is served at https://hostname:6446/admin and provides
certificate inventory, revocation status, CA health, and audit logs.
Authentication Methods
| Method | Setup | Security Level |
|---|---|---|
| HTTP Basic Auth | --admin-user / --admin-password-file | Standard |
| mTLS (Client Cert) | Import SuperAdmin PFX into browser | High |
| Bearer Token | Set via Configure > Web UI | Standard |
mTLS Setup
- During setup, the wizard generates a SuperAdmin PFX at
/opt/spork-acme/admin/superadmin.pfx - Copy the PFX to your workstation
- Import into your browser:
- Firefox: Settings → Privacy & Security → Certificates → View Certificates → Import
- Chrome: Settings → Privacy and Security → Security → Manage certificates → Import
- Navigate to
https://hostname:6446/adminand select the client certificate when prompted
Admin Certificate Hierarchy
| Level | Capabilities |
|---|---|
| SuperAdmin | Full control, issue admin certs, factory reset |
| Admin | Revoke certs, manage CRLs, issue certs |
| Operator | Issue certs, view logs |
| Viewer | View-only access |
Dashboard Features
- Certificate browser — search, filter, inspect issued certificates
- CA status — view CA hierarchy, validity, key status
- Revocation management — CRL status, OCSP responder health
- ACME dashboard — accounts, orders, challenge status
- Audit log — full trail of all operations with export (CSV/JSON)
Test with Certbot
Verify the ACME server works with a certbot dry-run:
# Dry-run test (does not save a certificate)
certbot certonly --standalone \
--server https://localhost:6446/acme/directory \
--no-verify-ssl \
--agree-tos \
-d test.quantumnexus.com \
--dry-run
Expected output:
Simulating a certificate request for test.quantumnexus.com
The dry run was successful.
Issue a real certificate:
certbot certonly --standalone \
--server https://localhost:6446/acme/directory \
--no-verify-ssl \
--agree-tos \
-d myhost.internal.quantumnexus.com
Rocky Linux / RHEL / CentOS Setup
Install Certbot
sudo dnf install -y epel-release
sudo dnf install -y certbot
Open the Firewall
sudo firewall-cmd --add-port=6446/tcp --permanent
sudo firewall-cmd --reload
SELinux Configuration
# Allow proxy connections (if using reverse proxy)
sudo setsebool -P httpd_can_network_connect 1
# Set file context for spork-acme binary
sudo semanage fcontext -a -t bin_t '/opt/spork-acme/bin/spork-acme'
sudo restorecon -v /opt/spork-acme/bin/spork-acme
# If denials persist, generate a targeted policy module
sudo ausearch -m avc -ts recent | audit2allow -M spork-acme
sudo semodule -i spork-acme.pp
audit2allow to create targeted policy
modules rather than switching to permissive mode.
Trust the CA Certificate
sudo cp /opt/spork-acme/ca/ca.crt /etc/pki/ca-trust/source/anchors/spork-ca.crt
sudo update-ca-trust
# Verify
openssl verify -CAfile /etc/pki/tls/certs/ca-bundle.crt /opt/spork-acme/ca/ca.crt
Keystore Passphrase for Service Mode
sudo mkdir -p /etc/spork-acme
sudo tee /etc/spork-acme/env > /dev/null <<'EOF'
SPORK_LOCKBOX_PASSPHRASE=your-passphrase-here
EOF
sudo chmod 600 /etc/spork-acme/env
sudo chown root:root /etc/spork-acme/env
Ubuntu / Debian Setup
Install Certbot
sudo apt update
sudo apt install -y certbot
Trust the CA Certificate
sudo cp /opt/spork-acme/ca/ca.crt /usr/local/share/ca-certificates/spork-ca.crt
sudo update-ca-certificates
Firewall (if UFW is enabled)
sudo ufw allow 6446/tcp
sudo ufw reload
Ubuntu and Debian do not run SELinux by default, so no additional security context configuration is needed. The keystore passphrase setup is the same as Rocky Linux (see above).
ACME Client Examples
SPORK ACME is compatible with any RFC 8555 ACME client. Below are examples using certbot and acme.sh, the two most popular clients.
Certbot
# Install certbot
sudo apt install certbot # Debian/Ubuntu
sudo dnf install certbot # RHEL/Fedora
# Request a certificate (standalone — certbot binds port 80)
sudo certbot certonly --standalone --non-interactive \
--server https://your-server:6446/directory \
-d myhost.quantumnexus.com
# Request a certificate (webroot — use existing web server)
sudo certbot certonly --webroot -w /var/www/html --non-interactive \
--server https://your-server:6446/directory \
-d myhost.quantumnexus.com
# Multiple SANs
sudo certbot certonly --webroot -w /var/www/html --non-interactive \
--server https://your-server:6446/directory \
-d quantumnexus.com -d www.quantumnexus.com -d mail.quantumnexus.com
# Check certificate status
sudo certbot certificates
# Renew all certificates nearing expiry
sudo certbot renew
# Test renewal (dry run)
sudo certbot renew --dry-run
/etc/letsencrypt/live/<domain>/. Each directory contains
fullchain.pem (certificate + chain), privkey.pem (private key),
cert.pem (certificate only), and chain.pem (chain only).
REQUESTS_CA_BUNDLE=/path/to/ca.pem in your
environment or use --no-verify-ssl (testing only).
acme.sh
# Install acme.sh
curl https://get.acme.sh | sh
# Request a certificate
~/.acme.sh/acme.sh --issue \
--server https://your-server:6446/directory \
-d myhost.quantumnexus.com \
--webroot /var/www/html
# Install to web server config directory
~/.acme.sh/acme.sh --install-cert -d myhost.quantumnexus.com \
--cert-file /etc/ssl/certs/myhost.pem \
--key-file /etc/ssl/private/myhost.key \
--fullchain-file /etc/ssl/certs/myhost-fullchain.pem \
--reloadcmd "systemctl reload nginx"
Apache Integration
After obtaining a certificate with certbot, configure your Apache virtual host:
# Update your vhost config:
SSLCertificateFile /etc/letsencrypt/live/myhost.quantumnexus.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/myhost.quantumnexus.com/privkey.pem
# Test and reload
sudo apachectl configtest
sudo systemctl reload apache2 # or httpd on RHEL
Or use certbot's built-in Apache plugin:
sudo certbot --apache --non-interactive \
--server https://your-server:6446/directory \
-d myhost.quantumnexus.com
Nginx Integration
location ~ /\. { deny all; },
it will block ACME HTTP-01 challenges at /.well-known/acme-challenge/. Add a
^~ prefix location before the deny rule:
location ^~ /.well-known/acme-challenge/ {
allow all;
root /var/www/html;
}
After obtaining a certificate with certbot, configure your nginx server block:
# Update your server block:
ssl_certificate /etc/letsencrypt/live/myhost.quantumnexus.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myhost.quantumnexus.com/privkey.pem;
# Test and reload
sudo nginx -t
sudo systemctl reload nginx
Or use certbot's built-in nginx plugin:
sudo certbot --nginx --non-interactive \
--server https://your-server:6446/directory \
-d myhost.quantumnexus.com
Backup & Restore
Interactive Backup
sudo spork-acme
# Navigate: Backup > Create Backup
# Choose encryption option
# Select backup directory
What Gets Backed Up
- CA private keys (from encrypted keystore)
- CA certificates and chain files
- Configuration files
- Issued certificate database
- Admin certificates
- TLS server certificates
- ACME account data
Restore from Backup
sudo spork-acme
# Navigate: Backup > Restore
# Select backup file
# Enter encryption passphrase if encrypted
Manual Restore
# Stop service
sudo systemctl stop spork-acme
# Extract backup
sudo tar -xzf /var/backups/spork/spork-backup-full-*.tar.gz -C /opt/spork-acme
# Start service
sudo systemctl start spork-acme
Scheduled Backups
sudo spork-acme
# Navigate: Backup > Schedule
# Select frequency: Daily, Weekly, or Monthly
# Enable encryption
CRL Management
The CRL timer runs every 6 hours by default (7-day validity with overlap).
# Check CRL timer
sudo systemctl status spork-acme-crl.timer
# Manual CRL update
sudo spork-acme --update-crl -s /opt/spork-acme
# View last CRL update
sudo journalctl -u spork-acme-crl.service --since today
CRL distribution:
- Local path:
/opt/spork-acme/ca/crl.pem - HTTP endpoint:
https://your-server:6446/crl
TLS Certificate Renewal
Renew the server's own TLS certificate (used for HTTPS on port 6446):
# Check expiration
openssl s_client -connect localhost:6446 </dev/null 2>/dev/null | \
openssl x509 -noout -dates
# Manual renewal
sudo spork-acme --renew-tls -s /opt/spork-acme
# Automatic renewal timer
sudo systemctl enable --now spork-acme-renew.timer
Using Your Own TLS Certificate
You can use an externally-obtained TLS certificate instead of the self-issued micro-CA cert.
Option 1: CLI flags (highest priority)
spork-acme -s /opt/spork-acme \
--tls-cert /path/to/your-cert.pem \
--tls-key /path/to/your-key.pem
Option 2: Drop-in replacement
# Full chain preferred (your cert + intermediate(s))
/opt/spork-acme/tls/server-chain.crt
# Private key (PEM format)
/opt/spork-acme/tls/server.key
--tls-cert/--tls-keyCLI flags- Auto-detect from state dir:
tls/server-chain.crt+tls/server.key - Encrypted lockbox (wizard-generated key)
For mTLS client authentication with an external TLS cert:
spork-acme -s /opt/spork-acme \
--tls-cert /path/to/your-cert.pem \
--tls-key /path/to/your-key.pem \
--client-ca /path/to/client-ca.pem
Log Management
# Real-time logs
sudo journalctl -u spork-acme -f
# Today's errors only
sudo journalctl -u spork-acme --since today -p err
# Export logs
sudo journalctl -u spork-acme --since "2026-01-01" > spork-logs.txt
Log Levels
| Level | Use Case |
|---|---|
error | Production (minimal) |
info | Normal operations (default) |
debug | Troubleshooting |
trace | Development only |
# Set via command line
spork-acme -s /opt/spork-acme --log-level debug
# Set via environment
export RUST_LOG=spork_acme=debug
Security Hardening
Automated Hardening
sudo spork-acme
# Navigate: Security > Harden
This creates a dedicated spork user/group, sets restrictive file permissions, and configures ownership on the state directory.
Manual Hardening
# Create dedicated user
sudo useradd -r -s /bin/false -d /opt/spork-acme spork
# Set ownership and permissions
sudo chown -R spork:spork /opt/spork-acme
sudo chmod 750 /opt/spork-acme
sudo chmod 600 /opt/spork-acme/keystore.db
sudo chmod 700 /opt/spork-acme/ca
sudo chmod 700 /opt/spork-acme/admin
sudo chmod 600 /opt/spork-acme/admin/*.pfx
Systemd Hardening
The default service file includes security restrictions. Add these for high-security deployments:
[Service]
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/opt/spork-acme
PrivateTmp=true
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
# Additional hardening
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
PrivateDevices=true
RestrictSUIDSGID=true
MemoryDenyWriteExecute=true
Network Hardening
# Bind to localhost only (behind reverse proxy)
spork-acme -s /opt/spork-acme --host 127.0.0.1
Rate Limiting
| Limit | Default |
|---|---|
| Requests per IP | 600/minute |
| Requests per account | 300/minute |
Disable with --no-rate-limit if running behind a reverse proxy with its own rate limiting.
Security Audit
sudo spork-acme
# Navigate: Security > Audit
Security Checklist
- Run security hardening wizard
- Create dedicated spork user
- Verify file permissions (keystore 0600, state dir 0750)
- Configure firewall (allow only port 6446)
- Bind to specific interface (not 0.0.0.0 in production)
- Enable audit logging and forward to SIEM
- Schedule regular backups with encryption
- Rotate admin certificates annually
Windows CA Integration
SPORK can operate as a subordinate CA under your Windows Active Directory Certificate Services (AD CS) infrastructure. The Windows CA signs SPORK's CA certificate, then SPORK issues end-entity certificates via ACME.
Windows AD CS Root CA (RSA/ECDSA)
|
+--- signs subordinate ---> SPORK Issuing CA
|
+----------+----------+
v v v
ECDSA Hybrid ML-DSA
Step 1: Configure Windows CA Template
- Open Certificate Templates console (
certtmpl.msc) - Duplicate "Subordinate Certification Authority" template
- Set: name=
SPORKSubCA, validity=5-10y, pathLenConstraint=0, CA:TRUE - Publish:
certutil -setcatemplates +SPORKSubCA
Step 2: Generate CSR on SPORK
sudo spork-acme
# Select: Subordinate to Windows CA
# Choose algorithm (ECDSA P-256 recommended for Windows compat)
# CSR saved to: /opt/spork-acme/spork-acme.csr
Step 3: Submit CSR to Windows CA
REM On Windows CA server:
certreq -submit -attrib "CertificateTemplate:SPORKSubCA" spork-acme.csr spork-ca.cer
REM If pending approval:
certutil -resubmit <RequestID>
Step 4: Export Root CA Certificate
certutil -ca.cert windows-root.cer
certutil -encode windows-root.cer windows-root.pem
Step 5: Import to SPORK
spork-acme --import-cert /opt/spork-acme/ca/spork-ca.cer \
--import-chain /opt/spork-acme/ca/windows-root.pem \
-s /opt/spork-acme
Step 6: Verify
# Test ACME directory
curl -s https://acme.yourcompany.com:6446/directory | jq
# Issue a certificate
certbot certonly --standalone \
--server https://acme.yourcompany.com:6446/directory \
--agree-tos -d myserver.yourcompany.com
# Verify chain: TLS cert -> SPORK Issuing CA -> Windows Root CA
openssl s_client -connect acme.yourcompany.com:6446 -showcerts
Troubleshooting
Port 6446 already in use
sudo ss -tlnp | grep 6446
# Kill the conflicting process or change the ACME bind port
Permission denied on startup
sudo chmod +x /opt/spork-acme/bin/spork-acme
sudo chown -R root:root /opt/spork-acme
sudo chmod 700 /opt/spork-acme
SELinux denials (Rocky / RHEL)
sudo ausearch -m avc -ts recent
sudo ausearch -m avc -ts recent | audit2allow -M spork-acme-local
sudo semodule -i spork-acme-local.pp
Firewall blocking connections
# Rocky / RHEL
sudo firewall-cmd --add-port=6446/tcp --permanent
sudo firewall-cmd --reload
# Ubuntu / Debian
sudo ufw allow 6446/tcp
Certbot fails with SSL errors
# Option 1: Use --no-verify-ssl
certbot certonly --standalone \
--server https://localhost:6446/acme/directory \
--no-verify-ssl --agree-tos -d test.quantumnexus.com --dry-run
# Option 2: Set REQUESTS_CA_BUNDLE
export REQUESTS_CA_BUNDLE=/opt/spork-acme/ca/ca.crt
certbot certonly --standalone \
--server https://localhost:6446/acme/directory \
--agree-tos -d test.quantumnexus.com --dry-run
Service fails to start (keystore error)
# Check logs
sudo journalctl -u spork-acme -n 50
# Verify environment file
ls -la /etc/spork-acme/env
sudo grep SPORK_LOCKBOX_PASSPHRASE /etc/spork-acme/env
CRL timer not running
sudo systemctl status spork-acme-crl.timer
sudo systemctl enable --now spork-acme-crl.timer
# Manual trigger
sudo systemctl start spork-acme-crl.service
Domain rejected by server
# Check that --allow-domain is configured
sudo journalctl -u spork-acme | grep -i "domain.*denied\|domain.*reject"
# Add allowed domains
# Edit the systemd ExecStart line or config to include:
# --allow-domain "**.yourdomain.com"
# Then restart:
sudo systemctl restart spork-acme
FIPS mode rejects algorithm
The official binary ships with FIPS enabled by default. Ed25519 and RSA-2048 are not available. Re-run setup and choose a FIPS-approved algorithm:
# Re-run setup with ECDSA P-256/P-384 or RSA ≥3072
sudo spork-acme
"No supported challenge type"
The ACME server did not offer HTTP-01 or DNS-01 challenges. Check that:
- The domain name is valid RFC 1035 format
- The ACME server is reachable at the specified URL
- Your ACME account is registered (certbot registers automatically on first use)
Certbot fails to deploy certificate
# Use certonly and deploy manually
sudo certbot certonly --webroot -w /var/www/html --non-interactive \
--server https://your-server:6446/directory \
-d quantumnexus.com
# Then configure web server with:
# /etc/letsencrypt/live/quantumnexus.com/fullchain.pem
# /etc/letsencrypt/live/quantumnexus.com/privkey.pem
Windows CA: "Key mismatch" during import
The certificate was signed from a different CSR. Verify you are importing the certificate that matches your CSR. If the CSR was regenerated, request a new certificate from Windows CA.
Windows CA: "Not a CA certificate"
The Windows CA used the wrong template. Verify the template has BasicConstraints CA:TRUE with pathLenConstraint=0, marked critical.