I’ve been using Certbot for a while now to manage my SSL certificates, using the http challenge to validate my domain ownership, but the process is very tedious: I needed to stop the NGINX server in order to certbot start the http server for the HTTP challenge and I also needed to disable the proxy on Cloudflare.

Has you can see, this is a very cumbersome process, so I decided to use the DNS challenge instead. This way, I avoid a lot of manual steps.

In this post, I’ll show you how to use the DNS challenge with Cloudflare. I’ll assume that you already have a domain and that you already have a Cloudflare account, since I’ll not cover those steps. I ran this commands on a Ubuntu 20.04 and 22.04 server, as well as Debian 11.

First of all, install the necessary packages:

sudo apt update

sudo apt install certbot python3-certbot-nginx python3-certbot-dns-cloudflare -y

Run the following command generate the certificates:

Note: In the command, you need to successfully make the HTTP challenge.

sudo certbot --nginx -d example.com

When running with the --nginx flag, it will automatically configure the NGINX server to use the certificates and add configuration for the domain. Since I personally prefer to manage the NGINX configuration myself, I’ll show you how to do it manually.

# comment out the config related to the domain that you used to configure nginx
sudo vim /etc/nginx/sites-enabled/default

Add the following configuration to the NGINX server in /etc/nginx/conf.d/example.com.conf.

Note: If you don’t run the certbot command with the flag --nginx, it will not generage the options-ssl-nginx.conf and the ssl_dhparam.

server {
    server_name example.com;

    location / {
        proxy_pass http://localhost:3000/;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_buffering off;
    # Following configuration is maintained by Let's Encrypt/Certbot   
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot


server {
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    server_name example.com;
    listen 80;
    return 404; # managed by Certbot


Make sure you generate a Cloudflare API Token key and store it in a safe place. You’ll need it to renew the certificates.

# create the following file that stores the cloudflare token key,
# used to renew the ssl certificate
vim cloudflare.ini

dns_cloudflare_api_token = <insert token>

Finally, run the certbort command using DNS challenge to generate the certificates and check if everything is working:

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /path/to/cloudflare.ini \
  -d example.com

If the command runs successfully, it should tell you that the certificates were generated and that it is scheculed to renew them.