# udm-le: Let's Encrypt certificates for UniFi OS devices

> udm-le is a shell script that issues Let's Encrypt certificates for Ubiquiti UniFi OS hardware using DNS-01 validation through Lego. It covers a long list of DNS providers, but the README now says you probably do not need it, because UniFi OS 5.1 has the same feature built in.

**kchristensen/udm-le** — Let's Encrypt support for Ubiquiti UniFi OS

- Repository: https://github.com/kchristensen/udm-le
- Stars: 775 · Forks: 97
- Language: Shell
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/kchristensen-udm-le

## The deprecation notice that defines this project today

The most important content in the README is the first section, and it argues against the project. UniFi OS 5.1 has support built in for DNS based issuance of Let's Encrypt certificates, found under Control Plane, then Console. The built-in feature supports several providers, and the README lists them: Cloudflare, DigitalOcean, Dyno, GoDaddy, OVH, Porkbun and Route53.

Then comes the summary: in a nutshell, you probably do not need to use udm-le, as it is for the most part obsolete.

The author then adds an honest caveat about the limits of that claim. They have not personally verified whether the built-in support manages the RADIUS and Hotspot certificates, and in all likelihood the project is not necessary any longer. That is a different statement from certainty, and it is the difference between a script that is retired and one that is retired except for two specific certificate types.

So the adoption test is narrow and concrete. If your console is on 5.1 or later and you only need a certificate for the console itself, use the built-in feature. If you are on an older console, or you depend on the RADIUS or Hotspot certificates, this script still does something the platform does not obviously replace.

## What the script does and which devices it covers

udm-le is a shell script that issues Let's Encrypt SSL certificates via DNS validation using Lego, the Go ACME client. The repository is small: the script itself, an environment file, a resources directory, and the standard governance files.

The device list is broad for a home-labelled tool. The README says it should work on UniFi devices running UniFi OS 2.x or later, including the UniFi Dream Machine, the Dream Machine Pro, the Dream Machine SE, the Dream Router, the Dream Wall and the UniFi Express, plus the Network Video Recorder, the Network Video Recorder Professional and the UniFi Enterprise Fortress Gateway. The topics list adds the UDM, UDMP, UDW and UniFi OS tags.

The mechanism is DNS-01 validation rather than HTTP-01, which is the reason the script needs DNS API credentials at all. It obtains a certificate, installs it where UniFi expects to find it, and arranges for renewal. Compared with HTTP-01 on a router behind a dynamic address, DNS-01 works without exposing a port and survives an address change, at the cost of handing a third party an API token that can edit DNS records.

The provider coverage is the asset. Out of the box the script has tested support for select DNS providers, and the README notes that with little work you could get it working with any of the Lego DNS providers. The tested ones include AWS Route53, Azure DNS, Cloudflare, DigitalOcean, DuckDNS, Gandi Live DNS v5, Google Cloud DNS, Google Domains, Linode, Loopia, Name.com and Oracle Cloud Infrastructure DNS.

## Installing on the device and setting up renewal

There is no package manager involved. The installation is four manual steps on the device itself.

First, copy the contents of the repository to the device at /data/udm-le. Second, edit /data/udm-le/udm-le.env and adjust the variables to meet your needs. Third, if the DNS provider needs credential files, create and populate a /data/udm-le/.secrets directory with the files that provider requires. Fourth, run the initial command.

```bash
/data/udm-le/udm-le.sh initial
```

That last command does three things at once. It handles the initial certificate generation, it sets up a systemd service to start the service on boot, and it creates a systemd timer to attempt certificate renewal each morning between 0300 and 0305.

The timer window is worth noticing. Renewal is attempted once a day in a five-minute slot, so a failing renewal has to be noticed by a later attempt rather than being retried constantly, and the narrow window keeps a fleet of devices from hitting the ACME server all at once.

The .secrets directory is a deliberate separation. The README suggests putting sensitive values such as a client secret in a .secrets/client-secret.txt file rather than in udm-le.env, and the Google Cloud DNS section points GCE_SERVICE_ACCOUNT_FILE at a path under .secrets. Keeping credentials out of the environment file means the file you edit and share does not carry the tokens.

## Per-provider configuration and the Azure example

Configuration works the same way for every provider. You set DNS_PROVIDER to the Lego identifier for your service and then set the variables the provider needs, and the naming convention is consistent enough to guess: AWS_ prefixed variables for Route53, DO_AUTH_TOKEN for DigitalOcean, DUCKDNS_TOKEN for DuckDNS, GANDIV5_PERSONAL_ACCESS_TOKEN for Gandi, GOOGLE_DOMAINS_ACCESS_TOKEN for Google Domains, LINODE_TOKEN for Linode, LOOPIA_API_USER and LOOPIA_API_PASSWORD for Loopia, and GCE_SERVICE_ACCOUNT_FILE for Google Cloud DNS.

The Cloudflare case is the simplest. You create an API token with Zone, Zone, Read and Zone, DNS, Edit, then add the value to udm-le.env. The Loopia case asks for four explicit privileges on the API user: addZoneRecord, getZoneRecords, removeZoneRecord and removeSubdomain. The Linode token needs a scope allowing read and write access to Domains.

Azure is the one that takes work outside the device, because an identity has to exist first. You delegate a domain to an Azure DNS zone, then use the Azure CLI to create a service principal with contributor permissions over the resource group that holds the zone.

```bash
# Login
az login
az ad sp create-for-rbac --name godns --scope /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/udm-le --role contributor
```

The command prints a JSON object, and the README says to use the printed properties to initialise the configuration in udm-le.env. It also flags that the password value is a secret, so you may want to omit it from udm-le.env and put it in a .secrets/client-secret.txt file instead.

## Uninstalling and restoring the self-signed certificates

Uninstallation is a documented block of shell commands, and the order matters because the last two steps put the device back to its original state.

First the service is stopped from starting at boot, and the script's own files are removed from both data locations.

```bash
systemctl disable udm-le
rm -rf /data/udm-le /mnt/data/udm-le
rm -f /etc/systemd/system/udm-le.*
```

Then the generated certificates are deleted and the services are restarted, which the README says causes them to generate new self-signed certificates.

```bash
rm -f /data/unifi-core/config/*.crt /data/unifi-core/config/*.key /data/unifi-core/config/*.pem
systemctl restart unifi-core
systemctl restart freeradius
```

That last restart of freeradius is the one to notice. udm-le manages the RADIUS certificate as well as the main one, so removing the certificates without restarting the radius service would leave it pointing at files that no longer exist. A restore that skips it produces an authentication failure rather than a visible error.

The two data paths in the removal command, /data/udm-le and /mnt/data/udm-le, reflect that UniFi devices have been mounted in more than one way, and removing only one of them can leave a copy of the configuration and secrets behind.

## Where udm-le is the wrong choice

The first and largest limitation is already in the README: on UniFi OS 5.1 and later, the platform does the same job with less to go wrong, and the built-in path covers seven named DNS providers without a third-party script, a systemd timer or credentials to manage.

The second is the security surface. Every supported provider requires an API token that can create and delete DNS records, and those tokens sit in a plaintext environment file or a .secrets directory on a device that is a router, a firewall and a VPN concentrator. A token leaked from that file is a token that can modify your zone records, which is a bigger prize than a certificate. The Loopia and Cloudflare privilege lists show the shape of the request: write access to DNS for a zone, which is what DNS-01 requires and cannot be narrowed further.

The third is that the script is a shell script maintained by one person, with a CHANGELOG implied by tags rather than a published release process, and no test suite in the repository. The last push was on 2026-05-20, and the most recent release listed is 2.0.5 from 2025-03-03, whose description mentions more customization along with captive portal and RADIUS fixes. A project with no tests and a single maintainer is a project you should read line by line before pointing it at your production DNS.

The fourth is scope. It is written for UniFi OS devices running version 2.x or later on a specific filesystem layout under /data. It is not a general ACME client, and it will not run on a UniFi device whose firmware layout differs from what the script expects.

## Licence, maintenance and the cost of running a certificate timer

The project is under the MIT licence, with the LICENSE file at the root, alongside a CONTRIBUTING.md and a CODE_OF_CONDUCT.md, and it is written in shell scripts, which is the right choice for something that has to run on a device with a minimal userland and no package manager.

The repository is not archived and its last push was on 2026-05-20, so the author is still touching it, although the deprecation notice and the age of the latest release, 2.0.5 dated 2025-03-03, suggest the effort going in is small. Release notes point to a rolling pattern: 2.0.3 fixed a Route53 credential problem and added custom upstream DNS resolvers in January 2024, and 2.0.4 was mostly documentation fixes and disabled CNAME support by default in June 2024.

The operational cost of staying on this path is a daily renewal attempt and a set of DNS credentials on a network device, for a benefit you can now get from the console. If you are keeping it, the sensible maintenance posture is to pin the certificate, watch the renewal timer rather than the certificate expiry, and plan the migration to the built-in feature before the next UniFi OS update removes the reason to stay.

## Conclusion

udm-le still makes sense on a UniFi OS device stuck below version 5.1, or on one where you need the RADIUS and Hotspot certificates the author could not confirm the built-in feature manages. On a current console, the built-in path under Control Plane, then Console is the better choice. Verify your UniFi OS version first, since the README's own advice is to stop using this script, and check the provider list before assuming your DNS service is covered.

## FAQ

### Do I still need udm-le now that UniFi OS supports Let's Encrypt?

Probably not. The README states that UniFi OS 5.1 has built-in support for DNS based issuance of Let's Encrypt certificates under Control Plane, then Console, and that udm-le is for the most part obsolete. The author notes they have not verified whether the built-in feature manages the RADIUS and Hotspot certificates.

### How do I install udm-le on a UniFi device?

Copy the repository contents to /data/udm-le on the device, edit /data/udm-le/udm-le.env, create and populate /data/udm-le/.secrets if your DNS provider needs credential files, then run /data/udm-le/udm-le.sh initial, which generates the certificate and sets up the boot service and the daily renewal timer.

### Which DNS providers does udm-le support?

The README documents tested support for AWS Route53, Azure DNS, Cloudflare, DigitalOcean, DuckDNS, Gandi Live DNS v5, Google Cloud DNS, Google Domains, Linode, Loopia, Name.com and Oracle Cloud Infrastructure DNS, and notes that with little work any Lego DNS provider could be made to work.

### How do I remove udm-le and restore the self-signed certificates?

Run systemctl disable udm-le, remove /data/udm-le and /mnt/data/udm-le along with the systemd unit files, delete the generated certificate files under /data/unifi-core/config, then restart unifi-core and freeradius so the services generate new self-signed certificates.

## Sources

- [Issues](https://github.com/kchristensen/udm-le/issues)
- [kchristensen/udm-le on GitHub](https://github.com/kchristensen/udm-le)
- [License: MIT](https://github.com/kchristensen/udm-le/blob/main/LICENSE)
- [README](https://github.com/kchristensen/udm-le/blob/main/README.md)
- [Releases](https://github.com/kchristensen/udm-le/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kchristensen-udm-le
