An open API service indexing awesome lists of open source software.

https://github.com/jirutka/muacme

A convenient wrapper for the ACMEv2 client uacme
https://github.com/jirutka/muacme

acme-client letsencrypt letsencrypt-cli uacme

Last synced: 4 months ago
JSON representation

A convenient wrapper for the ACMEv2 client uacme

Awesome Lists containing this project

README

          

= μacme
:toc: macro
:toc-title:
// custom
:proj-name: muacme
:gh-name: jirutka/{proj-name}
:version: 0.6.0
:muacme-conf: link:muacme.conf[/etc/muacme/muacme.conf]

This a convenient wrapper for the ACMEv2 client https://github.com/ndilieto/uacme[uacme] that provides a ready-to-go solution for a cron-based periodic renewal of an arbitrary number of TLS certificates.

[discrete]
== Table of Contents

toc::[]

== Requirements

* https://github.com/ndilieto/uacme[uacme]
* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html[POSIX-sh] compatible shell with `pipefail` (e.g. Busybox ash, ZSH, bash, …)
* `grep`, `sed`, `tr`, `xargs` (BSD, Busybox or GNU)
* `openssl` command (should work with OpenSSL and LibreSSL)

httpd-challenge-hook.sh:

* `busybox httpd`
* `start-stop-daemon` from OpenRC

nsupdate-challenge-hook.sh:

* `knsupdate` and `kdig` from Knot DNS tools or `nsupdate` and `dig` from BIND tools

acmedns-challenge-hook.sh:

* `kdig` from Knot DNS tools or `dig` from BIND tools
* `wget` (tested with Busybox or GNU)

== Installation

=== On Alpine Linux

Install package {proj-name} from the Alpine’s community repository:

[source, sh, subs="+attributes"]
apk add {proj-name}
# if you wanna use httpd-challenge-hook.sh:
apk add busybox-extras
# if you wanna use nsupdate-challenge-hook.sh or acmedns-challenge-hook.sh:
apk add knot-utils

=== From Tarball

[source, sh, subs="+attributes"]
wget https://github.com/{gh-name}/archive/v{version}/{proj-name}-{version}.tar.gz
tar -xzf {proj-name}-{version}.tar.gz
cd {proj-name}-{version}
make install

== Usage

See the help section in link:muacme#L3[muacme] (or run `muacme -h`) and comments in link:muacme.conf[].

Note that you have to create an ACME account first (see https://ndilieto.github.io/uacme/uacme.html#_usage[uacme(1)] for more information):

[source]
uacme -v -c /etc/ssl/uacme new [EMAIL]

== Examples

* Issue a certificate for domain _example.org_ with alternative name _www.example.org_ (and using options specified in the configuration file {muacme-conf}):
+
[source, sh]
muacme issue example.org www.example.org

* Issue a certificate for each domain listed in the given file (one per line with optional alternative names separated by a space) for which we don’t have one already.
Domains for which we already have a certificate will be ignored.
+
[source,sh]
muacme issue -F domains.list

* Renew all certificates that are close to their expiration:
+
[source, sh]
muacme renew all

* Renew certificate for domain _example.org_ even if it’s too soon:
+
[source, sh]
muacme renew -f example.org

* A renew hook for reloading nginx on a system using OpenRC:
+
[source, sh]
#!/bin/sh
/etc/init.d/nginx --ifstarted --quiet reload

* A cron script _/etc/periodic/weekly/muacme-renew-all_:
+
[source, sh]
#!/bin/sh
exec muacme renew -l all

== Challenge Hooks

=== httpd (HTTP-01)

link:httpd-challenge-hook.sh[] is a hook script for the https://letsencrypt.org/docs/challenge-types/#http-01-challenge[HTTP-01 challenge] that automatically starts https://busybox.net[busybox] httpd server on port 80 to serve the key authorization for the challenge verification and stops it right after it’s done.

The complete process of renewal looks like this:

. A cron job starts `muacme renew -l all`.
. `muacme` invokes `uacme` for each certificate found in _/etc/ssl/uacme/_.
. `uacme` checks the certificate expiration date; if it’s near expiration (parameter `days` in {muacme-conf}), uacme generates a CSR and creates a new order at Let’s Encrypt.
. `uacme` executes link:httpd-challenge-hook.sh[] script that writes the validation file for Let’s Encrypt into a temporary directory and *starts a webserver* (`busybox httpd`) *on port 80* to serve this file.
. Let’s Encrypt retrieves the validation file from `++http:///.well-known/acme-challenge/++`.
. `uacme` retrieves the issued certificate from Let’s Encrypt.
. `uacme` executes link:httpd-challenge-hook.sh[] script again to remove the verification file and *stop the webserver*.
. `uacme` executes your link:renew-hook.sh[] script to reload services etc.

=== nsupdate (DNS-01)

link:nsupdate-challenge-hook.sh[] is a hook script for https://letsencrypt.org/docs/challenge-types/#dns-01-challenge[DNS-01 challenge] that utilizes `knsupdate` (or `nsupdate`) to add/delete `_acme-challenge.` TXT record for the requested domain name.
This script can be configured using {muacme-conf} or environment variables.

If you want to use `nsupdate` and `dig` instead of their Knot variants, you have to overwrite options `dns01_nsupdate` and `dns01_dig`.

=== acmedns (DNS-01)

link:acmedns-challenge-hook.sh[] is a hook script for https://letsencrypt.org/docs/challenge-types/#dns-01-challenge[DNS-01 challenge] that calls REST API provided by the https://github.com/joohoi/acme-dns[acme-dns] server to add `_acme-challenge.` TXT record for the requested domain name.
This script can be configured using {muacme-conf} or environment variables.

Before you can issue a certificate for a domain, you must do a registration on the acme-dns server and add the obtained subdomain, username and password to `/etc/muacme/acme-dns.keys`.
This can be easily done using the provided `muacme-acmedns` script, for example `muacme-acmedns register https://auth.acme-dns.io`.

If you want to use `dig` instead of its Knot variants, you have to overwrite option `dns01_dig`.

== License

This project is licensed under http://opensource.org/licenses/MIT/[MIT License].
For the full text of the license, see the link:LICENSE[LICENSE] file.

== See Also

* https://ndilieto.github.io/uacme/[uacme(1)]
* https://www.knot-dns.cz/docs/3.0/html/man_kdig.html[kdig(1)]
* https://www.knot-dns.cz/docs/3.0/html/man_knsupdate.html[knsupdate(1)]