An Ansible role that allows one to automate Let's Encrypt certificate issuance and update using [gandi]('s LiveDNS service.
Go to file
Patryk Cisek e6880ec2ed
Corrected the name of the file in cron.daily -- got rid of forbidden dots.
2023-01-25 07:53:52 -08:00
meta Added GitLab Pipeline, added meta info to meta/main.yaml. 2022-11-17 10:22:10 -08:00
tasks Corrected the name of the file in cron.daily -- got rid of forbidden dots. 2023-01-25 07:53:52 -08:00
templates Added the missing cron job to renew the certificate. 2022-12-15 09:56:06 -08:00
.ansible-lint Added GitLab Pipeline, added meta info to meta/main.yaml. 2022-11-17 10:22:10 -08:00
.gitlab-ci.yml Corrected the path to the role in the Pipeline linting job. 2022-11-17 16:45:23 -08:00
LICENSE Initial commit 2022-02-10 17:13:03 +01:00 Added Pipeline status banner to the README. 2022-11-17 17:02:12 -08:00

pipeline status

certbot-gandi Ansible Role

This role allows one to automate issuance of an wildcard Let's Encrypt X.509 certificate for a domain using gandi.

For example, if you own, this role will allow you to automatically provision certificate for *

Caveat: The certificate will be valid only for subdomains of!!! E.g. it will be valid for,, but it will not be valid for itself!


I wrote this role to address specific use-case. I want to have an easy way to manage Let's Encrypt certificates for services that I self-host in my home network, but that are completely invisible outside my home. One way to achieve it is:

  1. I register a domain with gandi. E.g.
  2. At home I have my own DNS resolver. That could be for example something like pfSense, OPNSense, or even Pi-hole.
  3. On my private DNS resolver I add custom subdomains of For example
  4. I use this Ansible role to generate Let's Encrypt certificate for *, I hook it up to web-server (e.g. Nginx, Apache, whatever) that is hosting locally.

This way is visible (resolvable) only from within my home network. And the certificate that my private web-server presents is valid on any device -- my computer, smartphone, tablet, TV, whatever -- without any fiddling with accepting untrusted (e.g. self-signed, or signed by my own custom CA) certificate.


  1. It creates /srv/certbot directory. All activities except certbot logging will happen within subdirectories of /srv/certbot.
  2. It creates Python virtualenv in /srv/certbot/venv and installs certbot with gandi plugin in it.
  3. It generates Bash scripts for issuing ( and renewing ( the certificate. They are placed in /srv/certbot/ directory (assuming your domain is
  4. Then it calls to issue the certificate the very 1st time.
  5. It'll add a post-renew hook to certbot's config for reloading web server's configuration so that after renewing the certificate the web server reloads it.
  6. Adds a cron job to run once a day to check if the certificate needs renewing.

The generated certificate and corresponding key lands in /srv/certbot/ directory.

Quick start

Pull in the role to your system

First off you have to add proper dependency to your project. Create -- if it doesn't yet exist -- a file called requirements.yaml. Then add the dependency to it. If this role is the only one that your playbook is pulling in, then requirements.yaml should look like this:

- src: git+
  version: master
  name: certbot-gandi

Having that done, use ansible-galaxy to pull the role in:

$ ansible-galaxy install -r requirements.yaml

This is a one-time thing. Once you pull the role it, it'll live in your ~/.ansible/roles subdirectory.

Using the role in a playbook

The role requires you to set up a couple of Ansible variables:

  • domain: This is the name of your domain. E.g.
  • gandi_api_token: The API token you generated on your gandi account page.
  • contact_email: Let's Encrypt requires you to provide a contact email address.
  • web_server_reload_command: A command that will be executed by certbot to reload your web server's configuration after renewing the certificate.

The simplest and least secure way

If you want to quickly test the role out, you could add the following section to your roles in your playbook:

  - role: certbot-gandi
      domain: ""
      gandi_api_token: 12345SLFDKSLFKJSD # Your generated API token
      web_server_reload_command: "systemctl reload nginx.service" # Assuming you're using Nginx

But you better not check that into your VCS!!!

Using ansible-vault to store the token

You should absolutely never check the bare API key to your version control system. It's much better to use e.g. ansible-vault to encrypt all security sensitive variables. Ansible vault will maintain a file within your repository, but the file will be encrypted.

Alright, so first you create the encrypted vault file:

$ mkdir vars
$ ansible-vault create vars/secrets.yaml

You'll be asked to pick a password for your new file. Then, ansible-vault will automatically open an editor for you. You have to create the YAML with the sensitive variables. E.g.:

gandi_api_token: 12345SLFDKSLFKJSD # Your generated API token

Now when you save the file and quite the editor, take a look at the new file. It'll look similar to this:

$ cat vars/secrets.yaml

So this is what you add to your VCS. So now in your runbook you'll need to point to the encrypted vars file:

  - vars/secrets.yaml
  - role: certbot-gandi
      domain: ""
      web_server_reload_command: "systemctl reload nginx.service" # Assuming you're using Nginx
      # That's it. gandi_api_token will be picked up from vars/secret.yaml instead of from here.

Now, from this point on, you'll need to pass a new parameter to ansible-playbook, namely --ask-vault-pass. This will make ansible ask you the Vault password each time you execute the runbook.