Referencing AcmeClient Certificates from config files

Started by excavator fidelity, November 02, 2025, 06:33:41 PM

Previous topic - Next topic
I am trying to use some unexposed Unbound options that require referencing a TLS private key. I want to use my Let's Encrypt certificate which I renew each month via the ACME Client service, but there are two issues with just editing /usr/local/etc/unbound.opnsense.d/custom.conf.

  • The certificate files are not part of the unbound chroot. I don't believe the chroot setup is editable in a way that is safe from OPNsense updates.
  • The ACME Client puts its certificates in randomly-generated directory names, and uses the OPNsense Trust Store as the ultimate source of truth. Because that data is stored in XML I can't reference it from the unbound config.

I had run into this same issue with the Prometheus exporter plugin, and I hope that I'm just missing something.

To avoid an XY problem, I want to allow clients to connect to unbound via DoT, with a config file that looks like this:

server:
  interface: 192.168.0.1@853
  tls-port: 853
  tls-service-pem: /path/to/public/cert.pem
  tls-service-key: /path/to/private/cert.key

This works just fine; that's my custom conf include:

server:
  interface: 2001:db8:1:53::1@853
  interface: 2001:db8:1:53::1@443
  tls-service-key: "/var/etc/acme-client/keys/0123456789abcd.12345678/private.key"
  tls-service-pem: "/var/etc/acme-client/certs/0123456789abcd.12345678/fullchain.pem"

Just look up what "0123456789abcd.12345678" is for your certificate. This path won't change when the certificate renews.

Cheers
Maurice
OPNsense virtual machine images
OPNsense aarch64 firmware repository

Commercial support & engineering available. PM for details (en / de).

November 02, 2025, 08:34:43 PM #3 Last Edit: November 02, 2025, 08:38:33 PM by excavator fidelity
Hmm, thanks for the information but this still isn't working for me.
This may be an Unbound issue and not an OPNsense one, but I can't connect to the server.

$ dig @dns.example.com +tls google.com
;; Connection to 192.168.0.1#853(192.168.0.1) for google.com failed: timed out.
;; no servers could be reached

and on Unbound:

2025-11-02T13:33:36-06:00
Debug
unbound
[16668:0] debug: outnettcp got tcp error -1

2025-11-02T13:33:36-06:00
Debug
unbound
[16668:0] debug: outnettcp cb

2025-11-02T13:33:36-06:00
Debug
unbound
[16668:0] debug: close fd 37

2025-11-02T13:33:36-06:00
Debug
unbound
[16668:2] debug: outnettcp got tcp error -1

2025-11-02T13:33:36-06:00
Debug
unbound
[16668:2] debug: outnettcp cb

2025-11-02T13:33:36-06:00
Debug
unbound
[16668:2] debug: close fd 47

2025-11-02T13:33:36-06:00
Debug
unbound
[16668:0] debug: outnettcp got tcp error -1

2025-11-02T13:33:36-06:00
Debug
unbound
[16668:0] debug: outnettcp cb

2025-11-02T13:33:36-06:00
Debug
unbound
[16668:0] debug: close fd 40
...

# Config
server:
  # I have a static ULA setup in Virtual IPs
  interface: fd00:abcd::1@853
  interface: 192.168.0.1@853
  tls-service-key: "/var/etc/acme-client/keys/.../private.key"
  tls-service-pem: "/var/etc/acme-client/keys/.../fullchain.pem"

Hm, this has been working for me for years on two separate OPNsense instances.

Do your firewall settings allow access to 192.168.0.1:853 TCP?

Did you try a basic TLS connection test (on a client in the LAN as well as on OPNsense itself)?

openssl s_client -connect 192.168.0.1:853
OPNsense virtual machine images
OPNsense aarch64 firmware repository

Commercial support & engineering available. PM for details (en / de).

Quote from: excavator fidelity on November 02, 2025, 08:34:43 PM  tls-service-key: "/var/etc/acme-client/keys/.../private.key"
  tls-service-pem: "/var/etc/acme-client/keys/.../fullchain.pem"

There's a typo in the tls-service-pem path (must be acme-client/certs, not acme-client/keys).
OPNsense virtual machine images
OPNsense aarch64 firmware repository

Commercial support & engineering available. PM for details (en / de).

$ # This is on the OPNsense box
$ openssl s_client -connect 192.168.0.1:853
0810A5FFB6220000:error:8000003D:system library:BIO_connect:Connection refused:/usr/src/crypto/openssl/crypto/bio/bio_sock2.c:125:calling connect()
0810A5FFB6220000:error:10000067:BIO routines:BIO_connect:connect error:/usr/src/crypto/openssl/crypto/bio/bio_sock2.c:127:
connect:errno=61

That config typo is just from copying into the forum, my config correctly uses the `/var/etc/acme-client/certs/.../fullchain.pem` path.

Unbound is actually running and works fine when querying it using plain UDP / TCP on port 53?
OPNsense virtual machine images
OPNsense aarch64 firmware repository

Commercial support & engineering available. PM for details (en / de).

Using sockstat -l I realize that unbound isn't listening on port 853. I assume that means the configuration is not being loaded: is `extra-config.conf` not a valid filename for the `opnsense.unbound.d` directory? It is correctly moved into the chroot.

Custom includes are put in /usr/local/etc/unbound.opnsense.d/ get copied to /var/unbound/etc/ when Unbound reconfigures. Do the contents of these directories match?

root@router:~ # ls -l /usr/local/etc/unbound.opnsense.d/
total 20
-rw-r--r--  1 root wheel 127 Oct 22 08:53 README
-rw-r--r--  1 root wheel 313 Nov  2 20:41 access_lists.conf
-rw-r--r--  1 root wheel  66 Nov  2 20:41 domainoverrides.conf
-rw-r--r--  1 root wheel 976 Nov  2 20:41 dot.conf
-rw-r--r--  1 root wheel 253 Jan 30  2024 dot_doh_downstream.conf
-rw-r--r--  1 root wheel   0 Nov  2 20:41 safesearch.conf
root@router:~ # ls -l /var/unbound/etc/
total 16
-rw-r-----  1 unbound unbound 313 Nov  2 20:41 access_lists.conf
-rw-r-----  1 unbound unbound  66 Nov  2 20:41 domainoverrides.conf
-rw-r-----  1 unbound unbound 976 Nov  2 20:41 dot.conf
-rw-r-----  1 unbound unbound 253 Nov  2 20:41 dot_doh_downstream.conf
-rw-r-----  1 unbound unbound   0 Nov  2 20:41 safesearch.conf

dot_doh_downstream.conf is my custom include.
OPNsense virtual machine images
OPNsense aarch64 firmware repository

Commercial support & engineering available. PM for details (en / de).

Yes, these directories match exactly (including the contents).

Where are the unbound logs located? I've been using the UI since there isn't a /var/log/unbound directory.
I think it could be an issue where the ACME private key is not readable (since it's owned by root:wheel), but I can't see any errors in the UI log. I believe unbound is started as root though so maybe this isn't a problem.

root@router:~ # ls -l /var/etc/acme-client/keys/0123456789abcd.12345678/
total 4
-rwxr-x---  1 root wheel 288 Oct 25 00:02 private.key
root@router:~ # ls -l /var/etc/acme-client/certs/0123456789abcd.12345678/
total 12
-rwxr-x---  1 root wheel 1330 Oct 25 00:02 cert.pem
-rwxr-x---  1 root wheel 1567 Oct 25 00:02 chain.pem
-rwxr-x---  1 root wheel 2897 Oct 25 00:02 fullchain.pem

And just in case it matters, my DoT / DoH certs are from Let's Encrypt, no Alt Names, ec-384, OCSP Must Staple disabled.
OPNsense virtual machine images
OPNsense aarch64 firmware repository

Commercial support & engineering available. PM for details (en / de).

Exactly the same certificate profile here.
I checked with `openssl` that the files are correct and have an EC key and x509 cert (which I'm using for the Web UI so it is valid).

I can't get `service unbound restart` to work because the rc.d script assumes I'm in the chroot; I want to try and restart unbound from the shell instead of using the UI to make sure that isn't a source of issues.

Maybe I'm just too unfamiliar with OPNsense internals, but I was able to get DoT working by directly editing /usr/local/etc/unbound/unbound.conf and then running `sudo service unbound onestart`. But now I have two separate `unbound` instances running!

Quote from: excavator fidelity on November 02, 2025, 10:07:56 PMI want to try and restart unbound from the shell instead of using the UI to make sure that isn't a source of issues.

# configctl unbound restart

Quote from: excavator fidelity on November 02, 2025, 10:39:46 PMI was able to get DoT working by directly editing /usr/local/etc/unbound/unbound.conf

This file isn't used by OPNsense, it dynamically creates and uses /var/unbound/unbound.conf. You might want to post the contents of this file. I'm running out of ideas...
OPNsense virtual machine images
OPNsense aarch64 firmware repository

Commercial support & engineering available. PM for details (en / de).