Compare commits
@@ -1,195 +1,215 @@
|
||||
# le: means simp`Le`
|
||||
Simplest shell script for LetsEncrypt free Certificate client
|
||||
# An ACME Shell script: acme.sh
|
||||
- An ACME protocol client written purely in Shell (Unix shell) language.
|
||||
- Fully ACME protocol implementation.
|
||||
- Simple, powerful and very easy to use. You only need 3 minutes to learn.
|
||||
- Bash, dash and sh compatible.
|
||||
- Simplest shell script for Let's Encrypt free certificate client.
|
||||
- Purely written in Shell with no dependencies on python or Let's Encrypt official client.
|
||||
- Just one script, to issue, renew and install your certificates automatically.
|
||||
- DOES NOT require `root/sudoer` access.
|
||||
|
||||
Simple and Powerful, you only need 3 minutes to learn.
|
||||
It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt.
|
||||
|
||||
Pure written in bash, no dependencies to python, acme-tiny or LetsEncrypt official client.
|
||||
Just one script, to issue, renew your certificates automatically.
|
||||
|
||||
Probably it's the smallest&easiest&smartest shell script to automatically issue & renew the free certificates from LetsEncrypt.
|
||||
|
||||
NOT require to be `root/sudoer`.
|
||||
|
||||
Wiki: https://github.com/Neilpang/le/wiki
|
||||
Wiki: https://github.com/Neilpang/acme.sh/wiki
|
||||
|
||||
#Tested OS
|
||||
1. Ubuntu [](https://github.com/Neilpang/letest#here-are-the-latest-status)
|
||||
2. Debian [](https://github.com/Neilpang/letest#here-are-the-latest-status)
|
||||
3. CentOS [](https://github.com/Neilpang/letest#here-are-the-latest-status)
|
||||
4. Windows (cygwin with curl, openssl and crontab included) [](https://github.com/Neilpang/letest#here-are-the-latest-status)
|
||||
5. FreeBSD with bash [](https://github.com/Neilpang/letest#here-are-the-latest-status)
|
||||
6. pfsense with bash and curl
|
||||
7. openSUSE [](https://github.com/Neilpang/letest#here-are-the-latest-status)
|
||||
8. Alpine Linux [](https://github.com/Neilpang/letest#here-are-the-latest-status) (with bash, curl. https://github.com/Neilpang/le/issues/94)
|
||||
9. Archlinux [](https://github.com/Neilpang/letest#here-are-the-latest-status)
|
||||
10. fedora [](https://github.com/Neilpang/letest#here-are-the-latest-status)
|
||||
11. Kali Linux [](https://github.com/Neilpang/letest#here-are-the-latest-status)
|
||||
12. Oracle Linux [](https://github.com/Neilpang/letest#here-are-the-latest-status)
|
||||
13. Cloud Linux https://github.com/Neilpang/le/issues/111
|
||||
14. Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_le.sh
|
||||
| NO | Status| Platform|
|
||||
|----|-------|---------|
|
||||
|1|[](https://github.com/Neilpang/letest#here-are-the-latest-status)| Ubuntu
|
||||
|2|[](https://github.com/Neilpang/letest#here-are-the-latest-status)| Debian
|
||||
|3|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|CentOS
|
||||
|4|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Windows (cygwin with curl, openssl and crontab included)
|
||||
|5|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|FreeBSD
|
||||
|6|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|pfsense
|
||||
|7|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|openSUSE
|
||||
|8|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Alpine Linux (with curl)
|
||||
|9|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Archlinux
|
||||
|10|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|fedora
|
||||
|11|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Kali Linux
|
||||
|12|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Oracle Linux
|
||||
|13|[](https://github.com/Neilpang/letest#here-are-the-latest-status)| Proxmox https://pve.proxmox.com/wiki/HTTPSCertificateConfiguration#Let.27s_Encrypt_using_acme.sh
|
||||
|14|-----| Cloud Linux https://github.com/Neilpang/le/issues/111
|
||||
|15|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|OpenBSD
|
||||
|16|[](https://github.com/Neilpang/letest#here-are-the-latest-status)|Mageia
|
||||
|
||||
For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest):
|
||||
|
||||
For all the build status, check our daily build project:
|
||||
https://github.com/Neilpang/acmetest
|
||||
|
||||
https://github.com/Neilpang/letest.git
|
||||
# Supported Mode
|
||||
|
||||
#Supported Mode
|
||||
1. Webroot mode
|
||||
2. Standalone mode
|
||||
3. Apache mode
|
||||
4. Dns mode
|
||||
|
||||
#How to install
|
||||
# Upgrade from 1.x to 2.x
|
||||
|
||||
1. Install online:
|
||||
You can simply uninstall 1.x and re-install 2.x.
|
||||
2.x is 100% compatible to 1.x. You will feel right at home as if nothing has changed.
|
||||
|
||||
```
|
||||
curl https://raw.githubusercontent.com/Neilpang/le/master/le.sh | INSTALLONLINE=1 bash
|
||||
# le.sh renamed to acme.sh NOW!
|
||||
|
||||
All configurations are 100% compatible between `le.sh` and `acme.sh`. You just need to uninstall `le.sh` and re-install `acme.sh` again.
|
||||
Nothing will be broken during the process.
|
||||
|
||||
# How to install
|
||||
|
||||
### 1. Install online:
|
||||
|
||||
Check this project: https://github.com/Neilpang/get.acme.sh
|
||||
|
||||
```bash
|
||||
curl https://get.acme.sh | sh
|
||||
|
||||
```
|
||||
|
||||
Or:
|
||||
```
|
||||
wget -O - https://raw.githubusercontent.com/Neilpang/le/master/le.sh | INSTALLONLINE=1 bash
|
||||
|
||||
```bash
|
||||
wget -O - https://get.acme.sh | sh
|
||||
|
||||
```
|
||||
|
||||
|
||||
2. Or, Install from git:
|
||||
### 2. Or, Install from git:
|
||||
|
||||
Clone this project:
|
||||
```
|
||||
git clone https://github.com/Neilpang/le.git
|
||||
cd le
|
||||
./le.sh install
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Neilpang/acme.sh.git
|
||||
cd ./acme.sh
|
||||
./acme.sh --install
|
||||
```
|
||||
|
||||
You don't have to be root then, although it is recommended.
|
||||
You `don't have to be root` then, although `it is recommended`.
|
||||
|
||||
Which does 3 jobs:
|
||||
* create and copy `le.sh` to your home dir: `~/.le`
|
||||
All the certs will be placed in this folder.
|
||||
* create alias : `le.sh=~/.le/le.sh` and `le=~/.le/le.sh`.
|
||||
* create everyday cron job to check and renew the cert if needed.
|
||||
Advanced Installation: https://github.com/Neilpang/acme.sh/wiki/How-to-install
|
||||
|
||||
After install, you must close current terminal and reopen again to make the alias take effect.
|
||||
The installer will perform 3 actions:
|
||||
|
||||
1. Create and copy `acme.sh` to your home dir (`$HOME`): `~/.acme.sh/`.
|
||||
All certs will be placed in this folder.
|
||||
2. Create alias for: `acme.sh=~/.acme.sh/acme.sh`.
|
||||
3. Create everyday cron job to check and renew the cert if needed.
|
||||
|
||||
Cron entry example:
|
||||
|
||||
```bash
|
||||
0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null
|
||||
```
|
||||
|
||||
After the installation, you must close current terminal and reopen again to make the alias take effect.
|
||||
|
||||
Ok, you are ready to issue cert now.
|
||||
Show help message:
|
||||
```
|
||||
root@v1:~# le.sh
|
||||
https://github.com/Neilpang/le
|
||||
v1.2.2
|
||||
Usage: le.sh [command] ...[args]....
|
||||
Available commands:
|
||||
|
||||
install:
|
||||
Install le.sh to your system.
|
||||
issue:
|
||||
Issue a cert.
|
||||
installcert:
|
||||
Install the issued cert to apache/nginx or any other server.
|
||||
renew:
|
||||
Renew a cert.
|
||||
renewAll:
|
||||
Renew all the certs.
|
||||
uninstall:
|
||||
Uninstall le.sh, and uninstall the cron job.
|
||||
version:
|
||||
Show version info.
|
||||
installcronjob:
|
||||
Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
|
||||
uninstallcronjob:
|
||||
Uninstall the cron job. The 'uninstall' command can do this automatically.
|
||||
toPkcs:
|
||||
Export the certificate and key to a pfx file.
|
||||
createAccountKey:
|
||||
Create an account private key, professional use.
|
||||
createDomainKey:
|
||||
Create an domain private key, professional use.
|
||||
createCSR:
|
||||
Create CSR , professional use.
|
||||
|
||||
|
||||
|
||||
root@v1:~/le# le issue
|
||||
Usage: le issue webroot|no|apache|dns a.com [www.a.com,b.com,c.com]|no [key-length]|no
|
||||
|
||||
|
||||
```
|
||||
|
||||
Set the param value to "no" means you want to ignore it.
|
||||
|
||||
For example, if you give "no" to "key-length", it will use default length 2048.
|
||||
|
||||
And if you give 'no' to 'cert-file-path', it will not copy the issued cert to the "cert-file-path".
|
||||
|
||||
In all the cases, the issued cert will be placed in "~/.le/domain.com/"
|
||||
root@v1:~# acme.sh -h
|
||||
|
||||
```
|
||||
|
||||
# Just issue a cert:
|
||||
Example 1:
|
||||
Only one domain:
|
||||
```
|
||||
le issue /home/wwwroot/aa.com aa.com
|
||||
|
||||
**Example 1:** Single domain.
|
||||
|
||||
```bash
|
||||
acme.sh --issue -d aa.com -w /home/wwwroot/aa.com
|
||||
```
|
||||
|
||||
Example 2:
|
||||
Multiple domains in the same cert:
|
||||
**Example 2:** Multiple domains in the same cert.
|
||||
|
||||
```
|
||||
le issue /home/wwwroot/aa.com aa.com www.aa.com,cp.aa.com
|
||||
```bash
|
||||
acme.sh --issue -d aa.com -d www.aa.com -d cp.aa.com -w /home/wwwroot/aa.com
|
||||
```
|
||||
|
||||
First argument `/home/wwwroot/aa.com` is the web root folder, You must have `write` access to this folder.
|
||||
The parameter `/home/wwwroot/aa.com` is the web root folder. You **MUST** have `write access` to this folder.
|
||||
|
||||
Second argument "aa.com" is the main domain you want to issue cert for.
|
||||
Second argument **"aa.com"** is the main domain you want to issue cert for.
|
||||
You must have at least a domain there.
|
||||
|
||||
Third argument is the additional domain list you want to use. Comma separated list, which is Optional.
|
||||
You must point and bind all the domains to the same webroot dir: `/home/wwwroot/aa.com`.
|
||||
|
||||
You must point and bind all the domains to the same webroot dir:`/home/wwwroot/aa.com`
|
||||
|
||||
The cert will be placed in `~/.le/aa.com/`
|
||||
Generate/issued certs will be placed in `~/.acme.sh/aa.com/`
|
||||
|
||||
The issued cert will be renewed every 80 days automatically.
|
||||
|
||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
||||
|
||||
|
||||
# Install issued cert to apache/nginx etc.
|
||||
|
||||
After you issue a cert, you probably want to install the cert with your nginx/apache or other servers you may be using.
|
||||
|
||||
```bash
|
||||
acme.sh --installcert -d aa.com \
|
||||
--certpath /path/to/certfile/in/apache/nginx \
|
||||
--keypath /path/to/keyfile/in/apache/nginx \
|
||||
--capath /path/to/ca/certfile/apache/nginx \
|
||||
--fullchainpath path/to/fullchain/certfile/apache/nginx \
|
||||
--reloadcmd "service apache2|nginx reload"
|
||||
```
|
||||
le installcert aa.com /path/to/certfile/in/apache/nginx /path/to/keyfile/in/apache/nginx /path/to/ca/certfile/apache/nginx "service apache2|nginx reload"
|
||||
```
|
||||
|
||||
Only the domain is required, all the other parameters are optional.
|
||||
|
||||
Install the issued cert/key to the production apache or nginx path.
|
||||
|
||||
The cert will be renewed every 80 days by default (which is configurable), Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload`
|
||||
The cert will be `renewed every 80 days by default` (which is configurable). Once the cert is renewed, the apache/nginx will be automatically reloaded by the command: `service apache2 reload` or `service nginx reload`.
|
||||
|
||||
# Use Standalone server to issue cert
|
||||
|
||||
# Use Standalone server to issue cert (requires you be root/sudoer, or you have permission to listen tcp 80 port):
|
||||
Same usage as all above, just give `no` as the webroot.
|
||||
The tcp `80` port must be free to listen, otherwise you will be prompted to free the `80` port and try again.
|
||||
**(requires you be root/sudoer, or you have permission to listen tcp 80 port)**
|
||||
|
||||
```
|
||||
le issue no aa.com www.aa.com,cp.aa.com
|
||||
The tcp `80` port **MUST** be free to listen, otherwise you will be prompted to free the `80` port and try again.
|
||||
|
||||
```bash
|
||||
acme.sh --issue --standalone -d aa.com -d www.aa.com -d cp.aa.com
|
||||
```
|
||||
|
||||
# Use Apache mode (requires you be root/sudoer, since it is required to interact with apache server):
|
||||
If you are running a web server, apache or nginx, it is recommended to use the Webroot mode.
|
||||
Particularly, if you are running an apache server, you can use apache mode instead. Which doesn't write any file to your web root folder.
|
||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
||||
|
||||
Just set string "apache" to the first argument, it will use apache plugin automatically.
|
||||
# Use Standalone tls server to issue cert
|
||||
|
||||
**(requires you be root/sudoer, or you have permission to listen tcp 443 port)**
|
||||
|
||||
acme.sh supports `tls-sni-01` validation.
|
||||
|
||||
The tcp `443` port **MUST** be free to listen, otherwise you will be prompted to free the `443` port and try again.
|
||||
|
||||
```bash
|
||||
acme.sh --issue --tls -d aa.com -d www.aa.com -d cp.aa.com
|
||||
```
|
||||
|
||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
||||
|
||||
# Use Apache mode
|
||||
|
||||
**(requires you be root/sudoer, since it is required to interact with apache server)**
|
||||
|
||||
If you are running a web server, apache or nginx, it is recommended to use the `Webroot mode`.
|
||||
|
||||
Particularly, if you are running an apache server, you should use apache mode instead. This mode doesn't write any files to your web root folder.
|
||||
|
||||
Just set string "apache" as the second argument, it will force use of apache plugin automatically.
|
||||
|
||||
```
|
||||
le issue apache aa.com www.aa.com,user.aa.com
|
||||
acme.sh --issue --apache -d aa.com -d www.aa.com -d user.aa.com
|
||||
```
|
||||
All the other arguments are the same with previous.
|
||||
|
||||
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
|
||||
|
||||
# Use DNS mode:
|
||||
Support the latest dns-01 challenge.
|
||||
|
||||
```
|
||||
le issue dns aa.com www.aa.com,user.aa.com
|
||||
Support the `dns-01` challenge.
|
||||
|
||||
```bash
|
||||
acme.sh --issue --dns -d aa.com -d www.aa.com -d user.aa.com
|
||||
```
|
||||
|
||||
You will get the output like bellow:
|
||||
You should get the output like below:
|
||||
|
||||
```
|
||||
Add the following txt record:
|
||||
Domain:_acme-challenge.aa.com
|
||||
@@ -198,86 +218,88 @@ Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c
|
||||
Add the following txt record:
|
||||
Domain:_acme-challenge.www.aa.com
|
||||
Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
Please add those txt records to the domains. Waiting for the dns to take effect.
|
||||
|
||||
Then just retry with 'renew' command:
|
||||
|
||||
```
|
||||
le renew aa.com
|
||||
|
||||
Then just rerun with `renew` argument:
|
||||
|
||||
```bash
|
||||
acme.sh --renew -d aa.com
|
||||
```
|
||||
|
||||
Ok, it's finished.
|
||||
|
||||
# Automatic DNS API integration
|
||||
|
||||
#Automatic dns api integeration
|
||||
If your DNS provider supports API access, we can use API to automatically issue the certs.
|
||||
|
||||
If your dns provider supports api access, we can use api to automatically issue certs.
|
||||
You don't have do anything manually.
|
||||
You don't have do anything manually!
|
||||
|
||||
###Currently we support:
|
||||
### Currently acme.sh supports:
|
||||
|
||||
1. Cloudflare.com api
|
||||
2. Dnspod.cn api
|
||||
3. Cloudxns.com api
|
||||
4. AWS Route 53, see: https://github.com/Neilpang/le/issues/65
|
||||
1. Cloudflare.com API
|
||||
2. Dnspod.cn API
|
||||
3. Cloudxns.com API
|
||||
4. AWS Route 53, see: https://github.com/Neilpang/acme.sh/issues/65
|
||||
5. lexicon dns api: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
|
||||
(DigitalOcean, DNSimple, DnsMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)
|
||||
|
||||
More apis are coming soon....
|
||||
##### More APIs are coming soon...
|
||||
|
||||
If your dns provider is not in the supported list above, you can write your own script api easily.
|
||||
If your DNS provider is not on the supported list above, you can write your own script API easily. If you do please consider submitting a [Pull Request](https://github.com/Neilpang/acme.sh/pulls) and contribute to the project.
|
||||
|
||||
For more details: [How to use dns api](dnsapi)
|
||||
|
||||
|
||||
# Issue ECC certificate:
|
||||
LetsEncrypt now can issue ECDSA certificate.
|
||||
|
||||
`Let's Encrypt` now can issue **ECDSA** certificates.
|
||||
|
||||
And we also support it.
|
||||
|
||||
Just set the `length` parameter with a prefix `ec-`.
|
||||
|
||||
For example:
|
||||
|
||||
Single domain:
|
||||
```
|
||||
le issue /home/wwwroot/aa.com aa.com no ec-256
|
||||
### Single domain ECC cerfiticate:
|
||||
|
||||
```bash
|
||||
acme.sh --issue -w /home/wwwroot/aa.com -d aa.com --keylength ec-256
|
||||
```
|
||||
|
||||
SAN multiple domains:
|
||||
```
|
||||
le issue /home/wwwroot/aa.com aa.com www.aa.com,cp.aa.com ec-256
|
||||
SAN multi domain ECC certificate:
|
||||
|
||||
```bash
|
||||
acme.sh --issue -w /home/wwwroot/aa.com -d aa.com -d www.aa.com --keylength ec-256
|
||||
```
|
||||
|
||||
Please look at the last parameter above.
|
||||
|
||||
Valid values are:
|
||||
|
||||
1. ec-256 (prime256v1, "ECDSA P-256")
|
||||
2. ec-384 (secp384r1, "ECDSA P-384")
|
||||
3. ec-521 (secp521r1, "ECDSA P-521", which is not supported by letsencrypt yet.)
|
||||
1. **ec-256 (prime256v1, "ECDSA P-256")**
|
||||
2. **ec-384 (secp384r1, "ECDSA P-384")**
|
||||
3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
|
||||
|
||||
# Under the Hood
|
||||
|
||||
|
||||
#Under the Hood
|
||||
|
||||
Speak ACME language with bash directly to Let's encrypt.
|
||||
Speak ACME language using shell, directly to "Let's Encrypt".
|
||||
|
||||
TODO:
|
||||
|
||||
|
||||
#Acknowledgment
|
||||
# Acknowledgment
|
||||
1. Acme-tiny: https://github.com/diafygi/acme-tiny
|
||||
2. ACME protocol: https://github.com/ietf-wg-acme/acme
|
||||
3. letsencrypt: https://github.com/letsencrypt/letsencrypt
|
||||
3. Certbot: https://github.com/certbot/certbot
|
||||
|
||||
|
||||
|
||||
#License & Other
|
||||
# License & Other
|
||||
|
||||
License is GPLv3
|
||||
|
||||
Please Star and Fork me.
|
||||
|
||||
Issues and pull requests are welcomed.
|
||||
[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcomed.
|
||||
|
||||
|
||||
|
||||
|
||||
+14
-10
@@ -15,10 +15,10 @@ export CF_Email="xxxx@sss.com"
|
||||
|
||||
Ok, let's issue cert now:
|
||||
```
|
||||
le.sh issue dns-cf aa.com www.aa.com
|
||||
acme.sh --issue --dns dns_cf -d aa.com -d www.aa.com
|
||||
```
|
||||
|
||||
The `CF_Key` and `CF_Email` will be saved in `~/.le/account.conf`, when next time you use cloudflare api, it will reuse this key.
|
||||
The `CF_Key` and `CF_Email` will be saved in `~/.acme.sh/account.conf`, when next time you use cloudflare api, it will reuse this key.
|
||||
|
||||
|
||||
|
||||
@@ -37,10 +37,10 @@ export DP_Key="sADDsdasdgdsf"
|
||||
|
||||
Ok, let's issue cert now:
|
||||
```
|
||||
le.sh issue dns-dp aa.com www.aa.com
|
||||
acme.sh --issue --dns dns_dp -d aa.com -d www.aa.com
|
||||
```
|
||||
|
||||
The `DP_Id` and `DP_Key` will be saved in `~/.le/account.conf`, when next time you use dnspod.cn api, it will reuse this key.
|
||||
The `DP_Id` and `DP_Key` will be saved in `~/.acme.sh/account.conf`, when next time you use dnspod.cn api, it will reuse this key.
|
||||
|
||||
|
||||
## Use Cloudxns.com domain api to automatically issue cert
|
||||
@@ -58,10 +58,10 @@ export CX_Secret="sADDsdasdgdsf"
|
||||
|
||||
Ok, let's issue cert now:
|
||||
```
|
||||
le.sh issue dns-cx aa.com www.aa.com
|
||||
acme.sh --issue --dns dns_cx -d aa.com -d www.aa.com
|
||||
```
|
||||
|
||||
The `CX_Key` and `CX_Secret` will be saved in `~/.le/account.conf`, when next time you use Cloudxns.com api, it will reuse this key.
|
||||
The `CX_Key` and `CX_Secret` will be saved in `~/.acme.sh/account.conf`, when next time you use Cloudxns.com api, it will reuse this key.
|
||||
|
||||
|
||||
|
||||
@@ -71,16 +71,20 @@ If your api is not supported yet, you can write your own dns api.
|
||||
|
||||
Let's assume you want to name it 'myapi',
|
||||
|
||||
1. Create a bash script named `~/.le/dns-myapi.sh`,
|
||||
2. In the scrypt, you must have a function named `dns-myapi-add()`. Which will be called by le.sh to add dns records.
|
||||
1. Create a bash script named `~/.acme.sh/dns_myapi.sh`,
|
||||
2. In the scrypt, you must have a function named `dns_myapi_add()`. Which will be called by acme.sh to add dns records.
|
||||
3. Then you can use your api to issue cert like:
|
||||
|
||||
```
|
||||
le.sh issue dns-myapi aa.com www.aa.com
|
||||
acme.sh --issue --dns dns_myapi -d aa.com -d www.aa.com
|
||||
```
|
||||
|
||||
For more details, please check our sample script: [dns-myapi.sh](dns-myapi.sh)
|
||||
For more details, please check our sample script: [dns_myapi.sh](dns_myapi.sh)
|
||||
|
||||
|
||||
|
||||
# Use lexicon dns api
|
||||
|
||||
https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
|
||||
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#Here is a sample custom api script.
|
||||
#This file name is "dns-myapi.sh"
|
||||
#So, here must be a method dns-myapi-add()
|
||||
#Which will be called by le.sh to add the txt record to your api system.
|
||||
#returns 0 meanst success, otherwise error.
|
||||
|
||||
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns-myapi-add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_err "Not implemented!"
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#################### Private functions bellow ##################################
|
||||
|
||||
|
||||
_debug() {
|
||||
|
||||
if [ -z "$DEBUG" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] ; then
|
||||
echo $1
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_info() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1"
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_err() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1" >&2
|
||||
else
|
||||
echo "$1"="$2" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
|
||||
#
|
||||
@@ -7,12 +7,12 @@
|
||||
#CF_Email="xxxx@sss.com"
|
||||
|
||||
|
||||
CF_Api="https://api.cloudflare.com/client/v4/"
|
||||
CF_Api="https://api.cloudflare.com/client/v4"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns-cf-add() {
|
||||
dns_cf_add(){
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
@@ -36,18 +36,18 @@ dns-cf-add() {
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_cf_rest GET "/zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain"
|
||||
_cf_rest GET "zones/${_domain_id}/dns_records?type=TXT&name=$fulldomain"
|
||||
|
||||
if [ "$?" != "0" ] || ! printf $response | grep \"success\":true > /dev/null ; then
|
||||
if ! printf "$response" | grep \"success\":true > /dev/null ; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
count=$(printf $response | grep -o \"count\":[^,]* | cut -d : -f 2)
|
||||
|
||||
if [ "$count" == "0" ] ; then
|
||||
count=$(printf "$response" | grep -o \"count\":[^,]* | cut -d : -f 2)
|
||||
_debug count "$count"
|
||||
if [ "$count" = "0" ] ; then
|
||||
_info "Adding record"
|
||||
if _cf_rest POST "/zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
if _cf_rest POST "zones/$_domain_id/dns_records" "{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"; then
|
||||
if printf $response | grep $fulldomain > /dev/null ; then
|
||||
_info "Added, sleeping 10 seconds"
|
||||
sleep 10
|
||||
@@ -61,11 +61,11 @@ dns-cf-add() {
|
||||
_err "Add txt record error."
|
||||
else
|
||||
_info "Updating record"
|
||||
record_id=$(printf $response | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
|
||||
record_id=$(printf "$response" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \"| head -1)
|
||||
_debug "record_id" $record_id
|
||||
|
||||
_cf_rest PUT "/zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}"
|
||||
if [ "$?" == "0" ]; then
|
||||
_cf_rest PUT "zones/$_domain_id/dns_records/$record_id" "{\"id\":\"$record_id\",\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"zone_id\":\"$_domain_id\",\"zone_name\":\"$_domain\"}"
|
||||
if [ "$?" = "0" ]; then
|
||||
_info "Updated, sleeping 10 seconds"
|
||||
sleep 10
|
||||
#todo: check if the record takes effect
|
||||
@@ -102,7 +102,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if printf $response | grep \"name\":\"$h\" ; then
|
||||
if printf $response | grep \"name\":\"$h\" >/dev/null ; then
|
||||
_domain_id=$(printf "$response" | grep -o \"id\":\"[^\"]*\" | head -1 | cut -d : -f 2 | tr -d \")
|
||||
if [ "$_domain_id" ] ; then
|
||||
_sub_domain=$(printf $domain | cut -d . -f 1-$p)
|
||||
@@ -112,60 +112,34 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
let "i+=1"
|
||||
i=$(expr $i + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
_cf_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug $ep
|
||||
if [ "$3" ] ; then
|
||||
data="$3"
|
||||
|
||||
_H1="X-Auth-Email: $CF_Email"
|
||||
_H2="X-Auth-Key: $CF_Key"
|
||||
_H3="Content-Type: application/json"
|
||||
|
||||
if [ "$data" ] ; then
|
||||
_debug data "$data"
|
||||
response="$(curl --silent -X $m "$CF_Api/$ep" -H "X-Auth-Email: $CF_Email" -H "X-Auth-Key: $CF_Key" -H "Content-Type: application/json" --data $data)"
|
||||
response="$(_post "$data" "$CF_Api/$ep" "" $m)"
|
||||
else
|
||||
response="$(curl --silent -X $m "$CF_Api/$ep" -H "X-Auth-Email: $CF_Email" -H "X-Auth-Key: $CF_Key" -H "Content-Type: application/json")"
|
||||
response="$(_get "$CF_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ] ; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug response "$response"
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
_debug() {
|
||||
|
||||
if [ -z "$DEBUG" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] ; then
|
||||
echo $1
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_info() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1"
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_err() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1" >&2
|
||||
else
|
||||
echo "$1"="$2" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
Regular → Executable
+17
-42
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Cloudxns.com Domain api
|
||||
#
|
||||
@@ -14,7 +14,7 @@ CX_Api="https://www.cloudxns.net/api2"
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns-cx-add() {
|
||||
dns_cx_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
@@ -44,13 +44,13 @@ dns-cx-add() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$count" == "0" ] ; then
|
||||
if [ "$count" = "0" ] ; then
|
||||
add_record $_domain $_sub_domain $txtvalue
|
||||
else
|
||||
update_record $_domain $_sub_domain $txtvalue
|
||||
fi
|
||||
|
||||
if [ "$?" == "0" ] ; then
|
||||
if [ "$?" = "0" ] ; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
@@ -69,7 +69,7 @@ existing_records() {
|
||||
return 1
|
||||
fi
|
||||
count=0
|
||||
seg=$(printf "$response" | grep -o "{[^{]*host\":\"$_sub_domain[^}]*}")
|
||||
seg=$(printf "$response" | grep -o "{[^{]*host\":\"$_sub_domain\"[^}]*}")
|
||||
_debug seg "$seg"
|
||||
if [ -z "$seg" ] ; then
|
||||
return 0
|
||||
@@ -144,7 +144,7 @@ _get_root() {
|
||||
return 1;
|
||||
fi
|
||||
|
||||
if printf "$response" | grep "$h." ; then
|
||||
if printf "$response" | grep "$h." >/dev/null ; then
|
||||
seg=$(printf "$response" | grep -o "{[^{]*$h\.[^}]*\}" )
|
||||
_debug seg "$seg"
|
||||
_domain_id=$(printf "$seg" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
|
||||
@@ -159,7 +159,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
let "i+=1"
|
||||
i=$(expr $i + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
@@ -183,18 +183,23 @@ _rest() {
|
||||
_debug sec "$sec"
|
||||
hmac=$(printf "$sec"| openssl md5 |cut -d " " -f 2)
|
||||
_debug hmac "$hmac"
|
||||
|
||||
if [ "$3" ] ; then
|
||||
response="$(curl --silent -X $m "$url" -H "API-KEY: $CX_Key" -H "API-REQUEST-DATE: $cdate" -H "API-HMAC: $hmac" -H 'Content-Type: application/json' -d "$data")"
|
||||
|
||||
_H1="API-KEY: $CX_Key"
|
||||
_H2="API-REQUEST-DATE: $cdate"
|
||||
_H3="API-HMAC: $hmac"
|
||||
_H4="Content-Type: application/json"
|
||||
|
||||
if [ "$data" ] ; then
|
||||
response="$(_post "$data" "$url" "" $m)"
|
||||
else
|
||||
response="$(curl --silent -X $m "$url" -H "API-KEY: $CX_Key" -H "API-REQUEST-DATE: $cdate" -H "API-HMAC: $hmac" -H 'Content-Type: application/json')"
|
||||
response="$(_get "$url")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ] ; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug response "$response"
|
||||
_debug2 response "$response"
|
||||
if ! printf "$response" | grep '"message":"success"' > /dev/null ; then
|
||||
return 1
|
||||
fi
|
||||
@@ -202,33 +207,3 @@ _rest() {
|
||||
}
|
||||
|
||||
|
||||
_debug() {
|
||||
|
||||
if [ -z "$DEBUG" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] ; then
|
||||
echo $1
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_info() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1"
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_err() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1" >&2
|
||||
else
|
||||
echo "$1"="$2" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
Regular → Executable
+11
-42
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Dnspod.cn Domain api
|
||||
#
|
||||
@@ -14,7 +14,7 @@ DP_Api="https://dnsapi.cn"
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns-dp-add() {
|
||||
dns_dp_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
@@ -44,7 +44,7 @@ dns-dp-add() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$count" == "0" ] ; then
|
||||
if [ "$count" = "0" ] ; then
|
||||
add_record $_domain $_sub_domain $txtvalue
|
||||
else
|
||||
update_record $_domain $_sub_domain $txtvalue
|
||||
@@ -71,7 +71,6 @@ existing_records() {
|
||||
|
||||
if printf "$response" | grep "Action completed successful" >/dev/null ; then
|
||||
count=$(printf "$response" | grep '<type>TXT</type>' | wc -l)
|
||||
|
||||
record_id=$(printf "$response" | grep '^<id>' | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1)
|
||||
return 0
|
||||
else
|
||||
@@ -152,7 +151,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if printf "$response" | grep "Action completed successful" ; then
|
||||
if printf "$response" | grep "Action completed successful" >/dev/null ; then
|
||||
_domain_id=$(printf "$response" | grep -o \"id\":\"[^\"]*\" | cut -d : -f 2 | tr -d \")
|
||||
_debug _domain_id "$_domain_id"
|
||||
if [ "$_domain_id" ] ; then
|
||||
@@ -165,7 +164,7 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
let "i+=1"
|
||||
i=$(expr $i + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
@@ -175,55 +174,25 @@ _get_root() {
|
||||
_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug $ep
|
||||
url="$REST_API/$ep"
|
||||
|
||||
_debug url "$url"
|
||||
|
||||
if [ "$3" ] ; then
|
||||
data="$3"
|
||||
_debug data "$data"
|
||||
response="$(curl --silent -X $m "$url" -d $data)"
|
||||
if [ "$data" ] ; then
|
||||
_debug2 data "$data"
|
||||
response="$(_post $data "$url")"
|
||||
else
|
||||
response="$(curl --silent -X $m "$url" )"
|
||||
response="$(_get "$url")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ] ; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug response "$response"
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
_debug() {
|
||||
|
||||
if [ -z "$DEBUG" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$2" ] ; then
|
||||
echo $1
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_info() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1"
|
||||
else
|
||||
echo "$1"="$2"
|
||||
fi
|
||||
}
|
||||
|
||||
_err() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "$1" >&2
|
||||
else
|
||||
echo "$1"="$2" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# dns api wrapper of lexicon for acme.sh
|
||||
|
||||
lexicon_url="https://github.com/AnalogJ/lexicon"
|
||||
lexicon_cmd="lexicon"
|
||||
|
||||
wiki="https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_lexicon_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
domain=$(printf "$fulldomain" | cut -d . -f 2-999)
|
||||
|
||||
if ! _exists $lexicon_cmd ; then
|
||||
_err "Please install $lexicon_cmd first: $wiki"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$PROVIDER" ] ; then
|
||||
_err "Please define env PROVIDER first: $wiki"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_savedomainconf PROVIDER "$PROVIDER"
|
||||
export PROVIDER
|
||||
|
||||
Lx_name=$(echo LEXICON_${PROVIDER}_USERNAME | tr [a-z] [A-Z])
|
||||
eval Lx_name_v="\$$Lx_name"
|
||||
_debug "$Lx_name" "$Lx_name_v"
|
||||
if [ "$Lx_name_v" ] ; then
|
||||
_saveaccountconf $Lx_name "$Lx_name_v"
|
||||
export "$Lx_name"
|
||||
fi
|
||||
|
||||
Lx_token=$(echo LEXICON_${PROVIDER}_TOKEN | tr [a-z] [A-Z])
|
||||
eval Lx_token_v="\$$Lx_token"
|
||||
_debug "$Lx_token" "$Lx_token_v"
|
||||
if [ "$Lx_token_v" ] ; then
|
||||
_saveaccountconf $Lx_token "$Lx_token_v"
|
||||
export "$Lx_token"
|
||||
fi
|
||||
|
||||
Lx_password=$(echo LEXICON_${PROVIDER}_PASSWORD | tr [a-z] [A-Z])
|
||||
eval Lx_password_v="\$$Lx_password"
|
||||
_debug "$Lx_password" "$Lx_password_v"
|
||||
if [ "$Lx_password_v" ] ; then
|
||||
_saveaccountconf $Lx_password "$Lx_password_v"
|
||||
export "$Lx_password"
|
||||
fi
|
||||
|
||||
Lx_domaintoken=$(echo LEXICON_${PROVIDER}_DOMAINTOKEN | tr [a-z] [A-Z])
|
||||
eval Lx_domaintoken_v="\$$Lx_domaintoken"
|
||||
_debug "$Lx_domaintoken" "$Lx_domaintoken_v"
|
||||
if [ "$Lx_domaintoken_v" ] ; then
|
||||
export "$Lx_domaintoken"
|
||||
_saveaccountconf $Lx_domaintoken "$Lx_domaintoken_v"
|
||||
fi
|
||||
|
||||
$lexicon_cmd "$PROVIDER" create ${domain} TXT --name="_acme-challenge.${domain}." --content="${txtvalue}"
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Here is a sample custom api script.
|
||||
#This file name is "dns_myapi.sh"
|
||||
#So, here must be a method dns_myapi_add()
|
||||
#Which will be called by acme.sh to add the txt record to your api system.
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_myapi_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_err "Not implemented!"
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#################### Private functions bellow ##################################
|
||||
_info() {
|
||||
if [ -z "$2" ] ; then
|
||||
echo "[$(date)] $1"
|
||||
else
|
||||
echo "[$(date)] $1='$2'"
|
||||
fi
|
||||
}
|
||||
|
||||
_err() {
|
||||
_info "$@" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
_debug() {
|
||||
if [ -z "$DEBUG" ] ; then
|
||||
return
|
||||
fi
|
||||
_err "$@"
|
||||
return 0
|
||||
}
|
||||
|
||||
_debug2() {
|
||||
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
|
||||
_debug "$@"
|
||||
fi
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user