#!/usr/bin/env bash : <<'INTRO' acme-dns, which completely bypasses DNS provider limitations. Overview We will be running a small DNS server called acme-dns to respond to challenges issued by LetsEncrypt’s certbot. You can run acme-dns on any computer, but typically it will run on the same host server as your website. Certbot will issue an ACME DNS challenge to your DNS provider, which will then forward the request via some redirection to your acme-dns server. Assumptions You have a running web server that is properly configured to handle your site certificates. You are probably using Namecheap as a DNS host because you are deep enough in Google’s search index to find my site. Prerequisites I am using Ubuntu 16.04 for this tutorial, but it should not matter which distro you are using as long as you know how to modify the firewall and install the appropriate software from your package manager. Install a recent version of Certbot (via the PPA or EPEL) Install a recent version of golang-go (PPA is best option) Install acme-dns: go get github.com/joohoi/acme-dns/… Move the binary somewhere sensible since we will be using a systemd service: sudo cp ~/go/bin/acme-dns /usr/local/bin/acme-dns Make the necessary directories: sudo mkdir /etc/acme-dns/ /var/lib/acme-dns Make sure you’ve removed any existing _acme-challenge DNS records from your DNS host records acme-dns configuration Create the following file, substituting your site’s domain name for and your server’s IP address (yes the naming scheme is dumb, but leave “acme.”, “ns1.acme.”, etc): INTRO conf_print_acme_dns_config{ cat <.com. A 176.223.132.72", "ns1.acme..com. A 176.223.132.72", "acme..com. NS ns1.acme..com.", ] debug = false [database] engine = "sqlite3" connection = "/var/lib/acme-dns/acme-dns.db" [api] api_domain = "" ip = "127.0.0.1" disable_registration = false autocert_port = "80" port = "8081" tls = "none" corsorigins = [ "*" ] use_header = false header_name = "X-Forwarded-For" [logconfig] loglevel = "debug" logtype = "stdout" logformat = "text" EOF } conf_print_acme_dns_config | sudo tee /etc/acme-dns/config.cfg : <<'NOTE_1' A short explanation: you are configuring acme-dns to listen to DNS requests (from certbot via Namecheap) globally on the standard DNS port 53 and configuring the HTTP port for certbot to talk to acme-dns on port 8081 (since you are probably running something way cooler on port 8080). Since certbot has to traverse Namecheap to perform the challenge, we will need to open port 53 in the firewall (traffic on port 8081 is handled on the localhost, so we don’t need to open that port): sudo ufw allow 53/udp && sudo ufw reload Update 4-10-2021: Dynamic DNS users, please see this comment. Let’s start the acme-dns program automatically on startup. Create: NOTE_1 conf_print_systemd_service() { cat <.com pointing to ns1.acme..com a record for ns1.acme..com pointing to the public IP address of your host Example: Example Namecheap DNS records Configuring the Certbot auth hook Now you just need to get certbot and acme-dns to work together! NOTE_2 # Install python2 requests: sudo apt-get install python-requests # Acquire the acme-dns certbot hook file: sudo wget -O /etc/letsencrypt/acme-dns-auth.py https://raw.githubusercontent.com/joohoi/acme-dns-certbot-joohoi/master/acme-dns-auth.py # Configure the program you just downloaded: sudo nano /etc/letsencrypt/acme-dns-auth.py and change ACMEDNS_URL = "http://localhost:8081" : <<'NOTE_3' Run Certbot You will need to run certbot manually one time in order to be able to run certbot renew in the future to handle the certificate renewals manually. If you’ve followed the rest of this tutorial, go ahead and run certbot to acquire your certs: NOTE_3 sudo certbot certonly \ -d "*..com" \ -d ".com" \ --agree-tos \ --manual-public-ip-logging-ok \ --server https://acme-v02.api.letsencrypt.org/directory \ --preferred-challenges dns \ --manual \ --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py \ --debug-challenges : <<'NOTE_4' When you run the command certbot will prompt you to add one more DNS CNAME record to your DNS host. Example: _acme-challenge..com CNAME ch30791e-33f4-1af1-7db3-1ae95ecdde28.acme..com. Create a new CNAME record named _acme-challenge and give it a value of ch30791e-33f4-1af1-7db3-1ae95ecdde28.acme..com. Wait a few minutes and hit to complete the ACME challenge and receive your certificates! Automation The step I’m sure you’ve been waiting for. NOTE_4 # Create the certbot-renew.service (if you are using Apache in lieu of nginx, substitute “nginx” with “httpd”): conf_print_systemd_service() { cat <.com domain for the TXT record at: _acme-challenge.example.com to complete the challenge. The Namecheap DNS server responds with a CNAME record that points to: ch30791e-33f4-1af1-7db3-1ae95ecdde28.acme..com, so LetsEncrypt goes there instead. The authoritative DNS server for: *.acme..com is ns1.acme..com, which points at your server IP (running acme-dns) LetsEncrypt can finally ask ns1.acme.example.com what is the TXT record for ch30791e-33f4-1af1-7db3-1ae95ecdde28.acme..com and acme-dns will answer that question Additional Considerations On a critical server it may be a good idea to start and stop acme-dns (and open and close port 53) alongside certbot execution. This can be handled fairly trivially with systemd Requires=, but I’ll leave that up to you! NOTE_5