diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index ccce2ff6..b200f56b 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -232,7 +232,7 @@ jobs: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' prepare: pkg install -y socat curl usesh: true - copyback: false + sync: nfs run: | if [ "${{ secrets.TokenName1}}" ] ; then export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}" @@ -283,7 +283,7 @@ jobs: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' prepare: pkg_add socat curl libiconv usesh: true - copyback: false + sync: nfs run: | if [ "${{ secrets.TokenName1}}" ] ; then export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}" @@ -335,7 +335,7 @@ jobs: prepare: | /usr/sbin/pkg_add curl socat usesh: true - copyback: false + sync: nfs run: | if [ "${{ secrets.TokenName1}}" ] ; then export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}" @@ -387,7 +387,7 @@ jobs: prepare: | pkg install -y curl socat libnghttp2 usesh: true - copyback: false + sync: nfs run: | if [ "${{ secrets.TokenName1}}" ] ; then export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}" @@ -440,7 +440,7 @@ jobs: - uses: vmactions/solaris-vm@v1 with: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' - copyback: false + sync: nfs prepare: | pkgutil -U pkgutil -y -i socat @@ -493,7 +493,56 @@ jobs: - uses: vmactions/omnios-vm@v1 with: envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' - copyback: false + sync: nfs + prepare: pkg install socat + run: | + if [ "${{ secrets.TokenName1}}" ] ; then + export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}" + fi + if [ "${{ secrets.TokenName2}}" ] ; then + export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}" + fi + if [ "${{ secrets.TokenName3}}" ] ; then + export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}" + fi + if [ "${{ secrets.TokenName4}}" ] ; then + export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}" + fi + if [ "${{ secrets.TokenName5}}" ] ; then + export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}" + fi + cd ../acmetest + ./letest.sh + + + OpenIndiana: + runs-on: ubuntu-latest + needs: Omnios + env: + TEST_DNS : ${{ secrets.TEST_DNS }} + TestingDomain: ${{ secrets.TestingDomain }} + TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }} + TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }} + TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }} + CASE: le_test_dnsapi + TEST_LOCAL: 1 + DEBUG: ${{ secrets.DEBUG }} + http_proxy: ${{ secrets.http_proxy }} + https_proxy: ${{ secrets.https_proxy }} + HTTPS_INSECURE: 1 # always set to 1 to ignore https error, since OpenIndiana doesn't accept the expired ISRG X1 root + TokenName1: ${{ secrets.TokenName1}} + TokenName2: ${{ secrets.TokenName2}} + TokenName3: ${{ secrets.TokenName3}} + TokenName4: ${{ secrets.TokenName4}} + TokenName5: ${{ secrets.TokenName5}} + steps: + - uses: actions/checkout@v4 + - name: Clone acmetest + run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ + - uses: vmactions/openindiana-vm@v0 + with: + envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}' + sync: nfs prepare: pkg install socat run: | if [ "${{ secrets.TokenName1}}" ] ; then diff --git a/.github/workflows/DragonFlyBSD.yml b/.github/workflows/DragonFlyBSD.yml index 5c56168f..b047a210 100644 --- a/.github/workflows/DragonFlyBSD.yml +++ b/.github/workflows/DragonFlyBSD.yml @@ -63,7 +63,7 @@ jobs: prepare: | pkg install -y curl socat libnghttp2 usesh: true - copyback: false + sync: nfs run: | cd ../acmetest \ && ./letest.sh diff --git a/.github/workflows/FreeBSD.yml b/.github/workflows/FreeBSD.yml index 961907e8..a4fca67c 100644 --- a/.github/workflows/FreeBSD.yml +++ b/.github/workflows/FreeBSD.yml @@ -68,7 +68,7 @@ jobs: "8080": "80" prepare: pkg install -y socat curl wget usesh: true - copyback: false + sync: nfs run: | cd ../acmetest \ && ./letest.sh diff --git a/.github/workflows/NetBSD.yml b/.github/workflows/NetBSD.yml index a4f90f68..13b70350 100644 --- a/.github/workflows/NetBSD.yml +++ b/.github/workflows/NetBSD.yml @@ -63,7 +63,7 @@ jobs: prepare: | /usr/sbin/pkg_add curl socat usesh: true - copyback: false + sync: nfs run: | cd ../acmetest \ && ./letest.sh diff --git a/.github/workflows/Omnios.yml b/.github/workflows/Omnios.yml index 882cedf6..5d0af1b1 100644 --- a/.github/workflows/Omnios.yml +++ b/.github/workflows/Omnios.yml @@ -67,7 +67,7 @@ jobs: nat: | "8080": "80" prepare: pkg install socat wget - copyback: false + sync: nfs run: | cd ../acmetest \ && ./letest.sh diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index d5697c10..98e18545 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -68,7 +68,7 @@ jobs: "8080": "80" prepare: pkg_add socat curl wget libnghttp2 usesh: true - copyback: false + sync: nfs run: | cd ../acmetest \ && ./letest.sh diff --git a/.github/workflows/OpenIndiana.yml b/.github/workflows/OpenIndiana.yml new file mode 100644 index 00000000..19b1efaa --- /dev/null +++ b/.github/workflows/OpenIndiana.yml @@ -0,0 +1,75 @@ +name: OpenIndiana +on: + push: + branches: + - '*' + paths: + - '*.sh' + - '.github/workflows/OpenIndiana.yml' + + pull_request: + branches: + - dev + paths: + - '*.sh' + - '.github/workflows/OpenIndiana.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + + + +jobs: + OpenIndiana: + strategy: + matrix: + include: + - TEST_ACME_Server: "LetsEncrypt.org_test" + CA_ECDSA: "" + CA: "" + CA_EMAIL: "" + TEST_PREFERRED_CHAIN: (STAGING) + - TEST_ACME_Server: "LetsEncrypt.org_test" + CA_ECDSA: "" + CA: "" + CA_EMAIL: "" + TEST_PREFERRED_CHAIN: (STAGING) + ACME_USE_WGET: 1 + #- TEST_ACME_Server: "ZeroSSL.com" + # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA" + # CA: "ZeroSSL RSA Domain Secure Site CA" + # CA_EMAIL: "githubtest@acme.sh" + # TEST_PREFERRED_CHAIN: "" + runs-on: ubuntu-latest + env: + TEST_LOCAL: 1 + TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }} + CA_ECDSA: ${{ matrix.CA_ECDSA }} + CA: ${{ matrix.CA }} + CA_EMAIL: ${{ matrix.CA_EMAIL }} + TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }} + ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }} + steps: + - uses: actions/checkout@v4 + - uses: vmactions/cf-tunnel@v0 + id: tunnel + with: + protocol: http + port: 8080 + - name: Set envs + run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV + - name: Clone acmetest + run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ + - uses: vmactions/openindiana-vm@v0 + with: + envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET' + nat: | + "8080": "80" + prepare: pkg install socat curl + sync: nfs + run: | + cd ../acmetest \ + && ./letest.sh + + diff --git a/.github/workflows/Solaris.yml b/.github/workflows/Solaris.yml index 0ba3d2eb..21a16d1a 100644 --- a/.github/workflows/Solaris.yml +++ b/.github/workflows/Solaris.yml @@ -69,7 +69,7 @@ jobs: prepare: | pkgutil -U pkgutil -y -i socat curl wget - copyback: false + sync: nfs run: | cd ../acmetest \ && ./letest.sh diff --git a/Dockerfile b/Dockerfile index 88edc4a2..36b2adac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,7 @@ RUN apk --no-cache add -f \ tar \ libidn \ jq \ + yq-go \ cronie ENV LE_WORKING_DIR=/acmebin diff --git a/README.md b/README.md index 4afd90a8..41b6b272 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,71 @@ -[![zerossl.com](https://github.com/user-attachments/assets/7531085e-399b-4ac2-82a2-90d14a0b7f05)](https://zerossl.com/?fromacme.sh) - -# An ACME Shell script: acme.sh +

+ + zerossl.com + +

-[![FreeBSD](https://github.com/acmesh-official/acme.sh/actions/workflows/FreeBSD.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/FreeBSD.yml) -[![OpenBSD](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml) -[![NetBSD](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml) -[![MacOS](https://github.com/acmesh-official/acme.sh/actions/workflows/MacOS.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/MacOS.yml) -[![Ubuntu](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml) -[![Windows](https://github.com/acmesh-official/acme.sh/actions/workflows/Windows.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Windows.yml) -[![Solaris](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml) -[![DragonFlyBSD](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml) -[![Omnios](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml) +

๐Ÿ” acme.sh

+

An ACME Protocol Client Written Purely in Shell

-![Shellcheck](https://github.com/acmesh-official/acme.sh/workflows/Shellcheck/badge.svg) -![PebbleStrict](https://github.com/acmesh-official/acme.sh/workflows/PebbleStrict/badge.svg) -![DockerHub](https://github.com/acmesh-official/acme.sh/workflows/Build%20DockerHub/badge.svg) +

+ FreeBSD + OpenBSD + NetBSD + MacOS + Ubuntu + Windows + Solaris + DragonFlyBSD + Omnios + OpenIndiana +

+

+ Shellcheck + PebbleStrict + DockerHub +

- -[![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Docker stars](https://img.shields.io/docker/stars/neilpang/acme.sh.svg)](https://hub.docker.com/r/neilpang/acme.sh "Click to view the image on Docker Hub") -[![Docker pulls](https://img.shields.io/docker/pulls/neilpang/acme.sh.svg)](https://hub.docker.com/r/neilpang/acme.sh "Click to view the image on Docker Hub") +

+ Financial Contributors on Open Collective + Join the chat at Gitter + Docker stars + Docker pulls +

+--- -- An ACME protocol client written purely in Shell (Unix shell) language. -- Full ACME protocol implementation. -- Support ECDSA certs -- Support SAN and wildcard certs -- Simple, powerful and very easy to use. You only need 3 minutes to learn it. -- Bash, dash and sh compatible. -- Purely written in Shell with no dependencies on python. -- Just one script to issue, renew and install your certificates automatically. -- DOES NOT require `root/sudoer` access. -- Docker ready -- IPv6 ready -- Cron job notifications for renewal or error etc. +## โœจ Features -It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates. +- ๐Ÿš An ACME protocol client written **purely in Shell** (Unix shell) language +- ๐Ÿ“œ Full ACME protocol implementation +- ๐Ÿ”‘ Support **ECDSA** certificates +- ๐ŸŒ Support **SAN** and **wildcard** certificates +- โšก Simple, powerful and very easy to use โ€” only **3 minutes** to learn! +- ๐Ÿ”ง Compatible with **Bash**, **dash** and **sh** +- ๐Ÿšซ No dependencies on Python +- ๐Ÿ”„ One script to issue, renew and install your certificates automatically +- ๐Ÿ‘ค **DOES NOT** require `root/sudoer` access +- ๐Ÿณ Docker ready +- ๐ŸŒ IPv6 ready +- ๐Ÿ“ง Cron job notifications for renewal or error -Wiki: https://github.com/acmesh-official/acme.sh/wiki +> ๐Ÿ’ก It's probably the **easiest & smartest** shell script to automatically issue & renew free certificates. -For Docker Fans: [acme.sh :two_hearts: Docker ](https://github.com/acmesh-official/acme.sh/wiki/Run-acme.sh-in-docker) +

+ ๐Ÿ“š Wiki โ€ข + ๐Ÿณ Docker Guide โ€ข + ๐Ÿฆ Twitter +

-Twitter: [@neilpangxa](https://twitter.com/neilpangxa) +--- +## ๐ŸŒ [ไธญๆ–‡่ฏดๆ˜Ž](https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E) -# [ไธญๆ–‡่ฏดๆ˜Ž](https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E) +--- -# Who: +## ๐Ÿ† Who Uses acme.sh? - [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/) - [ruby-china.org](https://ruby-china.org/topics/31983) - [Proxmox](https://pve.proxmox.com/wiki/Certificate_Management) @@ -62,7 +79,9 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) - [lnmp.org](https://lnmp.org/) - [more...](https://github.com/acmesh-official/acme.sh/wiki/Blogs-and-tutorials) -# Tested OS +--- + +## ๐Ÿ–ฅ๏ธ Tested OS | NO | Status| Platform| |----|-------|---------| @@ -76,8 +95,8 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) |8|[![NetBSD](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml)|NetBSD |9|[![DragonFlyBSD](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml)|DragonFlyBSD |10|[![Omnios](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)|Omnios -|11|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian -|12|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS +|11|[![OpenIndiana](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenIndiana.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenIndiana.yml)|OpenIndiana +|12|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian |13|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE |14|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl) |15|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux @@ -85,56 +104,66 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa) |17|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux |18|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux |19|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia -|10|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux -|22|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111 -|23|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT) -|24|[![](https://acmesh-official.github.io/acmetest/status/proxmox.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management) +|20|[![Linux](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml/badge.svg)](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux +|21|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111 +|22|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT) +|23|[![](https://acmesh-official.github.io/acmetest/status/proxmox.svg)](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management) -Check our [testing project](https://github.com/acmesh-official/acmetest): +> ๐Ÿงช Check our [testing project](https://github.com/acmesh-official/acmetest) +> +> ๐Ÿ–ฅ๏ธ The testing VMs are supported by [vmactions.org](https://vmactions.org) -https://github.com/acmesh-official/acmetest +--- -# Supported CA +## ๐Ÿ›๏ธ Supported CA -- [ZeroSSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA)(default) -- Letsencrypt.org CA -- [SSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/SSL.com-CA) -- [Google.com Public CA](https://github.com/acmesh-official/acme.sh/wiki/Google-Public-CA) -- [Actalis.com CA](https://github.com/acmesh-official/acme.sh/wiki/Actalis.com-CA) -- [Pebble strict Mode](https://github.com/letsencrypt/pebble) -- Any other [RFC8555](https://tools.ietf.org/html/rfc8555)-compliant CA +| CA | Status | +|---|---| +| [ZeroSSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA) | โญ **Default** | +| Letsencrypt.org CA | โœ… Supported | +| [SSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/SSL.com-CA) | โœ… Supported | +| [Google.com Public CA](https://github.com/acmesh-official/acme.sh/wiki/Google-Public-CA) | โœ… Supported | +| [Actalis.com CA](https://github.com/acmesh-official/acme.sh/wiki/Actalis.com-CA) | โœ… Supported | +| [Pebble strict Mode](https://github.com/letsencrypt/pebble) | โœ… Supported | +| Any [RFC8555](https://tools.ietf.org/html/rfc8555)-compliant CA | โœ… Supported | -# Supported modes +--- -- Webroot mode -- Standalone mode -- Standalone tls-alpn mode -- Apache mode -- Nginx mode -- DNS mode -- [DNS alias mode](https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode) -- [Stateless mode](https://github.com/acmesh-official/acme.sh/wiki/Stateless-Mode) +## โš™๏ธ Supported Modes +| Mode | Description | +|------|-------------| +| ๐Ÿ“ Webroot mode | Use existing webroot directory | +| ๐Ÿ–ฅ๏ธ Standalone mode | Built-in webserver on port 80 | +| ๐Ÿ” Standalone tls-alpn mode | Built-in webserver on port 443 | +| ๐Ÿชถ Apache mode | Use Apache for verification | +| โšก Nginx mode | Use Nginx for verification | +| ๐ŸŒ DNS mode | Use DNS TXT records | +| ๐Ÿ”— [DNS alias mode](https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode) | Use DNS alias for verification | +| ๐Ÿ“ก [Stateless mode](https://github.com/acmesh-official/acme.sh/wiki/Stateless-Mode) | Stateless verification | -# 1. How to install +--- -### 1. Install online +## ๐Ÿ“– Usage Guide -Check this project: https://github.com/acmesh-official/get.acme.sh +### 1๏ธโƒฃ How to Install + +#### ๐Ÿ“ฅ Install Online + +> Check this project: https://github.com/acmesh-official/get.acme.sh ```bash curl https://get.acme.sh | sh -s email=my@example.com ``` -Or: +**Or:** ```bash wget -O - https://get.acme.sh | sh -s email=my@example.com ``` - -### 2. Or, Install from git +#### ๐Ÿ“ฆ Install from Git Clone this project and launch installation: @@ -144,11 +173,11 @@ cd ./acme.sh ./acme.sh --install -m my@example.com ``` -You `don't have to be root` then, although `it is recommended`. +> ๐Ÿ’ก You `don't have to be root` then, although `it is recommended`. -Advanced Installation: https://github.com/acmesh-official/acme.sh/wiki/How-to-install +๐Ÿ“š **Advanced Installation:** https://github.com/acmesh-official/acme.sh/wiki/How-to-install -The installer will perform 3 actions: +**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 too. @@ -161,17 +190,19 @@ Cron entry example: 0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null ``` -After the installation, you must close the current terminal and reopen it to make the alias take effect. +> โš ๏ธ After the installation, you must close the current terminal and reopen it to make the alias take effect. -Ok, you are ready to issue certs now. +โœ… **You are ready to issue certs now!** -Show help message: +**Show help message:** ```sh -root@v1:~# acme.sh -h +acme.sh -h ``` -# 2. Just issue a cert +--- + +### 2๏ธโƒฃ Issue a Certificate **Example 1:** Single domain. @@ -206,19 +237,21 @@ You must point and bind all the domains to the same webroot dir: `/home/wwwroot/ The certs will be placed in `~/.acme.sh/example.com/` -The certs will be renewed automatically every **60** days. +> ๐Ÿ”„ The certs will be renewed automatically every **30** days. -The certs will default to ECC certificates. +> ๐Ÿ” The certs will default to **ECC** certificates. -More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert +๐Ÿ“š **More examples:** https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert +--- -# 3. Install the cert to Apache/Nginx etc. +### 3๏ธโƒฃ Install the Certificate to Apache/Nginx After the cert is generated, you probably want to install/copy the cert to your Apache/Nginx or other servers. -You **MUST** use this command to copy the certs to the target files, **DO NOT** use the certs files in **~/.acme.sh/** folder, they are for internal use only, the folder structure may change in the future. -**Apache** example: +> โš ๏ธ **IMPORTANT:** You **MUST** use this command to copy the certs to the target files. **DO NOT** use the certs files in `~/.acme.sh/` folder โ€” they are for internal use only, the folder structure may change in the future. + +#### ๐Ÿชถ Apache Example: ```bash acme.sh --install-cert -d example.com \ --cert-file /path/to/certfile/in/apache/cert.pem \ @@ -227,7 +260,7 @@ acme.sh --install-cert -d example.com \ --reloadcmd "service apache2 force-reload" ``` -**Nginx** example: +#### โšก Nginx Example: ```bash acme.sh --install-cert -d example.com \ --key-file /path/to/keyfile/in/nginx/key.pem \ @@ -241,91 +274,89 @@ The ownership and permission info of existing files are preserved. You can pre-c Install/copy the cert/key to the production Apache or Nginx path. -The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`. +> ๐Ÿ”„ The cert will be renewed every **30** days by default (configurable). Once renewed, the Apache/Nginx service will be reloaded automatically. +> โš ๏ธ **IMPORTANT:** The `reloadcmd` is very important. The cert can be automatically renewed, but without a correct `reloadcmd`, the cert may not be flushed to your server (like nginx or apache), then your website will not be able to show the renewed cert. -**Please take care: The reloadcmd is very important. The cert can be automatically renewed, but, without a correct 'reloadcmd' the cert may not be flushed to your server(like nginx or apache), then your website will not be able to show renewed cert in 60 days.** +--- -# 4. Use Standalone server to issue cert +### 4๏ธโƒฃ Use Standalone Server to Issue Certificate -**(requires you to be root/sudoer or have permission to listen on port 80 (TCP))** +> ๐Ÿ” Requires root/sudoer or permission to listen on port **80** (TCP) -Port `80` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again. +> โš ๏ธ Port `80` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again. ```bash acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com ``` -More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert +๐Ÿ“š **More examples:** https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert -# 5. Use Standalone ssl server to issue cert +--- -**(requires you to be root/sudoer or have permission to listen on port 443 (TCP))** +### 5๏ธโƒฃ Use Standalone TLS Server to Issue Certificate -Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again. +> ๐Ÿ” Requires root/sudoer or permission to listen on port **443** (TCP) + +> โš ๏ธ Port `443` (TCP) **MUST** be free to listen on, otherwise you will be prompted to free it and try again. ```bash acme.sh --issue --alpn -d example.com -d www.example.com -d cp.example.com ``` -More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert +๐Ÿ“š **More examples:** https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert +--- -# 6. Use Apache mode +### 6๏ธโƒฃ Use Apache Mode -**(requires you to be root/sudoer, since it is required to interact with Apache server)** +> ๐Ÿ” Requires root/sudoer to interact with Apache server If you are running a web server, it is recommended to use the `Webroot mode`. Particularly, if you are running an Apache server, you can use Apache mode instead. This mode doesn't write any files to your web root folder. -Just set string "apache" as the second argument and it will force use of apache plugin automatically. - ```sh acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com ``` -**This apache mode is only to issue the cert, it will not change your apache config files. -You will need to configure your website config files to use the cert by yourself. -We don't want to mess with your apache server, don't worry.** +> ๐Ÿ’ก **Note:** This Apache mode is only to issue the cert, it will **not** change your Apache config files. You will need to configure your website config files to use the cert by yourself. We don't want to mess with your Apache server, don't worry! -More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert +๐Ÿ“š **More examples:** https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert -# 7. Use Nginx mode +--- -**(requires you to be root/sudoer, since it is required to interact with Nginx server)** +### 7๏ธโƒฃ Use Nginx Mode -If you are running a web server, it is recommended to use the `Webroot mode`. - -Particularly, if you are running an nginx server, you can use nginx mode instead. This mode doesn't write any files to your web root folder. +> ๐Ÿ” Requires root/sudoer to interact with Nginx server -Just set string "nginx" as the second argument. +If you are running a web server, it is recommended to use the `Webroot mode`. -It will configure nginx server automatically to verify the domain and then restore the nginx config to the original version. +Particularly, if you are running an Nginx server, you can use Nginx mode instead. This mode doesn't write any files to your web root folder. -So, the config is not changed. +It will configure Nginx server automatically to verify the domain and then restore the Nginx config to the original version. So, the config is not changed. ```sh acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com ``` -**This nginx mode is only to issue the cert, it will not change your nginx config files. -You will need to configure your website config files to use the cert by yourself. -We don't want to mess with your nginx server, don't worry.** +> ๐Ÿ’ก **Note:** This Nginx mode is only to issue the cert, it will **not** change your Nginx config files. You will need to configure your website config files to use the cert by yourself. We don't want to mess with your Nginx server, don't worry! -More examples: https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert +๐Ÿ“š **More examples:** https://github.com/acmesh-official/acme.sh/wiki/How-to-issue-a-cert -# 8. Automatic DNS API integration +--- + +### 8๏ธโƒฃ Automatic DNS API Integration If your DNS provider supports API access, we can use that API to automatically issue the certs. -You don't have to do anything manually! +> โœจ **You don't have to do anything manually!** -### Currently acme.sh supports most of the dns providers: +๐Ÿ“š **Currently acme.sh supports most DNS providers:** https://github.com/acmesh-official/acme.sh/wiki/dnsapi -https://github.com/acmesh-official/acme.sh/wiki/dnsapi +--- -# 9. Use DNS manual mode: +### 9๏ธโƒฃ Use DNS Manual Mode See: https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode first. @@ -355,67 +386,74 @@ Then just rerun with `renew` argument: acme.sh --renew -d example.com ``` -Ok, it's done. +โœ… **Done!** -**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.** +> โš ๏ธ **WARNING:** This is DNS manual mode โ€” it **cannot** be renewed automatically. You will have to add a new TXT record to your domain manually when you renew your cert. **Please use DNS API mode instead.** -**Please use dns api mode instead.** +--- -# 10. Issue certificates of different key types and lengths (ECC or RSA) +### ๐Ÿ”Ÿ Issue Certificates of Different Key Types (ECC or RSA) -Just set the `keylength` to a valid, supported, value. +Just set the `keylength` to a valid, supported value. -Valid values for the `keylength` parameter are: +**Valid values for the `keylength` parameter:** -1. **ec-256 (prime256v1, "ECDSA P-256", which is the default key type)** -2. **ec-384 (secp384r1, "ECDSA P-384")** -3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)** -4. **2048 (RSA2048)** -5. **3072 (RSA3072)** -6. **4096 (RSA4096)** +| Key Length | Description | +|------------|-------------| +| `ec-256` | prime256v1, "ECDSA P-256" โญ **Default** | +| `ec-384` | secp384r1, "ECDSA P-384" | +| `ec-521` | secp521r1, "ECDSA P-521" โš ๏ธ Not supported by Let's Encrypt yet | +| `2048` | RSA 2048-bit | +| `3072` | RSA 3072-bit | +| `4096` | RSA 4096-bit | -For example: +**Examples:** -### Single domain with ECDSA P-384 certificate +#### Single domain with ECDSA P-384 certificate ```bash acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-384 ``` -### SAN multi domain with RSA4096 certificate +#### SAN multi domain with RSA4096 certificate ```bash acme.sh --issue -w /home/wwwroot/example.com -d example.com -d www.example.com --keylength 4096 ``` -# 11. Issue Wildcard certificates +--- + +### 1๏ธโƒฃ1๏ธโƒฃ Issue Wildcard Certificates -It's simple, just give a wildcard domain as the `-d` parameter. +It's simple! Just give a wildcard domain as the `-d` parameter: ```sh -acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf +acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf ``` -# 12. How to renew the certs +--- -No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days. +### 1๏ธโƒฃ2๏ธโƒฃ How to Renew Certificates -However, you can also force to renew a cert: +> ๐Ÿ”„ No need to renew manually! All certs will be renewed automatically every **30** days. + +However, you can force a renewal: ```sh acme.sh --renew -d example.com --force ``` -or, for ECC cert: +**For ECC cert:** ```sh acme.sh --renew -d example.com --force --ecc ``` +--- -# 13. How to stop cert renewal +### 1๏ธโƒฃ3๏ธโƒฃ How to Stop Certificate Renewal To stop renewal of a cert, you can execute the following to remove the cert from the renewal list: @@ -425,73 +463,78 @@ acme.sh --remove -d example.com [--ecc] The cert/key file is not removed from the disk. -You can remove the respective directory (e.g. `~/.acme.sh/example.com`) by yourself. +> ๐Ÿ’ก You can remove the respective directory (e.g. `~/.acme.sh/example.com`) manually. +--- -# 14. How to upgrade `acme.sh` +### 1๏ธโƒฃ4๏ธโƒฃ How to Upgrade acme.sh -acme.sh is in constant development, so it's strongly recommended to use the latest code. +> ๐Ÿš€ acme.sh is in constant development โ€” it's strongly recommended to use the latest code. -You can update acme.sh to the latest code: +**Update to latest:** ```sh acme.sh --upgrade ``` -You can also enable auto upgrade: +**Enable auto upgrade:** ```sh acme.sh --upgrade --auto-upgrade ``` -Then **acme.sh** will be kept up to date automatically. - -Disable auto upgrade: +**Disable auto upgrade:** ```sh acme.sh --upgrade --auto-upgrade 0 ``` +--- -# 15. Issue a cert from an existing CSR +### 1๏ธโƒฃ5๏ธโƒฃ Issue a Certificate from an Existing CSR -https://github.com/acmesh-official/acme.sh/wiki/Issue-a-cert-from-existing-CSR +๐Ÿ“š https://github.com/acmesh-official/acme.sh/wiki/Issue-a-cert-from-existing-CSR +--- -# 16. Send notifications in cronjob +### 1๏ธโƒฃ6๏ธโƒฃ Send Notifications in Cronjob -https://github.com/acmesh-official/acme.sh/wiki/notify +๐Ÿ“š https://github.com/acmesh-official/acme.sh/wiki/notify +--- -# 17. Under the Hood +### 1๏ธโƒฃ7๏ธโƒฃ Under the Hood -Speak ACME language using shell, directly to "Let's Encrypt". +> ๐Ÿ”ง Speak ACME language using shell, directly to "Let's Encrypt". -TODO: +--- +### 1๏ธโƒฃ8๏ธโƒฃ Acknowledgments -# 18. Acknowledgments +| Project | Link | +|---------|------| +| ๐Ÿ™ Acme-tiny | https://github.com/diafygi/acme-tiny | +| ๐Ÿ“œ ACME protocol | https://github.com/ietf-wg-acme/acme | -1. Acme-tiny: https://github.com/diafygi/acme-tiny -2. ACME protocol: https://github.com/ietf-wg-acme/acme +--- +## ๐Ÿ‘ฅ Contributors -## Contributors - -### Code Contributors +### ๐Ÿ’ป Code Contributors This project exists thanks to all the people who contribute. + -### Financial Contributors +### ๐Ÿ’ฐ Financial Contributors Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/acmesh/contribute)] -#### Individuals +#### ๐Ÿ‘ค Individuals -#### Organizations +#### ๐Ÿข Organizations Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/acmesh/contribute)] @@ -506,25 +549,31 @@ Support this project with your organization. Your logo will show up here with a +--- + +### 1๏ธโƒฃ9๏ธโƒฃ License & Others +๐Ÿ“„ **License:** GPLv3 -# 19. License & Others +โญ Please **Star** and **Fork** this project! -License is GPLv3 +๐Ÿ› [Issues](https://github.com/acmesh-official/acme.sh/issues) and ๐Ÿ”€ [Pull Requests](https://github.com/acmesh-official/acme.sh/pulls) are welcome. -Please Star and Fork me. +--- -[Issues](https://github.com/acmesh-official/acme.sh/issues) and [pull requests](https://github.com/acmesh-official/acme.sh/pulls) are welcome. +### 2๏ธโƒฃ0๏ธโƒฃ Donate +> ๐Ÿ’ Your donation makes **acme.sh** better! -# 20. Donate -Your donation makes **acme.sh** better: +| Method | Link | +|--------|------| +| PayPal / Alipay(ๆ”ฏไป˜ๅฎ) / Wechat(ๅพฎไฟก) | [https://donate.acme.sh/](https://donate.acme.sh/) | -1. PayPal/Alipay(ๆ”ฏไป˜ๅฎ)/Wechat(ๅพฎไฟก): [https://donate.acme.sh/](https://donate.acme.sh/) +๐Ÿ“œ [Donate List](https://github.com/acmesh-official/acme.sh/wiki/Donate-list) -[Donate List](https://github.com/acmesh-official/acme.sh/wiki/Donate-list) +--- -# 21. About this repository +### 2๏ธโƒฃ1๏ธโƒฃ About This Repository > [!NOTE] > This repository is officially maintained by ZeroSSL as part of our commitment to providing secure and reliable SSL/TLS solutions. We welcome contributions and feedback from the community! @@ -532,7 +581,7 @@ Your donation makes **acme.sh** better: > > All donations made through this repository go directly to the original independent maintainer (Neil Pang), not to ZeroSSL.

- + diff --git a/acme.sh b/acme.sh index ba0f62bc..fc2afcc8 100755 --- a/acme.sh +++ b/acme.sh @@ -65,7 +65,7 @@ ID_TYPE_IP="ip" LOCAL_ANY_ADDRESS="0.0.0.0" -DEFAULT_RENEW=60 +DEFAULT_RENEW=30 NO_VALUE="no" @@ -2783,6 +2783,7 @@ _clearAPI() { ACME_REVOKE_CERT="" ACME_NEW_NONCE="" ACME_AGREEMENT="" + ACME_RENEWAL_INFO="" } #server @@ -2827,6 +2828,9 @@ _initAPI() { ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_AGREEMENT + ACME_RENEWAL_INFO=$(echo "$response" | _egrep_o 'renewalInfo" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_RENEWAL_INFO + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" @@ -2834,6 +2838,7 @@ _initAPI() { _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" _debug "ACME_AGREEMENT" "$ACME_AGREEMENT" _debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE" + _debug "ACME_RENEWAL_INFO" "$ACME_RENEWAL_INFO" if [ "$ACME_NEW_ACCOUNT" ] && [ "$ACME_NEW_ORDER" ]; then return 0 fi @@ -5840,7 +5845,7 @@ list() { if [ -z "$_domain" ]; then printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Profile${_sep}CA${_sep}Created${_sep}Renew" fi - for di in "${CERT_HOME}"/*.*/; do + for di in "${CERT_HOME}"/{*.*,*:*}/; do d=$(basename "$di") _debug d "$d" ( @@ -6537,6 +6542,36 @@ deactivate() { done } +#cert +_getAKI() { + _cert="$1" + openssl x509 -in "$_cert" -text -noout | grep "X509v3 Authority Key Identifier" -A 1 | _tail_n 1 | tr -d ' :' +} + +#cert +_getSerial() { + _cert="$1" + openssl x509 -in "$_cert" -serial -noout | cut -d = -f 2 +} + +#cert +_get_ARI() { + _cert="$1" + _aki=$(_getAKI "$_cert") + _ser=$(_getSerial "$_cert") + _debug2 "_aki" "$_aki" + _debug2 "_ser" "$_ser" + + _akiurl="$(echo "$_aki" | _h2b | _base64 | tr -d = | _url_encode)" + _debug2 "_akiurl" "$_akiurl" + _serurl="$(echo "$_ser" | _h2b | _base64 | tr -d = | _url_encode)" + _debug2 "_serurl" "$_serurl" + + _ARI_URL="$ACME_RENEWAL_INFO/$_akiurl.$_serurl" + _get "$_ARI_URL" + +} + # Detect profile file if not specified as environment variable _detect_profile() { if [ -n "$PROFILE" -a -f "$PROFILE" ]; then diff --git a/deploy/multideploy.sh b/deploy/multideploy.sh new file mode 100644 index 00000000..ef920f64 --- /dev/null +++ b/deploy/multideploy.sh @@ -0,0 +1,276 @@ +#!/usr/bin/env sh + +################################################################################ +# ACME.sh 3rd party deploy plugin for multiple (same) services +################################################################################ +# Authors: tomo2403 (creator), https://github.com/tomo2403 +# Updated: 2025-03-01 +# Issues: https://github.com/acmesh-official/acme.sh/issues and mention @tomo2403 +################################################################################ +# Usage (shown values are the examples): +# 1. Set optional environment variables +# - export MULTIDEPLOY_FILENAME="multideploy.yaml" - "multideploy.yml" will be automatically used if not set" +# +# 2. Run command: +# acme.sh --deploy --deploy-hook multideploy -d example.com +################################################################################ +# Dependencies: +# - yq +################################################################################ +# Return value: +# 0 means success, otherwise error. +################################################################################ + +MULTIDEPLOY_VERSION="1.0" + +# Description: This function handles the deployment of certificates to multiple services. +# It processes the provided certificate files and deploys them according to the +# configuration specified in the multideploy file. +# +# Parameters: +# _cdomain - The domain name for which the certificate is issued. +# _ckey - The private key file for the certificate. +# _ccert - The certificate file. +# _cca - The CA (Certificate Authority) file. +# _cfullchain - The full chain certificate file. +# _cpfx - The PFX (Personal Information Exchange) file. +multideploy_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + _cpfx="$6" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + _debug _cpfx "$_cpfx" + + MULTIDEPLOY_FILENAME="${MULTIDEPLOY_FILENAME:-$(_getdeployconf MULTIDEPLOY_FILENAME)}" + if [ -z "$MULTIDEPLOY_FILENAME" ]; then + MULTIDEPLOY_FILENAME="multideploy.yml" + _info "MULTIDEPLOY_FILENAME is not set, so I will use 'multideploy.yml'." + else + _savedeployconf "MULTIDEPLOY_FILENAME" "$MULTIDEPLOY_FILENAME" + _debug2 "MULTIDEPLOY_FILENAME" "$MULTIDEPLOY_FILENAME" + fi + + if ! file=$(_preprocess_deployfile "$MULTIDEPLOY_FILENAME"); then + _err "Failed to preprocess deploy file." + return 1 + fi + _debug3 "File" "$file" + + # Deploy to services + _deploy_services "$file" + _exitCode="$?" + + return "$_exitCode" +} + +# Description: +# This function preprocesses the deploy file by checking if 'yq' is installed, +# verifying the existence of the deploy file, and ensuring only one deploy file is present. +# Arguments: +# $@ - Posible deploy file names. +# Usage: +# _preprocess_deployfile "" "?" +_preprocess_deployfile() { + # Check if yq is installed + if ! command -v yq >/dev/null 2>&1; then + _err "yq is not installed! Please install yq and try again." + return 1 + fi + _debug3 "yq is installed." + + # Check if deploy file exists + for file in "$@"; do + _debug3 "Checking file" "$DOMAIN_PATH/$file" + if [ -f "$DOMAIN_PATH/$file" ]; then + _debug3 "File found" + if [ -n "$found_file" ]; then + _err "Multiple deploy files found. Please keep only one deploy file." + return 1 + fi + found_file="$file" + else + _debug3 "File not found" + fi + done + + if [ -z "$found_file" ]; then + _err "Deploy file not found. Go to https://github.com/acmesh-official/acme.sh/wiki/deployhooks#36-deploying-to-multiple-services-with-the-same-hooks to see how to create one." + return 1 + fi + if ! _check_deployfile "$DOMAIN_PATH/$found_file"; then + _err "Deploy file is not valid: $DOMAIN_PATH/$found_file" + return 1 + fi + + echo "$DOMAIN_PATH/$found_file" +} + +# Description: +# This function checks the deploy file for version compatibility and the existence of the specified configuration and services. +# Arguments: +# $1 - The path to the deploy configuration file. +# $2 - The name of the deploy configuration to use. +# Usage: +# _check_deployfile "" +_check_deployfile() { + _deploy_file="$1" + _debug2 "check: Deploy file" "$_deploy_file" + + # Check version + _deploy_file_version=$(yq -r '.version' "$_deploy_file") + if [ "$MULTIDEPLOY_VERSION" != "$_deploy_file_version" ]; then + _err "As of $PROJECT_NAME $VER, the deploy file needs version $MULTIDEPLOY_VERSION! Your current deploy file is of version $_deploy_file_version." + return 1 + fi + _debug2 "check: Deploy file version is compatible: $_deploy_file_version" + + # Extract all services from config + _services=$(yq -r '.services[].name' "$_deploy_file") + + if [ -z "$_services" ]; then + _err "Config does not have any services to deploy to." + return 1 + fi + _debug2 "check: Config has services." + echo "$_services" | while read -r _service; do + _debug3 " - $_service" + done + + # Check if extracted services exist in services list + echo "$_services" | while read -r _service; do + _debug2 "check: Checking service: $_service" + # Check if service exists + _service_config=$(yq -r ".services[] | select(.name == \"$_service\")" "$_deploy_file") + if [ -z "$_service_config" ] || [ "$_service_config" = "null" ]; then + _err "Service '$_service' not found." + return 1 + fi + + _service_hook=$(echo "$_service_config" | yq -r ".hook" -) + if [ -z "$_service_hook" ] || [ "$_service_hook" = "null" ]; then + _err "Service '$_service' does not have a hook." + return 1 + fi + + _service_environment=$(echo "$_service_config" | yq -r ".environment" -) + if [ -z "$_service_environment" ] || [ "$_service_environment" = "null" ]; then + _err "Service '$_service' does not have an environment." + return 1 + fi + done +} + +# Description: This function takes a list of environment variables in YAML format, +# parses them, and exports each key-value pair as environment variables. +# Arguments: +# $1 - A string containing the list of environment variables in YAML format. +# Usage: +# _export_envs "$env_list" +_export_envs() { + _env_list="$1" + + _secure_debug3 "Exporting envs" "$_env_list" + + echo "$_env_list" | yq -r 'to_entries | .[] | .key + "=" + .value' | while IFS='=' read -r _key _value; do + # Using eval to expand nested variables in the configuration file + _value=$(eval 'echo "'"$_value"'"') + _savedeployconf "$_key" "$_value" + _secure_debug3 "Saved $_key" "$_value" + done +} + +# Description: +# This function takes a YAML formatted string of environment variables, parses it, +# and clears each environment variable. It logs the process of clearing each variable. +# +# Note: Environment variables for a hook may be optional and differ between +# services using the same hook. +# If one service sets optional environment variables and another does not, the +# variables may persist and affect subsequent deployments. +# Clearing these variables after each service ensures that only the +# environment variables explicitly specified for each service in the deploy +# file are used. +# Arguments: +# $1 - A YAML formatted string containing environment variable key-value pairs. +# Usage: +# _clear_envs "" +_clear_envs() { + _env_list="$1" + + _secure_debug3 "Clearing envs" "$_env_list" + env_pairs=$(echo "$_env_list" | yq -r 'to_entries | .[] | .key + "=" + .value') + + echo "$env_pairs" | while IFS='=' read -r _key _value; do + _debug3 "Deleting key" "$_key" + _cleardomainconf "SAVED_$_key" + unset -v "$_key" + done +} + +# Description: +# This function deploys services listed in the deploy configuration file. +# Arguments: +# $1 - The path to the deploy configuration file. +# $2 - The list of services to deploy. +# Usage: +# _deploy_services "" "" +_deploy_services() { + _deploy_file="$1" + _debug3 "Deploy file" "$_deploy_file" + + _tempfile=$(mktemp) + trap 'rm -f $_tempfile' EXIT + + yq -r '.services[].name' "$_deploy_file" >"$_tempfile" + _debug3 "Services" "$(cat "$_tempfile")" + + _failedServices="" + _failedCount=0 + while read -r _service <&3; do + _debug2 "Service" "$_service" + _hook=$(yq -r ".services[] | select(.name == \"$_service\").hook" "$_deploy_file") + _envs=$(yq -r ".services[] | select(.name == \"$_service\").environment" "$_deploy_file") + + _export_envs "$_envs" + if ! _deploy_service "$_service" "$_hook"; then + _failedServices="$_service, $_failedServices" + _failedCount=$((_failedCount + 1)) + fi + _clear_envs "$_envs" + done 3<"$_tempfile" + + _debug3 "Failed services" "$_failedServices" + _debug2 "Failed count" "$_failedCount" + if [ -n "$_failedServices" ]; then + _info "$(__red "Deployment failed") for services: $_failedServices" + else + _debug "All services deployed successfully." + fi + + return "$_failedCount" +} + +# Description: Deploys a service using the specified hook. +# Arguments: +# $1 - The name of the service to deploy. +# $2 - The hook to use for deployment. +# Usage: +# _deploy_service +_deploy_service() { + _name="$1" + _hook="$2" + + _debug2 "SERVICE" "$_name" + _debug2 "HOOK" "$_hook" + + _info "$(__green "Deploying") to '$_name' using '$_hook'" + _deploy "$_cdomain" "$_hook" +} diff --git a/deploy/strongswan.sh b/deploy/strongswan.sh index 14567d17..80353c54 100644 --- a/deploy/strongswan.sh +++ b/deploy/strongswan.sh @@ -33,7 +33,7 @@ strongswan_deploy() { return 1 fi _info _confdir "${_confdir}" - __deploy_cert "$@" "stroke" "${_confdir}" + __deploy_cert "stroke" "${_confdir}" "$@" ${_ipsec} reload fi # For modern vici mode @@ -50,7 +50,7 @@ strongswan_deploy() { _err "no swanctl config dir is found" return 1 fi - __deploy_cert "$@" "vici" "${_confdir}" + __deploy_cert "vici" "${_confdir}" "$@" ${_swanctl} --load-creds fi if [ -z "${_swanctl}" ] && [ -z "${_ipsec}" ]; then @@ -63,13 +63,13 @@ strongswan_deploy() { #################### Private functions below ################################## __deploy_cert() { - _cdomain="${1}" - _ckey="${2}" - _ccert="${3}" - _cca="${4}" - _cfullchain="${5}" - _swan_mode="${6}" - _confdir="${7}" + _swan_mode="${1}" + _confdir="${2}" + _cdomain="${3}" + _ckey="${4}" + _ccert="${5}" + _cca="${6}" + _cfullchain="${7}" _debug _cdomain "${_cdomain}" _debug _ckey "${_ckey}" _debug _ccert "${_ccert}" diff --git a/dnsapi/dns_sotoon.sh b/dnsapi/dns_sotoon.sh index 4a0fc034..b94a220f 100644 --- a/dnsapi/dns_sotoon.sh +++ b/dnsapi/dns_sotoon.sh @@ -6,12 +6,11 @@ Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_sotoon Options: Sotoon_Token API Token Sotoon_WorkspaceUUID Workspace UUID - Sotoon_WorkspaceName Workspace Name Issues: github.com/acmesh-official/acme.sh/issues/6656 Author: Erfan Gholizade ' -SOTOON_API_URL="https://api.sotoon.ir/delivery/v2/global" +SOTOON_API_URL="https://api.sotoon.ir/delivery/v2.1/global" ######## Public functions ##################### @@ -25,7 +24,6 @@ dns_sotoon_add() { Sotoon_Token="${Sotoon_Token:-$(_readaccountconf_mutable Sotoon_Token)}" Sotoon_WorkspaceUUID="${Sotoon_WorkspaceUUID:-$(_readaccountconf_mutable Sotoon_WorkspaceUUID)}" - Sotoon_WorkspaceName="${Sotoon_WorkspaceName:-$(_readaccountconf_mutable Sotoon_WorkspaceName)}" if [ -z "$Sotoon_Token" ]; then _err_sotoon "You didn't specify \"Sotoon_Token\" token yet." @@ -37,16 +35,10 @@ dns_sotoon_add() { _err_sotoon "You can get yours from here https://ocean.sotoon.ir/profile/workspaces" return 1 fi - if [ -z "$Sotoon_WorkspaceName" ]; then - _err_sotoon "You didn't specify \"Sotoon_WorkspaceName\" Workspace Name yet." - _err_sotoon "You can get yours from here https://ocean.sotoon.ir/profile/workspaces" - return 1 - fi #save the info to the account conf file. _saveaccountconf_mutable Sotoon_Token "$Sotoon_Token" _saveaccountconf_mutable Sotoon_WorkspaceUUID "$Sotoon_WorkspaceUUID" - _saveaccountconf_mutable Sotoon_WorkspaceName "$Sotoon_WorkspaceName" _debug_sotoon "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -130,7 +122,6 @@ dns_sotoon_rm() { Sotoon_Token="${Sotoon_Token:-$(_readaccountconf_mutable Sotoon_Token)}" Sotoon_WorkspaceUUID="${Sotoon_WorkspaceUUID:-$(_readaccountconf_mutable Sotoon_WorkspaceUUID)}" - Sotoon_WorkspaceName="${Sotoon_WorkspaceName:-$(_readaccountconf_mutable Sotoon_WorkspaceName)}" _debug_sotoon "First detect the root zone" if ! _get_root "$fulldomain"; then @@ -197,7 +188,6 @@ _get_root() { _debug_sotoon "Getting root domain for: $domain" _debug_sotoon "Sotoon WorkspaceUUID: $Sotoon_WorkspaceUUID" - _debug_sotoon "Sotoon WorkspaceName: $Sotoon_WorkspaceName" while true; do h=$(printf "%s" "$domain" | cut -d . -f "$i"-100) @@ -212,7 +202,7 @@ _get_root() { _debug_sotoon "Fetching domain zones from Sotoon API" if ! _sotoon_rest GET ""; then _err_sotoon "Failed to get domain zones from Sotoon API" - _err_sotoon "Please check your Sotoon_Token, Sotoon_WorkspaceUUID, and Sotoon_WorkspaceName" + _err_sotoon "Please check your Sotoon_Token, Sotoon_WorkspaceUUID" return 1 fi @@ -271,7 +261,7 @@ _sotoon_rest() { token_trimmed=$(echo "$Sotoon_Token" | tr -d '"') # Construct the API endpoint - _api_path="$SOTOON_API_URL/workspaces/$Sotoon_WorkspaceUUID/namespaces/$Sotoon_WorkspaceName/domainzones" + _api_path="$SOTOON_API_URL/workspaces/$Sotoon_WorkspaceUUID/domainzones" if [ -n "$resource_id" ]; then _api_path="$_api_path/$resource_id"