Ansible collection: foundata.acmesh
Licensing
- Primary license: GPL-3.0-or-later
Miscellaneous
- Funding: Buy us a coffee
- Maintainer: foundata
- Status: Stable
The ansible collection foundata.acmesh provides resources to manage and use acme.sh, as shell-based Automatic Certificate Management Environment (ACME) client. It allows the issuance and maintenance of X.509 certificates, commonly used for securing HTTPS/TLS/SSL services on web servers.
The following lists the README.md files of the most important included contents (e.g. roles). You might browse the source code repositories for a better overview.
Ansible role: foundata.acmesh.run
The foundata.acmesh.run Ansible role (part of the foundata.acmesh Ansible collection). It provides automated management of ACME certificates using acme.sh.
Features
Main features:
- Dedicated, configurable storage locations for installation, configuration, and certificate files.
- Dedicated, configurable service user and group (non-root, rootless) for improved security, controlled via the
run_acmesh_userandrun_acmesh_groupvariables:- All
acme.shoperations (account registration, issuance, installation, renewal) run as this unprivileged account, so issuance and renewal behave identically and permission problems surface during the Ansible run instead of weeks later at the first renewal. Privileged ports forstandalone/alpnchallenges are covered by an automatically grantedCAP_NET_BIND_SERVICEcapability. - By default, other users cannot read certificates managed by
acme.sh. See the usage examples for ways to grant access if needed. - The
reloadcmdof each certificate runs asrootvia a systemd path unit watching the installed certificate files, so services get reloaded reliably after issuance and renewal without granting the service user any privileges. See the usage examples for details.
- All
- Staged certificate installation (default since version 4.0.0):
acme.shinstalls into a root-protected staging area and a root-owned, sandboxed systemd service validates and publishes the files to their final destinations. This supports destinations below protected directories such as/etc/ssl/privateand full ownership and mode control per certificate file viainstall.permissions, whileacme.shitself keeps running unprivileged. See Installation strategies for details and thedirectcompatibility strategy. - Automatic certificate renewal via systemd timer.
- Support for multiple ACME challenge types:
alpn,dns(including alias mode),standalone, andwebroot - Global
acme.shshell alias for easy execution. - Uploading of pre-seeded certificate files before issuing new ones: Helps to prevent hitting CA rate limits, especially when frequently reinstalling target systems during development.
Currently not supported:
- The acme.sh notify functionality.
- Native handling of the Apache and NGINX modes (but you can use
extra_flagsto pass--nginxor--apacheif really necessary).
Example playbooks, using this role
Webroot challenge (single domain)
Using only one domain per certificate and the webroot challenge. acme.sh runs as the unprivileged service user defined by run_acmesh_user (defaults to acmesh), which therefore needs write access to the webroot (it creates .well-known/acme-challenge below it), e.g. via group membership or a pre-created, service-user owned .well-known/acme-challenge directory:
---
- name: "Demo of the foundata.acmesh.run role"
hosts: localhost
gather_facts: false
tasks:
- name: "Trigger invocation of the foundata.acmesh.run role"
ansible.builtin.include_role:
name: "foundata.acmesh.run"
vars:
run_acmesh_autoupgrade: true
run_acmesh_cfg_accountemail: "hostmaster@example.org"
run_acmesh_certs:
- domains:
- name: "example.org"
challenge: # parameters depend on type
type: "webroot"
webroot: "/var/www/example.org"
install:
ca_file: "/etc/pki/tls/certs/example.org/ca.cer"
cert_file: "/etc/pki/tls/certs/example.org/cert.cer"
fullchain_file: "/etc/pki/tls/certs/example.org/fullchain.cer"
key_file: "/etc/pki/tls/certs/example.org/cert.key"
reloadcmd: "systemctl reload apache2.service" # executed as root by a systemd unit, see the "Service reloads" section below
server: "letsencrypt_test" # optional, CA alias or URL, defaults to "letsencrypt" see https://github.com/acmesh-official/acme.sh/wiki/Server for details.
The role clones acme.sh from GitHub by default. Use the run_acmesh_git_url parameter to point it at an internal Git mirror instead (e.g. for air-gapped environments).
DNS challenge (multiple domains and certificates)
Multiple domains per certificate with DNS challenge and challenge alias:
---
- name: "Demo of the foundata.acmesh.run role (multiple domains, DNS challenge)"
hosts: localhost
gather_facts: false
tasks:
- name: "Trigger invocation of the foundata.acmesh.run role"
ansible.builtin.include_role:
name: "foundata.acmesh.run"
vars:
run_acmesh_autoupgrade: true
run_acmesh_cfg_accountemail: "hostmaster@example.org"
run_acmesh_certs:
# first certificate: "example.org"
- domains:
- name: "example.org"
challenge:
type: "webroot"
webroot: "/var/www/example.org"
install:
ca_file: "/etc/pki/tls/certs/example.org/ca.cer"
cert_file: "/etc/pki/tls/certs/example.org/cert.cer"
fullchain_file: "/etc/pki/tls/certs/example.org/fullchain.cer"
key_file: "/etc/pki/tls/certs/example.org/cert.key"
reloadcmd: "systemctl reload apache2.service" # executed as root by a systemd unit, see the "Service reloads" section
# optional, CA alias or URL, defaults to "letsencrypt" see
# https://github.com/acmesh-official/acme.sh/wiki/Server
server: "zerossl"
# second certificate: "foo.example.com" with an additional "bar.example.com" SAN
- domains:
- name: "foo.example.com"
challenge: # parameters depend on type
type: "dns"
dns_provider: "dns_hetzner"
# CNAME _acme-challenge.foo.example.com => _acme-challenge.foo.example.com.example.net
challenge_alias: "foo.example.com.example.net"
- name: "bar.example.com"
challenge:
type: "dns"
dns_provider: "dns_inwx"
# CNAME _acme-challenge.bar.example.com => _acme-challenge.example.net
challenge_alias: "example.net"
install:
ca_file: "/etc/pki/tls/certs/foo.example.com/ca.cer"
cert_file: "/etc/pki/tls/certs/foo.example.com/cert.cer"
fullchain_file: "/etc/pki/tls/certs/foo.example.com/fullchain.cer"
key_file: "/etc/pki/tls/certs/foo.example.com/cert.key"
reloadcmd: "systemctl reload nginx.service; systemctl restart postfix.service"
# "{letsencrypt,buypass,google}_test" for staging, see
# https://github.com/acmesh-official/acme.sh/wiki/Server
server: "letsencrypt"
force: false # optional
debug: false # optional
post_hook: "" # optional
renew_hook: "" # optional
extra_flags: "" # optional (workaround for edge cases, put --whatever here)
# Environment variables needed for the DNS API authentication for
# type: "dns" and dns_provider: "dns_hetzner" / dns_provider: "dns_inwx"
run_acmesh_environment:
HETZNER_Token: "{{ lookup('ansible.builtin.unvault', '...') | ansible.builtin.string | ansible.builtin.trim }}"
INWX_User: "exampleuser"
INWX_Password: "{{ lookup('ansible.builtin.unvault', '...') | ansible.builtin.string | ansible.builtin.trim }}"
Installation strategies, ownership and permissions
Since version 4.0.0, every certificate’s install supports a strategy (default: staged) and partial permissions overrides:
staged(the default, also used whenstrategyis omitted):acme.shinstalls into an internal, root-protected staging area (one service-user writable directory per certificate belowrun_acmesh_cfg_cert_deploy_base_dir). A root-owned, heavily sandboxed systemd service (acmesh-deploy-<primary domain>.service, triggered by a path unit watching the staged files and started synchronously during the Ansible run) validates the staged files and publishes them to the final destinations with the configured ownership and modes. Because root performs the final copy, destinations below protected parent directories such as/etc/ssl/private(commonlyroot:ssl-certwith mode0710) work without granting the service user any additional group memberships.direct: the pre-4.0.0 behavior;acme.shwrites the final paths directly as the unprivileged service user. This is a compatibility option, not the recommended default: every destination must be writable byrun_acmesh_user— also during unattended renewal — and ownership overrides are rejected (the service account could not maintain them). Mode overrides are allowed (renewals preserve the mode becauseacme.shtruncates files in place).
The deployment chain of the staged strategy is an extension of the reload mechanism:
renewal (unprivileged acme.sh) → staging files
→ acmesh-deploy-<id>.path → acmesh-deploy-<id>.service (root helper, validates + publishes)
→ final files (completion artifact last)
→ acmesh-reload-<id>.path → reloadcmd (root)
The helper (/usr/libexec/acmesh-deploy) validates all staged input before publishing anything: PEM parsing, private key/certificate match, certificate domain coverage, size limits, rejection of symlinks and non-regular files. Ownership and modes are applied before atomic renames, the artifact acme.sh writes last is published last (so the reload only fires on complete sets), unchanged files are not replaced, and metadata-only reconciliation does not trigger reloads. On a publish failure the already published artifacts of that run are restored best-effort. Remaining limitation: a hard system crash while publishing files that live on different filesystems can leave a mixed set — a fully atomic transaction across filesystems is not possible.
install.permissions is a set of partial overrides. Effective values are calculated per key with later mappings overriding earlier ones (unspecified keys inherit):
- Role defaults: directory
run_acmesh_user:run_acmesh_groupmode"2750"; filesrun_acmesh_user:run_acmesh_groupmode"0640"(unchanged from 3.x). permissions.default(all certificate files).permissions.<artifact>(ca_file,cert_file,fullchain_file,key_file).
Example (key below /etc/ssl/private, readable by ssl-cert, the fullchain world-readable):
run_acmesh_certs:
- domains:
- name: "example.org"
challenge:
type: "webroot"
webroot: "/var/www/example.org"
install:
strategy: "staged" # the default, shown for clarity
key_file: "/etc/ssl/private/example.org/cert.key"
fullchain_file: "/etc/ssl/certs/example.org/fullchain.cer"
reloadcmd: "systemctl reload nginx.service"
permissions:
directory:
owner: "root"
group: "ssl-cert"
mode: "0750"
default:
owner: "root"
group: "ssl-cert"
mode: "0640"
fullchain_file:
mode: "0644"
Notes:
- Modes are quoted octal strings. Certificate files must not be executable or carry setuid/setgid/sticky bits; private keys must not be world-readable or group/world-writable (
"0600","0640","0400","0440"are typical values); directories may keep the setgid bit (default"2750"). - Only the immediate destination directories are managed; existing ancestors such as
/etc/sslor/etc/ssl/privateare never changed. - The role reconciles the final files and their metadata on every run. Playbooks which change certificate ownership or modes after applying the role must move those requirements into
install.permissions— the role may overwrite such external changes. - Troubleshooting: a failed deployment leaves
acmesh-deploy-<primary domain>.servicein a failed state (systemctl --failed); the helper logs concisely to the journal (journalctl -t acmesh-deploy, never private key material).systemctl cat acmesh-deploy-<primary domain>.serviceshows the unit,systemd-analyze verifychecks it. The helper reuses the Python interpreter Ansible discovered on the host; if that interpreter is removed, deployments fail visibly until the next role run rewrites the units.
Certificate file access for other services
The preferred way to grant services access to certificate files is the staged installation strategy with explicit install.permissions (e.g. group: "ssl-cert" plus a fitting mode), as shown above.
Alternatively — and as the only option for the direct strategy — add specific service users (e.g., www-data or nginx) to the group defined by run_acmesh_group (defaults to acmesh). ansible.builtin.user can help you with that:
- name: "Grant the webserver's service user read access to certs by adding it to the acmesh group"
ansible.builtin.user:
name: "www-data"
groups:
- "acmesh" # the groupname get set via run_acmesh_group role variable, defaults to "acmesh"
append: true # do not remove existing group memberships
The reverse direction also works: run_acmesh_user_supplementary_groups adds the service user to existing groups (e.g. ssl-cert for direct installations below /etc/ssl/private, or a webroot group). ⚠️ Note that privileged groups such as ssl-cert may grant the service user read access to unrelated private keys; with the staged strategy this should not be needed merely to deploy a certificate.
Service reloads after certificate changes (reloadcmd)
The reloadcmd of a certificate is not executed by acme.sh. Instead, the role creates a systemd path unit (acmesh-reload-<primary domain>.path) which watches the installed certificate files and starts a companion service unit that runs the reloadcmd as root whenever the files change:
- No sudo or polkit setup is needed; plain commands like
reloadcmd: "systemctl reload nginx.service"just work. The unprivileged service user defined byrun_acmesh_userdoes not get any privileges: it only writes the certificate files, root reacts to the change. - The behavior is identical no matter how the certificate files change: initial issuance through this role, automated renewal (
acmesh-renewal.service, which runs unprivileged), manualacme.shruns, or restoring pre-seeded files. - A failing
reloadcmdleavesacmesh-reload-<primary domain>.servicein a failed state, visible viasystemctl --failedand the journal (journalctl -t acmesh-reload), instead of being silently swallowed during renewal. - The command is inlined into the service unit’s
ExecStart=(systemd-escaped so the shell receives it exactly as configured, single line only);systemctl cat acmesh-reload-<primary domain>.serviceshows it. - The reload happens asynchronously (typically within milliseconds) after the certificate files were written, not synchronously as part of the Ansible task.
Reload units of certificates that are no longer listed in run_acmesh_certs are kept by default, as acme.sh continues to renew and reinstall already issued certificates until they are actively removed. Remove a certificate cleanly with a state: "absent" entry, or enable run_acmesh_certs_delete_unmanaged to reap such leftovers (see Removing certificates). All acmesh-reload-* resources get removed on run_acmesh_state: "absent".
The pre_hook, post_hook and renew_hook commands are different: they are executed by acme.sh itself and therefore always run as the unprivileged service user — consistently during issuance and automated renewal. Keep them free of privileged operations (or grant the needed permissions yourself, e.g. via community.general.sudoers, foundata.linux.sudo or a polkit rule).
dns-persist-01 challenge (long-lived TXT record)
A dns-persist-01 challenge, for a domain whose DNS you cannot (or do not want to) automate with an API plugin. Instead of a per-issue _acme-challenge TXT record, it uses a single, long-lived _validation-persist.<domain> TXT record bound to your ACME account key, so you publish the record once and renewals need no further DNS changes:
---
- name: "Demo of the foundata.acmesh.run role (dns-persist-01 challenge)"
hosts: localhost
gather_facts: false
tasks:
- name: "Trigger invocation of the foundata.acmesh.run role"
ansible.builtin.include_role:
name: "foundata.acmesh.run"
vars:
run_acmesh_autoupgrade: true
run_acmesh_cfg_accountemail: "hostmaster@example.org"
# The dns-persist-01 TXT record value is derived from the ACME account
# key. Pre-seed that key so the same long-lived record keeps working
# across reinstalls and on every server that shares this certificate.
# The server must match run_acmesh_certs[].server below.
run_acmesh_cfg_account_keys:
- server: "letsencrypt"
account_key: "{{ lookup('ansible.builtin.unvault', 'files/acmesh_account_key_letsencrypt.pem') }}"
# Seconds to wait after the role prints the TXT record instructions,
# giving you time to publish the record. Set to 0 in CI or when the
# record is already in place.
run_acmesh_dns_persist_pause: 600
run_acmesh_certs:
- domains:
- name: "example.org"
challenge: # parameters depend on type
type: "dns_persist"
dns_persist_wildcard: true # optional, also authorize *.example.org
# dns_persist_ca_name: "letsencrypt.org" # optional, override the CA identity in the record value
# dns_persist_days: 365 # optional, adds a "persistUntil" hint to the record
install:
ca_file: "/etc/pki/tls/certs/example.org/ca.cer"
cert_file: "/etc/pki/tls/certs/example.org/cert.cer"
fullchain_file: "/etc/pki/tls/certs/example.org/fullchain.cer"
key_file: "/etc/pki/tls/certs/example.org/cert.key"
reloadcmd: "systemctl reload apache2.service" # executed as root by a systemd unit, see the "Service reloads" section
# must match the server of the pre-seeded account key above
server: "letsencrypt"
On the first run the role prints the exact _validation-persist.<domain> TXT record(s) to create and then pauses for run_acmesh_dns_persist_pause seconds. Publish the record at your DNS provider, then let the play continue (or re-run it later). Because the record value is derived from the ACME account key, pre-seeding that key with run_acmesh_cfg_account_keys keeps the same TXT record valid across reinstalls and across multiple servers sharing the certificate. See the acme.sh DNS-persist-mode wiki for background.
Removing certificates
Set state: "absent" on a certificate entry to remove all of its data: the acme.sh data below run_acmesh_cfg_cert_home (this also stops the automated renewal for it), its acmesh-reload-* and acmesh-deploy-* systemd units, its staging data and deployment manifest, and the installed files listed under install (their directories are kept, as they may be shared with other software). The certificate is not revoked at the ACME CA:
run_acmesh_certs:
- domains:
- name: "example.org"
challenge:
type: "webroot"
webroot: "/var/www/example.org"
install:
ca_file: "/etc/pki/tls/certs/example.org/ca.cer"
cert_file: "/etc/pki/tls/certs/example.org/cert.cer"
fullchain_file: "/etc/pki/tls/certs/example.org/fullchain.cer"
key_file: "/etc/pki/tls/certs/example.org/cert.key"
state: "absent"
Certificates that are simply deleted from run_acmesh_certs keep their data and continue to be renewed (and, with the staged strategy, deployed) by the existing units. Set run_acmesh_certs_delete_unmanaged: true to reap such unmanaged leftovers declaratively (acme.sh data, reload units, deploy units, staging directories and manifests; installed files of unmanaged certificates are never touched because their paths are unknown to the role).
A full uninstall via run_acmesh_state: "absent" intentionally preserves all certificate data (see below).
Uninstall
Uninstall (certificate files, if present, will be preserved):
---
- name: "Demo of the foundata.acmesh.run role (removal, uninstall)"
hosts: localhost
gather_facts: false
tasks:
- name: "Trigger invocation of the foundata.acmesh.run role"
ansible.builtin.include_role:
name: "foundata.acmesh.run"
vars:
run_acmesh_state: "absent"
Pre-seeding certificate files
This role supports uploading backed-up acme.sh certificate folders from the Ansible control node to target systems before issuing new certificates. Files are only transferred if they do not already exist on the target, preventing the accidental overwrite of up-to-date certificates. This feature helps avoid CA rate limits, especially when frequently reinstalling target systems during development.
Usage:
- Back up a certificate directory such as
www.example.com_eccorexample.org_rsafrom acme.sh’s certificate home (run_acmesh_cfg_cert_home, default:/var/opt/acme.sh). - Place the backup under
files/acme.sh/certhomein your playbook directory on the control node.
Migration from 3.x and downgrades
Version 4.0.0 changes the default installation strategy to staged:
- The first run may report
changedfor an existing installation. It migrates the acme.sh installation paths (Le_Real*Path) to the staging area, creates the staged deployment resources (staging directories, helper, manifests,acmesh-deploy-*units) and reconciles the final files and their metadata. Subsequent runs are idempotent when certificate content, configuration, strategy, destinations and permissions are unchanged. - Move post-role permission fixes into
install.permissions. The role now reconciles final certificate ownership and modes on every run and may overwrite external changes (chmod/chowntasks after the role, relocation workarounds). Supplementaryssl-certgroup membership that was only needed for direct installation below/etc/ssl/privatecan usually be removed as well. - Keeping the old behavior: set
strategy: "direct"per certificate. Switching a certificate between the strategies is supported in both directions; the role re-points acme.sh and creates or removes the staged deployment resources accordingly. - Downgrading to 3.x after the migration requires an explicit direct reinstallation: 3.x does not understand the staging paths, so renewals would keep updating the staging area while the final destinations go stale. Re-run the 3.x role (its
--install-certre-points acme.sh at the final paths) and remove theacmesh-deploy-*units,/etc/acmesh-deploy.d,/usr/libexec/acmesh-deployand the staging base directory (default/var/opt/acme.sh-deploy) manually.
Supported tags
It might be useful and faster to only call parts of the role by using tags:
run_acmesh_setup: Manage basic resources, such as packages or service users.run_acmesh_config: Manage settings, such as adapting or creating configuration files.run_acmesh_cert: Manage and issue certificates.
There are also tags that are generally not intended to be called directly but are included for completeness and to cover edge cases:
run_acmesh_always,always: Tasks needed by the role itself for internal role setup and the Ansible environment.
Role variables
Main entry point for the foundata.acmesh.run role
The following variables can be configured for this role:
| Variable | Type | Required | Default | Description (abstract) |
|---|---|---|---|---|
run_acmesh_state | str | No | "present" | Determines whether the managed resources should be present or absent.present ensures that required components, such as software packages, are installed and configured.absent reverts changes as much as possible, such as … |
run_acmesh_autoupgrade | bool | No | false | If set to true, all managed packages will be upgraded during each Ansible run (e.g., when the package provider detects a newer version than the currently installed one). |
run_acmesh_autorenewal | bool | No | true | Enables daily automatic certificate renewal via systemd timer (this role is not using acme.sh’s cronjob function). |
run_acmesh_environment 🔒 | dict | No | {} | Defines environment variables required for ACME DNS challenges. This is typically needed for DNS challenge plugins, such as those requiring DNS API credentials (e.g., HETZNER_Token, INWX_User, INWX_Password). Multiple variables can be … |
run_acmesh_git_url | str | No | "https://github.com/acmesh-official/acme.sh.git" | The Git repository URL for acme.sh. The role uses this URL to clone the source code during installation or updates and to query available version tags via git ls-remote.Can be set to an internal Git mirror for air-gapped environments or to … |
run_acmesh_git_fallback_version_branch | str | No | "master" | The Git branch to clone when no version tag could be determined from the remote repository (e.g. because git ls-remote failed or returned no matching tags).See https://github.com/acmesh-official/acme.sh/issues/1162 for why acme.sh uses … |
run_acmesh_git_version | str | No | "" | Overrides the automatically detected acme.sh version with a specific Git ref (tag, branch, or commit hash). When set (non-empty string), the role skips the upstream version tag detection via git ls-remote and uses this value directly for the … |
run_acmesh_certs | list | No | [] | Defines certificates to be requested, their associated domains, challenge methods, and installation details. Each item in the list is a dictionary with suboptions / keys. Example: ``` run_acmesh_certs: # first certificate: “example.org” … |
run_acmesh_certs_delete_unmanaged | bool | No | false | If set to true, certificate data below run_acmesh_cfg_cert_home that does not belong to any certificate listed in run_acmesh_certs gets removed (which also stops the automated renewal for it), as do acmesh-reload-* and acmesh-deploy-* … |
run_acmesh_user | str | No | "acmesh" | Specifies the service user account that runs acme.sh and owns relevant files and directories. All acme.sh operations run as this account: account registration, certificate issuance and installation during the Ansible run as well as the … |
run_acmesh_group | str | No | "acmesh" | Specifies the group associated with the service user for managing acme.sh and the corresponding file permissions. |
run_acmesh_user_supplementary_groups | list | No | [] | Exact list of supplementary groups for the service user account (run_acmesh_user) beyond run_acmesh_group. The role manages the account’s supplementary groups as the exact unique union of run_acmesh_group and this list; group memberships added … |
run_acmesh_cfg_accountemail | str | No | "" | Specifies the email address to be associated with the ACME account. This email is used for expiration notices and recovery purposes. Some ACME providers might refuse to issue certificates if not set. |
run_acmesh_cfg_home | str | No | "/opt/acme.sh" | Specifies the installation directory for the acme.sh software (relates to acme.sh option –home). Will also be used as home directory of the service user defined (see run_acmesh_user). |
run_acmesh_cfg_config_home | str | No | "/etc/acme.sh" | Defines where configuration files are stored (relates to acme.sh option –config-home). |
run_acmesh_cfg_cert_home | str | No | "/var/opt/acme.sh" | Specifies the directory where certificates are maintained by acme.sh (relates to acme.sh option –certhome). ⚠️ Do not rely on the files in this directory directly. Instead, copy the certificates where needed using the “install” key of … |
run_acmesh_cfg_cert_deploy_base_dir | str | No | "/var/opt/acme.sh-deploy" | Base directory for the internal staging areas of certificates using the staged installation strategy. The directory itself is root-owned and holds one subdirectory per certificate which is writable by the service user: acme.sh installs into that … |
run_acmesh_cfg_logfile | str | No | "/var/log/acme.sh.log" | Path to the log file where acme.sh logs its operations (relates to acme.sh option –log). |
run_acmesh_cfg_log_level | int | No | 1 | Specifies the log level (relates to acme.sh option –log-level). Possible values are 1 (less logging) and 2 (more logging). |
run_acmesh_cfg_syslog | int | No | 3 | Specifies what to log (relates to acme.sh option –syslog). Possible values are 0 (disable syslog), 3 (errors), 6 (info) and 7 (debug) |
run_acmesh_cfg_ca_bundle | str | No | "" | Path to a custom CA certificate bundle file on the remote host. Passed as --ca-bundle to all acme.sh commands that make HTTPS requests (issue, register-account). Needed when the ACME server uses a certificate signed by a private or non-standard … |
run_acmesh_cfg_ca_path | str | No | "" | Path to a directory of CA certificates in PEM format on the remote host. Passed as --ca-path to all acme.sh commands that make HTTPS requests. Alternative to run_acmesh_cfg_ca_bundle when the HTTP client (curl/wget) requires a directory of … |
run_acmesh_cfg_account_keys | list | No | [] | List of ACME account keys to pre-seed. This is useful for dns-persist-01 challenges where the TXT record is bound to a specific account key, and you want to reuse the same key across multiple servers or after re-installations.Each item must … |
run_acmesh_dns_persist_pause | int | No | 600 | Controls the pause duration (in seconds) after displaying dns-persist-01 TXT record instructions. Set to 0 to disable the pause (useful for CI/CD pipelines or environments where TXT records are guaranteed to already be published).If the … |
run_acmesh_state
Determines whether the managed resources should be present or absent.
present ensures that required components, such as software packages, are
installed and configured.
absent reverts changes as much as possible, such as removing packages,
deleting created users, stopping services, restoring modified settings, …
- Type:
str - Required: No
- Default:
"present" - Choices:
present,absent
run_acmesh_autoupgrade
If set to true, all managed packages will be upgraded during each Ansible
run (e.g., when the package provider detects a newer version than the
currently installed one).
- Type:
bool - Required: No
- Default:
false
run_acmesh_autorenewal
Enables daily automatic certificate renewal via systemd timer (this role is not using acme.sh’s cronjob function).
- Type:
bool - Required: No
- Default:
true
run_acmesh_environment
Defines environment variables required for ACME DNS challenges.
This is typically needed for DNS challenge plugins, such as those requiring
DNS API credentials (e.g., HETZNER_Token, INWX_User, INWX_Password).
Multiple variables can be defined in parallel to support different providers
for different domains on the same server. For more details on acme.sh’s
DNS API support see https://github.com/acmesh-official/acme.sh/wiki/dnsapi
Example:
run_acmesh_environment:
"HETZNER_Token": "\{\{ lookup('ansible.builtin.unvault', '...') | ansible.builtin.string | ansible.builtin.trim \}\}"
- Type:
dict - Required: No
- Sensitive: Yes (
no_log, values are masked in logs) - Default:
{}
run_acmesh_git_url
The Git repository URL for acme.sh. The role uses this URL to clone the
source code during installation or updates and to query available version
tags via git ls-remote.
Can be set to an internal Git mirror for air-gapped environments or to avoid GitHub API rate limits.
- Type:
str - Required: No
- Default:
"https://github.com/acmesh-official/acme.sh.git"
run_acmesh_git_fallback_version_branch
The Git branch to clone when no version tag could be determined from the
remote repository (e.g. because git ls-remote failed or returned no
matching tags).
See https://github.com/acmesh-official/acme.sh/issues/1162 for why
acme.sh uses master as the branch for the latest release.
- Type:
str - Required: No
- Default:
"master"
run_acmesh_git_version
Overrides the automatically detected acme.sh version with a specific
Git ref (tag, branch, or commit hash). When set (non-empty string),
the role skips the upstream version tag detection via git ls-remote
and uses this value directly for the git clone operation.
This is useful when the latest tagged release does not yet include a
feature you need (setting to master is usually safe as acme.sh aims
for a production-ready master branch by default), or when you want
to pin a specific version for reproducibility.
When set, the upgrade task also respects this value and skips the normal semver comparison that gates upgrades.
- Type:
str - Required: No
- Default:
""
run_acmesh_certs
Defines certificates to be requested, their associated domains, challenge methods, and installation details. Each item in the list is a dictionary with suboptions / keys.
Example:
run_acmesh_certs:
## first certificate: "example.org"
- domains:
- name: "example.org"
challenge: # parameters depend on type
type: "webroot"
webroot: "/var/www/example.org"
install:
ca_file: "/etc/pki/tls/certs/example.org/ca.cer"
cert_file: "/etc/pki/tls/certs/example.org/cert.cer"
fullchain_file: "/etc/pki/tls/certs/example.org/fullchain.cer"
key_file: "/etc/pki/tls/certs/example.org/cert.key"
# Executed as root by a systemd unit whenever the installed
# certificate files change (see the README for details).
reloadcmd: "systemctl reload apache2.service"
## second certificate: "foo.example.com" with an additional "bar.example.com" SAN
- domains:
- name: "foo.example.com"
challenge: # parameters depend on type
type: "dns"
dns_provider: "dns_hetzner"
challenge_alias: "foo.example.com.example.net"
- name: "bar.example.com"
challenge:
type: "dns"
dns_provider: "dns_inwx"
challenge_alias: "bar.example.com.example.net"
install:
ca_file: "/etc/pki/tls/certs/foo.example.com/ca.cer"
cert_file: "/etc/pki/tls/certs/foo.example.com/cert.cer"
fullchain_file: "/etc/pki/tls/certs/foo.example.com/fullchain.cer"
key_file: "/etc/pki/tls/certs/foo.example.com/cert.key"
reloadcmd: "systemctl reload nginx.service; systemctl restart postfix.service"
# optional, CA alias or URL, defaults to "letsencrypt". "{letsencrypt,buypass,google}_test"
# for staging, see https://github.com/acmesh-official/acme.sh/wiki/Server for details.
server: "zerossl"
force: false # optional
debug: false # optional
post_hook: "" # optional
renew_hook: "" # optional
extra_flags: "" # optional (workaround for edge cases, put --whatever in here, used during issuing a cert")
Environment variables needed for the DNS API authentication for
type: "dns" and dns_provider: "dns_hetzner" / dns_provider: "dns_inwx"
run_acmesh_environment:
HETZNER_Token: "{{ lookup('ansible.builtin.unvault', '…') | ansible.builtin.string | ansible.builtin.trim }}"
INWX_User: "exampleuser"
INWX_Password: "{{ lookup('ansible.builtin.unvault', '…') | ansible.builtin.string | ansible.builtin.trim }}"
- Type:
list - Required: No
- Default:
[] - List Elements:
dict
run_acmesh_certs['domains']
List of dictionaries specifying the domains to be included in the certificate request, along with their challenge configurations. If multiple domains are defined, they will be included in the same certificate as Subject Alternative Names (SANs).
The first entry is the certificate’s primary domain and identity: it
names the acme.sh storage directory and the acmesh-reload-* systemd
units, so it must be unique across all run_acmesh_certs entries (the
role fails fast on duplicates).
- Type:
list - Required: Yes
- List Elements:
dict
run_acmesh_certs['domains']['name']
The domain name to request a certificate for.
- Type:
str - Required: Yes
run_acmesh_certs['domains']['challenge']
Dictionary defining the ACME challenge parameters. The required parameters depend on the challenge type
- Type:
dict - Required: No
run_acmesh_certs['domains']['challenge']['type']
Challenge method. See https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert for details.
- Type:
str - Required: No
- Choices:
alpn,dns,dns_persist,standalone,webroot
run_acmesh_certs['domains']['challenge']['dns_provider']
Optional. Required for “dns” challenges. Specifies
the DNS provider for API-based verification. See
https://github.com/acmesh-official/acme.sh/wiki/dnsapi for supported
providers and their name. You usually have to provide credentials for
their APIs via the global run_acmesh_environment variable or the
per-certificate environment key.
- Type:
str - Required: No
run_acmesh_certs['domains']['challenge']['challenge_alias']
Optional. Used with “dns” challenges when using CNAME delegation. Requires
a CNAME record such as:
_acme-challenge.example.com -> _acme-challenge.example.com.example.net
See https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode for
details.
- Type:
str - Required: No
run_acmesh_certs['domains']['challenge']['domain_alias']
Optional. Used with “dns” challenges as an alternative to
challenge_alias. Instead of CNAME delegation, the alias domain is
set directly as the domain to use for the DNS challenge validation.
See https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode
for details.
- Type:
str - Required: No
run_acmesh_certs['domains']['challenge']['webroot']
Optional. Required for “webroot” challenges. Specifies
the directory where the ACME challenge response should be placed
(e.g. the document root of the web server serving the domain).
The service user defined by run_acmesh_user needs write access
there (acme.sh creates .well-known/acme-challenge below it
during issuance and renewal), e.g. via group membership or a
pre-created, service-user owned .well-known/acme-challenge
directory.
See https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert
for details.
- Type:
str - Required: No
run_acmesh_certs['domains']['challenge']['httpport']
Optional. Used with “httpport” challenges. Specifies a non-standard port for acme.sh’s internal HTTP webserver to listen, might be needed behind a reverse proxy or load balancer.
- Type:
int - Required: No
run_acmesh_certs['domains']['challenge']['tlsport']
Optional. Used with “alpn” challenges. Specifies a non-standard port for acme.sh’s internal HTTPS webserver to listen, might be needed behind a reverse proxy or load balancer.
- Type:
int - Required: No
run_acmesh_certs['domains']['challenge']['dns_persist_wildcard']
Optional. Used with “dns_persist” challenges. If true, the persistent TXT record will also authorize wildcard certificates and matching subdomains for this domain. Corresponds to acme.sh –dns-persist-wildcard. See https://github.com/acmesh-official/acme.sh/wiki/DNS-persist-mode for details.
- Type:
bool - Required: No
run_acmesh_certs['domains']['challenge']['dns_persist_ca_name']
Optional. Used with “dns_persist” challenges. Specifies a custom CA identity domain name for the TXT record value (instead of deriving it from the server URL). Corresponds to acme.sh –dns-persist-ca-name. See https://github.com/acmesh-official/acme.sh/wiki/DNS-persist-mode for details.
- Type:
str - Required: No
run_acmesh_certs['domains']['challenge']['dns_persist_days']
Optional. Used with “dns_persist” challenges. Specifies the number of days the TXT record should be considered valid (adds a persistUntil field to the record). Corresponds to acme.sh –dns-persist-days. See https://github.com/acmesh-official/acme.sh/wiki/DNS-persist-mode for details.
- Type:
int - Required: No
run_acmesh_certs['install']
Dictionary defining where and how to install the issued certificates. The following keys specify file paths, the installation strategy, ownership and permission overrides and a reload command:
ca_file: String. Path to the certificate authority (CA) file.
cert_file: String. Path to the certificate file.
fullchain_file: String. Path to the full certificate chain file.
key_file: String. Path to the private key file.
strategy: String,
staged(the default) ordirect. See the suboption description for details.permissions: Dictionary of partial ownership and mode overrides for the destination directory and the installed files.
reloadcmd: String. Command to reload or restart services after certificate installation and renewal (e.g., web server or mail server). It is executed as root by a systemd unit whenever the installed certificate files change, so no sudo or polkit setup is needed. Requires at least one of the install file paths to be set. See the README of this role for details.
Type:
dictRequired: No
run_acmesh_certs['install']['ca_file']
- Type:
str - Required: No
run_acmesh_certs['install']['cert_file']
- Type:
str - Required: No
run_acmesh_certs['install']['fullchain_file']
- Type:
str - Required: No
run_acmesh_certs['install']['fullcain_file']
Deprecated alias of fullchain_file (typo, “cain” instead of “chain”). Do not use.
- Type:
str - Required: No
run_acmesh_certs['install']['key_file']
- Type:
str - Required: No
run_acmesh_certs['install']['strategy']
Installation strategy for the certificate files.
staged (the default, also used when this key is omitted):
acme.sh installs the certificate into an internal,
root-protected staging area below
run_acmesh_cfg_cert_deploy_base_dir and a root-owned
systemd service (acmesh-deploy-<primary domain>.service)
validates and publishes the files to the final destinations.
This supports destinations below protected parent directories
(such as /etc/ssl/private) and full ownership and mode
control via permissions, while acme.sh itself keeps running
unprivileged. See the README of this role for details.
direct: acme.sh installs directly to the final paths as the
unprivileged service user (the behavior of version 3.x and
below of this role). This is a compatibility option, not the
recommended default: every destination must be writable by
run_acmesh_user - also during unattended renewal - and
permissions ownership overrides are rejected because the
service account could not maintain them.
- Type:
str - Required: No
- Default:
"staged" - Choices:
staged,direct
run_acmesh_certs['install']['permissions']
Partial overrides for the ownership and permissions of the destination directory and the installed certificate files.
Effective values are calculated per key; later mappings override earlier mappings, unspecified keys inherit from the earlier ones:
- role defaults (directory:
run_acmesh_user:run_acmesh_groupwith mode"2750"; files:run_acmesh_user:run_acmesh_groupwith mode"0640") default(applies to all certificate files)- the per-artifact mapping (
ca_file,cert_file,fullchain_file,key_file)
mode values must be quoted octal strings (such as "0640").
Certificate files must not be executable and must not carry
setuid/setgid/sticky bits; private keys must additionally not
be world-readable or group/world-writable ("0600", "0640",
"0400" and "0440" are typical valid values). Directories
may keep the setgid bit (the default directory mode is
"2750"). owner and group accept names (recommended) or
numeric ID strings and must exist on the target.
Example:
permissions:
directory:
owner: "root"
group: "ssl-cert"
mode: "0750"
default:
owner: "root"
group: "ssl-cert"
mode: "0640"
fullchain_file:
mode: "0644"
key_file:
group: "dovecot"
- Type:
dict - Required: No
run_acmesh_certs['install']['permissions']['directory']
Ownership and mode overrides for the immediate
destination directories of the certificate files. Only
these directories are managed; existing ancestors (such
as /etc/ssl or /etc/ssl/private) are never changed.
- Type:
dict - Required: No
Note: This option has more options but this README shows nested options up to level 3. Please refer to the argument_specs file for complete details.
run_acmesh_certs['install']['permissions']['default']
Ownership and mode overrides applied to all installed certificate files (overridable per artifact).
- Type:
dict - Required: No
Note: This option has more options but this README shows nested options up to level 3. Please refer to the argument_specs file for complete details.
run_acmesh_certs['install']['permissions']['ca_file']
Ownership and mode overrides for the installed ca_file.
- Type:
dict - Required: No
Note: This option has more options but this README shows nested options up to level 3. Please refer to the argument_specs file for complete details.
run_acmesh_certs['install']['permissions']['cert_file']
Ownership and mode overrides for the installed cert_file.
- Type:
dict - Required: No
Note: This option has more options but this README shows nested options up to level 3. Please refer to the argument_specs file for complete details.
run_acmesh_certs['install']['permissions']['fullchain_file']
Ownership and mode overrides for the installed
fullchain_file.
- Type:
dict - Required: No
Note: This option has more options but this README shows nested options up to level 3. Please refer to the argument_specs file for complete details.
run_acmesh_certs['install']['permissions']['key_file']
Ownership and mode overrides for the installed key_file.
- Type:
dict - Required: No
Note: This option has more options but this README shows nested options up to level 3. Please refer to the argument_specs file for complete details.
run_acmesh_certs['install']['reloadcmd']
Optional. Command to reload or restart services after the certificate
was installed or renewed. It is not executed by acme.sh but by a
root-side systemd path unit (acmesh-reload-<primary domain>.path)
which watches the installed certificate files and runs the command
(as root, via a companion service unit) whenever they change. This
works identically for the initial issuance, automated renewal and
manual acme.sh runs, without granting the service user defined by
run_acmesh_user any privileges (no sudo or polkit setup needed).
A failing reload command leaves the acmesh-reload-<primary domain>.service unit in a failed state, visible via
systemctl --failed and the journal.
Requires at least one of fullchain_file, key_file, ca_file or
cert_file to be set (the unit watches the last one of these files
acme.sh writes). Reload units of certificates that are no longer
listed in run_acmesh_certs are kept by default (acme.sh keeps
renewing and reinstalling issued certificates until they are
actively removed). Remove a certificate with its state: absent or
enable run_acmesh_certs_delete_unmanaged to reap such leftovers;
everything gets removed when run_acmesh_state is absent.
- Type:
str - Required: No
run_acmesh_certs['server']
Optional. Specifies the ACME CA server to use. Defaults
to letsencrypt. Other options include:
“letsencrypt_test”, “buypass_test”, “google_test” for staging environments.
Custom CA URLs can also be used. See https://github.com/acmesh-official/acme.sh/wiki/Server for a full list and details.
Type:
strRequired: No
Default:
"letsencrypt"
run_acmesh_certs['force']
Optional. If true, forces certificate issuance even if
the current certificate is still valid. Defaults to false.
- Type:
bool - Required: No
run_acmesh_certs['debug']
- Type:
bool - Required: No
run_acmesh_certs['dnssleep']
- Type:
int - Required: No
run_acmesh_certs['pre_hook']
Optional. Command to execute before attempting certificate
issuance or renewal. Executed by acme.sh as the unprivileged service
user defined by run_acmesh_user (during issuance as well as
automated renewal), so it must not require root privileges. Use
reloadcmd for reloading or restarting services (it runs as root).
See
https://github.com/acmesh-official/acme.sh/wiki/Using-pre-hook-post-hook-renew-hook-reloadcmd
for details.
- Type:
str - Required: No
run_acmesh_certs['post_hook']
Optional. Command to execute after a successful certificate issuance
or renewal. Executed by acme.sh as the unprivileged service user
defined by run_acmesh_user (during issuance as well as automated
renewal), so it must not require root privileges. Use reloadcmd
for reloading or restarting services (it runs as root). See
https://github.com/acmesh-official/acme.sh/wiki/Using-pre-hook-post-hook-renew-hook-reloadcmd
for details.
- Type:
str - Required: No
run_acmesh_certs['renew_hook']
Optional. Command to execute after renewing the certificate.
Executed by acme.sh as the unprivileged service user defined by
run_acmesh_user, so it must not require root privileges. Use
reloadcmd for reloading or restarting services (it runs as root).
See
https://github.com/acmesh-official/acme.sh/wiki/Using-pre-hook-post-hook-renew-hook-reloadcmd
for details.
- Type:
str - Required: No
run_acmesh_certs['extra_flags']
Optional. Additional CLI flags for edge cases. Useful for passing custom parameters during certificate issuance wich are not natively supported by this role, just pass them as “–foo –bar ‘baz’”.
- Type:
str - Required: No
run_acmesh_certs['environment']
Optional. Dictionary of environment variables specific to this certificate. Setting environment variables per certificate can improve readability, as it clearly shows which certificate or domain is using which credentials in setups that involve multiple DNS provider credentials.
These are merged with the globalrun_acmesh_environment, with
per-certificate values taking precedence on key conflicts.
Please note that acme.sh DNS API plugins usually persist credentials per
provider (not per certificate) in account.conf, so using different
credentials for the same DNS provider across certificates will result in
only the last-written set being saved for automatic renewals.
- Type:
dict - Required: No
- Sensitive: Yes (
no_log, values are masked in logs)
run_acmesh_certs['state']
Optional. present (the default) issues and maintains the certificate.
absent removes all data of this certificate: the acme.sh data below
run_acmesh_cfg_cert_home (which also stops the automated renewal for
it), the acmesh-reload-* and acmesh-deploy-* systemd units, the
staging data and deployment manifest of the staged installation
strategy and the installed certificate files listed under install.
Directories holding installed files are kept, as they may be shared
with other software. The certificate is not revoked at the ACME CA.
This works independently of run_acmesh_certs_delete_unmanaged.
- Type:
str - Required: No
- Default:
"present" - Choices:
present,absent
run_acmesh_certs_delete_unmanaged
If set to true, certificate data below run_acmesh_cfg_cert_home that
does not belong to any certificate listed in run_acmesh_certs gets
removed (which also stops the automated renewal for it), as do
acmesh-reload-* and acmesh-deploy-* systemd units, staging
directories and deployment manifests the current configuration does
not define. Useful to declaratively clean up certificates that were
simply deleted from run_acmesh_certs (instead of being listed with
state: absent).
Two safety properties: installed certificate files of unmanaged
certificates are never touched (their installation paths are unknown to
the role), and nothing is removed while run_acmesh_certs is undefined.
Note that an empty certificate list (run_acmesh_certs: [], the
default) combined with true declares “no certificates”, so all
certificate data below run_acmesh_cfg_cert_home gets removed.
Prefer a per-certificate state: absent entry for targeted removal
including the installed files.
- Type:
bool - Required: No
- Default:
false
run_acmesh_user
Specifies the service user account that runs acme.sh and owns relevant files and directories.
All acme.sh operations run as this account: account registration,
certificate issuance and installation during the Ansible run as well
as the automated renewal (acmesh-renewal.service). Issuance and
renewal therefore behave identically, and permission problems surface
during the Ansible run instead of weeks later at the first renewal.
When a certificate uses the standalone or alpn challenge on a
privileged port (below 1024), the needed CAP_NET_BIND_SERVICE
capability is granted automatically for both issuance and renewal.
This must be a dedicated account fully owned by this role. The role
rewrites the account’s password, shell, home directory and supplementary
group membership on installation. When user management is enabled, the
role fully manages and removes the account named by run_acmesh_user,
regardless of who originally created it: run_acmesh_state: absent
deletes the account together with its home directory.
Do not point this at a shared, pre-existing or privileged account. The
role refuses to run when run_acmesh_user resolves to root, a UID 0
account, or the account Ansible connects with, to avoid damaging or
deleting an account that is not meant to be managed by it.
- Type:
str - Required: No
- Default:
"acmesh"
run_acmesh_group
Specifies the group associated with the service user for managing acme.sh and the corresponding file permissions.
- Type:
str - Required: No
- Default:
"acmesh"
run_acmesh_user_supplementary_groups
Exact list of supplementary groups for the service user account
(run_acmesh_user) beyond run_acmesh_group. The role manages the
account’s supplementary groups as the exact unique union of
run_acmesh_group and this list; group memberships added outside of
this role are removed again on the next run. Every listed group must
already exist on the target (the role fails fast otherwise).
Both the automated renewal service (acmesh-renewal.service) and all
acme.sh invocations of this role (which run via
setpriv --init-groups) pick these groups up.
⚠️ Privileged groups (such as ssl-cert on Debian-based systems) may
grant read access to unrelated private keys. This escape hatch is
useful for direct certificate installations below protected
directories, webroot write access, hooks and similar local
requirements, but should not be needed merely to deploy a
certificate through the (default) staged installation strategy.
- Type:
list - Required: No
- Default:
[] - List Elements:
str
run_acmesh_cfg_accountemail
Specifies the email address to be associated with the ACME account. This email is used for expiration notices and recovery purposes. Some ACME providers might refuse to issue certificates if not set.
- Type:
str - Required: No
- Default:
""
run_acmesh_cfg_home
Specifies the installation directory for the acme.sh software (relates
to acme.sh option –home). Will also be used as home directory of the
service user defined (see run_acmesh_user).
- Type:
str - Required: No
- Default:
"/opt/acme.sh"
run_acmesh_cfg_config_home
Defines where configuration files are stored (relates to acme.sh option –config-home).
- Type:
str - Required: No
- Default:
"/etc/acme.sh"
run_acmesh_cfg_cert_home
Specifies the directory where certificates are maintained by
acme.sh (relates to acme.sh option –certhome).
⚠️ Do not rely on the files in this directory directly. Instead, copy
the certificates where needed using the “install” key of run_acmesh_certs
(relates to acme.sh option –install-cert). This ensures that the
certificates are properly maintained and automatically reinstalled
upon renewal. See the following for more information:
https://github.com/acmesh-official/acme.sh/issues/2350#issuecomment-1449235599
- Type:
str - Required: No
- Default:
"/var/opt/acme.sh"
run_acmesh_cfg_cert_deploy_base_dir
Base directory for the internal staging areas of certificates using
the staged installation strategy. The directory itself is
root-owned and holds one subdirectory per certificate which is
writable by the service user: acme.sh installs into that staging
area and the root-owned acmesh-deploy-* systemd units validate and
publish the files to their final destinations.
Must not be located below (or be a parent of) run_acmesh_cfg_home,
run_acmesh_cfg_config_home or run_acmesh_cfg_cert_home; the role
fails fast otherwise.
- Type:
str - Required: No
- Default:
"/var/opt/acme.sh-deploy"
run_acmesh_cfg_logfile
Path to the log file where acme.sh logs its operations (relates to acme.sh option –log).
- Type:
str - Required: No
- Default:
"/var/log/acme.sh.log"
run_acmesh_cfg_log_level
Specifies the log level (relates to acme.sh option –log-level). Possible values are 1 (less logging) and 2 (more logging).
- Type:
int - Required: No
- Default:
1 - Choices:
1,2
run_acmesh_cfg_syslog
Specifies what to log (relates to acme.sh option –syslog). Possible values are 0 (disable syslog), 3 (errors), 6 (info) and 7 (debug)
- Type:
int - Required: No
- Default:
3 - Choices:
0,3,6,7
run_acmesh_cfg_ca_bundle
Path to a custom CA certificate bundle file on the remote host. Passed
as --ca-bundle to all acme.sh commands that make HTTPS requests (issue,
register-account). Needed when the ACME server uses a certificate signed
by a private or non-standard CA.
This is a global acme.sh setting, acme.sh persists it to its account.conf
and applies it to all operations including cron renewals.
- Type:
str - Required: No
- Default:
""
run_acmesh_cfg_ca_path
Path to a directory of CA certificates in PEM format on the remote host.
Passed as --ca-path to all acme.sh commands that make HTTPS requests.
Alternative to run_acmesh_cfg_ca_bundle when the HTTP client (curl/wget)
requires a directory of individual CA certificate files.
This is a global acme.sh setting, acme.sh persists it to its account.conf
and applies it to all operations including cron renewals.
- Type:
str - Required: No
- Default:
""
run_acmesh_cfg_account_keys
List of ACME account keys to pre-seed. This is useful for dns-persist-01
challenges where the TXT record is bound to a specific account key, and
you want to reuse the same key across multiple servers or after
re-installations.
Each item must specify a server (CA alias or URL, same value used in
run_acmesh_certs[].server) and account_key (PEM-encoded private key
content). The role seeds the key and then runs acme.sh --register-account
which confirms the account with the CA and may generate the account.json
metadata automatically if needed (per RFC 8555 section 7.3.1, the CA
identifies accounts by their public key).
Example:
run_acmesh_cfg_account_keys:
- server: "letsencrypt"
account_key: "\{\{ lookup('ansible.builtin.unvault', 'files/acmesh_account_key_letsencrypt.pem') \}\}"
- Type:
list - Required: No
- Default:
[] - List Elements:
dict
run_acmesh_cfg_account_keys['server']
The CA alias or full ACME directory URL. Must match the value used in
run_acmesh_certs[].server (e.g., “letsencrypt”, “zerossl”, or a URL).
- Type:
str - Required: Yes
run_acmesh_cfg_account_keys['account_key']
PEM-encoded ACME account private key content. Sensitive - use
ansible.builtin.unvault or similar secret management to supply this
value.
- Type:
str - Required: Yes
- Sensitive: Yes (
no_log, values are masked in logs)
run_acmesh_dns_persist_pause
Controls the pause duration (in seconds) after displaying dns-persist-01
TXT record instructions. Set to 0 to disable the pause (useful for
CI/CD pipelines or environments where TXT records are guaranteed to
already be published).
If the pause expires without user confirmation, the play continues.
- Type:
int - Required: No
- Default:
600
Dependencies
See dependencies in meta/main.yml.
Compatibility
See min_ansible_version in meta/main.yml and __run_acmesh_supported_platforms in vars/main.yml.
External requirements
- Git repository access: The role uses
git ls-remoteto query available version tags from the configured git repository. This works with any git remote (GitHub, GitLab, local mirrors), making it suitable for air-gapped environments with internal mirrors (seerun_acmesh_git_urlparameter). - systemd: The role requires systemd as init system, there is no fallback for others. It automates renewals with its own
acmesh-renewal.timer/acmesh-renewal.servicepair (acme.sh’s built-in cron support is disabled with--nocronon purpose) and executesreloadcmdvia root-side systemd path units watching the installed certificate files. - SELinux: This role does not handle SELinux configurations. Please add additional tasks before or after this role to accommodate these changes (e.g.
cert_tmight be needed as context). The following Ansible modules may help with SELinux configuration: - Permissions to restart services for the service user: Not needed for
reloadcmd, which runs asrootvia a systemd path unit (see Service reloads after certificate changes). However, thepre_hook,post_hookandrenew_hookcommands are executed byacme.shitself and therefore always run as the unprivileged service user defined byrun_acmesh_user(defaults toacmesh); privileged operations in these hooks have to be allowed explicitly (e.g. viasudoor polkit). - Webroot write access for the service user: When using the
webrootchallenge, the service user needs write access to the configured webroot directory (acme.shcreates.well-known/acme-challengebelow it during issuance and renewal).
Beside that, there are no special requirements not covered by the role or Ansible itself.