acme.sh icon indicating copy to clipboard operation
acme.sh copied to clipboard

Automatic renewed with docker

Open RudmanMario opened this issue 6 years ago • 10 comments

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?

RudmanMario avatar Sep 12 '18 08:09 RudmanMario

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

FernandoMiguel avatar Sep 12 '18 11:09 FernandoMiguel

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.

xiaket avatar Dec 01 '18 09:12 xiaket

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 avatar Nov 26 '19 11:11 moqmar

@moqmar why not use our docker deploy hook: https://github.com/Neilpang/acme.sh/wiki/deploy-to-docker-containers

Neilpang avatar Nov 27 '19 12:11 Neilpang

Ah, seems like this solves this whole issue 😄

Is there any possibility to target multiple containers with that approach though?!

moqmar avatar Nov 28 '19 07:11 moqmar

@moqmar you can assign the same label with multiple containers.

PMExtra avatar Jul 08 '20 08:07 PMExtra

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 avatar Dec 23 '21 17:12 StrangePeanut

@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 avatar Dec 24 '21 08:12 PMExtra

@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?

yvolchkov avatar Jun 11 '22 19:06 yvolchkov

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.

maffe avatar Mar 20 '24 19:03 maffe