ACME Client Administration Guide#
-This guide covers installation and system-level configuration of ACME clients for use with acme-proxy. It is intended for system administrators deploying certificate automation on behalf of end users.
-For certificate issuance commands and per-scenario usage, see user.md.
--
Recommended Client#
-acme.sh is the recommended ACME client. Reasons:
--
-
- Distributed as native
.deband.rpmpackages through standard Linux distribution repositories — no curl-pipe-to-shell installation.
- - Certbot’s only actively maintained distribution channel is Snap. The
.debpackages in apt repositories are unmaintained and ship outdated versions. If your organization prohibits Snap packages, certbot is not viable.
- - acme.sh’s
--cronmode renews all configured certificates in a single invocation, making a single systemd timer sufficient regardless of how many certificates are managed.
- - Lego has no maintained packages in major distribution repositories and requires manual binary management. -
-
Table of Contents#
--
-
- Installing ACME Clients -
- Account Registration -
- Configuring Auto-Renewal via Systemd -
- Log Management -
-
Installing ACME Clients#
-acme.sh (Recommended)#
-Debian / Ubuntu:
-sudo apt-get update
-sudo apt-get install -y acme.shRHEL / Rocky / AlmaLinux — requires EPEL:
-sudo dnf install -y epel-release
-sudo dnf install -y acme.shThe package installs the binary to /usr/bin/acme.sh. Use /etc/acme.sh as the configuration home for system-wide installations (passed via --home in all commands).
-Standalone mode requires
-socat. acme.sh usessocatto bind port 80 for HTTP-01 challenges in standalone mode. Package dependencies vary by distribution — verify it is present before using standalone mode:socat -V 2>/dev/null || echo "socat not found"Install if missing:
-sudo apt-get install -y socat(Debian/Ubuntu) orsudo dnf install -y socat(RHEL/Rocky). This is not required if you use NGINX or Apache plugin mode.
-
Certbot#
--Note: Certbot’s actively maintained distribution is via Snap. The
-.debpackages available in apt repositories are no longer maintained by the Certbot project and ship outdated versions. If your organization prohibits Snap, use acme.sh instead.
Install via Snap:
-sudo snap install --classic certbot
-sudo ln -s /snap/bin/certbot /usr/local/bin/certbotThe Snap package installs certbot.timer and certbot.service systemd units automatically.
For the NGINX plugin:
-sudo snap set certbot trust-plugin-with-root=ok
-sudo snap install certbot-nginxFor the Apache plugin:
-sudo snap set certbot trust-plugin-with-root=ok
-sudo snap install certbot-apache-
Lego#
-Lego has no official packages in major Linux distribution repositories. Install the release binary directly:
-LEGO_VERSION=4.33.0
-curl -fsSL "https://github.com/go-acme/lego/releases/download/v${LEGO_VERSION}/lego_v${LEGO_VERSION}_linux_amd64.tar.gz" \
- | tar xz lego
-sudo install -o root -g root -m 0755 lego /usr/local/bin/lego
-rm lego
-lego --version-Verify the checksum from the GitHub releases page before deploying to production. Pin
-LEGO_VERSIONin your configuration management tool and treat upgrades as a deliberate change.
-
Account Registration#
-Each ACME client must register an account with acme-proxy before any certificates can be issued. This is a one-time step per host.
-acme.sh#
-sudo acme.sh --register-account \
- --server https://acme-proxy.example.com/acme/acme/directory \
- --email admin@example.com \
- --home /etc/acme.shCertbot#
-Certbot registers automatically on first use. No separate registration step is required.
-Lego#
-Lego registers automatically on the first run invocation. No separate registration step is required.
-
Configuring Auto-Renewal via Systemd#
-Replacing cron-based renewal with systemd timers provides:
--
-
- Missed-run recovery via
Persistent=true— if the system was off at the scheduled time, the timer fires on next boot.
- - Structured log output to the systemd journal, queryable and forwardable to syslog. -
- Visibility via
systemctl list-timers.
-
All service units below set SyslogIdentifier so logs can be filtered by tag regardless of which syslog daemon is in use.
-
acme.sh#
-acme.sh’s --cron flag iterates over all configured certificates and renews those expiring within 30 days. A single service and timer unit covers all certificates on the host.
Create the service unit:
-sudo tee /etc/systemd/system/acme-renewal.service <<'EOF'
-[Unit]
-Description=Renew ACME certificates (acme.sh)
-After=network-online.target
-Wants=network-online.target
-
-[Service]
-Type=oneshot
-User=root
-ExecStart=/usr/bin/acme.sh --cron --home /etc/acme.sh
-StandardOutput=journal
-StandardError=journal
-SyslogIdentifier=acme-renewal
-EOFCreate the timer unit:
-sudo tee /etc/systemd/system/acme-renewal.timer <<'EOF'
-[Unit]
-Description=Daily ACME certificate renewal check (acme.sh)
-
-[Timer]
-OnCalendar=daily
-RandomizedDelaySec=1h
-Persistent=true
-
-[Install]
-WantedBy=timers.target
-EOFEnable and start:
-sudo systemctl daemon-reload
-sudo systemctl enable --now acme-renewal.timerVerify:
-systemctl status acme-renewal.timer
-systemctl list-timers acme-renewal.timer-
Certbot#
-The Snap-installed certbot ships certbot.timer and certbot.service units automatically. Enable the timer and confirm it is active:
sudo systemctl enable --now certbot.timer
-systemctl status certbot.timerConfigure the SyslogIdentifier so certbot’s renewal logs are tagged consistently alongside other ACME clients:
-sudo mkdir -p /etc/systemd/system/certbot.service.d
-sudo tee /etc/systemd/system/certbot.service.d/logging.conf <<'EOF'
-[Service]
-StandardOutput=journal
-StandardError=journal
-SyslogIdentifier=certbot-renewal
-EOF
-sudo systemctl daemon-reloadTest renewal without issuing:
-sudo certbot renew --dry-run-
Lego#
-Lego has no built-in renewal scheduling. Create service and timer units manually.
-Unlike acme.sh and certbot, lego’s renew command targets one domain at a time. If you manage multiple certificates, use a wrapper script.
Wrapper script for multiple certificates:
-sudo tee /usr/local/sbin/lego-renew-all.sh <<'EOF'
-#!/bin/bash
-set -euo pipefail
-
-LEGO=/usr/local/bin/lego
-SERVER=https://acme-proxy.example.com/acme/acme/directory
-EMAIL=admin@example.com
-
-# Add each managed domain below
-domains=(
- myserver.example.com
- anotherserver.example.com
-)
-
-for domain in "${domains[@]}"; do
- "$LEGO" \
- --server "$SERVER" \
- --accept-tos \
- --email "$EMAIL" \
- --http \
- -d "$domain" \
- renew
-done
-EOF
-sudo chmod 0700 /usr/local/sbin/lego-renew-all.shCreate the service unit:
-sudo tee /etc/systemd/system/lego-renewal.service <<'EOF'
-[Unit]
-Description=Renew ACME certificates (lego)
-After=network-online.target
-Wants=network-online.target
-
-[Service]
-Type=oneshot
-User=root
-ExecStart=/usr/local/sbin/lego-renew-all.sh
-StandardOutput=journal
-StandardError=journal
-SyslogIdentifier=lego-renewal
-EOFCreate the timer unit:
-sudo tee /etc/systemd/system/lego-renewal.timer <<'EOF'
-[Unit]
-Description=Daily ACME certificate renewal check (lego)
-
-[Timer]
-OnCalendar=daily
-RandomizedDelaySec=1h
-Persistent=true
-
-[Install]
-WantedBy=timers.target
-EOFEnable and start:
-sudo systemctl daemon-reload
-sudo systemctl enable --now lego-renewal.timerVerify:
-systemctl status lego-renewal.timer
-systemctl list-timers lego-renewal.timer-
Log Management#
-All service units above write to the systemd journal with a unique SyslogIdentifier. Logs are accessible via journalctl and forwarded to syslog if your system runs rsyslog or syslog-ng with journal forwarding enabled.
Filter renewal logs by client:
-| Client | -Command | -
|---|---|
| acme.sh | -journalctl -t acme-renewal |
-
| Certbot | -journalctl -t certbot-renewal |
-
| Lego | -journalctl -t lego-renewal |
-
Follow logs in real time:
-journalctl -t acme-renewal -fForward to syslog — rsyslog:
-Ensure the journal input module is loaded in /etc/rsyslog.conf or a drop-in under /etc/rsyslog.d/:
module(load="imjournal" StateFile="imjournal.state")Forward to syslog — syslog-ng:
-Ensure the systemd-journal source is present in your syslog-ng configuration:
source s_systemd { systemd-journal(); };Log retention:
-Journal retention is controlled by /etc/systemd/journald.conf. Set MaxRetentionSec and SystemMaxUse appropriate to your environment:
[Journal]
-SystemMaxUse=500M
-MaxRetentionSec=90dayApply changes with:
-sudo systemctl restart systemd-journald