Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Setup automatic LetsEncrypt wildcard certificate renewal on Ubuntu server 18.04 with Namecheap

All credits go to by Bryan Roessler for his original post that I followed on how to setup LetsEncrypt wildcard certificate auto-renewal with Namecheap. I highly recommend you read his tutorial first and if you bump into issues, check out this gist next.

Unfortunately the original article is not up-to-date and doesn't have the option to leave comments so I can't communicate with the author for updates so I decided to write the updates in a Gist. I highlighted the sections that required an updated with Correction #:. I managed to get the correct setup with the help of the amazing guys at LetsEncrypt community. Here's the help thread.

Set up acme-dns

  1. Download acme-dns from https://github.com/joohoi/acme-dns/releases
  2. Move the binary somewhere sensible since we will be using a systemd service: sudo cp ~/downloads/acme-dns /usr/local/bin/acme-dns
  3. Make the necessary directories: sudo mkdir /etc/acme-dns/ /var/lib/acme-dns
  4. Make sure you’ve removed any existing _acme-challenge DNS records from your DNS host records
  5. Modify the provided config file like so:
[general]
listen = "public_server_IP:53"
protocol = "both"
domain = "acme.example.com"
nsname = "ns1.example.com"
nsadmin = "admin.example.com"
records = [
    "acme.example.com. A public_server_IP",
    "ns1.example.com. A public_server_IP",
    "acme.example.com. NS ns1.example.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 = "9000"
tls = "none"
tls_cert_privkey = "/etc/tls/example.org/privkey.pem"
tls_cert_fullchain = "/etc/tls/example.org/fullchain.pem"
acme_cache_dir = "api-certs"
corsorigins = [
    "*"
]
use_header = false
header_name = "X-Forwarded-For"

[logconfig]
loglevel = "debug"
logtype = "stdout"
logformat = "text"

Correction 1: In Bryan's tutorial he configures the listen IP as :53, which prevents acme-dns from starting in my case. Having it set to local IP 127.0.0.1 caused it to be unreachable from outside, thus I set it to the public server IP.

  1. Open port 53: sudo ufw allow 53 && sudo ufw reload
  2. Move acme-dns.service file to /etc/systemd/system/acme-dns.service and remove the user and group
  3. Enable and start the service: sudo systemctl daemon-reload && sudo systemctl enable --now acme-dns.service
  4. Check that the service is running sudo systemctl status acme-dns
  5. Test that it is working curl http://localhost:9000/health if you get nothing, it means it works.

Configure Namecheap

  1. Configure Namecheap with an A record called ns1 pointing the public IP of the server running acme-dns
  2. Confgiure Namecheap with an NS record called acme pointing to ns1.example.com

Correction 2: Notice that unlike's Bryan's tutorial, I created a ns1 A record instead of ns1.acme which for some odd reason didn't work in my case.

Configuring the Certbot auth hook

  1. Install python2 requests: sudo apt-get install python-requests
  2. 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
  3. Configure the program you just downloaded: sudo vim /etc/letsencrypt/acme-dns-auth.py and change ACMEDNS_URL = "http://localhost:9000"

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:

sudo certbot certonly -d "*.<yoursite>.com" -d "<youresite>.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

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.

In Namecheap, create a new CNAME record named _acme-challenge and give it the value you got from certbot. In this example, it's ch30791e-33f4-1af1-7db3-1ae95ecdde28.acme.<yoursite>.com..

Wait a few minutes and hit to complete the ACME challenge and receive your certificates!

Correction 3: In Bryan's tutorial, he instructs us to add a CNAME record with name: \_acme-challenge, which I believe is an unintentional typo.

Auto renewal setup

Follow Bryan's tutorial from this point and on.

@TheEmpty
Copy link

TheEmpty commented Jun 29, 2020

public_server_IP can be set to 0.0.0.0 instead if you have a dynamic IP which means "all IPs that end up directed to this host"

@scribe777
Copy link

scribe777 commented Aug 23, 2020

Hey guys. If you don't want to setup your own DNS server, you can simply turn on Namecheap API access for your account and use a certbot manual-auth script like the one here:

https://github.com/scribe777/letsencrypt-namecheap-dns-auth

@Ghosty141
Copy link

Ghosty141 commented May 7, 2021

@TheEmpty
How did you handle the A-Record ? From my very basic understanding I have to use the public IP which can change, thus making it kinda manual again. Is there a way around it?

@Ghosty141
Copy link

Ghosty141 commented May 7, 2021

"When you run the command certbot will prompt you to add one more DNS CNAME record to your DNS host."

I actually don't get the prompt, I just the an error that the expected txt record was not found. Has something changed with certbot/this procedure?

@TheEmpty
Copy link

TheEmpty commented Jun 13, 2021

@Ghosty141 I used CNAME instead of A. The CNAME is to my dynamic DNS record.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment