Management > Private CA > ACME Certificate Renewal Guide (Certbot, acme.sh)
The Private CA service supports the automatic certificate management environment (ACME) protocol, enabling automated issuance and renewal of certificates. ACME client (e.g., Certbot, acme.sh) allows you to issue and periodically renew certificates without manual intervention.
This guide explains how to use a Private CA ACME server with Certbot or acme.sh to issue and automatically renew certificates.
Notice
Before you can begin issuing certificates through ACME, you need to prepare the following:
The base certificate acts as a "template" that the ACME server references for automatic renewal.
In the Private CA console, verify the following information:
https://kr1-pca.api.nhncloudservice.com/acme/v2.0/cert/{certId}/directoryYou can use either Certbot or acme.sh as your ACME client. Please choose the tool that best fits your environment to proceed.
!!! tip "Notice" To automate certificate management in Kubernetes, please refer to the ACME Certificate Renewal Guide (cert-manager).
Certbot is the most widely used ACME client. Refer to the official Certbot documentation to install it for your operating system.
Installation example (Ubuntu/Debian)
sudo apt update
sudo apt install certbot
Installation example (CentOS/RHEL)
sudo yum install certbot
Here's an example of a basic certificate issuance command:
certbot certonly \
--manual \
--manual-auth-hook ./pre.sh \
--deploy-hook ./post.sh \
--preferred-challenges http \
--server https://kr1-pca.api.nhncloudservice.com/acme/v2.0/cert/{certId}/directory \
-d example.com -d www.example.com \
--eab-kid "YOUR_ACME_TOKEN_ID" \
--eab-hmac-key "YOUR_ACME_TOKEN_HMAC_KEY" \
--key-type rsa \
--rsa-key-size 2048 \
--agree-tos \
--register-unsafely-without-email
| Option | Description | Required | Default |
|---|---|---|---|
--manual |
Manually perform challenge verification. Use manual mode instead of Apache or Nginx automatic configuration. | O | - |
--manual-auth-hook |
Specifies a script to run before challenge verification. Even an empty script is required to prevent errors during renewal. | O | - |
--deploy-hook |
Specifies a script to run after successful certificate issuance. Used for post-processing, such as certificate transfer and deployment. | X | - |
| --preferred-challenges | Specifies the challenge method ( http, dns, tls-alpn ). Typically, http is used. |
O | - |
--server |
Specifies the Directory URL of the ACME server. | O | - |
-d |
Specifies the domains to include in the certificate. The CN and SAN of the base certificate must be entered correctly, as verified in the console. | O | - |
--eab-kid |
Key ID for External Account Binding. Enter the ACME token ID issued by the Private CA. | O | - |
--eab-hmac-key |
EAB HMAC key (Base64 encoded). Enter the ACME token HMAC key issued by the Private CA. | O | - |
--key-type |
Specifies the private key type ( rsa , ecdsa ). |
X | rsa |
--rsa-key-size |
Specifies the RSA key length. Only used when --key-type is rsa . Valid values are 2048, 3072, and 4096. |
X | 2048 |
--elliptic-curve |
Specifies the ECDSA key curve. Only used when it is --key-type ecdsa . Valid values are secp256r1, secp384r1, and secp521r1. |
X | secp256r1 |
--agree-tos |
Automatically agree to the Terms of Service. Prevents interactive input. | X | - |
--register-unsafely-without-email |
Register an account without an email. Prevents interactive input. | X | - |
Notice
--manual mode is used for manual challenge validation.The manual-auth-hook is required for reliability when renewing certificates.deploy-hook allows you to automatically perform deployment and post-processing tasks after certificate issuance.--server, --eab-kid, --eab-hmac-key are required for Private CA ACME server integration.Caution
When specifying domains, you must ensure they match the Common Name (CN) and Subject Alternative Name (SAN) of the Base certificate. Before issuance, please verify the certificate details in the console to confirm that the correct domains are assigned to the -d option.
The manual-auth-hook must exist as a file, even if its contents are empty. This is to prevent errors during certificate renewal.
#!/bin/bash
# You can add any necessary authentication preprocessing tasks here.
The deploy-hook is only executed if the certificate is successfully issued.
#!/bin/bash
# Processing tasks after certificate issuance is complete
echo "\[post.sh] Certificate issued successfully!"
# Copy the certificate to the target location
cp /etc/letsencrypt/live/example.com/fullchain.pem ~/Downloads/
cp /etc/letsencrypt/live/example.com/privkey.pem ~/Downloads/
# Additional tasks, such as restarting the web server
# systemctl reload nginx
Certificates are stored in the following paths by default:
/etc/letsencrypt/live/<domain name (CN)>/
├── cert.pem # server certificate
├── chain.pem # intermediate certificate chain
├── fullchain.pem # cert.pem + chain.pem
└── privkey.pem # private key
# Verify Certificate Information
openssl x509 -in /etc/letsencrypt/live/<domain name (CN)>/cert.pem -text -noout
# Verify Certificate Validity
openssl x509 -in /etc/letsencrypt/live/<domain name (CN)>/cert.pem -noout -dates
Certbot can automatically renew certificates that are nearing expiration.
/etc/letsencrypt/renewal/<domain>.conf must exist./etc/letsencrypt/live/<domain>/ directory.When you install Certbot, it automatically registers a cron or systemd timer to periodically check for certificate expiration.
Default renewal cycle: Attempt to auto-renew 30 days before expiration
If necessary, you can perform a manual renewal with the following commands:
# All certificate renewal attempts
sudo certbot renew
# Force renewal
sudo certbot renew --force-renewal
If auto-renewal is not registered, you can manually add a cron job.
# Edit crontab
sudo crontab -e
# Check renewals at 2 AM every day
0 2 * * * certbot renew --no-random-sleep-on-renew
You can adjust the renewal interval in the /etc/letsencrypt/renewal/<domain>.conf file.
[renewalparams] renew_before_expiry = 30 days
You can change the renew_before_expiry value to set how many days before the certificate expires to attempt to renew.
Caution
renew_before_expiry value must be carefully adjusted to account for the ACME server's Rate Limit policy./etc/cron.d/certbot file as needed.(perl -e 'sleep int(rand(43200))'). This is to prevent overloading the ACME server, and if you need it to execute immediately, you should remove the syntax or use the --no-random-sleep-on-renew option.--server option is correct.--eab-kid and --eab-hmac-key values are correct.pre.sh and post.sh files have execute permissions./etc/letsencrypt/renewal/<domain>.conf file exists and is correct.with manual-auth-hook still exists.acme.sh is a lightweight ACME client written in pure Shell script, with minimal dependencies and an easy installation process.
acme.sh can be easily installed via an install script.
Installation
curl https://get.acme.sh | sh
After the installation is complete, load the environment variables.
. ~/.acme.sh/acme.sh.env acme.sh --version
!!! tip "Notice" - When reconnecting to a container or a new shell session, you must reload environment variables with the command . ~/.acme.sh/acme.sh.env. - The email address is optional during installation.
Installation Example (Manual Download)
git clone https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install
Before you can issue a certificate, you must first register an account with the ACME server.
acme.sh --register-account \
--server https://kr1-pca.api.nhncloudservice.com/acme/v2.0/cert/{certId}/directory \
--eab-kid "YOUR_ACME_TOKEN_ID" \
--eab-hmac-key "YOUR_ACME_TOKEN_HMAC_KEY"
!!! DANGER "Caution" - Account registration only needs to be done once for the first time. - After registration, you can omit the --eab-kid and --eab-hmac-key options when issuing a certificate.
You can issue certificates after you sign up for an account.
Example of Basic Issuance Commands
acme.sh --issue \
-d example.com -d www.example.com \
--server https://kr1-pca.api.nhncloudservice.com/acme/v2.0/cert/{certId}/directory \
--keylength 2048 \
--standalone
| Options | Description | Required | Default |
|------|------|------|------|--------|
| --register-account | Registers an account with the ACME server. Runs one time only. | O (first time) | - |
| --issue | Issues a certificate. | O | - |
| --server | Specifies the Directory URL of the ACME server. | O | - |
| --eab-kid | Key ID for External Account Binding. Enter the ACME token ID issued by the Private CA. Required only for account registration. | O (at registration) | - |
| --eab-hmac-key | EAB HMAC key (Base64 encoded). Enter the ACME token HMAC key issued by the Private CA. Required only when you enroll for an account. | O (at enrollment) | - | |
| -d | Specifies the domains to include in the certificate. The CN and SAN of the base certificate must be verified in the console to ensure they are entered correctly. Multiple can be specified. | O | - |
| --standalone | Process HTTP-01 challenges in standalone mode. acme.sh runs a temporary web server. | O | - |
| --httpport | Specifies the port number to use for HTTP-01 challenges. | X | 80 |
| --keylength | Specifies the private key length. You can use values of 2048, 3072, 4096 for RSA and ec-256, ec-384, ec-521 for ECDSA. | X | 2048 |
| --debug | Runs in debug mode to output a detailed log. | X | - |
Notice
--standalone mode causes acme.sh to run a temporary web server to handle the Challenge. Port 80 must be available.--eab-kid and --eab-hmac-key options.Caution
When specifying domains, you must ensure they match the Common Name (CN) and Subject Alternative Name (SAN) of the Base certificate. Before issuance, please verify the certificate details in the console to confirm that the correct domains are assigned to the -d option..
acme.sh runs a temporary web server to handle HTTP-01 challenges.
acme.sh --issue \
-d example.com \
--server https://kr1-pca.api.nhncloudservice.com/acme/v2.0/cert/{certId}/directory \
--keylength 2048 \
--standalone
Caution
- Port 80 must be open and available.
- If an existing web server is using port 80, it must be temporarily stopped.
- To use a different port, add the --httpport option.
Certificates are stored in the following paths by default:
~/.acme.sh/<domain name (CN)>/
├── <domain name>.cer # Server certificate (leaf certificate)
├── <domain name>.key # Private key
├── ca.cer # CA chain (Intermediate + Root)
└── fullchain.cer # Full chain (leaf certificate + CA chain) ```
!!! tip "Notice"
- `<domain name>.cer`: contains only leaf certificates
- `fullchain.cer`: full chain of leaf certificates + intermediate certificates + root certificate
- `ca.cer`: CA chain (intermediate certificates + root certificate)
##### Verify Certificate Contents
```bash
# Verify Certificate Information
openssl x509 -in ~/.acme.sh/example.com/example.com.cer -text -noout
# Verify Certificate Validity
openssl x509 -in ~/.acme.sh/example.com/example.com.cer -noout -dates
acme.sh can use the --install-cert command to copy the certificate to the desired location and restart the web server.
Nginx Example
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/privkey.pem \
--cert-file /etc/nginx/ssl/cert.pem \
--fullchain-file /etc/nginx/ssl/fullchain.pem \
--ca-file /etc/nginx/ssl/ca.pem \
--reloadcmd "nginx -s reload"
Apache Example
acme.sh --install-cert -d example.com \
--key-file /etc/apache2/ssl/privkey.pem \
--cert-file /etc/apache2/ssl/cert.pem \
--fullchain-file /etc/apache2/ssl/fullchain.pem \
--ca-file /etc/apache2/ssl/ca.pem \
--reloadcmd "systemctl reload apache2"
Notice
--key-file: private key file storage path--cert-file: leaf certificate storage path--fullchain-file: full chain (leaf + CA chain) storage path--ca-file: CA chain storage path--reloadcmd: command to run automatically after certificate installationacme.sh automatically registers a cron job upon installation to check and renew certificate expirations.
~/.acme.sh/<domain>/ directory.The cron job is automatically registered when you install acme.sh.
Default renewal cycle: Attempt to auto-renew 60 days before expiration
Check a Cron job
crontab -l | grep acme.sh
They are typically registered in the following form:
0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null
If necessary, you can perform a manual renewal with the following commands:
# All certificate renewal attempts
acme.sh --cron
# Force Renewal of Specific Certificates
acme.sh --renew -d example.com --force
By default, acme.sh attempts to renew 60 days before expiration. To change this value, modify the ~/.acme.sh/account.conf file.
# Edit account.conf
vim ~/.acme.sh/account.conf
Add or modify the following lines:
Le_RenewalDays=30
This setting will attempt to renew 30 days before expiration.
Caution
Le_RenewalDays value must be carefully adjusted to account for the ACME server's Rate Limit policy.--server option is correct.--register-account command.--debug option to view detailed logs.acme.sh --issue \
-d example.com \
--server https://kr1-pca.api.nhncloudservice.com/acme/v2.0/cert/{certId}/directory \
--keylength 2048 \
--standalone \
--debug
~/.acme.sh/<domain>/<domain>.log file for error messages.acme.sh --renew -d example.com --force --debug.Through the ACME Directory URL (/directory) provided by the private CA, the ACME client automatically gets all the endpoint information it needs.
The ACME protocol workflow is fully automated by the client, requiring only the Directory URL from the user.
For more information about the ACME protocol, see RFC 8555.