acme.sh
acme.sh copied to clipboard
Automatic renewed with docker
I'm trying to issue and install wildcard certificate for Apache using Docker image neilpang/acme.sh. So I have one container with Apache running in it. I've managed to issue a certificate and install it with the following command:
docker run --rm -it \
-v "${HOME}/.acme":/acme.sh \
-e GANDI_LIVEDNS_KEY=$GANDI_LIVEDNS_KEY \
-e HOME=/root \
neilpang/acme.sh --issue -d example.com -d '*.example.com' --dns dns_gandi_livedns
and then:
docker run --rm -it \
-v "${HOME}/.acme":/acme.sh \
-v "${HOME}/letsencrypt/inxelo.aero":/letsencrypt/inxelo.aero \
-e HOME=/root \
neilpang/acme.sh --install-cert -d inxelo.aero \
--cert-file /letsencrypt/inxelo.aero/cert.pem \
--key-file /letsencrypt/inxelo.aero/key.pem \
--fullchain-file /letsencrypt/inxelo.aero/fullchain.pem \
--reloadcmd "service apache2 force-reload"
So I've got my certificate in ${HOME}/letsencrypt/inxelo.aero
and I've managed to connect it with Apache container and everything works fine.
The problem I'm having is with automatic renewing the certificate. The command service apache2 force-reload
will not work as Apache is run in another container. How is automatic renewing supposed to work with Docker in this case?
you will have to use some sort of script that talks to your apache to restart it.... since you are inside the docker, it isnt so easy
I was facing the same problem and my approach is to have a cron job running on the host and generate the cert using one docker run command, then run another docker command to reload the cert.
Would it make sense to add the Docker CLI to the image? That way it would just be possible to use --reloadcmd "docker restart myapachecontainer"
, assuming the image was started with -v /var/run/docker.sock:/var/run/docker.sock
.
This would obviously create a larger attack surface, as acme.sh now has practically full root access to the host system, but I think it would still be a viable solution for this use case, as restarting production services should require root access anyways, with or without Docker.
Edit: a workaround for the problem is to use --reloadcmd "apk add --no-cache docker-cli && docker restart myapachecontainer"
and mount docker.sock
as described above. It's not a beautiful solution, but a simple one.
@moqmar why not use our docker deploy hook: https://github.com/Neilpang/acme.sh/wiki/deploy-to-docker-containers
Ah, seems like this solves this whole issue 😄
Is there any possibility to target multiple containers with that approach though?!
@moqmar you can assign the same label with multiple containers.
Is there any possibility to target multiple containers with that approach though?!
Would also like a better solution to dealing with multiple Docker containers.
@moqmar you can assign the same label with multiple containers.
Passing multiple reload conditions to every labelled container is not very clean considering different containers run different services in almost every situation.
@StrangePeanut I have a solution. Make a reload script such as /etc/acme/reload
. Then set DEPLOY_DOCKER_CONTAINER_RELOAD_CMD=/etc/acme/reload domain.tld
. The argument domain.tld
was optional, if your script want to know which domain should be reloaded.
For nginx, the reload script should be
#!/bin/sh
service nginx force-reload
For openldap, the reload script should be
#!/bin/sh
service slapd force-reload
By the way, for manage multiple domains (eg. doamin1 and domain2 for container A, domain3 for container B).
I use the label sh.acme.autoload.example.com=true
rather than sh.acme.autoload.domain=example.com
, the latter is the official docs suggested.
After that, I can deploy multiple domains for one container. (You can also ignore the domains which is not its own business in the reload script)
Notice that, don't forget to grant execute permission for reload script.
@PMExtra, could you help me figure out how your solution is working without granting permissions? Does it mean you don't have to pass the /var/run/docker.sock
?
You can build a very basic API to send commands from one container to another without the need for /var/run/docker.sock
using Ncat and GNU sed, see this StackOverflow answer.