For HTTPS you need a TLS certificate. By default the OpenWrt generates one (self-signed). You can open the Luci by the HTTPS URL. But your browser will complain that the certificate is self made and we can't know if the cert was't forged by an attacker in the middle.

You can generate (“issue”) a TLS certificate on a device and ask a Certificate Authority (CA) to sign it so that browsers will accept it without a warning. The LetsEncrypt and ZeroSSL are two CAs that allows to do that for free and automatically by using ACME verification protocol. You'll need an ACME client i.e. the installed and configured that will do the work to issue certificate and renew it after 3 months. The uses the ZeroSSL by default starting from v3.0 Aug 2021 but the OpenWrt package didn't followed the change and still uses the LetsEncrypt by default.

You must understand ACME Challenge Validation Types.

If you making your router public or you are going to use a HTTP-01 challenge validation via Webroot or Standalone validation method, then you need to allow access from the internet. The ACME protocol needs for the HTTP port 80 for a challenge validation but for a Webroot you better to enable a Redirect to HTTPS so the 443 port needs to be open too.

If you are want to have a valid cert for a domain without opening an access to a wild internet then the only option for you is a DNS challenge validation. But not all DNS providers have an API to do this, or you have to specify a password from a full admin panel which is not acceptable from security perspective.

There are few ACME clients available on OpenWrt:, uacme, certbot. Currently the is best supported and the acme package will install it.

Since version 4.0.0 (Aug 2022) the acme package was reorganized and now we have a few packages:

  • acme-common that provide the UCI config in the /etc/config/acme
  • acme-acmesh that contains the script
  • acme-acmesh-dnsapi that contains additional scripts to use DNS validation.

There was a PR to add acme-uacme package but it was lack of interest and staled. In future we may have more acme clients integrated.

The acme package now is empty and it become a transitional virtual package that installs the acme-common and acme-acmesh.

The acme v4 also had a breaking change. Auto deployment of cert to Luci was removed. Now you must configure certs manually, you may try the luci-app-uhttpd to set a path to a cert. Old options like update_uhttpd and update_nginx are gone.

The Luci admin panel has apps that can be installed to extend GUI with additional configuration pages. The luci-app-acme provides a GUI to configure issuing of certificates.

Open LUCI dashboard then in main menu go to System -> Software. Then click on Update lists... to load list of available packages. The into the Filter search type luci-app-acme and press Enter. Click on install button. As a dependency it will install acme that itself will install acme-common and acme-acmesh packages. If you are going to use DNS validation please also install the acme-acmesh-dnsapi.

To configure in LUCI in the main menu open Services -> ACME certs.

Basic configuration:

  • Account email: put your email to receive expiry notices when your certificate is coming up for renewal.
  • You'll see a two pre-configured but disabled EXAMPLE domains. But we'll make a new one for ourselves.
  • At bottom find a field for a new domain config, type your domain but with underscores e.g. example_com and click on Add.
  • A new config section will be added. Now let's edit it.
  • Check Enabled
  • Domain names: add your domain If you need a wildcard cert then also add * (needs for DNS challenge).
  • Switch to Challenge Validation tab and select Validation method:
    • If you have a public web server then select Webroot. The default webroot path is /var/run/acme/challenge/. See details below
    • If you wish to get a wildcard cert e.g. * or you don't have a public webserver then the only option is the DNS validation and you must configure DNS API
    • If you don't have any webserver or the it's not accessible from internet then you can may use the Standalone mode
  • Click on Save and Apply

In a minute the cert should be generated. You can check logs in Status -> System Log.

If any error occurred fix it and restart the acme service to trigger issuing. Go to System -> Startup, find the acme service and click of Restart.

For experienced users this may be more preferable than GUI.

Step 1: Install packages Use a command line and type opkg install acme. If you want to use DNS-based certificate verification, also install the DNS provider hooks: opkg install acme-acmesh-dnsapi

Step 2: Configure the Edit /etc/config/acme to configure your personal email, domain name and validation method. For the Webroot challenge validation use option validation_method 'webroot'.

If you have acme-common version older that 1.4 (May 2024) then you may have to create a symlink before:

mkdir /www/.well-known/
ln -s /var/run/acme/challenge/ /www/.well-known/acme-challenge

See next section with details.

For the DNS challenge validation use option validation_method 'dns'.

For example if you use the DDNS provider and wish to have a wildcard certificate * then install the acme-acmesh-dnsapi package and configure the acme like:

config acme
        option account_email ''

config cert 'example_duckdns_wildcard'
        option enabled '1'
        option validation_method 'dns'
        option dns 'dns_duckdns'
        list credentials 'DuckDNS_Token="YOUR_TOKEN"'
        list domains ''
        list domains '*'

See DNS API: for details.

Step 3: Issue your certificate by restarting the acme service with /etc/init.d/acme restart. This may take for some time. You can read logs with logread -e acme. In case of problems please try to enable the debug 1 option that will print more details.

When the webroot validation is used the acme client stores challenge files to a folder (called “webroot”) that is accessible from internet and the Certificate Authority (e.g. LetsEncrypt, ZeroSSL) checks it the files the site by a URL This allows for CA to ensure that you have an access to the domain settings.

The has a an option -w to specify a path to the webroot folder and the UCI config at /etc/config/acme allowed to specify it too. The problem is that if you have to always change to a place where your website files are located e.g. /www/.well-known/acme-challenge/. Creating files on a disk may eventually ruin the NAND flash but also the folder may be actually read only.

Since version 4.0.0 (Aug 2022) the acme switched to always use the same /var/run/acme/challenge/ folder for webroot. The folder is in memory and it's path is always the same so the webroot config option is not needed anymore and was deprecated.

Instead you can create a symlink:

mkdir /www/.well-known/
ln -s /var/run/acme/challenge/ /www/.well-known/acme-challenge

Now test if it's accessible from internet:

mkdir -p /var/run/acme/challenge/
echo Hi > /var/run/acme/challenge/README.txt
# open in browser or execute the wget
wget -qO -

Since acme-common v1.4 (May 2024) the default symlink is automatically created on installation. But you may have other http document roots so please create the symlink yourself.

I hope that eventually OpenWrt web servers will serve the folder /var/run/acme/challenge/ under /.well-known/acme-challenge/ URL path by default. So no any additional symlinks will be needed.

After that you can find the certificates in a folder at /etc/ssl/acme/ e.g.:

  • /etc/ssl/acme/* the TLS private key. Never share it!
  • /etc/ssl/acme/* the TLS certificate and chain of CA that signed it.

Detailed certificate configs are stored in /etc/acme/.

You can use them in uhttpd, lighttpd, nginx, EmailRelay and any other server that you want to configure with TLS.

The standalone mode is intended to be used if you don't have a webserver (e.g. mail only) or it's not publicly accessible from internet. It will start a socat that will imitate a temporary web-server to return a the file with a random value of ACME challenge to the CA (e.g. LetsEncrypt) so that they can ensure that you really own the server and the domain. That server needs to be publicly accessible, so you may have to forward the external public WAN port 80 to it. However, that server listens on port 80 by default, which might clash with uhttpd which by default listens 80 port on all interfaces and IPs. You can change the listening port to something like 8080, by editing the value of Le_HTTPPort in /usr/lib/acme/, or by passing it the --httpport argument. Then you must forward WAN port 80 (external port remains the same) to device port 8080. See Accessing LuCI web interface securely for more details about port changing.

When a certificate issued or renewed the OpenWrt acme calls hotplug hooks in the /etc/hotplug.d/acme/ with an $ACTION correspondingly issued or renewed. Then it also sends a UBUS event acme.issue and acme.renew.

The uhttpd, nginx, haproxy are listening for the UBUS event acme.renew and performing a service reload on a cert renewal. So no any additional deployment hooks are needed. Just specify a correct path to a cert.

But the reloading is triggered only on a renewal. So you need to issue a cert, then configure a path to it in uhttpd/nginx/haproxy config and then restart a service.

But other web webservers like Apache and Lighttpd don't have such a reload trigger.

You may try to add a hotplug script yourself:

Create a file /etc/hotplug.d/acme/00-apache with the content:

if [ "$ACTION" = "renewed" ]; then
	/etc/init.d/apache reload

Please note: Calling /etc/init.d/apache reload directly in the acme hotplug script can inadvertently start a stopped instance.

Name Type Required Default Description
account_email string yes Email address to associate with account key. If a certificate wasn't renewed in time then you'll receive a notice at 20 days before expiry.
debug boolean no 0 Enable debug logging
state_dir string no /etc/ssl/acme Deprecated, now is unchangeable. The state folder where account data is stored
Name Type Required Default Description
enabled boolean no 1 Enabled issuing of certs for the domains
staging boolean no 0 Get certificate from the Letsencrypt staging server (use for testing; the certificate won't be valid).
domains list yes Domain names to include in the certificate. The first name will be the subject name, subsequent names will be alt names.
validation_method string yes Challenge validation mode: dns, webroot or standalone. Standalone mode will use the built-in webserver of to issue a certificate. Webroot mode will use an existing webserver to issue a certificate. DNS mode will allow you to use the DNS API of your DNS provider to issue a certificate.
dns string yes for dns mode DNS API name. See wiki: DNS API for the list of available APIs. In DNS mode, the domain name does not have to resolve to the router IP. DNS mode is also the only mode that supports wildcard certificates. Using this mode requires the acme-dnsapi package to be installed.
dns_wait integer no Seconds to wait for a DNS record to be updated and then continue. See wiki: dnssleep
credentials list yes for dns mode The credentials for the DNS API mode selected above. See wiki: DNS API for the credentials required by each API. Add multiple entries here in KEY=VAL shell variable format to supply multiple credential variables.
calias string no Challenge Alias. The challenge alias to use for ALL domains. See wiki: DNS Alias Mode for the details of this process. LUCI only supports one challenge alias per certificate.
dalias string no Domain Alias. The domain alias to use for ALL domains. See wiki: DNS Alias Mode for the details of this process. LUCI only supports one challenge domain per certificate.
webroot string no /var/run/acme/challenge Deprecated. Webserver root directory. Set this to the webserver document root to run Acme in webroot mode. The web server must be accessible from the internet on port 80.
key_type string no ec256 Key size (and type) for the generated certificate. rsa2048, rsa3072, rsa4096, ec256, ec384
keylength string no Deprecated, use key_type instead. The RSA key length in bits.
acme_server string no letsencrypt A custom CA ACME server directory URL. See wiki: servers.
standalone boolean no 0 Deprecated. Use option validation_method 'standalone' instead.
days integer no 60 Days until renewal
update_uhttp boolean no 0 Removed in acme v4.0.0. After issuing a cert configure the uhttpd UCI main section (e.g. Luci) to use the new cert. E.g. set UCI uhttpd.main.key and uhttpd.main.cert. Then reload the uhttpd service. Update the uhttpd config with this certificate once issued (only select this for one certificate). It's also available the luci-app-uhttpd to configure uhttpd form the LuCI interface.
update_nginx boolean no 0 Removed in acme v4.0.0. After issuing a cert configure the Nginx to use the new cert. E.g. call the nginx-util add_ssl. Then reload the nginx service. Update the nginx config with this certificate once issued (only select this for one certificate). Nginx must support ssl, if not it won't start as it needs to be compiled with ssl support to use cert options
update_haproxy boolean no 0 Removed in acme v4.0.0. After issuing a cert configure the HAProxy to use the new cert. E.g. change the bind option in the . Then reload the haproxy service.
user_setup path no none Removed in acme v4.0.0. User-provided setup script
user_cleanup path no none Removed in acme v4.0.0. User-provided cleanup script

The acme-acmesh package installs the full script to /usr/lib/acme/client/ so you can call it directly without UCI config e.g.:

mkdir /www/.well-known/
ln -s /var/run/acme/challenge/ /www/.well-known/acme-challenge
/usr/lib/acme/client/ --issue -d -w /var/run/acme/challenge/

See more samples in the wiki: How to issue a cert

Before the acme v4 the path was /usr/lib/acme/

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2024/06/04 14:42
  • by stokito