ACME Server Install Guide
spork-acme-server 0.3.0-alpha.2 -- a standalone ACME certificate authority you can deploy on any Linux server in under five minutes. It implements RFC 8555 and works with certbot, acme.sh, Caddy, Traefik, and any other ACME client.
Table of Contents
- Requirements
- Download
- Install
- CA Setup (Interactive Wizard)
- Running the Server
- Client Configuration
- Quick Start Example
- CLI Reference
- Systemd Service
- Trust Helper Scripts
- Admin Web UI
- Troubleshooting
1. 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 |
| Privileges | Root or sudo for installation and service management |
Should work on any x86_64 Linux with kernel 4.x or later. Tested on Ubuntu 24.04 and Rocky Linux 9.
2. Download
curl -fSL -o spork-acme-installer \
https://rayketcham.com/CRLs/sp0rk/static/spork-acme-server-0.3.0-alpha.2-linux-x86_64-installer
Verify Integrity
The installer is Ed25519-signed and contains embedded SHA3-256 checksums. Verify before running:
chmod +x spork-acme-installer
./spork-acme-installer --verify
If verification passes, the installer prints OK and exits with status 0.
If it fails, do not proceed -- download a fresh copy.
3. Install
sudo ./spork-acme-installer
The installer does three things:
- Verifies the embedded SHA3-256 checksums and Ed25519 signature
- Extracts the
spork-acmebinary to/usr/local/bin/ - Launches the interactive setup wizard automatically
/opt/spork-acme/, the installer detects it and presents an
upgrade/configure/uninstall menu instead.
4. CA Setup (Interactive Wizard)
The setup wizard runs automatically after installation. You can also invoke it manually at any time:
sudo spork-acme
The wizard walks through the following steps:
4.1 Deployment Type
| Option | Description | When to Use |
|---|---|---|
| 2-Tier CA | Root CA + Issuing CA | Recommended for most deployments |
| 3-Tier CA | Root + Policy CA + Issuing CA | Enterprise / compliance requirements |
| Subordinate to Windows CA | Issuing CA under existing AD CS | Hybrid Windows PKI environments |
| Import PFX | Migrate from existing CA | Replacing another CA product |
4.2 Algorithm Selection
| Algorithm | Type | Notes |
|---|---|---|
| ECDSA P-256 | Classical | Fastest, broadest client compatibility. Start here if unsure. |
| ECDSA P-384 | Classical | Higher security margin, still broadly compatible. |
| RSA 2048 / 4096 | Classical | Legacy device support only. |
| ML-DSA-65 | Post-Quantum | NIST FIPS 204. Requires PQC-aware clients. |
| ML-DSA-65 + ECDSA P-256 | Hybrid | Composite signature (RFC 9621). Quantum-safe with classical fallback. |
| ML-DSA-87 + ECDSA P-384 | Hybrid | Maximum security for both classical and PQC. |
| SLH-DSA-SHA2-128s | Post-Quantum | Hash-based signatures, conservative security assumptions. |
4.3 Organization Details
The wizard prompts for your organization name, country, and state. These appear in the
CA certificate Subject DN (e.g., CN=My Org Issuing CA, O=My Org, C=US).
4.4 Network Configuration
| Setting | Default | Description |
|---|---|---|
| Bind address | 0.0.0.0 | IP address to listen on |
| Port | 6446 | HTTPS port for ACME protocol |
| External URL | https://hostname:6446 | URL clients use to reach this server |
4.5 Lockbox Passphrase
All CA private keys are encrypted in a lockbox (AES-256-GCM with Argon2id key derivation). The wizard prompts you to create a passphrase:
Set lockbox passphrase (encrypts all CA private keys): ********
Confirm passphrase: ********
4.6 SuperAdmin Credentials
At the end of setup, the wizard generates a SuperAdmin mTLS certificate and displays credentials that are shown only once:
+==============================================================+
| SAVE THESE CREDENTIALS NOW - SHOWN ONLY ONCE! |
+==============================================================+
| Algorithm: ECDSA P-256 |
| PFX Password: abc123xyz |
| Recovery Code: XXXX-XXXX-XXXX-XXXX |
+==============================================================+
/opt/spork-acme/admin/superadmin.pfx. You need the PFX password to
import it into your browser for admin UI access. These credentials cannot be recovered later.
5. Running the Server
After the wizard completes, the server is running and ready. If the wizard installed a systemd service, it starts automatically on boot.
Verify the Server
# Check service status
sudo systemctl status spork-acme
# Test the ACME directory endpoint
curl -k https://localhost:6446/acme/directory
Expected response:
{
"newNonce": "https://your-server:6446/acme/new-nonce",
"newAccount": "https://your-server:6446/acme/new-acct",
"newOrder": "https://your-server:6446/acme/new-order",
"revokeCert": "https://your-server:6446/acme/revoke-cert"
}
Manual Foreground Mode
For debugging or when not using systemd:
sudo SPORK_LOCKBOX_PASSPHRASE="your-passphrase" \
spork-acme -s /opt/spork-acme --port 6446 --host 0.0.0.0
Management Menu
After initial setup, running spork-acme without a --state-dir flag
detects the existing installation and presents a management menu:
sudo spork-acme
SPORK ACME Server v0.3.0-alpha.2
Existing installation detected at /opt/spork-acme/
1) Configure - Web UI, TLS certificates, proxy settings
2) Backup - Create/restore encrypted backups
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]:
6. Client Configuration
Before ACME clients can verify your server's TLS certificate and the certificates it issues, they need to trust your CA.
Install the CA Certificate
The CA root certificate is served at https://your-server:6446/ca.crt (PEM)
and https://your-server:6446/ca.cer (DER).
Debian / Ubuntu
sudo curl -fsSk https://your-server:6446/ca.crt \
-o /usr/local/share/ca-certificates/spork-ca.crt
sudo update-ca-certificates
Rocky Linux / RHEL / CentOS / Fedora
sudo curl -fsSk https://your-server:6446/ca.crt \
-o /etc/pki/ca-trust/source/anchors/spork-ca.pem
sudo update-ca-trust
Alpine Linux
sudo curl -fsSk https://your-server:6446/ca.crt \
-o /usr/local/share/ca-certificates/spork-ca.crt
sudo update-ca-certificates
Windows (PowerShell, as Administrator)
# Download the trust helper script
Invoke-WebRequest -Uri "https://your-server:6446/ca.cer" -OutFile "$env:TEMP\spork-ca.cer" -SkipCertificateCheck
Import-Certificate -FilePath "$env:TEMP\spork-ca.cer" -CertStoreLocation Cert:\LocalMachine\Root
Using Trust Helper Scripts
SPORK includes platform-specific trust helper scripts for automated CA trust installation:
# Linux (auto-detects distro)
sudo ./install-ca-cert.sh https://your-server:6446
# Windows PowerShell (as Administrator)
.\Install-CACert.ps1 -AcmeUrl https://your-server:6446
# Windows PowerShell (current user only, no admin)
.\Install-CACert.ps1 -AcmeUrl https://your-server:6446 -CurrentUser
-k / --insecure flag is needed for the initial
CA cert download because the server's TLS certificate is signed by the CA you are trying to
install. After trusting the CA, all subsequent connections verify normally.
Configure Certbot
Once the CA is trusted system-wide, certbot works without any special flags:
certbot certonly --standalone \
--server https://your-server:6446/acme/directory \
--agree-tos \
--email admin@example.com \
-d myhost.example.com
If you have not yet installed the CA certificate, add --no-verify-ssl:
certbot certonly --standalone \
--server https://your-server:6446/acme/directory \
--no-verify-ssl \
--agree-tos \
-d myhost.example.com
Configure acme.sh
acme.sh --issue \
--server https://your-server:6446/acme/directory \
-d myhost.example.com \
--standalone
Automatic Renewal
Certbot's built-in renewal works as expected:
# Enable the certbot timer
sudo systemctl enable --now certbot.timer
# Or add a cron entry
0 0 * * * certbot renew --quiet
7. Quick Start Example
End-to-end: download the installer, set up a CA, issue your first certificate.
Step 1: Install
curl -fSL -o spork-acme-installer \
https://rayketcham.com/CRLs/sp0rk/static/spork-acme-server-0.3.0-alpha.2-linux-x86_64-installer
chmod +x spork-acme-installer
sudo ./spork-acme-installer
Step 2: Complete the Setup Wizard
The wizard starts automatically. Accept the defaults or customize:
- Deployment type: 2-Tier CA (press Enter)
- Algorithm: ECDSA P-256 (press Enter)
- Organization: type your org name
- External hostname: type your server's FQDN or IP
- Port: 6446 (press Enter)
- Lockbox passphrase: type a strong passphrase (8+ characters)
- Install systemd service: Yes
Step 3: Verify the Server
curl -k https://localhost:6446/acme/directory
Step 4: Trust the CA
# Debian/Ubuntu
sudo curl -fsSk https://localhost:6446/ca.crt \
-o /usr/local/share/ca-certificates/spork-ca.crt
sudo update-ca-certificates
# Rocky/RHEL
sudo curl -fsSk https://localhost:6446/ca.crt \
-o /etc/pki/ca-trust/source/anchors/spork-ca.pem
sudo update-ca-trust
Step 5: Issue Your First Certificate
# Install certbot if needed
sudo apt install certbot # Debian/Ubuntu
sudo dnf install certbot # Rocky/RHEL
# Issue a certificate
certbot certonly --standalone \
--server https://localhost:6446/acme/directory \
--agree-tos \
--email admin@example.com \
-d myhost.example.com
Your certificate is now at:
- Certificate:
/etc/letsencrypt/live/myhost.example.com/fullchain.pem - Private key:
/etc/letsencrypt/live/myhost.example.com/privkey.pem
Configure your web server (nginx, Apache, etc.) to use these files, and enable the
certbot.timer for automatic renewal.
8. CLI Reference
Subcommands and Modes
| Invocation | Behavior |
|---|---|
spork-acme | Auto-detect: setup wizard if no installation, management menu if installed |
spork-acme -s /opt/spork-acme | Start server with explicit state directory |
spork-acme --status | Show installation status |
spork-acme --uninstall | Remove an existing installation |
spork-acme --update-crl | Regenerate the CRL (run via timer) |
spork-acme --renew-tls | Renew the server's own TLS certificate if expiring |
spork-acme --install-service | Install the systemd service unit |
Server Flags
| Flag | Default | Description |
|---|---|---|
-s, --state-dir | (required) | Path to the CA state directory (keys, certs, database) |
-p, --port | 8080 | HTTPS port to listen on |
--host | 0.0.0.0 | IP address to bind to |
--external-url | (auto) | Public URL for ACME responses (e.g., https://acme.example.com:6446) |
--tls-cert | (auto) | Path to TLS certificate file (PEM) |
--tls-key | (auto) | Path to TLS private key file (PEM) |
--allow-wildcards | disabled | Allow wildcard certificates (requires DNS-01 validation) |
--dns-server | system default | Custom DNS server for challenge validation (e.g., 192.168.1.1:53) |
--terms-of-service | (none) | URL to terms of service document |
--website | (none) | URL to CA website (included in ACME directory) |
--caa-identity | (none) | CAA identity for CAA record checking (repeatable) |
--cdp-url | (none) | CRL Distribution Point URL embedded in issued certificates |
--aia-base-url | (none) | AIA base URL for OCSP and CA Issuer URLs in issued certificates |
--http-challenge-dir | (none) | Directory for HTTP-01 webroot challenge files |
--auto-validate | disabled | Auto-validate challenges (testing only, INSECURE) |
--log-level | info | Log level: trace, debug, info, warn, error |
-y, --yes | disabled | Auto-accept all confirmation prompts (scripted/automated setup) |
Environment Variables
| Variable | Description |
|---|---|
SPORK_LOCKBOX_PASSPHRASE | Lockbox passphrase for non-interactive startup (systemd, scripts) |
SPORK_KEYSTORE_PASSPHRASE | Deprecated alias for SPORK_LOCKBOX_PASSPHRASE |
9. Systemd Service
The setup wizard can install the systemd service automatically. To install it manually:
sudo spork-acme --install-service
Or create the unit file by hand:
Service Unit
[Unit]
Description=SPORK ACME Server - Private Certificate Authority
Documentation=https://github.com/rayketcham/spork-ca
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/spork-acme -s /opt/spork-acme --port 6446 --host 0.0.0.0 --external-url https://your-server:6446
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5
User=root
WorkingDirectory=/opt/spork-acme
# Lockbox passphrase (use EnvironmentFile for production)
EnvironmentFile=/etc/spork-acme/env
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/spork-acme
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Passphrase Environment File
# Create the passphrase file
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
CRL Timer
[Unit]
Description=SPORK ACME CRL Update
[Service]
Type=oneshot
ExecStart=/usr/local/bin/spork-acme --update-crl -s /opt/spork-acme
EnvironmentFile=/etc/spork-acme/env
[Unit]
Description=SPORK ACME CRL Update Timer
[Timer]
OnCalendar=*-*-* 00/6:00:00
Persistent=true
[Install]
WantedBy=timers.target
Enable and Start
sudo systemctl daemon-reload
sudo systemctl enable --now spork-acme.service
sudo systemctl enable --now spork-acme-crl.timer
10. Trust Helper Scripts
SPORK ships platform-specific scripts that automate installing the CA root certificate into the operating system trust store.
Linux: install-ca-cert.sh
Auto-detects distro (Debian, RHEL, Alpine) and installs the CA certificate:
sudo ./install-ca-cert.sh https://your-server:6446
The script:
- Downloads the CA certificate from
https://your-server:6446/ca.crt - Validates the PEM format
- Displays the certificate subject, issuer, and fingerprint
- Copies it to the correct trust store path for your distro
- Runs
update-ca-certificatesorupdate-ca-trust
Windows: Install-CACert.ps1
Installs the CA certificate into the Windows certificate store:
# LocalMachine\Root (requires Administrator)
.\Install-CACert.ps1 -AcmeUrl https://your-server:6446
# CurrentUser\Root (no admin required)
.\Install-CACert.ps1 -AcmeUrl https://your-server:6446 -CurrentUser
The script downloads the DER certificate from /ca.cer, removes any existing
certificates with the same Subject to prevent duplicates, and installs the new certificate.
11. Admin Web UI
The admin portal is served at https://your-server:6446/admin and is protected
by mutual TLS (mTLS). Only clients presenting a valid admin certificate can access it.
Access Setup
- Copy
/opt/spork-acme/admin/superadmin.pfxto your workstation - Import the PFX into your browser (Firefox: Settings > Certificates > Import; Chrome: Settings > Security > Manage Certificates > Import)
- Enter the PFX password from the setup wizard
- Navigate to
https://your-server:6446/admin
Admin Roles
| Role | Capabilities |
|---|---|
| SuperAdmin | Full control: issue admin certs, factory reset, all operations |
| Admin | Revoke certificates, manage CRLs, issue certificates |
| Operator | Issue certificates, view audit logs |
| Viewer | Read-only access to dashboard and certificate inventory |
12. Troubleshooting
Server will not start
# Check logs
sudo journalctl -u spork-acme -n 50 --no-pager
# Common cause: missing or wrong passphrase
# Verify the env file exists and is correct
sudo cat /etc/spork-acme/env
Port already in use
sudo ss -tlnp | grep 6446
Kill the conflicting process or change the port with --port.
Certbot SSL verification error
Add --no-verify-ssl or install the CA certificate to the system trust store
first (see Client Configuration). Alternatively, point certbot
at the CA cert directly:
export REQUESTS_CA_BUNDLE=/opt/spork-acme/ca/ca.crt
certbot certonly --standalone \
--server https://localhost:6446/acme/directory \
--agree-tos -d test.example.com
SELinux denials (Rocky / RHEL)
# Check for denials
sudo ausearch -m avc -ts recent
# Fix binary context after copy
sudo restorecon -v /usr/local/bin/spork-acme
# If further denials, generate a policy module
sudo ausearch -m avc -ts recent | audit2allow -M spork-acme-local
sudo semodule -i spork-acme-local.pp
Firewall blocking connections
# Rocky / RHEL / CentOS
sudo firewall-cmd --add-port=6446/tcp --permanent
sudo firewall-cmd --reload
# Ubuntu / Debian (if UFW is active)
sudo ufw allow 6446/tcp
No TTY error in systemd
The server requires the lockbox passphrase via environment variable when running
non-interactively. Ensure SPORK_LOCKBOX_PASSPHRASE is set in the
EnvironmentFile:
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
Directory Structure
After installation, the state directory at /opt/spork-acme/ contains:
| Path | Purpose |
|---|---|
ca/ | CA certificates (root, issuing, chain) |
tls/ | Server TLS certificate and key |
admin/ | Admin PFX certificates |
keystore.db | Encrypted lockbox containing all CA private keys |
config.json | Server configuration |
acme.db | ACME accounts, orders, and certificate records |
backups/ | Automatic backup snapshots |