New lightweight Let's Encrypt client

I have written and recently released uacme, an open source, lightweight ACME client written in C with minimal dependencies. ACME is the protocol used by to issue free SSL certificates. Version 2 of the protocol was standardized as RFC8555 in March 2019 ( ).

Other than libc, uacme depends only on libcurl and either GnuTLS or mbedTLS. Particularly when built against mbedTLS, it is small enough that it can even run on embedded systems with limited memory. Therefore I think it may be of interest for OpenWRT users.

The software is at:


Looks very interesting!

Is it possible to build and link against OpenSSL as that is what is used by nginx?


+1 for openssl version.

1 Like

It is not in the code and I wasn't planning to use OpenSSL, but I will see what I can do. Stay tuned...

1 Like

what is the advantage over the "plain" script?


Interpreted solutions such as "" usually depend on openssl and/or other large packages. Error reporting when something goes wrong is lacking. Most are plain ugly. Those that aren't so ugly usually depend on python, which is huge.


I've just added support for openssl on uacme master branch in the github repo with commit 656b6e53. It can be enabled with ./configure --with-openssl. Version 1.1.1 or later is required (earlier ones will soon go out of maintenance, are a security risk and are deprecated).

Any testing before I release it officially is welcome.


Thank you for your effort!

Seems this is exactly what I'm looking for. Is this supposed to work on a WR1043ND (8MB Flash/32MB RAM)?

Due to the limited storage size I use luci-ssl (libustream-mbedtls) and have to care for it (in addition, ddns-scripts comes on top).


In principle there is no reason why it wouldn't work if you can squeeze it into the flash image together with libcurl and mbedtls. It will compile to around 60kB not counting libcurl and mbedtls, but they may already be included in your image.

As there is no uacme OpenWRT package yet, you will need to either create your own or ask one of the devs.

1 Like

You can resolve both RAM and flash issues with swap and extroot via USB:

1 Like


Thank you guys. I think I'm going to try to expand the memory size of my device first before building a custom image or writing a uacme openwrt package. If that doesn't work I'll try it the other way and see how far I can come. Keep up the good work :slightly_smiling_face:

Based on user request I've added ECC support and released it in version 1.0.9. EC cryptography is less computationally intensive than RSA and therefore particularly well suited for small embedded devices such as OpenWRT routers.


Do you consider this stable, there is more "TO-DO" on your list ?
if not I'll try to make a package with it

1 Like

Yes it is stable. I am using it on a couple of production servers without any issue and I am not planning major changes at the moment.

One feature I might add at some point when I find the time is built-in support of IDN domain names, even though these can already be handled by just passing the "punycoded" domain name ( for example) on the command line.

If you go ahead with packaging, please use tarballs from upstream/latest (for example upstream/1.0.12) rather than the master branch, so you get the proper .tarball-version file.

Let me know how it goes and/or if you need any help.

is there a possibility to trigger some scripts pre and post (successfully) certificate creation ?

@ndilieto so I made packages with all mbedtls,openssl and gnutls

--disable-maintainer-mode --disable-docs --with-mbedtls --without-gnutls --without-openssl
mbedtls is failing with

crypto.c:(.text+0x6be): undefined reference tombedtls_version_get_number'`

checking for libcurl >= 7.38.0... found 7.65.0
checking for curl_global_init in -lcurl... yes
checking for mbedtls_entropy_init in -lmbedtls... yes
configure: detected mbedTLS
crypto.c:164:9: warning: implicit declaration of function 'mbedtls_version_get_number'; did you mean 'mbedtls_x509_get_name'? [-Wimplicit-function-declaration]
     if (mbedtls_version_get_number() < 0x02100000)

GnuTLS and OpenSSL are working well
mbedTLS is 2.16.1

Use the exit code. It is 0 if and only if the certificate has been renewed successfully, 1 if there is no error but the certificate has not been renewed, 2 on any error. To check the return code, use the '$?' shell special variable after running uacme.

See this pull request

I have just merged it and made a new release 1.0.13

Hi and thanks for all the work. Seems like a good solution for openwrt but I run into problem which I need to resolve.
I want to create & refresh certificate for router luci webinterface (uhttpd webserver on port 443). Port 80 access is blocked and I use free DynDNS provider ( so no TXT DNS records possible. The only usable challenge seems tls-alpn-01.
Today I tried to use uacme but need help with 2 issues.

  1. Is it possible to setup proxy protocol in uhttpd webserver (used in openwrt), or I must change the default uhttpd ssl port to 4443?
  2. After installation of openwrt 21.02.1 uacme package (v 1.6-1) I can't find ualpn installed anywhere. Is there a link where can I download it?
    Thanks in advance.

See this GitHub...

Scroll down to the tls-alpn-01 challenge support section.