Obtain SSL Certificate from Let’s Encrypt Manually
1. Install Certbot
sudo su
apt install certbot -y
I’ve tried to install the certbot docker container. It lacks the manual plugin. I’ve also tried WSL which gives the following error. This can’t be fixed. Therefore I install certbot in a Ubuntu VM.
Traceback (most recent call last):
File "/usr/bin/certbot", line 6, in <module>
from pkg_resources import load_entry_point
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 57, in <module>
from pkg_resources.extern import six
ImportError: cannot import name 'six' from 'pkg_resources.extern' (/usr/lib/python3/dist-packages/pkg_resources/extern/__init__.py)
2. Generate the Certificate
Certbot starts an ACME session with Let’s Encrypt. It asks to enter an TXT entry for DNS resolution.
certbot certonly --manual --preferred-challenges dns -d "DOMAIN_NAME" -d "panhui.top" --email EMAIL_ADDRESS --agree-tos --manual-public-ip-logging-ok
Use of --manual-public-ip-logging-ok is deprecated.
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
......
Requesting a certificate for DOMAIN_NAME and *.DOMAIN_NAME
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:
_acme-challenge.DOMAIN_NAME.
with the following value:
XcO0V9iHpL94MjlCmAy5qnxZnXc9Kd-isnE0JRQU9BY
(This must be set up in addition to the previous challenges; do not remove,
replace, or undo the previous challenge tasks yet. Note that you might be
asked to create multiple distinct TXT records with the same name. This is
permitted by DNS standards.)
Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.DOMAIN_NAME.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
DNS entry in the DNS Web UI.
| Name | Type | Value |
| ----------------- | ---- | --------------------------------------------- |
| _acme-challenge | TXT | KgSDs0sCIWSI-18wa-EkG95bxCVExNpkyDtFFXdIA1M |
It takes at least half an hour for the DNS entry to propagate even though I can dig it in some other server. Or check the resolution at https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.DOMAIN_NAME
dig TXT _acme-challenge.panhui.top +short
"KgSDs0sCIWSI-18wa-EkG95bxCVExNpkyDtFFXdIA1M"
When the check is OK, hit ENTER to continue. Now the certificate is successfully issued and saved locally.
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/DOMAIN_NAME/fullchain.pem
Key is saved at: /etc/letsencrypt/live/DOMAIN_NAME/privkey.pem
This certificate expires on 2025-09-23.
These files will be updated when the certificate renews.
NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.
......
File | Purpose | Used in |
---|---|---|
cert.pem | Public certificate for your domain only | Rarely used directly |
chain.pem | Proves Let’s Encrypt’s identity | Some clients/servers |
fullchain.pem | Combines both above | Nginx, Apache |
privkey.pem | Secures your HTTPS connection | Nginx, Apache, TLS |
3. Transfer the Private Key and Cert to Server
Encrypt the private key before sending it out to the server.
openssl pkcs8 -topk8 -inform PEM -in privkey.pem -out privkey.pem.enc -outform PEM -v2 aes-256-cbc
Enter Encryption Password:
Verifying - Enter Encryption Password:
Decrypt the private key on the destination server.
openssl pkcs8 -in privkey.pem.enc -inform PEM -out privkey.pem -outform PEM
Enter Password:
The cert is public which doesn’t require encryption. Now the cert and private key are ready for use for any app or Nginx. Just make sure their owner and access level.