What is acme.sh? Why use acme.sh?
An ACME protocol client written purely in Shell (Unix shell) language. Full ACME protocol implementation.
-- From the acme.sh Github project description
In short, acme.sh helps you painlessly apply for and deploy free ssl certificates
Compared to the Certbotclient recommended by Let’s Encrypt on her website, acme.sh supports more DNS vendors, such as DNSPod (the default DNS vendor when registering domain names using Tencent Cloud), which saves time and effort when using DNS authentication
And Because acme.sh is 100% using Shell Language, so you also do not need to do software adapter can use, also won't produce basic software conflict (I currently use experience)
And, no matter who you are, you don't need root permission to install acme.sh
(But if you apply for a certificate using Webroot mode, it is better to install it using root, as the application process requires the file to be written to the root directory of the website, of course, this is later)
And she has Docker deployment. (what Docker Fans)
(I believe you will love her.)
Currently, acme.sh supports the following ways to apply for a certificate:
- Webroot mode (Requires the user to have the webroot directory write permission)
- Standalone mode (Need to install socat service)
- Standalone tls-alpn mode (Need to install socat service)
- Apache mode (Alternative to Webroot mode verification)
- Nginx mode (Alternative to Webroot mode verification)
- DNS mode (Need to apply for DNS API or manually add DNS resolution)
- DNS alias mode (Please refer to the official documents)
- Stateless mode (Please refer to the official documents)
This article is written with reference to the official documents of acme.sh and the author's personal experience
If you have any questions about this article, please feel free to comment in the comments section below
Less talk and more action
You can click here to see the detailed operation document
If you need A tutorial on Docker deployment, select the A little reference for Docker Fans section
from the left menu
⚠️ Attention! This article only describes the basic usage, please go to acme.sh to see the detailed operation document
Install acme.sh
You only need one command to install acme.sh
But please note that you need to replace this my@example.com
with your own email address
curl https://get.acme.sh | sh -s email=my@example.com
You can also clone a GIT repository to install it
git clone --depth 1 https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install -m my@example.com
If your server is in China and the cloning may fail due to network issues, you can use the following command instead
git clone --depth 1 https://gitee.com/neilpang/acme.sh.git
cd acme.sh
./acme.sh --install -m my@example.com
Due to automatically update the certificate need to use the crond service to run, so you need to install the crond service first
You can also add the --nocron
parameter to install without the crond service, but the automatic certificate update will not work
curl https://get.acme.sh | sh -s email=example@example.com --nocron
Tips after installation
During the installation process, acme.sh automatically writes your .bashrc
file, which allows you to invoke it as if it were a command
That is, you don't need to be in the acme.sh installation directory to use it
Since the default CA of acme.sh is ZeroSSL, in my actual use, I found that ZeroSSL does not seem to adapt to the Chinese network environment, while Let's Encrypt can fully withstand it well, so let's change the CA first
acme.sh --set-default-ca --server letsenctypt
The letsenctypt field can be replaced with a CA that acme.sh supports by default or a link that supports the acme protocol
Click to see which CA acme.sh supports by default
Since acme.sh is currently updated frequently, it is recommended to turn on its automatic updates and check for updates before using it
acme.sh --upgrade --auto-upgrade
Apply for a certificate!
But before you apply, I'd like you to check out these things:
- In the following section, I'll use
example.com
as the request domain, and you need to change this domain name to your own domain - If there are any errors during the application process, you can add the
—-debug
parameter to debug (duh)
This article will not explore how to debug - You can apply for multiple types of certificates by adding the parameter
—-keylength (2048|3072|4096|8192|ec-256|ec-384|ec-521)
- You can apply for certificates for multiple domains at the same time. When you do this, generally speaking, the first domain name that appears in your application command is the main domain name of the certificate. If you are not sure which certificate's primary domain name is, you can use
acme.sh --list
to find out - When you apply for certificates for multiple domain names at the same time, if you specify only one authentication method, then all domains will be authenticated using this method. Of course, you can also specify different authentication methods for different domain names, which is similar to this format:
acme.sh --issue
-d aa.com -w /home/wwwroot/aa.com
-d bb.com --dns dns_cf
-d cc.com --apache
-d dd.com -w /home/wwwroot/dd.com
So now, let's get to work
DNS mode
DNS authentication is divided into automatic DNS authentication (which requires the API provided by the DNS vendor) and manual DNS authentication. Manual DNS authentication does not support automatic renewal
Only DNS authentication supports the application for a universal domain name certificate
(Maybe DNS alias mode works as well? I'll try it then.)
Automatic DNS authentication
Before doing so, please open this page: How to use DNS API
Now, you need to find the DNS vendor that your domain is currently using. Here, choose the commonly used Cloudflare
and DNSPod
as examples
(Some vendors have special requirements for automatic verification, which is why it is always better to read documentation than to read someone else's article)
Cloudflare
Cloudflare has two API keys, User API Token and Global API Key
Click here to go to the API acquisition page
Using a Global API Key is easier, of course, but it also increases security risks
Global API keys require your Cloudflare Global API Key
and Cloudflare Login Email
, while User API Token require your User API Token
and Zone ID
To view your Global API Key, click the View button in the Global API Key
line of your API page to get your global key
To get the zone key, Please click Create Token
-> Edit zone DNS
-> Select your domain name under Zone Resources
-> Continue to summary
to get your User API Token, you can find your domain name Zone ID
under your Website Overview
Using Global API Key
export CF_Key="Your Cloudflare Global API Key"
export CF_Email="Your Cloudflare Login Email"
Using User API Token
export CF_Zone_ID="Your Cloudflare Website Zone ID"
export CF_Token="Your Cloudflare User API Token"
Finally, let's apply for the certificate!
acme.sh --issue --dns dns_cf -d example.com -d *.example.com
DNSPod
Even the official DNSPod has a tutorial for acme.sh on DNSPod
If all is well, your certificate will be downloaded automatically
Manual DNS authentication
acme.sh --issue --dns -d example.com
--yes-I-know-dns-manual-mode-enough-go-ahead-please
You'll get a response like this:
[Sun Feb 11 18:52:50 CST 2024] Add the following TXT record:
[Sun Feb 11 18:52:50 CST 2024] Domain: "_acme-challenge.example.com"
[Sun Feb 11 18:52:50 CST 2024] TXT value: "xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
Please add a DNS resolution:
- The DNS resolution type is
TXT
- The name is the content of
Domain
in the output above, in this case is_acme-challenge.example.com
⚠ Note that in general the dns vendor will automatically add theexample.com
field for you when you add TXT parsing - The DNS resolution content is in the output
TXT value
, in this case isXXXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
After adding DNS resolution, use this command to continue
acme.sh --issue --renew -d example.com
--yes-I-know-dns-manual-mode-enough-go-ahead-please
If all is well, your certificate will be downloaded automatically
Webroot mode
As the simplest (and easiest) way to verify, you only need to specify the webroot directory to which your domain name is bound
This example used /home/wwwroot/example.com
as the webroot directory
acme.sh --issue -d example.com -w /home/wwwroot/example.com
If all is well, your certificate will be downloaded automatically
Standalone mode
There are two kinds of independent verification, but they're pretty much the same
If your server is not running a website service, it is easier to use this method of authentication
This mode is applicable to the server that has no service listen to port 80 or port 443
Since this method depends on the socat service, we need to install the socat service first
#For RHEL Series
sudo dnf install -y socat
#For Debian Series
sudo apt install -y socat
This authentication method needs to listen on port 80/443, so you need to use root permission to authenticate
(What is shown here is only simple usage, if the server has a reverse proxy please check the official documentation of acme.sh)
Using port 80
acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com
Using port 443
acme.sh --issue --alpn -d example.com -d www.example.com -d cp.example.com
If all is well, your certificate will be downloaded automatically
Website service verification
Web service authentication, as the name implies, requires either nginx or Apache httpd to be installed before you use it.
acme.sh will change your website service configuration, but rest assured that it will be changed back to you after the certificate is issued
In fact, according to my tests,
Website service verification
is just an automation ofStateless mode
It's actually another way ofWebroot mode
Nginx mode
acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com
Apache mode
acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com
If all is well, your certificate will be downloaded automatically
Install the certificate!
Due to acme.sh does not automatically help us change the web service (such as nginx and Apache httpd) configuration file, so we need to manually tell acme.sh where to place the certificate issued, and what command to reload or restart the website service
Using nginx as an example:
- The primary domain name of the certificate we installed is
example.com
- The public key is written to
/etc/nginx/conf.d/ssl/server.crt
- The private key is written to
/etc/nginx/conf.d/ssl/server.key
- CA certificate is written to
/etc/nginx/conf.d/ssl/ca.crt
- FullChain is written to
/etc/nginx/conf.d/ssl/fullchain.pem
- The command for the nginx server to reload the configuration file is
nginx -s reload
So, our command should look like this
acme.sh --install-cert -d example.com
--cert-file /etc/nginx/conf.d/ssl/server.crt
--key-file /etc/nginx/conf.d/ssl/server.key
--ca-file /etc/nginx/conf.d/ssl/ca.crt
--fullchain-file /etc/nginx/conf.d/ssl/fullchain.pem
--reloadcmd "nginx -s reload"
After executing this command, if all is well, you will find the certificates in the specified location (they are very good and cute)
If you also specify —-reloadcmd
parameter, acme.sh will attempt to run the specified command and print the output of the command at run time
Don't worry if you get an error running the reload-cmd in acme.sh, just adjust your —-reloadcmd
and run the above installation certificate command once, and —-reloadcmd
will be overwritten with the latest specified command
⚠️ Note: Applying for a certificate without modifying any configuration file will not work. You will need to modify the configuration file of the website service yourself to deploy the ssl certificate
Please click here to check out the ssl certificate deployment tutorial
That's all! Thank you for reading this article
A little reference for Docker Fans section
Okay, okay, now I know you're going to use Docker
You can refer to The official Docker documentation for acme.sh
I don't like his documentation very much because you have to mount the docker.sock
file, which can have security implications
(Docker = Root)
And if you want to deploy to multiple containers at the same time (seems possible?) it can be a bit cumbersome
So here is my solution that supports executing the commands you want on the Docker host after install-cert
Following my lazy habits, I may write an automatic deployment script later, so expect it
Deploy acme-reloader
There are several files that you need to download and unzip
wget https://ftp.esaps.net/dockersh/acme.sh/acme-reloader.tar.gz
tar xzvf acme-reloader.tar.gz
After unzipped, the file directory looks like this
acme-reloader
|- ssl/
| |-
|- config/
| |-
|- acme-reloader/
| |-
|- acme-reloader-host.service
|- acme-reloader-host.sh
|- acme-reloader.sh
|- docker-compose.yml
Normally, we just need to go into the acme-reloader
directory and run docker compose up -d
to start the acme.sh container
How to reload a Docker container without mounting docker.sock
Change files first
If you are using Webroot mode, you need to mount your webroot directory into the container
Please find our acme-reloader-host-sh
file and find this fragment and modify the file according to the comments (English site users please check the annotation in the file)
function restart_command() {
#请在这里放下你在证书申请完成之后需要在docker宿主机上执行的命令
#请类似于这样的格式书写:restart_with "需要执行的命令",一行一条
#这样才可以在本目录下acme-reloader.log查找到命令执行异常时的日志
restart_with "YOUR_OWN_SH_COMMAND"
#输入完成!请不要更改其他文段并享受你的自动化过程吧 :)
echo "Complete" >> ./socket/acme-reloader.sock
}
Find our acme-reloader-host.service
file and make the following changes
- Replace
/path/to/acme-reloader-host.sh_directory
with the absolute path of theacme-reloader directory
- Replace
/path/acme-reloader-host.sh
with the absolute path toacme-reloader-host.sh
Then, copy the file into the /usr/lib/systemd/system/
directory
(Note that if your Linux distribution is too early, you may be using init.d instead of systemd, and I'm sure you can write your own service script) (sure)
(Forget it. I'll write another one then.)
acme-reloader-host, start!
Run the command to let systemd manipulate our acme-reloader
systemctl daemon-reload #重载配置文件,必须执行一次,否则可能提示找不到acme-reloader-host.service
systemctl start acme-reloader-host.service #启动acme-reloader-host
systemctl stop acme-reloader-host.service #关闭acme-reloader-host
systemctl restart acme-reloader-host.service #重启acme-reloader-host
systemctl status acme-reloader-host.service #查看acme-reloader-host运行状态
Before proceeding, you need to start the acme-reloader-host
service, otherwise you may receive an error message when acme.sh executes the restart command
It takes a little more work
Copy the acme-reloader.sh
file to the root directory of the acme.sh
container (replace it with your own container name, but don't change it if you use my docker-compose.yml)
docker cp ./acme-reloader.sh acme.sh:/
Then, apply for a certificate as described in this article~
sudo docker exec -it acme.sh acme.sh
Since we're running in a Docker container, we're replacing the neat acme.sh command in this cumbersome way
If you are annoyed of it, you can execute this command to make it easier
alias acme.sh="docker exec -it acme.sh acme.sh"
You can also go directly into the acme.sh container to do this
docker exec -it acme.sh ash
Next I'll demonstrate directly using the acme.sh command
Since we are running a Docker container, we need to set up an account with the CA
acme.sh --register-account --server letsencrypt -m myemail@example.com
And change the default CA of acme.sh
acme.sh --set-default-ca --server letsencrypt
Then you can apply for the certificate as described in this article
Note: If you're using automated DNS authentication, it's better to go straight into the container and apply first, letting acme.sh hold your API key
Last little bit!
Yes, we need to install the certificate
acme.sh --install-cert -d example.com \
--cert-file /etc/nginx/conf.d/ssl/server.crt \
--key-file /etc/nginx/conf.d/ssl/server.key \
--ca-file /etc/nginx/conf.d/ssl/ca.crt \
--fullchain-file /etc/nginx/conf.d/ssl/fullchain.pem \
--reloadcmd "sh /acme-reloader.sh"
By default, I mounted the /ssl
directory for you to the docker container, which is the same directory as docker-compose.yml
--reloadcmd
must be changed to sh /acme-reloader.sh
so that we can notify the host to execute the reload command
If you have not started the acme-reloader-host service on the host machine, you will be prompted
Host error: Unable to connect to host.
In this case, you need to start the acme-reloader-host service before re-installing the certificate
Also, the logs of the acme-reloader-host service are in the same directory as acme-reloader-hoaster.sh. If the reload fails, you can see which command is wrong. meow~docker-compose.yml
帮你挂载了/ssl
目录,这个目录docker-compose.yml的同级目录下
--reloadcmd
必须改为sh /acme-reloader.sh
,这样子我们才可以通知宿主机来执行重载命令
If you have not started the acme-reloader-host service on the host machine, you will be prompted
Host error: Unable to connect to host.
In this case, you need to start the acme-reloader-host service before re-installing the certificate
Also, the logs of the acme-reloader-host service are in the same directory as acme-reloader-hoaster.sh. If the reload fails, you can see which command is wrong. meow~
Finished~! Enjoy your certificate automation!
(BTW, you need to change the web server configuration file to deploy certificate yourself, see here)
Leave a Reply