Skip to content

Instantly share code, notes, and snippets.

@Nimrodda
Last active February 17, 2024 12:53
Show Gist options
  • Save Nimrodda/af1c35264799fed663088c01b71c9e21 to your computer and use it in GitHub Desktop.
Save Nimrodda/af1c35264799fed663088c01b71c9e21 to your computer and use it in GitHub Desktop.
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.

@ghosty141
Copy link

"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

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

@maarriola
Copy link

Is there a reason it might not show the prompt? I noticed my error message says it's expecting a TXT record, not a CNAME record:

Domain: *****.com
Type:   unauthorized
Detail: No TXT record found at _acme-challenge.*****.com

@carmatana
Copy link

carmatana commented Dec 8, 2022

I implemented successfully what comes in the original article with a couple of tweaks from this page.

However, after that, I found:

https://www.hostwinds.com/tutorials/install-lets-encrypt-ssl-using-certbot-ubuntu

It also works and it is less complicated.

Certbot install instructions are not up to date but it can be installed with snapd or PIP. In my case I used a docker container.

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