Skip to content

Multideploy: Deploy to multiple hooks of the same type #6241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 28 commits into
base: dev
Choose a base branch
from

Conversation

tomo2403
Copy link
Contributor

This hook allows the user to deploy certificates to multiple services at once. It can store configurations for numerous services, even for the same hook.

Example

You have three Docker containers and a Synology NAS (DSM). However, using the docker and synology_dsm hooks, you can only deploy to one Docker container with renewals. This problem is solved with Multideploy.

Sample config file

The file can be named multideploy.yml or multideploy.yaml. It is stored in the domain folder. $DOMAIN_DIR is a variable that allows deploying certificated to a dir named after the certificate's domain to make changes easier.

version: 1.0

configs:
  - name: "default"
    services:
      - "webserver"
      - "webserver2"

services:
  - name: "webserver"
    hook: "docker"
    environment:
      - DEPLOY_DOCKER_CONTAINER_LABEL: "sh.acme.autoload.domain=example.com"
      - DEPLOY_DOCKER_CONTAINER_KEY_FILE: "/etc/nginx/ssl/$DOMAIN_DIR/key.pem"
      - DEPLOY_DOCKER_CONTAINER_CERT_FILE: "/etc/nginx/ssl/$DOMAIN_DIR/cert.pem"
      - DEPLOY_DOCKER_CONTAINER_CA_FILE: "/etc/nginx/ssl/$DOMAIN_DIR/ca.pem"
      - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE: "/etc/nginx/ssl/$DOMAIN_DIR/full.pem"
      - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD: "service nginx force-reload"
  - name: "webserver2"
    hook: "docker"
    environment:
      - DEPLOY_DOCKER_CONTAINER_LABEL: "sh.acme.autoload.domain=example.com"
      - DEPLOY_DOCKER_CONTAINER_KEY_FILE: "/etc/nginx/ssl/$DOMAIN_DIR/key.pem"
      - DEPLOY_DOCKER_CONTAINER_CERT_FILE: "/etc/nginx/ssl/$DOMAIN_DIR/cert.pem"
      - DEPLOY_DOCKER_CONTAINER_CA_FILE: "/etc/nginx/ssl/$DOMAIN_DIR/ca.pem"
      - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE: "/etc/nginx/ssl/$DOMAIN_DIR/full.pem"
      - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD: "service nginx force-reload"

Wiki

Please tell me if you will merge this first before I start writing a wiki entry for this. thx
https://github.com/acmesh-official/acme.sh/wiki/deployhooks#36-deploying-to-multiple-services-with-the-same-hooks

@gilman88
Copy link

+1 on this kind of capability at least for wildcard certs. I was recently looking at a situation with multiple mikrotik routers where this would have been helpful.

@Neilpang
Copy link
Member

please update the wiki page first.

@tomo2403
Copy link
Contributor Author

tomo2403 commented Mar 1, 2025

@Neilpang done

@Neilpang
Copy link
Member

Neilpang commented Mar 2, 2025

let's remove the configs part:

configs:
  - name: "default"
    services:
      - "webserver"
      - "webserver2"

It's not necessary.

In the yaml example, please add some other hooks, not just docker hook. because it should work with any hooks.

Don't use a hardcoded 'multideploy.yml" file, let's make it a env variable, just like the others:

export  DEPLOY_YAML="/path/to/my/multideploy.yaml"
acme.sh --deploy -d xxxx.com  --deploy-hook  multideploy

You can just copy the "$DEPLOY_YAML" file to the domain folder, it will be easier for the user to use.

@tomo2403
Copy link
Contributor Author

tomo2403 commented Mar 2, 2025

The configurations (configs) are intended to simplify the testing/staging process. They allow the user to quickly select or deselect the services the certificate should be deployed to without having to comment out every line. Soon, I also want to implement an overriding functionality similar to Docker (compose.override.yaml). Configurations will then be even more necessary to enhance testing and deployment further when multiple certificates are deployed to the same services. This would allow the user to maintain a minimal, non-redundant configuration. That is also the reason for the hardcoded filepath.

Do you agree with this @Neilpang?

@Neilpang
Copy link
Member

Neilpang commented Mar 4, 2025

The configurations (configs) are intended to simplify the testing/staging process.

no, this is too complicated.

That is also the reason for the hardcoded filepath.

no, use the env variable to pass value. it's the same way as others.

@tomo2403
Copy link
Contributor Author

@Neilpang, I removed configs and introduced a variable deploy file name. The wiki is now up to date.

@tomo2403 tomo2403 requested review from lojzik and zeocax April 12, 2025 17:46
Copy link

@zeocax zeocax left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tested and working fine for me

_debug _cfullchain "$_cfullchain"
_debug _cpfx "$_cpfx"

DOMAIN_DIR=$_cdomain
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need this DOMAIN_DIR ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be used in the deploy file to specify the path for a cert if you are going to have multiple certs on the same service. This makes it easier to copy the deploy file to another domain dir.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which deploy file uses it ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have a look at the sample config above

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which one ?

Copy link
Contributor Author

@tomo2403 tomo2403 Apr 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first comment after pr opening. Both services use DOMAIN_DIR. I use it for all my domains because they are deployed to the same service. If I change something in one deploy file I can just copy the file to all other domains without having to change the path for each domain in my docker container


IFS=$(printf '\n')
echo "$_env_list" | yq e -r 'to_entries | .[] | .key + "=" + .value' | while IFS='=' read -r _key _value; do
_value=$(eval echo "$_value")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need to use eval, just use export env=value

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed to make the use of DOMAIN_DIR and all other custom vars work that the user might use

IFS=$(printf '\n')
echo "$_env_list" | yq e -r 'to_entries | .[] | .key + "=" + .value' | while IFS='=' read -r _key _value; do
_value=$(eval echo "$_value")
_savedomainconf "$_key" "$_value"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't save it in the domain conf. everytime, you should just use the values from the multiply.yml file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thought was that maybe not every hook checks the exported variables first and maybe takes them directly from the config. Overwriting the config prevents a hook from taking obsolete values.

# $1 - A YAML formatted string containing environment variable key-value pairs.
# Usage:
# _clear_envs "<yaml_string>"
_clear_envs() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to clear

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a hook has optional envs and you have two services that use the same hook, but one service uses the optional envs and the other doesn't, both services will use the optional envs because they are saved by the first service. Clearing them ensures that multideploy only uses the envs specified in the deploy file

@tomo2403 tomo2403 requested a review from Neilpang April 13, 2025 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants