security/acme-client: missing accounts directory causes DNS-01 validation failure
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 75/100
Research direction
Start at the os-acme-client plugin entry point that launches acme.sh with --accountconf, then trace how the account configuration path is built. Verify the parent directory is created with the expected permissions before execution, and reproduce the DNS-01 flow to confirm account.conf can be written and validation reaches the DNS provider.
Written by the indexing model from the issue text.
Description
Important notices
I have read the contributing guidelines.
I searched open and closed issues and did not find this specific issue.
Describe the bug
os-acme-client invokes acme.sh with an explicit account configuration path beneath:
/var/etc/acme-client/accounts/_prod/account.conf
However, on my system the accounts directory was not created.
This causes DNS-01 validation to fail before the DNS provider API is called.
Environment:
OPNsense 26.7.4_1 (amd64) os-acme-client 4.17 acme.sh 3.1.4 FreeBSD 15.1-RELEASE-p3 ACME CA: Let's Encrypt Challenge: DNS-01 DNS provider: DreamHost
Symptoms
Certificate configuration:
CN: ryanhome.us
SAN: *.ryanhome.us
The ACME operation failed with:
Error adding TXT record to domain: _acme-challenge.ryanhome.us domain validation failed (dns01)
Debug 3 showed:
ACCOUNT_CONF_PATH='/var/etc/acme-client/accounts/_prod/account.conf'
But the runtime directory contained only:
cert-home certs challenges configs home keys
There was no:
/var/etc/acme-client/accounts
Investigation
The installed DreamHost DNS provider calls validate() before submit().
validate() ends by calling:
_saveaccountconf_mutable DH_API_KEY "$DH_API_KEY"
_saveaccountconf_mutable ultimately writes to ACCOUNT_CONF_PATH.
In acme.sh 3.1.4, _setopt() does:
if [ ! -f "$__conf" ]; then touch "$__conf" chmod 600 "$__conf" fi
but it does not create the parent directory.
As a result, account.conf cannot be created when the parent directory does not exist. The DreamHost provider exits before submit() is reached.
Debug logging showed "Using dreamhost" and then the TXT-add failure, but no URL debug output from the provider's submit() function.
Verification that DreamHost is not the cause
From the same OPNsense shell, using the same DreamHost API key:
dns-list_records succeeds.
A manual dns-add_record also succeeds for:
_acme-challenge.ryanhome.us TXT
DreamHost returns:
{"result":"success","data":"record_added"}
The record is then visible using DreamHost's dns-list_records API.
I also tested a direct query-string request equivalent to that constructed by dns_dreamhost.sh, which also returns:
{"result":"success","data":"record_added"}
Workaround / reproduction proof
Before the workaround:
ls -ld /var/etc/acme-client/accounts
returned:
No such file or directory
I manually created:
mkdir -p /var/etc/acme-client/accounts/_prod
chmod 750 /var/etc/acme-client/accounts chmod 750 /var/etc/acme-client/accounts/_prod
I did NOT manually create account.conf and made no other ACME configuration changes.
I then issued the exact same certificate again.
The ACME log immediately progressed to:
response='success record_added' The TXT record has been successfully added. Sleeping for 120 seconds to wait for the TXT records to take effect
The certificate was subsequently issued successfully.
OPNsense now reports:
Last ACME Status: OK
and acme.sh automatically created:
/var/etc/acme-client/accounts/_prod/account.conf
with permissions 0600.
Expected behavior
os-acme-client should ensure the parent directory for the account configuration exists before invoking acme.sh with --accountconf.
For example:
/var/etc/acme-client/accounts/_prod/
should already exist before acme.sh is executed.
Additional information
The workaround is currently present under /var/etc and therefore may not survive reboot or runtime-directory recreation.
No modification to acme.sh or dns_dreamhost.sh was required.
Proposed Fix is conceptually like:
$accountConfDir = dirname($accountConf);
if (!is_dir($accountConfDir)) {
mkdir($accountConfDir, 0750, true);
}
immediately before the plugin launches acme.sh with:
--accountconf $accountConf
Before & After Workaround:
Before workaround:
ls -ld /var/etc/acme-client/accounts
ls: /var/etc/acme-client/accounts: No such file or directory
Workaround:
mkdir -p /var/etc/acme-client/accounts/_prod
chmod 750 /var/etc/acme-client/accounts
chmod 750 /var/etc/acme-client/accounts/_prod
No other ACME settings were changed.
The next issuance succeeded:
response='success record_added'
The TXT record has been successfully added.
Sleeping for 120 seconds to wait for the TXT records to take effect
Issue/Renewal Date: 10/3/2026 3:57:06 PM
Last ACME Status: OK
Environment
OPNsense 26.7.4_1 (amd64)
os-acme-client 4.17
acme.sh 3.1.4
FreeBSD 15.1-RELEASE-p3
ACME CA: Let's Encrypt
Challenge: DNS-01
DNS provider: DreamHost
Last known working os-acme-client version: Unknown.
This is a new pfSense-to-OPNsense migration, so I do not have an
earlier OPNsense plugin version known to work.
GUI pages involved:
Services > ACME Client > Certificates
Services > ACME Client > Challenge Types
- Dominant language
- PHP
- Stars
- 1.2k
- Forks
- 869
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 13
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from opnsense/plugins
-
net/freeradius: Fallback VLAN interferes with other authentication methodsPossibly taken @claudioguareschi claimed this 2 days ago. Open
Difficulty 1/5 Under an hour Newbie friendliness 92/100
Maintainers usually reply within 1 day
-
security/tor: Advanced mode / help toggles are brokenPossibly taken @txr13 claimed this 15 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
os-opnproxy 1.0.5_5Openincomplete
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
opnsense/plugins#5710 · 1 comment ·
Maintainers usually reply within 1 day
-
net/vnstat: use OPNsense interface names in dashboard widgetPossibly taken @joeroback claimed this 78 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
All issues in opnsense/plugins
Similar issues
-
RFC
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 1 day
-
Performance: faster AopComposerLoader::findFile() for classes outside the cache (~1.6 µs per class)OpenEnhancement Performance
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
bug customer-reported
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
MagnaCapax/PMSS#1009 ·
Maintainers usually reply within 5 days
-
product / databases product / functions product / self-hosted product / storage sdk / cli
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day