Compare commits

..

No commits in common. "master" and "v4.28.0" have entirely different histories.

842 changed files with 2539 additions and 27215 deletions

View file

@ -45,7 +45,6 @@ body:
- Through Bitnami
- Through 1Panel
- Through Zoraxy
- Through Certimate
- go install
- Other
validations:

View file

@ -24,7 +24,6 @@ body:
- Through Bitnami
- Through 1Panel
- Through Zoraxy
- Through Certimate
- go install
- Other
validations:

View file

@ -14,15 +14,9 @@ body:
required: true
- label: Yes, I know that the lego maintainers don't have an account in all DNS providers in the world.
required: true
- type: checkboxes
id: pr
attributes:
label: Implementation
options:
- label: Yes, I'm able to create a pull request and be able to maintain the implementation.
required: false
- label: Yes, I can test an implementation with the help of the maintainers if someone creates a pull request.
- label: Yes, I'm able to test an implementation if someone creates a pull request to add the support of this DNS provider.
required: false
- type: dropdown
@ -40,23 +34,11 @@ body:
- Through Bitnami
- Through 1Panel
- Through Zoraxy
- Through Certimate
- go install
- Other
validations:
required: true
- type: dropdown
id: profile
attributes:
label: Who are you?
options:
- A customer of this DNS provider
- An employee of this DNS provider
- Other (please explain)
validations:
required: true
- type: input
id: provider-link
attributes:

View file

@ -1,12 +0,0 @@
<!--
IMPORTANT:
1. Create an issue and wait for a maintainer to approve it BEFORE opening a pull request.
2. Don't open a work-in-progress pull request. If you open a PR, the PR must be ready to be reviewed.
3. If a pull request doesn't follow one of the previous elements, it will be closed.
Also, pull requests from a fork inside a GitHub organization are not allowed because of access limitation on them.
Only pull requests from personal forks are allowed.
-->

View file

@ -17,11 +17,15 @@ jobs:
steps:
- uses: actions/checkout@v6
# https://github.com/marketplace/actions/checkout
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v6
# https://github.com/marketplace/actions/setup-go-environment
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}

View file

@ -20,8 +20,13 @@ jobs:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
# https://github.com/marketplace/actions/checkout
- name: Checkout code
uses: actions/checkout@v4
# https://github.com/marketplace/actions/setup-go-environment
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}

View file

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
env:
GO_VERSION: stable
GOLANGCI_LINT_VERSION: v2.10
GOLANGCI_LINT_VERSION: v2.6.0
HUGO_VERSION: 0.148.2
CGO_ENABLED: 0
LEGO_E2E_TESTS: CI
@ -21,36 +21,43 @@ jobs:
steps:
- uses: actions/checkout@v6
# https://github.com/marketplace/actions/checkout
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v6
# https://github.com/marketplace/actions/setup-go-environment
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Check and get dependencies
run: |
go mod tidy --diff
go mod tidy
git diff --exit-code go.mod
git diff --exit-code go.sum
- name: Generate and Check generated elements
run: |
make generate-dns
git diff --exit-code
- uses: golangci/golangci-lint-action@v9
with:
version: ${{ env.GOLANGCI_LINT_VERSION }}
install-only: true
# https://golangci-lint.run/usage/install#other-ci
- name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }}
run: |
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION}
golangci-lint --version
- name: Install Pebble
run: go install github.com/letsencrypt/pebble/v2/cmd/pebble@v2.9.0
run: go install github.com/letsencrypt/pebble/v2/cmd/pebble@v2.7.0
- name: Install challtestsrv
run: go install github.com/letsencrypt/pebble/v2/cmd/pebble-challtestsrv@v2.9.0
run: go install github.com/letsencrypt/pebble/v2/cmd/pebble-challtestsrv@v2.7.0
- name: Set up a Memcached server
run: docker run -d --rm -p 11211:11211 memcached:1.6-alpine
uses: niden/actions-memcached@v7
- name: Make
run: |

View file

@ -42,11 +42,13 @@ jobs:
docker-images: true
swap-storage: false
- uses: actions/checkout@v6
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v6
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
@ -67,10 +69,9 @@ jobs:
# https://goreleaser.com/ci/actions/
- name: Run GoReleaser
id: goreleaser
uses: goreleaser/goreleaser-action@v6
with:
version: v2.13.0
version: v2.12.3
args: release -p 1 --clean --timeout=90m
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO }}
@ -79,9 +80,7 @@ jobs:
- uses: actions/attest-build-provenance@v3
with:
subject-checksums: ./dist/lego_${{ fromJSON(steps.goreleaser.outputs.metadata).version }}_checksums.txt
github-token: ${{ secrets.GH_TOKEN_REPO }}
subject-checksums: ./dist/lego_*_checksums.txt
- uses: actions/attest-build-provenance@v3
with:
subject-checksums: ./dist/digests.txt
github-token: ${{ secrets.GH_TOKEN_REPO }}

View file

@ -180,12 +180,6 @@ linters:
text: Error return value of `fmt.Fprintln` is not checked
linters:
- errcheck
- text: "var-naming: avoid meaningless package names"
linters:
- revive
- text: "var-naming: avoid package names that conflict with Go standard library package names"
linters:
- revive
- path: certcrypto/crypto.go
text: (tlsFeatureExtensionOID|ocspMustStapleFeature) is a global variable
linters:
@ -222,7 +216,11 @@ linters:
text: load is a global variable
linters:
- gochecknoglobals
- path: providers/(dns|http)/([\d\w]+/)*[\d\w]+_test.go
- path: providers/dns/([\d\w]+/)*[\d\w]+_test.go
text: envTest is a global variable
linters:
- gochecknoglobals
- path: providers/http/([\d\w]+/)*[\d\w]+_test.go
text: envTest is a global variable
linters:
- gochecknoglobals
@ -230,10 +228,6 @@ linters:
text: testCases is a global variable
linters:
- gochecknoglobals
- path: providers/dns/namecheap/transport.go
text: (envProxyOnce|envProxyFuncValue) is a global variable
linters:
- gochecknoglobals
- path: providers/dns/acmedns/mock_test.go
text: egTestAccount is a global variable
linters:
@ -269,10 +263,6 @@ linters:
text: cyclomatic complexity 13 of func `\(\*DNSProvider\)\.CleanUp` is high
linters:
- gocyclo
- path: providers/dns/manual/manual.go
text: 'SA1019: dns01.DNSProviderManual is deprecated'
linters:
- staticcheck
# Those elements have been replaced by non-exposed structures.
- path: providers/dns/linode/linode_test.go
text: 'SA1019: linodego\.(DomainsPagedResponse|DomainRecordsPagedResponse) is deprecated'

View file

@ -90,9 +90,8 @@ dockers_v2:
- linux/arm/v7
tags:
- 'latest'
- 'v{{ .Major }}'
- 'v{{ .Major }}.{{ .Minor }}'
- '{{ .Tag }}'
- 'v{{ .Major }}.{{ .Minor }}'
labels:
# https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
'org.opencontainers.image.title': '{{.ProjectName}}'

View file

@ -1,129 +1,11 @@
# Changelog
lego is an independent, free, open-source project, if you value it, consider [supporting it](https://donate.ldez.dev)! ❤️
lego is an independent, free, and open-source project, if you value it, consider [supporting it](https://donate.ldez.dev)! ❤️
Everybody thinks that the others will donate, but in the end, nobody does.
So if you think that lego is worth it, please consider [donating](https://donate.ldez.dev).
## v4.32.0
- Release date: 2026-02-19
- Tag: [v4.32.0](https://github.com/go-acme/lego/releases/tag/v4.32.0)
### Added
- **[dnsprovider]** Add DNS provider for ArtFiles
- **[dnsprovider]** Add DNS provider for Leaseweb
- **[dnsprovider]** Add DNS provider for FusionLayer NameSurfer
- **[dnsprovider]** Add DNS provider for DDNSS
- **[dnsprovider]** Add DNS provider for Bluecat v2
- **[dnsprovider]** Add DNS provider for TodayNIC/时代互联
- **[dnsprovider]** Add DNS provider for DNSExit
- **[dnsprovider]** alidns: add line record option
### Changed
- **[dnsprovider]** azure: reinforces deprecation
- **[dnsprovider]** allinkl: detect zone through API
### Fixed
- **[ari]** fix: implement parsing for Retry-After header according to RFC 7231
- **[dnsprovider]** namesurfer: fix updateDNSHost
- **[dnsprovider]** timewebcloud: fix subdomain support
- **[dnsprovider]** fix: deduplicate authz for DNS01 challenge
- **[lib,cli]** fix: use IPs to define the main domain
- **[lib]** fix: preserve domain order
## v4.31.0
- Release date: 2026-01-08
- Tag: [v4.31.0](https://github.com/go-acme/lego/releases/tag/v4.31.0)
### Added
- **[dnsprovider]** Add DNS provider for ISPConfig
- **[dnsprovider]** Add DNS Provider for ISPConfig (DDNS Module)
- **[dnsprovider]** Add DNS provider for Alwaysdata
- **[dnsprovider]** Add DNS provider for JDCloud
- **[dnsprovider]** Add DNS provider for 35.com/三五互联
- **[dnsprovider]** f5xc: add an option to configure the domain of the server
### Changed
- **[lib]** feat: improve ACME error types
- **[dnsprovider,cname]** namedotcom: follow CNAME
### Fixed
- **[dnsprovider]** hetzner: fix compatibility with _FILE suffix
- **[dnsprovider]** gandiv5: fix API Key header
## v4.30.1
- Release date: 2025-12-16
- Tag: [v4.30.1](https://github.com/go-acme/lego/releases/tag/v4.30.1)
Due to an error related to `aliyun/credentials-go`, some artifacts of the v4.30.0 release have not been published.
This release contains the same things as v4.30.0.
## v4.30.0
- Release date: 2025-12-16
- Tag: [v4.30.0](https://github.com/go-acme/lego/releases/tag/v4.30.0)
### Added
- **[dnsprovider]** Add DNS provider for Ionos Cloud
- **[dnsprovider]** Add DNS provider for Virtualname
- **[dnsprovider]** Add DNS Provider for Neodigit
- **[dnsprovider]** Add DNS provider for Syse.no
- **[dnsprovider]** Add DNS provider for Gravity
- **[dnsprovider]** Add DNS provider for hosting.nl
### Changed
- **[cli]** feat: remove email requirement
### Fixed
- **[dnsprovider]** autodns: use the right response structure
## v4.29.0
- Release date: 2025-11-29
- Tag: [v4.29.0](https://github.com/go-acme/lego/releases/tag/v4.29.0)
### Added
- **[dnsprovider]** Add DNS provider for United-Domains
- **[dnsprovider]** Add DNS provider for Gigahost.no
- **[dnsprovider]** Add DNS provider for EdgeCenter
- **[dnsprovider]** Add DNS provider for AlibabaCloud ESA
- **[dnsprovider]** edgeone: add zones mapping
- **[dnsprovider]** namecheap: add experimental proxy support
### Changed
- **[dnsprovider]** gandiv5: update base API URL
### Fixed
- **[dnsprovider]** hetzner: use int64 for IDs
- **[dnsprovider]** baiducloud: pagination and TTL
- **[dnsprovider]** inwx: fix API breaking changes with record IDs
## v4.28.1
- Release date: 2025-11-06
- Tag: [v4.28.1](https://github.com/go-acme/lego/releases/tag/v4.28.1)
### Fixed
- **[cli]** fix: skip nil response
## v4.28.0
- Release date: 2025-10-31

View file

@ -10,7 +10,7 @@ To ensure a great and easy experience for everyone, please review the few guidel
- If both of the above do not apply, create a new issue and include as much information as possible.
Bug reports should include all information a person could need to reproduce your problem without the need to
follow up for more information. If possible, provide detailed steps for us to reproduce it, the expected behavior and the actual behavior.
follow up for more information. If possible, provide detailed steps for us to reproduce it, the expected behaviour and the actual behaviour.
## Feature proposals and requests
@ -20,26 +20,31 @@ It is up to you to make a strong point about your proposal and convince us of th
## Pull requests
Create an issue and wait for a maintainer to approve it BEFORE opening a pull request.
Patches, new features and improvements are a great way to help the project.
Please keep them focused on one thing and do not include unrelated commits.
All pull requests that alter the behavior of the program,
add new behavior or somehow alter code in a non-trivial way should **always** include tests.
All pull requests which alter the behaviour of the program, add new behaviour or somehow alter code in a non-trivial way should **always** include tests.
**IMPORTANT**: By submitting a patch, you agree to allow the project owners to license your work under the terms of the [MIT License](LICENSE).
If you want to contribute a significant pull request (with a non-trivial workload for you) please **ask first**. We do not want you to spend
a lot of time on something the project's developers might not want to merge into the project.
**IMPORTANT**: By submitting a patch, you agree to allow the project
owners to license your work under the terms of the [MIT License](LICENSE).
### How to create a pull request
Requirements:
- `go` v1.24+
- `go` v1.15+
- environment variable: `GO111MODULE=on`
First, you have to install [GoLang](https://golang.org/doc/install) and [golangci-lint](https://github.com/golangci/golangci-lint#install).
```bash
# Create the root folder
mkdir -p $GOPATH/src/github.com/go-acme
cd $GOPATH/src/github.com/go-acme
# clone your fork
git clone git@github.com:YOUR_USERNAME/lego.git
cd lego
@ -51,12 +56,14 @@ git fetch upstream
```bash
# Create your branch
git switch -c my-feature
git checkout -b my-feature
## Create your code ##
```
```bash
# Format
make fmt
# Linters
make checks
# Tests

102
README.md
View file

@ -5,7 +5,7 @@
# Lego
[ACME](https://www.rfc-editor.org/rfc/rfc8555.html) client and library for Let's Encrypt and other ACME CAs written in Go.
Let's Encrypt client and ACME library written in Go.
[![Go Reference](https://pkg.go.dev/badge/github.com/go-acme/lego/v4.svg)](https://pkg.go.dev/github.com/go-acme/lego/v4)
[![Build Status](https://github.com//go-acme/lego/workflows/Main/badge.svg?branch=master)](https://github.com//go-acme/lego/actions)
@ -24,7 +24,7 @@ So if you think that lego is worth it, please consider [donating](https://donate
- Support [RFC 8738](https://www.rfc-editor.org/rfc/rfc8738.html): certificates for IP addresses
- Support [RFC 9773](https://www.rfc-editor.org/rfc/rfc9773.html): Renewal Information (ARI) Extension
- Support [draft-ietf-acme-profiles-00](https://datatracker.ietf.org/doc/draft-ietf-acme-profiles/): Profiles Extension
- Comes with about [180 DNS providers](https://go-acme.github.io/lego/dns)
- Comes with about [170 DNS providers](https://go-acme.github.io/lego/dns)
- Register with CA
- Obtain certificates, both from scratch or with an existing CSR
- Renew certificates
@ -56,63 +56,51 @@ Documentation is hosted live at https://go-acme.github.io/lego/.
Detailed documentation is available [here](https://go-acme.github.io/lego/dns).
If your DNS provider is not supported, please open an [issue](https://github.com/go-acme/lego/issues/new?assignees=&labels=enhancement%2C+new-provider&template=new_dns_provider.yml).
<!-- START DNS PROVIDERS LIST -->
<table><tr>
<td><a href="https://go-acme.github.io/lego/dns/com35/">35.com/三五互联</a></td>
<td><a href="https://go-acme.github.io/lego/dns/active24/">Active24</a></td>
<td><a href="https://go-acme.github.io/lego/dns/edgedns/">Akamai EdgeDNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/alidns/">Alibaba Cloud DNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/aliesa/">AlibabaCloud ESA</a></td>
<td><a href="https://go-acme.github.io/lego/dns/allinkl/">all-inkl</a></td>
<td><a href="https://go-acme.github.io/lego/dns/alwaysdata/">Alwaysdata</a></td>
<td><a href="https://go-acme.github.io/lego/dns/lightsail/">Amazon Lightsail</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/lightsail/">Amazon Lightsail</a></td>
<td><a href="https://go-acme.github.io/lego/dns/route53/">Amazon Route 53</a></td>
<td><a href="https://go-acme.github.io/lego/dns/anexia/">Anexia CloudDNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/safedns/">ANS SafeDNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/artfiles/">ArtFiles</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/arvancloud/">ArvanCloud</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/auroradns/">Aurora DNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/autodns/">Autodns</a></td>
<td><a href="https://go-acme.github.io/lego/dns/axelname/">Axelname</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/azion/">Azion</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/azure/">Azure (deprecated)</a></td>
<td><a href="https://go-acme.github.io/lego/dns/azuredns/">Azure DNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/baiducloud/">Baidu Cloud</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/beget/">Beget.com</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/binarylane/">Binary Lane</a></td>
<td><a href="https://go-acme.github.io/lego/dns/bindman/">Bindman</a></td>
<td><a href="https://go-acme.github.io/lego/dns/bluecat/">Bluecat</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/bluecatv2/">Bluecat v2</a></td>
<td><a href="https://go-acme.github.io/lego/dns/bookmyname/">BookMyName</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/brandit/">Brandit (deprecated)</a></td>
<td><a href="https://go-acme.github.io/lego/dns/bunny/">Bunny</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/checkdomain/">Checkdomain</a></td>
<td><a href="https://go-acme.github.io/lego/dns/civo/">Civo</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/cloudru/">Cloud.ru</a></td>
<td><a href="https://go-acme.github.io/lego/dns/clouddns/">CloudDNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/cloudflare/">Cloudflare</a></td>
<td><a href="https://go-acme.github.io/lego/dns/cloudns/">ClouDNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/cloudxns/">CloudXNS (Deprecated)</a></td>
<td><a href="https://go-acme.github.io/lego/dns/conoha/">ConoHa v2</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/conohav3/">ConoHa v3</a></td>
<td><a href="https://go-acme.github.io/lego/dns/constellix/">Constellix</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/corenetworks/">Core-Networks</a></td>
<td><a href="https://go-acme.github.io/lego/dns/cpanel/">CPanel/WHM</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/czechia/">Czechia</a></td>
<td><a href="https://go-acme.github.io/lego/dns/ddnss/">DDnss (DynDNS Service)</a></td>
<td><a href="https://go-acme.github.io/lego/dns/derak/">Derak Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/desec/">deSEC.io</a></td>
</tr><tr>
@ -121,48 +109,38 @@ If your DNS provider is not supported, please open an [issue](https://github.com
<td><a href="https://go-acme.github.io/lego/dns/directadmin/">DirectAdmin</a></td>
<td><a href="https://go-acme.github.io/lego/dns/dnsmadeeasy/">DNS Made Easy</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/dnsexit/">DNSExit</a></td>
<td><a href="https://go-acme.github.io/lego/dns/dnshomede/">dnsHome.de</a></td>
<td><a href="https://go-acme.github.io/lego/dns/dnsimple/">DNSimple</a></td>
<td><a href="https://go-acme.github.io/lego/dns/dnspod/">DNSPod (deprecated)</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/dode/">Domain Offensive (do.de)</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/domeneshop/">Domeneshop</a></td>
<td><a href="https://go-acme.github.io/lego/dns/dreamhost/">DreamHost</a></td>
<td><a href="https://go-acme.github.io/lego/dns/duckdns/">Duck DNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/dyn/">Dyn</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/dyndnsfree/">DynDnsFree.de</a></td>
<td><a href="https://go-acme.github.io/lego/dns/dynu/">Dynu</a></td>
<td><a href="https://go-acme.github.io/lego/dns/easydns/">EasyDNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/edgecenter/">EdgeCenter</a></td>
<td><a href="https://go-acme.github.io/lego/dns/efficientip/">Efficient IP</a></td>
<td><a href="https://go-acme.github.io/lego/dns/epik/">Epik</a></td>
<td><a href="https://go-acme.github.io/lego/dns/eurodns/">EuroDNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/excedo/">Excedo</a></td>
<td><a href="https://go-acme.github.io/lego/dns/epik/">Epik</a></td>
<td><a href="https://go-acme.github.io/lego/dns/exoscale/">Exoscale</a></td>
<td><a href="https://go-acme.github.io/lego/dns/exec/">External program</a></td>
<td><a href="https://go-acme.github.io/lego/dns/f5xc/">F5 XC</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/freemyip/">freemyip.com</a></td>
<td><a href="https://go-acme.github.io/lego/dns/namesurfer/">FusionLayer NameSurfer</a></td>
<td><a href="https://go-acme.github.io/lego/dns/gcore/">G-Core</a></td>
<td><a href="https://go-acme.github.io/lego/dns/gandi/">Gandi</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/gandiv5/">Gandi Live DNS (v5)</a></td>
<td><a href="https://go-acme.github.io/lego/dns/gigahostno/">Gigahost.no</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/glesys/">Glesys</a></td>
<td><a href="https://go-acme.github.io/lego/dns/godaddy/">Go Daddy</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/gcloud/">Google Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/googledomains/">Google Domains</a></td>
<td><a href="https://go-acme.github.io/lego/dns/gravity/">Gravity</a></td>
<td><a href="https://go-acme.github.io/lego/dns/hetzner/">Hetzner</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/hetzner/">Hetzner</a></td>
<td><a href="https://go-acme.github.io/lego/dns/hostingde/">Hosting.de</a></td>
<td><a href="https://go-acme.github.io/lego/dns/hostingnl/">Hosting.nl</a></td>
<td><a href="https://go-acme.github.io/lego/dns/hostinger/">Hostinger</a></td>
<td><a href="https://go-acme.github.io/lego/dns/hosttech/">Hosttech</a></td>
</tr><tr>
@ -182,124 +160,114 @@ If your DNS provider is not supported, please open an [issue](https://github.com
<td><a href="https://go-acme.github.io/lego/dns/inwx/">INWX</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/ionos/">Ionos</a></td>
<td><a href="https://go-acme.github.io/lego/dns/ionoscloud/">Ionos Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/ipv64/">IPv64</a></td>
<td><a href="https://go-acme.github.io/lego/dns/ispconfig/">ISPConfig 3</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/ispconfigddns/">ISPConfig 3 - Dynamic DNS (DDNS) Module</a></td>
<td><a href="https://go-acme.github.io/lego/dns/iwantmyname/">iwantmyname (Deprecated)</a></td>
<td><a href="https://go-acme.github.io/lego/dns/jdcloud/">JD Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/joker/">Joker</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/acme-dns/">Joohoi&#39;s ACME-DNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/keyhelp/">KeyHelp</a></td>
<td><a href="https://go-acme.github.io/lego/dns/leaseweb/">Leaseweb</a></td>
<td><a href="https://go-acme.github.io/lego/dns/liara/">Liara</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/limacity/">Lima-City</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/linode/">Linode (v4)</a></td>
<td><a href="https://go-acme.github.io/lego/dns/liquidweb/">Liquid Web</a></td>
<td><a href="https://go-acme.github.io/lego/dns/loopia/">Loopia</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/luadns/">LuaDNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/mailinabox/">Mail-in-a-Box</a></td>
<td><a href="https://go-acme.github.io/lego/dns/manageengine/">ManageEngine CloudDNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/manual/">Manual</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/metaname/">Metaname</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/metaregistrar/">Metaregistrar</a></td>
<td><a href="https://go-acme.github.io/lego/dns/mijnhost/">mijn.host</a></td>
<td><a href="https://go-acme.github.io/lego/dns/mittwald/">Mittwald</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/myaddr/">myaddr.{tools,dev,io}</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/mydnsjp/">MyDNS.jp</a></td>
<td><a href="https://go-acme.github.io/lego/dns/mythicbeasts/">MythicBeasts</a></td>
<td><a href="https://go-acme.github.io/lego/dns/namedotcom/">Name.com</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/namecheap/">Namecheap</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/namesilo/">Namesilo</a></td>
<td><a href="https://go-acme.github.io/lego/dns/nearlyfreespeech/">NearlyFreeSpeech.NET</a></td>
<td><a href="https://go-acme.github.io/lego/dns/neodigit/">Neodigit</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/netcup/">Netcup</a></td>
<td><a href="https://go-acme.github.io/lego/dns/netlify/">Netlify</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/nicmanager/">Nicmanager</a></td>
<td><a href="https://go-acme.github.io/lego/dns/nifcloud/">NIFCloud</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/njalla/">Njalla</a></td>
<td><a href="https://go-acme.github.io/lego/dns/nodion/">Nodion</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/ns1/">NS1</a></td>
<td><a href="https://go-acme.github.io/lego/dns/octenium/">Octenium</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/otc/">Open Telekom Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/oraclecloud/">Oracle Cloud</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/ovh/">OVH</a></td>
<td><a href="https://go-acme.github.io/lego/dns/plesk/">plesk.com</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/porkbun/">Porkbun</a></td>
<td><a href="https://go-acme.github.io/lego/dns/pdns/">PowerDNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/rackspace/">Rackspace</a></td>
<td><a href="https://go-acme.github.io/lego/dns/rainyun/">Rain Yun/雨云</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/rcodezero/">RcodeZero</a></td>
<td><a href="https://go-acme.github.io/lego/dns/regru/">reg.ru</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/regfish/">Regfish</a></td>
<td><a href="https://go-acme.github.io/lego/dns/rfc2136/">RFC2136</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/rimuhosting/">RimuHosting</a></td>
<td><a href="https://go-acme.github.io/lego/dns/nicru/">RU CENTER</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/sakuracloud/">Sakura Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/scaleway/">Scaleway</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/selectel/">Selectel</a></td>
<td><a href="https://go-acme.github.io/lego/dns/selectelv2/">Selectel v2</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/selfhostde/">SelfHost.(de|eu)</a></td>
<td><a href="https://go-acme.github.io/lego/dns/servercow/">Servercow</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/shellrent/">Shellrent</a></td>
<td><a href="https://go-acme.github.io/lego/dns/simply/">Simply.com</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/sonic/">Sonic</a></td>
<td><a href="https://go-acme.github.io/lego/dns/spaceship/">Spaceship</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/stackpath/">Stackpath</a></td>
<td><a href="https://go-acme.github.io/lego/dns/syse/">Syse</a></td>
<td><a href="https://go-acme.github.io/lego/dns/technitium/">Technitium</a></td>
<td><a href="https://go-acme.github.io/lego/dns/tencentcloud/">Tencent Cloud DNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/tencentcloud/">Tencent Cloud DNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/edgeone/">Tencent EdgeOne</a></td>
<td><a href="https://go-acme.github.io/lego/dns/timewebcloud/">Timeweb Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/todaynic/">TodayNIC/时代互联</a></td>
<td><a href="https://go-acme.github.io/lego/dns/transip/">TransIP</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/safedns/">UKFast SafeDNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/ultradns/">Ultradns</a></td>
<td><a href="https://go-acme.github.io/lego/dns/uniteddomains/">United-Domains</a></td>
<td><a href="https://go-acme.github.io/lego/dns/variomedia/">Variomedia</a></td>
<td><a href="https://go-acme.github.io/lego/dns/vegadns/">VegaDNS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/vercel/">Vercel</a></td>
<td><a href="https://go-acme.github.io/lego/dns/versio/">Versio.[nl|eu|uk]</a></td>
<td><a href="https://go-acme.github.io/lego/dns/vinyldns/">VinylDNS</a></td>
<td><a href="https://go-acme.github.io/lego/dns/virtualname/">Virtualname</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/vkcloud/">VK Cloud</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/volcengine/">Volcano Engine/火山引擎</a></td>
<td><a href="https://go-acme.github.io/lego/dns/vscale/">Vscale</a></td>
<td><a href="https://go-acme.github.io/lego/dns/vultr/">Vultr</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/webnamesca/">webnames.ca</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/webnames/">webnames.ru</a></td>
<td><a href="https://go-acme.github.io/lego/dns/websupport/">Websupport</a></td>
<td><a href="https://go-acme.github.io/lego/dns/wedos/">WEDOS</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/westcn/">West.cn/西部数码</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/yandex360/">Yandex 360</a></td>
<td><a href="https://go-acme.github.io/lego/dns/yandexcloud/">Yandex Cloud</a></td>
<td><a href="https://go-acme.github.io/lego/dns/yandex/">Yandex PDD</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/zoneee/">Zone.ee</a></td>
</tr><tr>
<td><a href="https://go-acme.github.io/lego/dns/zoneedit/">ZoneEdit</a></td>
<td><a href="https://go-acme.github.io/lego/dns/zonomi/">Zonomi</a></td>
<td></td>
<td></td>
</tr></table>
<!-- END DNS PROVIDERS LIST -->

View file

@ -2,6 +2,7 @@ package api
import (
"cmp"
"maps"
"net"
"slices"
@ -9,9 +10,7 @@ import (
)
func createIdentifiers(domains []string) []acme.Identifier {
uniqIdentifiers := make(map[string]struct{})
var identifiers []acme.Identifier
uniqIdentifiers := make(map[string]acme.Identifier)
for _, domain := range domains {
if _, ok := uniqIdentifiers[domain]; ok {
@ -24,12 +23,10 @@ func createIdentifiers(domains []string) []acme.Identifier {
ident.Type = "ip"
}
identifiers = append(identifiers, ident)
uniqIdentifiers[domain] = struct{}{}
uniqIdentifiers[domain] = ident
}
return identifiers
return slices.AppendSeq(make([]acme.Identifier, 0, len(uniqIdentifiers)), maps.Values(uniqIdentifiers))
}
// compareIdentifiers compares 2 slices of [acme.Identifier].

View file

@ -120,46 +120,39 @@ func (d *Doer) formatUserAgent() string {
}
func checkError(req *http.Request, resp *http.Response) error {
if resp.StatusCode < http.StatusBadRequest {
return nil
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("%d :: %s :: %s :: %w", resp.StatusCode, req.Method, req.URL, err)
}
var errorDetails *acme.ProblemDetails
err = json.Unmarshal(body, &errorDetails)
if err != nil {
return fmt.Errorf("%d ::%s :: %s :: %w :: %s", resp.StatusCode, req.Method, req.URL, err, string(body))
}
errorDetails.Method = req.Method
errorDetails.URL = req.URL.String()
if errorDetails.HTTPStatus == 0 {
errorDetails.HTTPStatus = resp.StatusCode
}
// Check for errors we handle specifically
switch {
case errorDetails.HTTPStatus == http.StatusBadRequest && errorDetails.Type == acme.BadNonceErr:
return &acme.NonceError{ProblemDetails: errorDetails}
case errorDetails.HTTPStatus == http.StatusConflict && errorDetails.Type == acme.AlreadyReplacedErr:
return &acme.AlreadyReplacedError{ProblemDetails: errorDetails}
case errorDetails.HTTPStatus == http.StatusTooManyRequests && errorDetails.Type == acme.RateLimitedErr:
return &acme.RateLimitedError{
ProblemDetails: errorDetails,
RetryAfter: resp.Header.Get("Retry-After"),
if resp.StatusCode >= http.StatusBadRequest {
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("%d :: %s :: %s :: %w", resp.StatusCode, req.Method, req.URL, err)
}
var errorDetails *acme.ProblemDetails
err = json.Unmarshal(body, &errorDetails)
if err != nil {
return fmt.Errorf("%d ::%s :: %s :: %w :: %s", resp.StatusCode, req.Method, req.URL, err, string(body))
}
errorDetails.Method = req.Method
errorDetails.URL = req.URL.String()
if errorDetails.HTTPStatus == 0 {
errorDetails.HTTPStatus = resp.StatusCode
}
// Check for errors we handle specifically
if errorDetails.HTTPStatus == http.StatusBadRequest && errorDetails.Type == acme.BadNonceErr {
return &acme.NonceError{ProblemDetails: errorDetails}
}
if errorDetails.HTTPStatus == http.StatusConflict && errorDetails.Type == acme.AlreadyReplacedErr {
return &acme.AlreadyReplacedError{ProblemDetails: errorDetails}
}
default:
return errorDetails
}
return nil
}
type httpsOnly struct {

View file

@ -1,14 +1,11 @@
package sender
import (
"bytes"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/go-acme/lego/v4/acme"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -81,70 +78,3 @@ func TestDo_failWithHTTP(t *testing.T) {
_, err := sender.Post(server.URL, strings.NewReader("data"), "text/plain", nil)
require.ErrorContains(t, err, "HTTPS is required: http://")
}
func Test_checkError(t *testing.T) {
testCases := []struct {
desc string
resp *http.Response
assert func(t *testing.T, err error)
}{
{
desc: "default",
resp: &http.Response{
StatusCode: http.StatusNotFound,
Body: io.NopCloser(bytes.NewBufferString(`{"type":"urn:ietf:params:acme:error:example","detail":"message","status":404}`)),
},
assert: errorAs[*acme.ProblemDetails],
},
{
desc: "badNonce",
resp: &http.Response{
StatusCode: http.StatusBadRequest,
Body: io.NopCloser(bytes.NewBufferString(`{"type":"urn:ietf:params:acme:error:badNonce","detail":"message","status":400}`)),
},
assert: errorAs[*acme.NonceError],
},
{
desc: "alreadyReplaced",
resp: &http.Response{
StatusCode: http.StatusConflict,
Body: io.NopCloser(bytes.NewBufferString(`{"type":"urn:ietf:params:acme:error:alreadyReplaced","detail":"message","status":409}`)),
},
assert: errorAs[*acme.AlreadyReplacedError],
},
{
desc: "rateLimited",
resp: &http.Response{
StatusCode: http.StatusConflict,
Header: http.Header{
"Retry-After": []string{"1"},
},
Body: io.NopCloser(bytes.NewBufferString(`{"type":"urn:ietf:params:acme:error:rateLimited","detail":"message","status":429}`)),
},
assert: errorAs[*acme.RateLimitedError],
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
req := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "https://example.com", nil)
err := checkError(req, test.resp)
require.Error(t, err)
pb := &acme.ProblemDetails{}
assert.ErrorAs(t, err, &pb)
test.assert(t, err)
})
}
}
func errorAs[T error](t *testing.T, err error) {
t.Helper()
var zero T
assert.ErrorAs(t, err, &zero)
}

View file

@ -4,10 +4,10 @@ package sender
const (
// ourUserAgent is the User-Agent of this underlying library package.
ourUserAgent = "xenolf-acme/4.32.0"
ourUserAgent = "xenolf-acme/4.28.0"
// ourUserAgentComment is part of the UA comment linked to the version status of this underlying library package.
// values: detach|release
// NOTE: Update this with each tagged release.
ourUserAgentComment = "detach"
ourUserAgentComment = "release"
)

View file

@ -1,11 +1,8 @@
package api
import (
"fmt"
"net/http"
"regexp"
"strconv"
"time"
)
type service struct {
@ -59,29 +56,3 @@ func getRetryAfter(resp *http.Response) string {
return resp.Header.Get("Retry-After")
}
// ParseRetryAfter parses the Retry-After header value according to RFC 7231.
// The header can be either delay-seconds (numeric) or HTTP-date (RFC 1123 format).
// https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.3
// Returns the duration until the retry time.
// TODO(ldez): unexposed this function in v5.
func ParseRetryAfter(value string) (time.Duration, error) {
if value == "" {
return 0, nil
}
if seconds, err := strconv.ParseInt(value, 10, 64); err == nil {
return time.Duration(seconds) * time.Second, nil
}
if retryTime, err := time.Parse(time.RFC1123, value); err == nil {
duration := time.Until(retryTime)
if duration < 0 {
return 0, nil
}
return duration, nil
}
return 0, fmt.Errorf("invalid Retry-After value: %q", value)
}

View file

@ -3,10 +3,8 @@ package api
import (
"net/http"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_getLink(t *testing.T) {
@ -55,38 +53,3 @@ func Test_getLink(t *testing.T) {
})
}
}
func TestParseRetryAfter(t *testing.T) {
testCases := []struct {
desc string
value string
expected time.Duration
}{
{
desc: "empty header value",
value: "",
expected: time.Duration(0),
},
{
desc: "delay-seconds",
value: "123",
expected: 123 * time.Second,
},
{
desc: "HTTP-date",
value: time.Now().Add(3 * time.Second).Format(time.RFC1123),
expected: 3 * time.Second,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
rt, err := ParseRetryAfter(test.value)
require.NoError(t, err)
assert.InDelta(t, test.expected.Seconds(), rt.Seconds(), 1)
})
}
}

View file

@ -10,7 +10,6 @@ const (
errNS = "urn:ietf:params:acme:error:"
BadNonceErr = errNS + "badNonce"
AlreadyReplacedErr = errNS + "alreadyReplaced"
RateLimitedErr = errNS + "rateLimited"
)
// ProblemDetails the problem details object.
@ -29,18 +28,18 @@ type ProblemDetails struct {
}
func (p *ProblemDetails) Error() string {
msg := new(strings.Builder)
var msg strings.Builder
_, _ = fmt.Fprintf(msg, "acme: error: %d", p.HTTPStatus)
msg.WriteString(fmt.Sprintf("acme: error: %d", p.HTTPStatus))
if p.Method != "" || p.URL != "" {
_, _ = fmt.Fprintf(msg, " :: %s :: %s", p.Method, p.URL)
msg.WriteString(fmt.Sprintf(" :: %s :: %s", p.Method, p.URL))
}
_, _ = fmt.Fprintf(msg, " :: %s :: %s", p.Type, p.Detail)
msg.WriteString(fmt.Sprintf(" :: %s :: %s", p.Type, p.Detail))
for _, sub := range p.SubProblems {
_, _ = fmt.Fprintf(msg, ", problem: %q :: %s", sub.Type, sub.Detail)
msg.WriteString(fmt.Sprintf(", problem: %q :: %s", sub.Type, sub.Detail))
}
if p.Instance != "" {
@ -64,30 +63,9 @@ type NonceError struct {
*ProblemDetails
}
func (e *NonceError) Unwrap() error {
return e.ProblemDetails
}
// AlreadyReplacedError represents the error which is returned
// if the Server rejects the request because the identified certificate has already been marked as replaced.
// If the Server rejects the request because the identified certificate has already been marked as replaced.
// - https://www.rfc-editor.org/rfc/rfc9773.html#section-5
type AlreadyReplacedError struct {
*ProblemDetails
}
func (e *AlreadyReplacedError) Unwrap() error {
return e.ProblemDetails
}
// RateLimitedError represents the error which is returned
// if the server rejects the request because the client has exceeded the rate limit.
// - https://www.rfc-editor.org/rfc/rfc8555.html#section-6.6
type RateLimitedError struct {
*ProblemDetails
RetryAfter string
}
func (e *RateLimitedError) Unwrap() error {
return e.ProblemDetails
}

View file

@ -242,15 +242,15 @@ func ParsePEMCertificate(cert []byte) (*x509.Certificate, error) {
}
func GetCertificateMainDomain(cert *x509.Certificate) (string, error) {
return getMainDomain(cert.Subject, cert.DNSNames, cert.IPAddresses)
return getMainDomain(cert.Subject, cert.DNSNames)
}
func GetCSRMainDomain(cert *x509.CertificateRequest) (string, error) {
return getMainDomain(cert.Subject, cert.DNSNames, cert.IPAddresses)
return getMainDomain(cert.Subject, cert.DNSNames)
}
func getMainDomain(subject pkix.Name, dnsNames []string, ips []net.IP) (string, error) {
if subject.CommonName == "" && len(dnsNames) == 0 && len(ips) == 0 {
func getMainDomain(subject pkix.Name, dnsNames []string) (string, error) {
if subject.CommonName == "" && len(dnsNames) == 0 {
return "", errors.New("missing domain")
}
@ -258,11 +258,7 @@ func getMainDomain(subject pkix.Name, dnsNames []string, ips []net.IP) (string,
return subject.CommonName, nil
}
if len(dnsNames) > 0 {
return dnsNames[0], nil
}
return ips[0].String(), nil
return dnsNames[0], nil
}
func ExtractDomains(cert *x509.Certificate) []string {

View file

@ -11,7 +11,6 @@ import (
"time"
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/acme/api"
)
// RenewalInfoRequest contains the necessary renewal information.
@ -93,9 +92,9 @@ func (c *Certifier) GetRenewalInfo(req RenewalInfoRequest) (*RenewalInfoResponse
}
if retry := resp.Header.Get("Retry-After"); retry != "" {
info.RetryAfter, err = api.ParseRetryAfter(retry)
info.RetryAfter, err = time.ParseDuration(retry + "s")
if err != nil {
return nil, fmt.Errorf("failed to parse Retry-After header: %w", err)
return nil, err
}
}

View file

@ -74,42 +74,6 @@ func TestCertifier_GetRenewalInfo(t *testing.T) {
assert.Equal(t, time.Duration(21600000000000), ri.RetryAfter)
}
func TestCertifier_GetRenewalInfo_retryAfter(t *testing.T) {
leaf, err := certcrypto.ParsePEMCertificate([]byte(ariLeafPEM))
require.NoError(t, err)
server := tester.MockACMEServer().
Route("GET /renewalInfo/"+ariLeafCertID,
servermock.RawStringResponse(`{
"suggestedWindow": {
"start": "2020-03-17T17:51:09Z",
"end": "2020-03-17T18:21:09Z"
},
"explanationUrl": "https://aricapable.ca.example/docs/renewal-advice/"
}
}`).
WithHeader("Content-Type", "application/json").
WithHeader("Retry-After", time.Now().UTC().Add(6*time.Hour).Format(time.RFC1123))).
BuildHTTPS(t)
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err, "Could not generate test key")
core, err := api.New(server.Client(), "lego-test", server.URL+"/dir", "", key)
require.NoError(t, err)
certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048})
ri, err := certifier.GetRenewalInfo(RenewalInfoRequest{leaf})
require.NoError(t, err)
require.NotNil(t, ri)
assert.Equal(t, "2020-03-17T17:51:09Z", ri.SuggestedWindow.Start.Format(time.RFC3339))
assert.Equal(t, "2020-03-17T18:21:09Z", ri.SuggestedWindow.End.Format(time.RFC3339))
assert.Equal(t, "https://aricapable.ca.example/docs/renewal-advice/", ri.ExplanationURL)
assert.InDelta(t, 6, ri.RetryAfter.Hours(), 0.001)
}
func TestCertifier_GetRenewalInfo_errors(t *testing.T) {
leaf, err := certcrypto.ParsePEMCertificate([]byte(ariLeafPEM))
require.NoError(t, err)

View file

@ -12,14 +12,9 @@ const (
)
// DNSProviderManual is an implementation of the ChallengeProvider interface.
// TODO(ldez): move this to providers/dns/manual
//
// Deprecated: Use the manual.DNSProvider instead.
type DNSProviderManual struct{}
// NewDNSProviderManual returns a DNSProviderManual instance.
//
// Deprecated: Use the manual.NewDNSProvider instead.
func NewDNSProviderManual() (*DNSProviderManual, error) {
return &DNSProviderManual{}, nil
}

View file

@ -1,14 +1,22 @@
package manual
package dns01
import (
"io"
"os"
"testing"
"github.com/go-acme/lego/v4/platform/tester/dnsmock"
"github.com/miekg/dns"
"github.com/stretchr/testify/require"
)
func TestDNSProviderManual(t *testing.T) {
useAsNameserver(t, dnsmock.NewServer().
Query("_acme-challenge.example.com. CNAME", dnsmock.Noop).
Query("_acme-challenge.example.com. SOA", dnsmock.Error(dns.RcodeNameError)).
Query("example.com. SOA", dnsmock.SOA("")).
Build(t))
backupStdin := os.Stdin
defer func() { os.Stdin = backupStdin }()
@ -44,7 +52,7 @@ func TestDNSProviderManual(t *testing.T) {
os.Stdin = file
manualProvider, err := NewDNSProvider()
manualProvider, err := NewDNSProviderManual()
require.NoError(t, err)
err = manualProvider.Present("example.com", "", "")

View file

@ -3,8 +3,6 @@ package resolver
import (
"bytes"
"fmt"
"maps"
"slices"
"sort"
)
@ -27,7 +25,3 @@ func (e obtainError) Error() string {
return buffer.String()
}
func (e obtainError) Unwrap() []error {
return slices.AppendSeq(make([]error, 0, len(e)), maps.Values(e))
}

View file

@ -1,70 +0,0 @@
package resolver
import (
"errors"
"testing"
"github.com/go-acme/lego/v4/acme"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_obtainError_Error(t *testing.T) {
err := obtainError{
"a": &acme.ProblemDetails{Type: "001"},
"b": errors.New("oops"),
"c": errors.New("I did it again"),
}
require.EqualError(t, err, `error: one or more domains had a problem:
[a] acme: error: 0 :: 001 ::
[b] oops
[c] I did it again
`)
}
func Test_obtainError_Unwrap(t *testing.T) {
testCases := []struct {
desc string
err obtainError
assert assert.BoolAssertionFunc
}{
{
desc: "one ok",
err: obtainError{
"a": &acme.ProblemDetails{},
"b": errors.New("oops"),
"c": errors.New("I did it again"),
},
assert: assert.True,
},
{
desc: "all ok",
err: obtainError{
"a": &acme.ProblemDetails{Type: "001"},
"b": &acme.ProblemDetails{Type: "002"},
"c": &acme.ProblemDetails{Type: "002"},
},
assert: assert.True,
},
{
desc: "nope",
err: obtainError{
"a": errors.New("hello"),
"b": errors.New("oops"),
"c": errors.New("I did it again"),
},
assert: assert.False,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
var pd *acme.ProblemDetails
test.assert(t, errors.As(test.err, &pd))
})
}
}

View file

@ -98,24 +98,11 @@ func (p *Prober) Solve(authorizations []acme.Authorization) error {
}
func sequentialSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
// Some CA are using the same token,
// this can be a problem with the DNS01 challenge when the DNS provider doesn't support duplicate TXT records.
// In the sequential mode, this is not a problem because we can solve the challenges in order.
// But it can reduce the number of call the DNS provider APIs.
uniq := make(map[string]struct{})
for i, authSolver := range authSolvers {
// Submit the challenge
domain := challenge.GetTargetedDomain(authSolver.authz)
chlg, _ := challenge.FindChallenge(challenge.DNS01, authSolver.authz)
if solvr, ok := authSolver.solver.(preSolver); ok {
if _, ok := uniq[authSolver.authz.Identifier.Value+chlg.Token]; ok && chlg.Token != "" {
log.Infof("acme: duplicate token for %q (DNS-01); skipping pre-solve.", authSolver.authz.Identifier.Value)
continue
}
err := solvr.PreSolve(authSolver.authz)
if err != nil {
failures[domain] = err
@ -124,8 +111,6 @@ func sequentialSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
continue
}
uniq[authSolver.authz.Identifier.Value+chlg.Token] = struct{}{}
}
// Solve challenge
@ -138,43 +123,22 @@ func sequentialSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
continue
}
if _, ok := uniq[authSolver.authz.Identifier.Value+chlg.Token]; ok || chlg.Token == "" {
// Clean challenge
cleanUp(authSolver.solver, authSolver.authz)
// Clean challenge
cleanUp(authSolver.solver, authSolver.authz)
if len(authSolvers)-1 > i {
solvr := authSolver.solver.(sequential)
_, interval := solvr.Sequential()
log.Infof("sequence: wait for %s", interval)
time.Sleep(interval)
}
delete(uniq, authSolver.authz.Identifier.Value+chlg.Token)
} else {
log.Infof("acme: duplicate token for %q (DNS-01); skipping cleanup.", authSolver.authz.Identifier.Value)
if len(authSolvers)-1 > i {
solvr := authSolver.solver.(sequential)
_, interval := solvr.Sequential()
log.Infof("sequence: wait for %s", interval)
time.Sleep(interval)
}
}
}
func parallelSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
// Some CA are using the same token,
// this can be a problem with the DNS01 challenge when the DNS provider doesn't support duplicate TXT records.
uniq := make(map[string]struct{})
// For all valid preSolvers, first submit the challenges, so they have max time to propagate
for _, authSolver := range authSolvers {
authz := authSolver.authz
chlg, err := challenge.FindChallenge(challenge.DNS01, authz)
if err == nil {
if _, ok := uniq[authz.Identifier.Value+chlg.Token]; ok {
log.Infof("acme: duplicate token for %q (DNS-01); skipping pre-solve.", authSolver.authz.Identifier.Value)
continue
}
uniq[authz.Identifier.Value+chlg.Token] = struct{}{}
}
if solvr, ok := authSolver.solver.(preSolver); ok {
err := solvr.PreSolve(authz)
if err != nil {
@ -186,16 +150,6 @@ func parallelSolve(authSolvers []*selectedAuthSolver, failures obtainError) {
defer func() {
// Clean all created TXT records
for _, authSolver := range authSolvers {
chlg, err := challenge.FindChallenge(challenge.DNS01, authSolver.authz)
if err == nil {
if _, ok := uniq[authSolver.authz.Identifier.Value+chlg.Token]; ok {
delete(uniq, authSolver.authz.Identifier.Value+chlg.Token)
} else {
log.Infof("acme: duplicate token for %q (DNS-01); skipping cleanup.", authSolver.authz.Identifier.Value)
continue
}
}
cleanUp(authSolver.solver, authSolver.authz)
}
}()

View file

@ -1,7 +1,6 @@
package resolver
import (
"fmt"
"time"
"github.com/go-acme/lego/v4/acme"
@ -12,68 +11,34 @@ type preSolverMock struct {
preSolve map[string]error
solve map[string]error
cleanUp map[string]error
preSolveCounter int
solveCounter int
cleanUpCounter int
}
func (s *preSolverMock) PreSolve(authorization acme.Authorization) error {
s.preSolveCounter++
return s.preSolve[authorization.Identifier.Value]
}
func (s *preSolverMock) Solve(authorization acme.Authorization) error {
s.solveCounter++
return s.solve[authorization.Identifier.Value]
}
func (s *preSolverMock) CleanUp(authorization acme.Authorization) error {
s.cleanUpCounter++
return s.cleanUp[authorization.Identifier.Value]
}
func (s *preSolverMock) String() string {
return fmt.Sprintf("PreSolve: %d, Solve: %d, CleanUp: %d", s.preSolveCounter, s.solveCounter, s.cleanUpCounter)
}
func createStubAuthorizationHTTP01(domain, status string) acme.Authorization {
return createStubAuthorization(domain, status, false, acme.Challenge{
Type: challenge.HTTP01.String(),
Validated: time.Now(),
})
}
func createStubAuthorizationDNS01(domain string, wildcard bool) acme.Authorization {
var chlgs []acme.Challenge
if wildcard {
chlgs = append(chlgs, acme.Challenge{
Type: challenge.HTTP01.String(),
Validated: time.Now(),
})
}
chlgs = append(chlgs, acme.Challenge{
Type: challenge.DNS01.String(),
Validated: time.Now(),
})
return createStubAuthorization(domain, acme.StatusProcessing, wildcard, chlgs...)
}
func createStubAuthorization(domain, status string, wildcard bool, chlgs ...acme.Challenge) acme.Authorization {
return acme.Authorization{
Wildcard: wildcard,
Status: status,
Expires: time.Now(),
Status: status,
Expires: time.Now(),
Identifier: acme.Identifier{
Type: "dns",
Type: challenge.HTTP01.String(),
Value: domain,
},
Challenges: chlgs,
Challenges: []acme.Challenge{
{
Type: challenge.HTTP01.String(),
Validated: time.Now(),
Error: nil,
},
},
}
}

View file

@ -2,22 +2,19 @@ package resolver
import (
"errors"
"fmt"
"testing"
"github.com/go-acme/lego/v4/acme"
"github.com/go-acme/lego/v4/challenge"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestProber_Solve(t *testing.T) {
testCases := []struct {
desc string
solvers map[challenge.Type]solver
authz []acme.Authorization
expectedError string
expectedCounters map[challenge.Type]string
desc string
solvers map[challenge.Type]solver
authz []acme.Authorization
expectedError string
}{
{
desc: "success",
@ -33,30 +30,6 @@ func TestProber_Solve(t *testing.T) {
createStubAuthorizationHTTP01("example.org", acme.StatusProcessing),
createStubAuthorizationHTTP01("example.net", acme.StatusProcessing),
},
expectedCounters: map[challenge.Type]string{
challenge.HTTP01: "PreSolve: 3, Solve: 3, CleanUp: 3",
},
},
{
desc: "DNS-01 deduplicate",
solvers: map[challenge.Type]solver{
challenge.DNS01: &preSolverMock{
preSolve: map[string]error{},
solve: map[string]error{},
cleanUp: map[string]error{},
},
},
authz: []acme.Authorization{
createStubAuthorizationDNS01("a.example", false),
createStubAuthorizationDNS01("a.example", true),
createStubAuthorizationDNS01("b.example", false),
createStubAuthorizationDNS01("b.example", true),
createStubAuthorizationDNS01("c.example", true),
createStubAuthorizationDNS01("d.example", false),
},
expectedCounters: map[challenge.Type]string{
challenge.DNS01: "PreSolve: 4, Solve: 6, CleanUp: 4",
},
},
{
desc: "already valid",
@ -72,9 +45,6 @@ func TestProber_Solve(t *testing.T) {
createStubAuthorizationHTTP01("example.org", acme.StatusValid),
createStubAuthorizationHTTP01("example.net", acme.StatusValid),
},
expectedCounters: map[challenge.Type]string{
challenge.HTTP01: "PreSolve: 0, Solve: 0, CleanUp: 0",
},
},
{
desc: "when preSolve fail, auth is flagged as error and skipped",
@ -99,9 +69,6 @@ func TestProber_Solve(t *testing.T) {
expectedError: `error: one or more domains had a problem:
[example.com] preSolve error example.com
`,
expectedCounters: map[challenge.Type]string{
challenge.HTTP01: "PreSolve: 3, Solve: 2, CleanUp: 3",
},
},
{
desc: "errors at different stages",
@ -128,9 +95,6 @@ func TestProber_Solve(t *testing.T) {
[example.com] preSolve error example.com
[example.org] solve error example.org
`,
expectedCounters: map[challenge.Type]string{
challenge.HTTP01: "PreSolve: 3, Solve: 2, CleanUp: 3",
},
},
}
@ -148,10 +112,6 @@ func TestProber_Solve(t *testing.T) {
} else {
require.NoError(t, err)
}
for n, s := range test.solvers {
assert.Equal(t, test.expectedCounters[n], fmt.Sprintf("%s", s))
}
})
}
}

View file

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"sort"
"strconv"
"time"
"github.com/cenkalti/backoff/v5"
@ -93,20 +94,22 @@ func validate(core *api.Core, domain string, chlg acme.Challenge) error {
return nil
}
retryAfter, err := api.ParseRetryAfter(chlng.RetryAfter)
if err != nil || retryAfter == 0 {
ra, err := strconv.Atoi(chlng.RetryAfter)
if err != nil {
// The ACME server MUST return a Retry-After.
// If it doesn't, or if it's invalid, we'll just poll hard.
// If it doesn't, we'll just poll hard.
// Boulder does not implement the ability to retry challenges or the Retry-After header.
// https://github.com/letsencrypt/boulder/blob/master/docs/acme-divergences.md#section-82
retryAfter = 5 * time.Second
ra = 5
}
initialInterval := time.Duration(ra) * time.Second
ctx := context.Background()
bo := backoff.NewExponentialBackOff()
bo.InitialInterval = retryAfter
bo.MaxInterval = 10 * retryAfter
bo.InitialInterval = initialInterval
bo.MaxInterval = 10 * initialInterval
// After the path is sent, the ACME server will access our server.
// Repeatedly check the server for an updated status on our request.
@ -131,7 +134,7 @@ func validate(core *api.Core, domain string, chlg acme.Challenge) error {
return wait.Retry(ctx, operation,
backoff.WithBackOff(bo),
backoff.WithMaxElapsedTime(100*retryAfter))
backoff.WithMaxElapsedTime(100*initialInterval))
}
func checkChallengeStatus(chlng acme.ExtendedChallenge) (bool, error) {

View file

@ -16,8 +16,6 @@ import (
"github.com/urfave/cli/v2"
)
const userIDPlaceholder = "noemail@example.com"
const (
baseAccountsRootFolderName = "accounts"
baseKeysFolderName = "keys"
@ -34,7 +32,7 @@ const (
//
// rootUserPath:
//
// ./.lego/accounts/localhost_14000/foo@example.com/
// ./.lego/accounts/localhost_14000/hubert@hubert.com/
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
// │ └── root accounts directory
@ -42,7 +40,7 @@ const (
//
// keysPath:
//
// ./.lego/accounts/localhost_14000/foo@example.com/keys/
// ./.lego/accounts/localhost_14000/hubert@hubert.com/keys/
// │ │ │ │ └── root keys directory
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
@ -51,7 +49,7 @@ const (
//
// accountFilePath:
//
// ./.lego/accounts/localhost_14000/foo@example.com/account.json
// ./.lego/accounts/localhost_14000/hubert@hubert.com/account.json
// │ │ │ │ └── account file
// │ │ │ └── userID ("email" option)
// │ │ └── CA server ("server" option)
@ -59,7 +57,6 @@ const (
// └── "path" option
type AccountsStorage struct {
userID string
email string
rootPath string
rootUserPath string
keysPath string
@ -69,13 +66,8 @@ type AccountsStorage struct {
// NewAccountsStorage Creates a new AccountsStorage.
func NewAccountsStorage(ctx *cli.Context) *AccountsStorage {
// TODO: move to account struct?
email := ctx.String(flgEmail)
userID := email
if userID == "" {
userID = userIDPlaceholder
}
// TODO: move to account struct? Currently MUST pass email.
email := getEmail(ctx)
serverURL, err := url.Parse(ctx.String(flgServer))
if err != nil {
@ -85,11 +77,10 @@ func NewAccountsStorage(ctx *cli.Context) *AccountsStorage {
rootPath := filepath.Join(ctx.String(flgPath), baseAccountsRootFolderName)
serverPath := strings.NewReplacer(":", "_", "/", string(os.PathSeparator)).Replace(serverURL.Host)
accountsPath := filepath.Join(rootPath, serverPath)
rootUserPath := filepath.Join(accountsPath, userID)
rootUserPath := filepath.Join(accountsPath, email)
return &AccountsStorage{
userID: userID,
email: email,
userID: email,
rootPath: rootPath,
rootUserPath: rootUserPath,
keysPath: filepath.Join(rootUserPath, baseKeysFolderName),
@ -121,10 +112,6 @@ func (s *AccountsStorage) GetUserID() string {
return s.userID
}
func (s *AccountsStorage) GetEmail() string {
return s.email
}
func (s *AccountsStorage) Save(account *Account) error {
jsonBytes, err := json.MarshalIndent(account, "", "\t")
if err != nil {
@ -137,14 +124,14 @@ func (s *AccountsStorage) Save(account *Account) error {
func (s *AccountsStorage) LoadAccount(privateKey crypto.PrivateKey) *Account {
fileBytes, err := os.ReadFile(s.accountFilePath)
if err != nil {
log.Fatalf("Could not load file for account %s: %v", s.GetUserID(), err)
log.Fatalf("Could not load file for account %s: %v", s.userID, err)
}
var account Account
err = json.Unmarshal(fileBytes, &account)
if err != nil {
log.Fatalf("Could not parse file for account %s: %v", s.GetUserID(), err)
log.Fatalf("Could not parse file for account %s: %v", s.userID, err)
}
account.key = privateKey
@ -152,14 +139,14 @@ func (s *AccountsStorage) LoadAccount(privateKey crypto.PrivateKey) *Account {
if account.Registration == nil || account.Registration.Body.Status == "" {
reg, err := tryRecoverRegistration(s.ctx, privateKey)
if err != nil {
log.Fatalf("Could not load account for %s. Registration is nil: %#v", s.GetUserID(), err)
log.Fatalf("Could not load account for %s. Registration is nil: %#v", s.userID, err)
}
account.Registration = reg
err = s.Save(&account)
if err != nil {
log.Fatalf("Could not save account for %s. Registration is nil: %#v", s.GetUserID(), err)
log.Fatalf("Could not save account for %s. Registration is nil: %#v", s.userID, err)
}
}
@ -167,15 +154,15 @@ func (s *AccountsStorage) LoadAccount(privateKey crypto.PrivateKey) *Account {
}
func (s *AccountsStorage) GetPrivateKey(keyType certcrypto.KeyType) crypto.PrivateKey {
accKeyPath := filepath.Join(s.keysPath, s.GetUserID()+".key")
accKeyPath := filepath.Join(s.keysPath, s.userID+".key")
if _, err := os.Stat(accKeyPath); os.IsNotExist(err) {
log.Printf("No key found for account %s. Generating a %s key.", s.GetUserID(), keyType)
log.Printf("No key found for account %s. Generating a %s key.", s.userID, keyType)
s.createKeysFolder()
privateKey, err := generatePrivateKey(accKeyPath, keyType)
if err != nil {
log.Fatalf("Could not generate RSA private account key for account %s: %v", s.GetUserID(), err)
log.Fatalf("Could not generate RSA private account key for account %s: %v", s.userID, err)
}
log.Printf("Saved key to %s", accKeyPath)
@ -193,7 +180,7 @@ func (s *AccountsStorage) GetPrivateKey(keyType certcrypto.KeyType) crypto.Priva
func (s *AccountsStorage) createKeysFolder() {
if err := createNonExistingFolder(s.keysPath); err != nil {
log.Fatalf("Could not check/create directory for account %s: %v", s.GetUserID(), err)
log.Fatalf("Could not check/create directory for account %s: %v", s.userID, err)
}
}

View file

@ -3,7 +3,6 @@ package cmd
import (
"encoding/json"
"fmt"
"net"
"net/url"
"os"
"path/filepath"
@ -37,7 +36,7 @@ func createList() *cli.Command {
// fake email, needed by NewAccountsStorage
&cli.StringFlag{
Name: flgEmail,
Value: "",
Value: "unknown",
Hidden: true,
},
},
@ -101,11 +100,6 @@ func listCertificates(ctx *cli.Context) error {
} else {
fmt.Println(" Certificate Name:", name)
fmt.Println(" Domains:", strings.Join(pCert.DNSNames, ", "))
if len(pCert.IPAddresses) > 0 {
fmt.Println(" IPs:", formatIPAddresses(pCert.IPAddresses))
}
fmt.Println(" Expiry Date:", pCert.NotAfter)
fmt.Println(" Certificate Path:", filename)
fmt.Println()
@ -156,12 +150,3 @@ func listAccount(ctx *cli.Context) error {
return nil
}
func formatIPAddresses(ipAddresses []net.IP) string {
var ips []string
for _, ip := range ipAddresses {
ips = append(ips, ip.String())
}
return strings.Join(ips, ", ")
}

View file

@ -144,9 +144,7 @@ func renew(ctx *cli.Context) error {
bundle := !ctx.Bool(flgNoBundle)
meta := map[string]string{
hookEnvAccountEmail: account.Email,
}
meta := map[string]string{hookEnvAccountEmail: account.Email}
// CSR
if ctx.IsSet(flgCSR) {

View file

@ -104,9 +104,9 @@ Your account credentials have been saved in your
configuration directory at "%s".
You should make a secure backup of this folder now. This
configuration directory will also contain private keys
generated by lego and certificates obtained from the ACME
server. Making regular backups of this folder is ideal.
configuration directory will also contain certificates and
private keys obtained from the ACME server so making regular
backups of this folder is ideal.
`
func run(ctx *cli.Context) error {

View file

@ -2,7 +2,7 @@
package main
const defaultVersion = "v4.32.0+dev-detach"
const defaultVersion = "v4.28.0+dev-release"
var version = ""

View file

@ -40,7 +40,7 @@ func setupAccount(ctx *cli.Context, accountsStorage *AccountsStorage) (*Account,
if accountsStorage.ExistsAccountFilePath() {
account = accountsStorage.LoadAccount(privateKey)
} else {
account = &Account{Email: accountsStorage.GetEmail(), key: privateKey}
account = &Account{Email: accountsStorage.GetUserID(), key: privateKey}
}
return account, keyType
@ -118,6 +118,15 @@ func getKeyType(ctx *cli.Context) certcrypto.KeyType {
return ""
}
func getEmail(ctx *cli.Context) string {
email := ctx.String(flgEmail)
if email == "" {
log.Fatalf("You have to pass an account (email address) to the program using --%s or -m", flgEmail)
}
return email
}
func getUserAgent(ctx *cli.Context) string {
return strings.TrimSpace(fmt.Sprintf("%s lego-cli/%s", ctx.String(flgUserAgent), ctx.App.Version))
}
@ -171,10 +180,6 @@ func checkRetry(ctx context.Context, resp *http.Response, err error) (bool, erro
return rt, err
}
if resp == nil {
return rt, nil
}
if resp.StatusCode/100 == 2 {
return rt, nil
}

View file

@ -12,14 +12,12 @@ import (
func allDNSCodes() string {
providers := []string{
"manual",
"acme-dns",
"active24",
"alidns",
"aliesa",
"allinkl",
"alwaysdata",
"anexia",
"artfiles",
"arvancloud",
"auroradns",
"autodns",
@ -32,7 +30,6 @@ func allDNSCodes() string {
"binarylane",
"bindman",
"bluecat",
"bluecatv2",
"bookmyname",
"brandit",
"bunny",
@ -43,20 +40,16 @@ func allDNSCodes() string {
"cloudns",
"cloudru",
"cloudxns",
"com35",
"conoha",
"conohav3",
"constellix",
"corenetworks",
"cpanel",
"czechia",
"ddnss",
"derak",
"desec",
"designate",
"digitalocean",
"directadmin",
"dnsexit",
"dnshomede",
"dnsimple",
"dnsmadeeasy",
@ -69,13 +62,10 @@ func allDNSCodes() string {
"dyndnsfree",
"dynu",
"easydns",
"edgecenter",
"edgedns",
"edgeone",
"efficientip",
"epik",
"eurodns",
"excedo",
"exec",
"exoscale",
"f5xc",
@ -84,15 +74,12 @@ func allDNSCodes() string {
"gandiv5",
"gcloud",
"gcore",
"gigahostno",
"glesys",
"godaddy",
"googledomains",
"gravity",
"hetzner",
"hostingde",
"hostinger",
"hostingnl",
"hosttech",
"httpnet",
"httpreq",
@ -107,15 +94,10 @@ func allDNSCodes() string {
"internetbs",
"inwx",
"ionos",
"ionoscloud",
"ipv64",
"ispconfig",
"ispconfigddns",
"iwantmyname",
"jdcloud",
"joker",
"keyhelp",
"leaseweb",
"liara",
"lightsail",
"limacity",
@ -125,7 +107,6 @@ func allDNSCodes() string {
"luadns",
"mailinabox",
"manageengine",
"manual",
"metaname",
"metaregistrar",
"mijnhost",
@ -136,9 +117,7 @@ func allDNSCodes() string {
"namecheap",
"namedotcom",
"namesilo",
"namesurfer",
"nearlyfreespeech",
"neodigit",
"netcup",
"netlify",
"nicmanager",
@ -174,20 +153,16 @@ func allDNSCodes() string {
"sonic",
"spaceship",
"stackpath",
"syse",
"technitium",
"tencentcloud",
"timewebcloud",
"todaynic",
"transip",
"ultradns",
"uniteddomains",
"variomedia",
"vegadns",
"vercel",
"versio",
"vinyldns",
"virtualname",
"vkcloud",
"volcengine",
"vscale",
@ -269,38 +244,13 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "ALICLOUD_HTTP_TIMEOUT": API request timeout in seconds (Default: 10)`)
ew.writeln(` - "ALICLOUD_LINE": Line (Default: default)`)
ew.writeln(` - "ALICLOUD_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "ALICLOUD_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "ALICLOUD_REGION_ID": Region ID (Default: cn-hangzhou)`)
ew.writeln(` - "ALICLOUD_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 600)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/alidns`)
case "aliesa":
// generated from: providers/dns/aliesa/aliesa.toml
ew.writeln(`Configuration for AlibabaCloud ESA.`)
ew.writeln(`Code: 'aliesa'`)
ew.writeln(`Since: 'v4.29.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "ALIESA_ACCESS_KEY": Access key ID`)
ew.writeln(` - "ALIESA_RAM_ROLE": Your instance RAM role (https://www.alibabacloud.com/help/en/ecs/user-guide/attach-an-instance-ram-role-to-an-ecs-instance)`)
ew.writeln(` - "ALIESA_SECRET_KEY": Access Key secret`)
ew.writeln(` - "ALIESA_SECURITY_TOKEN": STS Security Token (optional)`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "ALIESA_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "ALIESA_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "ALIESA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "ALIESA_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/aliesa`)
case "allinkl":
// generated from: providers/dns/allinkl/allinkl.toml
ew.writeln(`Configuration for all-inkl.`)
@ -321,27 +271,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/allinkl`)
case "alwaysdata":
// generated from: providers/dns/alwaysdata/alwaysdata.toml
ew.writeln(`Configuration for Alwaysdata.`)
ew.writeln(`Code: 'alwaysdata'`)
ew.writeln(`Since: 'v4.31.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "ALWAYSDATA_API_KEY": API Key`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "ALWAYSDATA_ACCOUNT": Account name`)
ew.writeln(` - "ALWAYSDATA_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "ALWAYSDATA_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "ALWAYSDATA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "ALWAYSDATA_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/alwaysdata`)
case "anexia":
// generated from: providers/dns/anexia/anexia.toml
ew.writeln(`Configuration for Anexia CloudDNS.`)
@ -363,27 +292,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/anexia`)
case "artfiles":
// generated from: providers/dns/artfiles/artfiles.toml
ew.writeln(`Configuration for ArtFiles.`)
ew.writeln(`Code: 'artfiles'`)
ew.writeln(`Since: 'v4.32.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "ARTFILES_PASSWORD": API password`)
ew.writeln(` - "ARTFILES_USERNAME": API username`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "ARTFILES_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "ARTFILES_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "ARTFILES_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 360)`)
ew.writeln(` - "ARTFILES_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/artfiles`)
case "arvancloud":
// generated from: providers/dns/arvancloud/arvancloud.toml
ew.writeln(`Configuration for ArvanCloud.`)
@ -563,7 +471,7 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "BAIDUCLOUD_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "BAIDUCLOUD_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "BAIDUCLOUD_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)`)
ew.writeln(` - "BAIDUCLOUD_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/baiducloud`)
@ -653,31 +561,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/bluecat`)
case "bluecatv2":
// generated from: providers/dns/bluecatv2/bluecatv2.toml
ew.writeln(`Configuration for Bluecat v2.`)
ew.writeln(`Code: 'bluecatv2'`)
ew.writeln(`Since: 'v4.32.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "BLUECATV2_CONFIG_NAME": Configuration name`)
ew.writeln(` - "BLUECATV2_PASSWORD": API password`)
ew.writeln(` - "BLUECATV2_USERNAME": API username`)
ew.writeln(` - "BLUECATV2_VIEW_NAME": DNS View Name`)
ew.writeln(` - "BLUECAT_SERVER_URL": The server URL: it should have a scheme, hostname, and port (if required) of the authoritative Bluecat BAM serve`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "BLUECATV2_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "BLUECATV2_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "BLUECATV2_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "BLUECATV2_SKIP_DEPLOY": Skip quick deployements`)
ew.writeln(` - "BLUECATV2_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/bluecatv2`)
case "bookmyname":
// generated from: providers/dns/bookmyname/bookmyname.toml
ew.writeln(`Configuration for BookMyName.`)
@ -896,27 +779,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/cloudxns`)
case "com35":
// generated from: providers/dns/com35/com35.toml
ew.writeln(`Configuration for 35.com/三五互联.`)
ew.writeln(`Code: 'com35'`)
ew.writeln(`Since: 'v4.31.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "COM35_PASSWORD": API password`)
ew.writeln(` - "COM35_USERNAME": Username`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "COM35_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "COM35_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
ew.writeln(` - "COM35_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
ew.writeln(` - "COM35_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/com35`)
case "conoha":
// generated from: providers/dns/conoha/conoha.toml
ew.writeln(`Configuration for ConoHa v2.`)
@ -1029,47 +891,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/cpanel`)
case "czechia":
// generated from: providers/dns/czechia/czechia.toml
ew.writeln(`Configuration for Czechia.`)
ew.writeln(`Code: 'czechia'`)
ew.writeln(`Since: 'v4.33.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "CZECHIA_TOKEN": Authorization token`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "CZECHIA_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "CZECHIA_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "CZECHIA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "CZECHIA_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/czechia`)
case "ddnss":
// generated from: providers/dns/ddnss/ddnss.toml
ew.writeln(`Configuration for DDnss (DynDNS Service).`)
ew.writeln(`Code: 'ddnss'`)
ew.writeln(`Since: 'v4.32.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "DDNSS_KEY": Update key`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "DDNSS_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "DDNSS_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "DDNSS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "DDNSS_SEQUENCE_INTERVAL": Time between sequential requests in seconds (Default: 60)`)
ew.writeln(` - "DDNSS_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ddnss`)
case "derak":
// generated from: providers/dns/derak/derak.toml
ew.writeln(`Configuration for Derak Cloud.`)
@ -1185,26 +1006,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/directadmin`)
case "dnsexit":
// generated from: providers/dns/dnsexit/dnsexit.toml
ew.writeln(`Configuration for DNSExit.`)
ew.writeln(`Code: 'dnsexit'`)
ew.writeln(`Since: 'v4.32.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "DNSEXIT_API_KEY": API key`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "DNSEXIT_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "DNSEXIT_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
ew.writeln(` - "DNSEXIT_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 300)`)
ew.writeln(` - "DNSEXIT_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/dnsexit`)
case "dnshomede":
// generated from: providers/dns/dnshomede/dnshomede.toml
ew.writeln(`Configuration for dnsHome.de.`)
@ -1451,26 +1252,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/easydns`)
case "edgecenter":
// generated from: providers/dns/edgecenter/edgecenter.toml
ew.writeln(`Configuration for EdgeCenter.`)
ew.writeln(`Code: 'edgecenter'`)
ew.writeln(`Since: 'v4.29.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "EDGECENTER_PERMANENT_API_TOKEN": Permanent API token (https://edgecenter.ru/blog/permanent-api-token-explained/)`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "EDGECENTER_HTTP_TIMEOUT": API request timeout in seconds (Default: 10)`)
ew.writeln(` - "EDGECENTER_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 20)`)
ew.writeln(` - "EDGECENTER_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 360)`)
ew.writeln(` - "EDGECENTER_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/edgecenter`)
case "edgedns":
// generated from: providers/dns/edgedns/edgedns.toml
ew.writeln(`Configuration for Akamai EdgeDNS.`)
@ -1515,7 +1296,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(` - "EDGEONE_REGION": Region`)
ew.writeln(` - "EDGEONE_SESSION_TOKEN": Access Key token`)
ew.writeln(` - "EDGEONE_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
ew.writeln(` - "EDGEONE_ZONES_MAPPING": Mapping between DNS zones and site IDs. (ex: 'example.org:id1,example.com:id2')`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/edgeone`)
@ -1564,48 +1344,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/epik`)
case "eurodns":
// generated from: providers/dns/eurodns/eurodns.toml
ew.writeln(`Configuration for EuroDNS.`)
ew.writeln(`Code: 'eurodns'`)
ew.writeln(`Since: 'v4.33.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "EURODNS_API_KEY": API key`)
ew.writeln(` - "EURODNS_APP_ID": Application ID`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "EURODNS_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "EURODNS_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "EURODNS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "EURODNS_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 600)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/eurodns`)
case "excedo":
// generated from: providers/dns/excedo/excedo.toml
ew.writeln(`Configuration for Excedo.`)
ew.writeln(`Code: 'excedo'`)
ew.writeln(`Since: 'v4.33.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "EXCEDO_API_KEY": API key`)
ew.writeln(` - "EXCEDO_API_URL": API base URL`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "EXCEDO_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "EXCEDO_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
ew.writeln(` - "EXCEDO_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 300)`)
ew.writeln(` - "EXCEDO_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 60)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/excedo`)
case "exec":
// generated from: providers/dns/exec/exec.toml
ew.writeln(`Configuration for External program.`)
@ -1655,7 +1393,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(` - "F5XC_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "F5XC_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "F5XC_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "F5XC_SERVER": Server domain (Default: console.ves.volterra.io)`)
ew.writeln(` - "F5XC_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
@ -1768,28 +1505,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/gcore`)
case "gigahostno":
// generated from: providers/dns/gigahostno/gigahostno.toml
ew.writeln(`Configuration for Gigahost.no.`)
ew.writeln(`Code: 'gigahostno'`)
ew.writeln(`Since: 'v4.29.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "GIGAHOSTNO_PASSWORD": Password`)
ew.writeln(` - "GIGAHOSTNO_USERNAME": Username`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "GIGAHOSTNO_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "GIGAHOSTNO_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "GIGAHOSTNO_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "GIGAHOSTNO_SECRET": TOTP secret`)
ew.writeln(` - "GIGAHOSTNO_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/gigahostno`)
case "glesys":
// generated from: providers/dns/glesys/glesys.toml
ew.writeln(`Configuration for Glesys.`)
@ -1851,28 +1566,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/googledomains`)
case "gravity":
// generated from: providers/dns/gravity/gravity.toml
ew.writeln(`Configuration for Gravity.`)
ew.writeln(`Code: 'gravity'`)
ew.writeln(`Since: 'v4.30.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "GRAVITY_PASSWORD": Password`)
ew.writeln(` - "GRAVITY_SERVER_URL": URL of the server`)
ew.writeln(` - "GRAVITY_USERNAME": Username`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "GRAVITY_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "GRAVITY_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "GRAVITY_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "GRAVITY_SEQUENCE_INTERVAL": Time between sequential requests in seconds (Default: 1)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/gravity`)
case "hetzner":
// generated from: providers/dns/hetzner/hetzner.toml
ew.writeln(`Configuration for Hetzner.`)
@ -1934,26 +1627,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/hostinger`)
case "hostingnl":
// generated from: providers/dns/hostingnl/hostingnl.toml
ew.writeln(`Configuration for Hosting.nl.`)
ew.writeln(`Code: 'hostingnl'`)
ew.writeln(`Since: 'v4.30.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "HOSTINGNL_API_KEY": The API key`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "HOSTINGNL_HTTP_TIMEOUT": API request timeout in seconds (Default: 10)`)
ew.writeln(` - "HOSTINGNL_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "HOSTINGNL_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
ew.writeln(` - "HOSTINGNL_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/hostingnl`)
case "hosttech":
// generated from: providers/dns/hosttech/hosttech.toml
ew.writeln(`Configuration for Hosttech.`)
@ -2253,26 +1926,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ionos`)
case "ionoscloud":
// generated from: providers/dns/ionoscloud/ionoscloud.toml
ew.writeln(`Configuration for Ionos Cloud.`)
ew.writeln(`Code: 'ionoscloud'`)
ew.writeln(`Since: 'v4.30.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "IONOSCLOUD_API_TOKEN": API token`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "IONOSCLOUD_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "IONOSCLOUD_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "IONOSCLOUD_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
ew.writeln(` - "IONOSCLOUD_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ionoscloud`)
case "ipv64":
// generated from: providers/dns/ipv64/ipv64.toml
ew.writeln(`Configuration for IPv64.`)
@ -2292,50 +1945,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ipv64`)
case "ispconfig":
// generated from: providers/dns/ispconfig/ispconfig.toml
ew.writeln(`Configuration for ISPConfig 3.`)
ew.writeln(`Code: 'ispconfig'`)
ew.writeln(`Since: 'v4.31.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "ISPCONFIG_PASSWORD": Password`)
ew.writeln(` - "ISPCONFIG_SERVER_URL": Server URL`)
ew.writeln(` - "ISPCONFIG_USERNAME": Username`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "ISPCONFIG_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "ISPCONFIG_INSECURE_SKIP_VERIFY": Whether to verify the API certificate`)
ew.writeln(` - "ISPCONFIG_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "ISPCONFIG_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "ISPCONFIG_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ispconfig`)
case "ispconfigddns":
// generated from: providers/dns/ispconfigddns/ispconfigddns.toml
ew.writeln(`Configuration for ISPConfig 3 - Dynamic DNS (DDNS) Module.`)
ew.writeln(`Code: 'ispconfigddns'`)
ew.writeln(`Since: 'v4.31.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "ISPCONFIG_DDNS_SERVER_URL": API server URL (ex: https://panel.example.com:8080)`)
ew.writeln(` - "ISPCONFIG_DDNS_TOKEN": DDNS API token`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "ISPCONFIG_DDNS_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "ISPCONFIG_DDNS_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "ISPCONFIG_DDNS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "ISPCONFIG_DDNS_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 3600)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ispconfigddns`)
case "iwantmyname":
// generated from: providers/dns/iwantmyname/iwantmyname.toml
ew.writeln(`Configuration for iwantmyname (Deprecated).`)
@ -2357,28 +1966,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/iwantmyname`)
case "jdcloud":
// generated from: providers/dns/jdcloud/jdcloud.toml
ew.writeln(`Configuration for JD Cloud.`)
ew.writeln(`Code: 'jdcloud'`)
ew.writeln(`Since: 'v4.31.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "JDCLOUD_ACCESS_KEY_ID": Access key ID`)
ew.writeln(` - "JDCLOUD_ACCESS_KEY_SECRET": Access key secret`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "JDCLOUD_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "JDCLOUD_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "JDCLOUD_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "JDCLOUD_REGION_ID": Region ID (Default: cn-north-1)`)
ew.writeln(` - "JDCLOUD_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/jdcloud`)
case "joker":
// generated from: providers/dns/joker/joker.toml
ew.writeln(`Configuration for Joker.`)
@ -2424,26 +2011,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/keyhelp`)
case "leaseweb":
// generated from: providers/dns/leaseweb/leaseweb.toml
ew.writeln(`Configuration for Leaseweb.`)
ew.writeln(`Code: 'leaseweb'`)
ew.writeln(`Since: 'v4.32.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "LEASEWEB_API_KEY": API key`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "LEASEWEB_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "LEASEWEB_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "LEASEWEB_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "LEASEWEB_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/leaseweb`)
case "liara":
// generated from: providers/dns/liara/liara.toml
ew.writeln(`Configuration for Liara.`)
@ -2459,7 +2026,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln(` - "LIARA_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "LIARA_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "LIARA_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "LIARA_TEAM_ID": The team ID to access services in a team`)
ew.writeln(` - "LIARA_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 3600)`)
ew.writeln()
@ -2634,16 +2200,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/manageengine`)
case "manual":
// generated from: providers/dns/manual/manual.toml
ew.writeln(`Configuration for Manual.`)
ew.writeln(`Code: 'manual'`)
ew.writeln(`Since: 'v0.3.0'`)
ew.writeln()
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/manual`)
case "metaname":
// generated from: providers/dns/metaname/metaname.toml
ew.writeln(`Configuration for Metaname.`)
@ -2852,30 +2408,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/namesilo`)
case "namesurfer":
// generated from: providers/dns/namesurfer/namesurfer.toml
ew.writeln(`Configuration for FusionLayer NameSurfer.`)
ew.writeln(`Code: 'namesurfer'`)
ew.writeln(`Since: 'v4.32.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "NAMESURFER_API_KEY": API key name`)
ew.writeln(` - "NAMESURFER_API_SECRET": API secret`)
ew.writeln(` - "NAMESURFER_BASE_URL": The base URL of NameSurfer API (jsonrpc10) endpoint URL (e.g., https://foo.example.com:8443/API/NSService_10)`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "NAMESURFER_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "NAMESURFER_INSECURE_SKIP_VERIFY": Whether to verify the API certificate`)
ew.writeln(` - "NAMESURFER_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "NAMESURFER_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 120)`)
ew.writeln(` - "NAMESURFER_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)`)
ew.writeln(` - "NAMESURFER_VIEW": DNS view name (optional, default: empty string)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/namesurfer`)
case "nearlyfreespeech":
// generated from: providers/dns/nearlyfreespeech/nearlyfreespeech.toml
ew.writeln(`Configuration for NearlyFreeSpeech.NET.`)
@ -2898,26 +2430,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/nearlyfreespeech`)
case "neodigit":
// generated from: providers/dns/neodigit/neodigit.toml
ew.writeln(`Configuration for Neodigit.`)
ew.writeln(`Code: 'neodigit'`)
ew.writeln(`Since: 'v4.30.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "NEODIGIT_TOKEN": API token`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "NEODIGIT_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "NEODIGIT_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
ew.writeln(` - "NEODIGIT_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 300)`)
ew.writeln(` - "NEODIGIT_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/neodigit`)
case "netcup":
// generated from: providers/dns/netcup/netcup.toml
ew.writeln(`Configuration for Netcup.`)
@ -3439,7 +2951,7 @@ func displayDNSHelp(w io.Writer, name string) error {
case "safedns":
// generated from: providers/dns/safedns/safedns.toml
ew.writeln(`Configuration for ANS SafeDNS.`)
ew.writeln(`Configuration for UKFast SafeDNS.`)
ew.writeln(`Code: 'safedns'`)
ew.writeln(`Since: 'v4.6.0'`)
ew.writeln()
@ -3697,26 +3209,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/stackpath`)
case "syse":
// generated from: providers/dns/syse/syse.toml
ew.writeln(`Configuration for Syse.`)
ew.writeln(`Code: 'syse'`)
ew.writeln(`Since: 'v4.30.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "SYSE_CREDENTIALS": Comma-separated list of 'zone:password' credential pairs`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "SYSE_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "SYSE_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
ew.writeln(` - "SYSE_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 1200)`)
ew.writeln(` - "SYSE_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/syse`)
case "technitium":
// generated from: providers/dns/technitium/technitium.toml
ew.writeln(`Configuration for Technitium.`)
@ -3780,27 +3272,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/timewebcloud`)
case "todaynic":
// generated from: providers/dns/todaynic/todaynic.toml
ew.writeln(`Configuration for TodayNIC/时代互联.`)
ew.writeln(`Code: 'todaynic'`)
ew.writeln(`Since: 'v4.32.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "TODAYNIC_API_KEY": API key`)
ew.writeln(` - "TODAYNIC_AUTH_USER_ID": account ID`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "TODAYNIC_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "TODAYNIC_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "TODAYNIC_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 60)`)
ew.writeln(` - "TODAYNIC_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 600)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/todaynic`)
case "transip":
// generated from: providers/dns/transip/transip.toml
ew.writeln(`Configuration for TransIP.`)
@ -3843,26 +3314,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/ultradns`)
case "uniteddomains":
// generated from: providers/dns/uniteddomains/uniteddomains.toml
ew.writeln(`Configuration for United-Domains.`)
ew.writeln(`Code: 'uniteddomains'`)
ew.writeln(`Since: 'v4.29.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "UNITEDDOMAINS_API_KEY": API key '<prefix>.<secret>' https://www.united-domains.de/help/faq-article/getting-started-with-the-united-domains-dns-api/`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "UNITEDDOMAINS_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "UNITEDDOMAINS_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 2)`)
ew.writeln(` - "UNITEDDOMAINS_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 900)`)
ew.writeln(` - "UNITEDDOMAINS_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 300)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/uniteddomains`)
case "variomedia":
// generated from: providers/dns/variomedia/variomedia.toml
ew.writeln(`Configuration for Variomedia.`)
@ -3972,26 +3423,6 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/vinyldns`)
case "virtualname":
// generated from: providers/dns/virtualname/virtualname.toml
ew.writeln(`Configuration for Virtualname.`)
ew.writeln(`Code: 'virtualname'`)
ew.writeln(`Since: 'v4.30.0'`)
ew.writeln()
ew.writeln(`Credentials:`)
ew.writeln(` - "VIRTUALNAME_TOKEN": API token`)
ew.writeln()
ew.writeln(`Additional Configuration:`)
ew.writeln(` - "VIRTUALNAME_HTTP_TIMEOUT": API request timeout in seconds (Default: 30)`)
ew.writeln(` - "VIRTUALNAME_POLLING_INTERVAL": Time between DNS propagation check in seconds (Default: 10)`)
ew.writeln(` - "VIRTUALNAME_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation in seconds (Default: 300)`)
ew.writeln(` - "VIRTUALNAME_TTL": The TTL of the TXT record used for the DNS challenge in seconds (Default: 120)`)
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/virtualname`)
case "vkcloud":
// generated from: providers/dns/vkcloud/vkcloud.toml
ew.writeln(`Configuration for VK Cloud.`)
@ -4307,6 +3738,8 @@ func displayDNSHelp(w io.Writer, name string) error {
ew.writeln()
ew.writeln(`More information: https://go-acme.github.io/lego/dns/zonomi`)
case "manual":
ew.writeln(`Solving the DNS-01 challenge using CLI prompt.`)
default:
return fmt.Errorf("%q is not yet supported", name)
}

View file

@ -7,16 +7,6 @@ chapter: false
Let's Encrypt client and ACME library written in Go.
{{% notice important %}}
lego is an independent, free, and open-source project, if you value it, consider [supporting it](https://donate.ldez.dev)! ❤️
This project is not owned by a company. I'm not an employee of a company.
I don't have gifted domains/accounts from DNS companies.
I've been maintaining it for about 10 years.
{{% /notice %}}
## Features
- ACME v2 [RFC 8555](https://www.rfc-editor.org/rfc/rfc8555.html)
@ -24,7 +14,7 @@ I've been maintaining it for about 10 years.
- Support [RFC 8738](https://www.rfc-editor.org/rfc/rfc8738.html): issues certificates for IP addresses
- Support [RFC 9773](https://www.rfc-editor.org/rfc/rfc9773.html): Renewal Information (ARI) Extension
- Support [draft-ietf-acme-profiles-00](https://datatracker.ietf.org/doc/draft-ietf-acme-profiles/): Profiles Extension
- Comes with about [180 DNS providers]({{% ref "dns" %}})
- Comes with about [150 DNS providers]({{% ref "dns" %}})
- Register with CA
- Obtain certificates, both from scratch or with an existing CSR
- Renew certificates

View file

@ -5,16 +5,6 @@ draft: false
weight: 3
---
{{% notice important %}}
lego is an independent, free, and open-source project, if you value it, consider [supporting it](https://donate.ldez.dev)! ❤️
This project is not owned by a company. I'm not an employee of a company.
I don't have gifted domains/accounts from DNS companies.
I've been maintaining it for about 10 years.
{{% /notice %}}
## Configuration and Credentials
Credentials and DNS configuration for DNS providers must be passed through environment variables.

View file

@ -1,19 +1,24 @@
Name = "Manual"
Description = '''Solving the DNS-01 challenge using CLI prompt.'''
Code = "manual"
Since = "v0.3.0"
---
title: "Manual"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: manual
dnsprovider:
since: v0.3.0
code: manual
url:
---
Example = '''
lego --dns manual -d '*.example.com' -d example.com run
'''
Solving the DNS-01 challenge using CLI prompt.
<!--more-->
Additional = '''
## Example
To start using the CLI prompt "provider", start lego with `--dns manual`:
```console
$ lego --dns manual -d example.com run
$ lego --email "you@example.com" --domains="example.com" --dns "manual" run
```
What follows are a few log print-outs, interspersed with some prompts, asking for you to do perform some actions:
@ -31,13 +36,13 @@ If you accept the linked Terms of Service, hit `Enter`.
[INFO] acme: Registering account for you@example.com
!!!! HEADS UP !!!!
Your account credentials have been saved in your
configuration directory at "./.lego/accounts".
Your account credentials have been saved in your Let's Encrypt
configuration directory at "./.lego/accounts".
You should make a secure backup of this folder now. This
configuration directory will also contain private keys
generated by lego and certificates obtained from the ACME
server. Making regular backups of this folder is ideal.
You should make a secure backup of this folder now. This
configuration directory will also contain certificates and
private keys obtained from Let's Encrypt so making regular
backups of this folder is ideal.
[INFO] [example.com] acme: Obtaining bundled SAN certificate
[INFO] [example.com] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/2345678901
[INFO] [example.com] acme: Could not find solver for: tls-alpn-01
@ -65,5 +70,3 @@ _acme-challenge.example.com. 120 IN TXT "hX0dPkG6Gfs9hUvBAchQclkyyoEKbShbpvJ9mY5
```
As mentioned, you can now remove the TXT record again.
'''

View file

@ -28,13 +28,13 @@ Here is an example bash command using the Joohoi's ACME-DNS provider:
```bash
ACME_DNS_API_BASE=http://10.0.0.8:4443 \
ACME_DNS_STORAGE_PATH=/root/.lego-acme-dns-accounts.json \
lego --dns "acme-dns" -d '*.example.com' -d example.com run
lego --email you@example.com --dns "acme-dns" -d '*.example.com' -d example.com run
# or
ACME_DNS_API_BASE=http://10.0.0.8:4443 \
ACME_DNS_STORAGE_BASE_URL=http://10.10.10.10:80 \
lego --dns "acme-dns" -d '*.example.com' -d example.com run
lego --email you@example.com --dns "acme-dns" -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Active24 provider:
```bash
ACTIVE24_API_KEY="xxx" \
ACTIVE24_SECRET="yyy" \
lego --dns active24 -d '*.example.com' -d example.com run
lego --email you@example.com --dns active24 -d '*.example.com' -d example.com run
```

View file

@ -28,13 +28,13 @@ Here is an example bash command using the Alibaba Cloud DNS provider:
```bash
# Setup using instance RAM role
ALICLOUD_RAM_ROLE=lego \
lego --dns alidns -d '*.example.com' -d example.com run
lego --email you@example.com --dns alidns -d '*.example.com' -d example.com run
# Or, using credentials
ALICLOUD_ACCESS_KEY=abcdefghijklmnopqrstuvwx \
ALICLOUD_SECRET_KEY=your-secret-key \
ALICLOUD_SECURITY_TOKEN=your-sts-token \
lego --dns alidns - -d '*.example.com' -d example.com run
lego --email you@example.com --dns alidns - -d '*.example.com' -d example.com run
```
@ -58,10 +58,8 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `ALICLOUD_HTTP_TIMEOUT` | API request timeout in seconds (Default: 10) |
| `ALICLOUD_LINE` | Line (Default: default) |
| `ALICLOUD_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `ALICLOUD_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
| `ALICLOUD_REGION_ID` | Region ID (Default: cn-hangzhou) |
| `ALICLOUD_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 600) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.

View file

@ -1,78 +0,0 @@
---
title: "AlibabaCloud ESA"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: aliesa
dnsprovider:
since: "v4.29.0"
code: "aliesa"
url: "https://www.alibabacloud.com/en/product/esa"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/aliesa/aliesa.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [AlibabaCloud ESA](https://www.alibabacloud.com/en/product/esa).
<!--more-->
- Code: `aliesa`
- Since: v4.29.0
Here is an example bash command using the AlibabaCloud ESA provider:
```bash
# Setup using instance RAM role
ALIESA_RAM_ROLE=lego \
lego --dns aliesa -d '*.example.com' -d example.com run
# Or, using credentials
ALIESA_ACCESS_KEY=abcdefghijklmnopqrstuvwx \
ALIESA_SECRET_KEY=your-secret-key \
ALIESA_SECURITY_TOKEN=your-sts-token \
lego --dns aliesa - -d '*.example.com' -d example.com run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `ALIESA_ACCESS_KEY` | Access key ID |
| `ALIESA_RAM_ROLE` | Your instance RAM role (https://www.alibabacloud.com/help/en/ecs/user-guide/attach-an-instance-ram-role-to-an-ecs-instance) |
| `ALIESA_SECRET_KEY` | Access Key secret |
| `ALIESA_SECURITY_TOKEN` | STS Security Token (optional) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `ALIESA_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `ALIESA_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `ALIESA_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
| `ALIESA_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
- [API documentation](https://www.alibabacloud.com/help/en/edge-security-acceleration/esa/api-esa-2024-09-10-overview?spm=a2c63.p38356.help-menu-2673927.d_6_0_0.20b224c28PSZDc#:~:text=DNS-,DNS%20records,-DNS%20records)
- [Go client](https://github.com/alibabacloud-go/esa-20240910)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/aliesa/aliesa.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

View file

@ -28,7 +28,7 @@ Here is an example bash command using the all-inkl provider:
```bash
ALL_INKL_LOGIN=xxxxxxxxxxxxxxxxxxxxxxxxxx \
ALL_INKL_PASSWORD=yyyyyyyyyyyyyyyyyyyyyyyyyy \
lego --dns allinkl -d '*.example.com' -d example.com run
lego --email you@example.com --dns allinkl -d '*.example.com' -d example.com run
```

View file

@ -1,68 +0,0 @@
---
title: "Alwaysdata"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: alwaysdata
dnsprovider:
since: "v4.31.0"
code: "alwaysdata"
url: "https://alwaysdata.com/"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/alwaysdata/alwaysdata.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [Alwaysdata](https://alwaysdata.com/).
<!--more-->
- Code: `alwaysdata`
- Since: v4.31.0
Here is an example bash command using the Alwaysdata provider:
```bash
ALWAYSDATA_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
lego --dns alwaysdata -d '*.example.com' -d example.com run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `ALWAYSDATA_API_KEY` | API Key |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `ALWAYSDATA_ACCOUNT` | Account name |
| `ALWAYSDATA_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `ALWAYSDATA_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `ALWAYSDATA_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
| `ALWAYSDATA_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
- [API documentation](https://help.alwaysdata.com/en/api/resources/)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/alwaysdata/alwaysdata.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Anexia CloudDNS provider:
```bash
ANEXIA_TOKEN=xxx \
lego --dns anexia -d '*.example.com' -d example.com run
lego --email you@example.com --dns anexia -d '*.example.com' -d example.com run
```

View file

@ -1,69 +0,0 @@
---
title: "ArtFiles"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: artfiles
dnsprovider:
since: "v4.32.0"
code: "artfiles"
url: "https://www.artfiles.de/extras/domains/"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/artfiles/artfiles.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [ArtFiles](https://www.artfiles.de/extras/domains/).
<!--more-->
- Code: `artfiles`
- Since: v4.32.0
Here is an example bash command using the ArtFiles provider:
```bash
ARTFILES_USERNAME="xxx" \
ARTFILES_PASSWORD="yyy" \
lego --dns artfiles -d '*.example.com' -d example.com run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `ARTFILES_PASSWORD` | API password |
| `ARTFILES_USERNAME` | API username |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `ARTFILES_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `ARTFILES_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `ARTFILES_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 360) |
| `ARTFILES_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
- [API documentation](https://support.artfiles.de/DCP-API#dns)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/artfiles/artfiles.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

View file

@ -27,7 +27,7 @@ Here is an example bash command using the ArvanCloud provider:
```bash
ARVANCLOUD_API_KEY="Apikey xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \
lego --dns arvancloud -d '*.example.com' -d example.com run
lego --email you@example.com --dns arvancloud -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Aurora DNS provider:
```bash
AURORA_API_KEY=xxxxx \
AURORA_SECRET=yyyyyy \
lego --dns auroradns -d '*.example.com' -d example.com run
lego --email you@example.com --dns auroradns -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Autodns provider:
```bash
AUTODNS_API_USER=username \
AUTODNS_API_PASSWORD=supersecretpassword \
lego --dns autodns -d '*.example.com' -d example.com run
lego --email you@example.com --dns autodns -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Axelname provider:
```bash
AXELNAME_NICKNAME="yyy" \
AXELNAME_TOKEN="xxx" \
lego --dns axelname -d '*.example.com' -d example.com run
lego --email you@example.com --dns axelname -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Azion provider:
```bash
AZION_PERSONAL_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxx \
lego --dns azion -d '*.example.com' -d example.com run
lego --email you@example.com --dns azion -d '*.example.com' -d example.com run
```

View file

@ -31,32 +31,32 @@ Here is an example bash command using the Azure DNS provider:
AZURE_CLIENT_ID=<your service principal client ID> \
AZURE_TENANT_ID=<your service principal tenant ID> \
AZURE_CLIENT_SECRET=<your service principal client secret> \
lego --dns azuredns -d '*.example.com' -d example.com run
lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using client certificate
AZURE_CLIENT_ID=<your service principal client ID> \
AZURE_TENANT_ID=<your service principal tenant ID> \
AZURE_CLIENT_CERTIFICATE_PATH=<your service principal certificate path> \
lego --dns azuredns -d '*.example.com' -d example.com run
lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using Azure CLI
az login \
lego --dns azuredns -d '*.example.com' -d example.com run
lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using Managed Identity (Azure VM)
AZURE_TENANT_ID=<your service principal tenant ID> \
AZURE_RESOURCE_GROUP=<your target zone resource group name> \
lego --dns azuredns -d '*.example.com' -d example.com run
lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
### Using Managed Identity (Azure Arc)
AZURE_TENANT_ID=<your service principal tenant ID> \
IMDS_ENDPOINT=http://localhost:40342 \
IDENTITY_ENDPOINT=http://localhost:40342/metadata/identity/oauth2/token \
lego --dns azuredns -d '*.example.com' -d example.com run
lego --email you@example.com --dns azuredns -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Baidu Cloud provider:
```bash
BAIDUCLOUD_ACCESS_KEY_ID="xxx" \
BAIDUCLOUD_SECRET_ACCESS_KEY="yyy" \
lego --dns baiducloud -d '*.example.com' -d example.com run
lego --email you@example.com --dns baiducloud -d '*.example.com' -d example.com run
```
@ -51,7 +51,7 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
|--------------------------------|-------------|
| `BAIDUCLOUD_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `BAIDUCLOUD_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
| `BAIDUCLOUD_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 300) |
| `BAIDUCLOUD_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Beget.com provider:
```bash
BEGET_USERNAME=xxxxxx \
BEGET_PASSWORD=yyyyyy \
lego --dns beget -d '*.example.com' -d example.com run
lego --email you@example.com --dns beget -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Binary Lane provider:
```bash
BINARYLANE_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
lego --dns binarylane -d '*.example.com' -d example.com run
lego --email you@example.com --dns binarylane -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Bindman provider:
```bash
BINDMAN_MANAGER_ADDRESS=<your bindman manager address> \
lego --dns bindman -d '*.example.com' -d example.com run
lego --email you@example.com --dns bindman -d '*.example.com' -d example.com run
```

View file

@ -32,7 +32,7 @@ BLUECAT_USER_NAME=myusername \
BLUECAT_CONFIG_NAME=myconfig \
BLUECAT_SERVER_URL=https://bam.example.com \
BLUECAT_TTL=30 \
lego --dns bluecat -d '*.example.com' -d example.com run
lego --email you@example.com --dns bluecat -d '*.example.com' -d example.com run
```

View file

@ -1,76 +0,0 @@
---
title: "Bluecat v2"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: bluecatv2
dnsprovider:
since: "v4.32.0"
code: "bluecatv2"
url: "https://www.bluecatnetworks.com"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/bluecatv2/bluecatv2.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [Bluecat v2](https://www.bluecatnetworks.com).
<!--more-->
- Code: `bluecatv2`
- Since: v4.32.0
Here is an example bash command using the Bluecat v2 provider:
```bash
BLUECATV2_SERVER_URL="https://example.com" \
BLUECATV2_USERNAME="xxx" \
BLUECATV2_PASSWORD="yyy" \
BLUECATV2_CONFIG_NAME="myConfiguration" \
BLUECATV2_VIEW_NAME="myView" \
lego --dns bluecatv2 -d '*.example.com' -d example.com run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `BLUECATV2_CONFIG_NAME` | Configuration name |
| `BLUECATV2_PASSWORD` | API password |
| `BLUECATV2_USERNAME` | API username |
| `BLUECATV2_VIEW_NAME` | DNS View Name |
| `BLUECAT_SERVER_URL` | The server URL: it should have a scheme, hostname, and port (if required) of the authoritative Bluecat BAM serve |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `BLUECATV2_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `BLUECATV2_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `BLUECATV2_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
| `BLUECATV2_SKIP_DEPLOY` | Skip quick deployements |
| `BLUECATV2_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
- [API documentation](https://docs.bluecatnetworks.com/r/Address-Manager-RESTful-v2-API-Guide/Introduction/9.6.0)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/bluecatv2/bluecatv2.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

View file

@ -28,7 +28,7 @@ Here is an example bash command using the BookMyName provider:
```bash
BOOKMYNAME_USERNAME="xxx" \
BOOKMYNAME_PASSWORD="yyy" \
lego --dns bookmyname -d '*.example.com' -d example.com run
lego --email you@example.com --dns bookmyname -d '*.example.com' -d example.com run
```

View file

@ -31,7 +31,7 @@ Here is an example bash command using the Brandit (deprecated) provider:
```bash
BRANDIT_API_KEY=xxxxxxxxxxxxxxxxxxxxx \
BRANDIT_API_USERNAME=yyyyyyyyyyyyyyyyyyyy \
lego --dns brandit -d '*.example.com' -d example.com run
lego --email you@example.com --dns brandit -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Bunny provider:
```bash
BUNNY_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
lego --dns bunny -d '*.example.com' -d example.com run
lego --email you@example.com --dns bunny -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Checkdomain provider:
```bash
CHECKDOMAIN_TOKEN=yoursecrettoken \
lego --dns checkdomain -d '*.example.com' -d example.com run
lego --email you@example.com --dns checkdomain -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Civo provider:
```bash
CIVO_TOKEN=xxxxxx \
lego --dns civo -d '*.example.com' -d example.com run
lego --email you@example.com --dns civo -d '*.example.com' -d example.com run
```

View file

@ -29,7 +29,7 @@ Here is an example bash command using the CloudDNS provider:
CLOUDDNS_CLIENT_ID=bLsdFAks23429841238feb177a572aX \
CLOUDDNS_EMAIL=you@example.com \
CLOUDDNS_PASSWORD=b9841238feb177a84330f \
lego --dns clouddns -d '*.example.com' -d example.com run
lego --email you@example.com --dns clouddns -d '*.example.com' -d example.com run
```

View file

@ -28,12 +28,12 @@ Here is an example bash command using the Cloudflare provider:
```bash
CLOUDFLARE_EMAIL=you@example.com \
CLOUDFLARE_API_KEY=b9841238feb177a84330febba8a83208921177bffe733 \
lego --dns cloudflare -d '*.example.com' -d example.com run
lego --email you@example.com --dns cloudflare -d '*.example.com' -d example.com run
# or
CLOUDFLARE_DNS_API_TOKEN=1234567890abcdefghijklmnopqrstuvwxyz \
lego --dns cloudflare -d '*.example.com' -d example.com run
lego --email you@example.com --dns cloudflare -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the ClouDNS provider:
```bash
CLOUDNS_AUTH_ID=xxxx \
CLOUDNS_AUTH_PASSWORD=yyyy \
lego --dns cloudns -d '*.example.com' -d example.com run
lego --email you@example.com --dns cloudns -d '*.example.com' -d example.com run
```

View file

@ -29,7 +29,7 @@ Here is an example bash command using the Cloud.ru provider:
CLOUDRU_SERVICE_INSTANCE_ID=ppp \
CLOUDRU_KEY_ID=xxx \
CLOUDRU_SECRET=yyy \
lego --dns cloudru -d '*.example.com' -d example.com run
lego --email you@example.com --dns cloudru -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the CloudXNS (Deprecated) provider:
```bash
CLOUDXNS_API_KEY=xxxx \
CLOUDXNS_SECRET_KEY=yyyy \
lego --dns cloudxns -d '*.example.com' -d example.com run
lego --email you@example.com --dns cloudxns -d '*.example.com' -d example.com run
```

View file

@ -1,69 +0,0 @@
---
title: "35.com/三五互联"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: com35
dnsprovider:
since: "v4.31.0"
code: "com35"
url: "https://www.35.cn/"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/com35/com35.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [35.com/三五互联](https://www.35.cn/).
<!--more-->
- Code: `com35`
- Since: v4.31.0
Here is an example bash command using the 35.com/三五互联 provider:
```bash
COM35_USERNAME="xxx" \
COM35_PASSWORD="yyy" \
lego --dns com35 -d '*.example.com' -d example.com run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `COM35_PASSWORD` | API password |
| `COM35_USERNAME` | Username |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `COM35_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `COM35_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 10) |
| `COM35_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 120) |
| `COM35_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
- [API documentation](https://api.35.cn/CustomerCenter/doc/domain_v2.html)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/com35/com35.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

View file

@ -29,7 +29,7 @@ Here is an example bash command using the ConoHa v2 provider:
CONOHA_TENANT_ID=487727e3921d44e3bfe7ebb337bf085e \
CONOHA_API_USERNAME=xxxx \
CONOHA_API_PASSWORD=yyyy \
lego --dns conoha -d '*.example.com' -d example.com run
lego --email you@example.com --dns conoha -d '*.example.com' -d example.com run
```

View file

@ -29,7 +29,7 @@ Here is an example bash command using the ConoHa v3 provider:
CONOHAV3_TENANT_ID=487727e3921d44e3bfe7ebb337bf085e \
CONOHAV3_API_USER_ID=xxxx \
CONOHAV3_API_PASSWORD=yyyy \
lego --dns conohav3 -d '*.example.com' -d example.com run
lego --email you@example.com --dns conohav3 -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Constellix provider:
```bash
CONSTELLIX_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
CONSTELLIX_SECRET_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
lego --dns constellix -d '*.example.com' -d example.com run
lego --email you@example.com --dns constellix -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Core-Networks provider:
```bash
CORENETWORKS_LOGIN="xxxx" \
CORENETWORKS_PASSWORD="yyyy" \
lego --dns corenetworks -d '*.example.com' -d example.com run
lego --email you@example.com --dns corenetworks -d '*.example.com' -d example.com run
```

View file

@ -31,7 +31,7 @@ Here is an example bash command using the CPanel/WHM provider:
CPANEL_USERNAME="yyyy" \
CPANEL_TOKEN="xxxx" \
CPANEL_BASE_URL="https://example.com:2083" \
lego --dns cpanel -d '*.example.com' -d example.com run
lego --email you@example.com --dns cpanel -d '*.example.com' -d example.com run
## WHM
@ -39,7 +39,7 @@ CPANEL_MODE=whm \
CPANEL_USERNAME="yyyy" \
CPANEL_TOKEN="xxxx" \
CPANEL_BASE_URL="https://example.com:2087" \
lego --dns cpanel -d '*.example.com' -d example.com run
lego --email you@example.com --dns cpanel -d '*.example.com' -d example.com run
```

View file

@ -1,67 +0,0 @@
---
title: "Czechia"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: czechia
dnsprovider:
since: "v4.33.0"
code: "czechia"
url: "https://www.czechia.com/"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/czechia/czechia.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [Czechia](https://www.czechia.com/).
<!--more-->
- Code: `czechia`
- Since: v4.33.0
Here is an example bash command using the Czechia provider:
```bash
CZECHIA_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \
lego --dns czechia -d '*.example.com' -d example.com run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `CZECHIA_TOKEN` | Authorization token |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `CZECHIA_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `CZECHIA_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `CZECHIA_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
| `CZECHIA_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
- [API documentation](https://api.czechia.com/swagger/index.html)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/czechia/czechia.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

View file

@ -1,68 +0,0 @@
---
title: "DDnss (DynDNS Service)"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: ddnss
dnsprovider:
since: "v4.32.0"
code: "ddnss"
url: "https://ddnss.de/"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/ddnss/ddnss.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [DDnss (DynDNS Service)](https://ddnss.de/).
<!--more-->
- Code: `ddnss`
- Since: v4.32.0
Here is an example bash command using the DDnss (DynDNS Service) provider:
```bash
DDNSS_KEY="xxxxxxxxxxxxxxxxxxxxx" \
lego --dns ddnss -d '*.example.com' -d example.com run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `DDNSS_KEY` | Update key |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `DDNSS_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `DDNSS_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 2) |
| `DDNSS_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 60) |
| `DDNSS_SEQUENCE_INTERVAL` | Time between sequential requests in seconds (Default: 60) |
| `DDNSS_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
- [API documentation](https://ddnss.de/info.php)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/ddnss/ddnss.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Derak Cloud provider:
```bash
DERAK_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
lego --dns derak -d '*.example.com' -d example.com run
lego --email you@example.com --dns derak -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the deSEC.io provider:
```bash
DESEC_TOKEN=x-xxxxxxxxxxxxxxxxxxxxxxxxxx \
lego --dns desec -d '*.example.com' -d example.com run
lego --email you@example.com --dns desec -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Designate DNSaaS for Openstack provide
```bash
# With a `clouds.yaml`
OS_CLOUD=my_openstack \
lego --dns designate -d '*.example.com' -d example.com run
lego --email you@example.com --dns designate -d '*.example.com' -d example.com run
# or
@ -37,7 +37,7 @@ OS_REGION_NAME=RegionOne \
OS_PROJECT_ID=23d4522a987d4ab529f722a007c27846
OS_USERNAME=myuser \
OS_PASSWORD=passw0rd \
lego --dns designate -d '*.example.com' -d example.com run
lego --email you@example.com --dns designate -d '*.example.com' -d example.com run
# or
@ -46,7 +46,7 @@ OS_REGION_NAME=RegionOne \
OS_AUTH_TYPE=v3applicationcredential \
OS_APPLICATION_CREDENTIAL_ID=imn74uq0or7dyzz20dwo1ytls4me8dry \
OS_APPLICATION_CREDENTIAL_SECRET=68FuSPSdQqkFQYH5X1OoriEIJOwyLtQ8QSqXZOc9XxFK1A9tzZT6He2PfPw0OMja \
lego --dns designate -d '*.example.com' -d example.com run
lego --email you@example.com --dns designate -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Digital Ocean provider:
```bash
DO_AUTH_TOKEN=xxxxxx \
lego --dns digitalocean -d '*.example.com' -d example.com run
lego --email you@example.com --dns digitalocean -d '*.example.com' -d example.com run
```

View file

@ -29,7 +29,7 @@ Here is an example bash command using the DirectAdmin provider:
DIRECTADMIN_API_URL="http://example.com:2222" \
DIRECTADMIN_USERNAME=xxxx \
DIRECTADMIN_PASSWORD=yyy \
lego --dns directadmin -d '*.example.com' -d example.com run
lego --email you@example.com --dns directadmin -d '*.example.com' -d example.com run
```

View file

@ -1,67 +0,0 @@
---
title: "DNSExit"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: dnsexit
dnsprovider:
since: "v4.32.0"
code: "dnsexit"
url: "https://dnsexit.com"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/dnsexit/dnsexit.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [DNSExit](https://dnsexit.com).
<!--more-->
- Code: `dnsexit`
- Since: v4.32.0
Here is an example bash command using the DNSExit provider:
```bash
DNSEXIT_API_KEY="xxxxxxxxxxxxxxxxxxxxx" \
lego --dns dnsexit -d '*.example.com' -d example.com run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `DNSEXIT_API_KEY` | API key |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `DNSEXIT_HTTP_TIMEOUT` | API request timeout in seconds (Default: 30) |
| `DNSEXIT_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 10) |
| `DNSEXIT_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 300) |
| `DNSEXIT_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
- [API documentation](https://dnsexit.com/dns/dns-api/)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/dnsexit/dnsexit.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

View file

@ -27,10 +27,10 @@ Here is an example bash command using the dnsHome.de provider:
```bash
DNSHOMEDE_CREDENTIALS=example.org:password \
lego --dns dnshomede -d '*.example.com' -d example.com run
lego --email you@example.com --dns dnshomede -d '*.example.com' -d example.com run
DNSHOMEDE_CREDENTIALS=my.example.org:password1,demo.example.org:password2 \
lego --dns dnshomede -d my.example.org -d demo.example.org
lego --email you@example.com --dns dnshomede -d my.example.org -d demo.example.org
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the DNSimple provider:
```bash
DNSIMPLE_OAUTH_TOKEN=1234567890abcdefghijklmnopqrstuvwxyz \
lego --dns dnsimple -d '*.example.com' -d example.com run
lego --email you@example.com --dns dnsimple -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the DNS Made Easy provider:
```bash
DNSMADEEASY_API_KEY=xxxxxx \
DNSMADEEASY_API_SECRET=yyyyy \
lego --dns dnsmadeeasy -d '*.example.com' -d example.com run
lego --email you@example.com --dns dnsmadeeasy -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the DNSPod (deprecated) provider:
```bash
DNSPOD_API_KEY=xxxxxx \
lego --dns dnspod -d '*.example.com' -d example.com run
lego --email you@example.com --dns dnspod -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Domain Offensive (do.de) provider:
```bash
DODE_TOKEN=xxxxxx \
lego --dns dode -d '*.example.com' -d example.com run
lego --email you@example.com --dns dode -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Domeneshop provider:
```bash
DOMENESHOP_API_TOKEN=<token> \
DOMENESHOP_API_SECRET=<secret> \
lego --dns domeneshop -d '*.example.com' -d example.com run
lego --email example@example.com --dns domeneshop -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the DreamHost provider:
```bash
DREAMHOST_API_KEY="YOURAPIKEY" \
lego --dns dreamhost -d '*.example.com' -d example.com run
lego --email you@example.com --dns dreamhost -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Duck DNS provider:
```bash
DUCKDNS_TOKEN=xxxxxx \
lego --dns duckdns -d '*.example.com' -d example.com run
lego --email you@example.com --dns duckdns -d '*.example.com' -d example.com run
```

View file

@ -29,7 +29,7 @@ Here is an example bash command using the Dyn provider:
DYN_CUSTOMER_NAME=xxxxxx \
DYN_USER_NAME=yyyyy \
DYN_PASSWORD=zzzz \
lego --dns dyn -d '*.example.com' -d example.com run
lego --email you@example.com --dns dyn -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the DynDnsFree.de provider:
```bash
DYNDNSFREE_USERNAME="xxx" \
DYNDNSFREE_PASSWORD="yyy" \
lego --dns dyndnsfree -d '*.example.com' -d example.com run
lego --email you@example.com --dns dyndnsfree -d '*.example.com' -d example.com run
```

View file

@ -27,7 +27,7 @@ Here is an example bash command using the Dynu provider:
```bash
DYNU_API_KEY=1234567890abcdefghijklmnopqrstuvwxyz \
lego --dns dynu -d '*.example.com' -d example.com run
lego --email you@example.com --dns dynu -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the EasyDNS provider:
```bash
EASYDNS_TOKEN=xxx \
EASYDNS_KEY=yyy \
lego --dns easydns -d '*.example.com' -d example.com run
lego --email you@example.com --dns easydns -d '*.example.com' -d example.com run
```

View file

@ -1,67 +0,0 @@
---
title: "EdgeCenter"
date: 2019-03-03T16:39:46+01:00
draft: false
slug: edgecenter
dnsprovider:
since: "v4.29.0"
code: "edgecenter"
url: "https://edgecenter.ru/dns"
---
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/edgecenter/edgecenter.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
Configuration for [EdgeCenter](https://edgecenter.ru/dns).
<!--more-->
- Code: `edgecenter`
- Since: v4.29.0
Here is an example bash command using the EdgeCenter provider:
```bash
EDGECENTER_PERMANENT_API_TOKEN=xxxxx \
lego --dns edgecenter -d '*.example.com' -d example.com run
```
## Credentials
| Environment Variable Name | Description |
|-----------------------|-------------|
| `EDGECENTER_PERMANENT_API_TOKEN` | Permanent API token (https://edgecenter.ru/blog/permanent-api-token-explained/) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## Additional Configuration
| Environment Variable Name | Description |
|--------------------------------|-------------|
| `EDGECENTER_HTTP_TIMEOUT` | API request timeout in seconds (Default: 10) |
| `EDGECENTER_POLLING_INTERVAL` | Time between DNS propagation check in seconds (Default: 20) |
| `EDGECENTER_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation in seconds (Default: 360) |
| `EDGECENTER_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 120) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).
## More information
- [API documentation](https://apidocs.edgecenter.ru/dns)
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
<!-- providers/dns/edgecenter/edgecenter.toml -->
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->

View file

@ -30,7 +30,7 @@ AKAMAI_CLIENT_SECRET=abcdefghijklmnopqrstuvwxyz1234567890ABCDEFG= \
AKAMAI_CLIENT_TOKEN=akab-mnbvcxzlkjhgfdsapoiuytrewq1234567 \
AKAMAI_HOST=akab-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.luna.akamaiapis.net \
AKAMAI_ACCESS_TOKEN=akab-1234567890qwerty-asdfghjklzxcvtnu \
lego --dns edgedns -d '*.example.com' -d example.com run
lego --email you@example.com --dns edgedns -d '*.example.com' -d example.com run
```

View file

@ -28,7 +28,7 @@ Here is an example bash command using the Tencent EdgeOne provider:
```bash
EDGEONE_SECRET_ID=abcdefghijklmnopqrstuvwx \
EDGEONE_SECRET_KEY=your-secret-key \
lego --dns edgeone -d '*.example.com' -d example.com run
lego --email you@example.com --dns edgeone -d '*.example.com' -d example.com run
```
@ -55,7 +55,6 @@ More information [here]({{% ref "dns#configuration-and-credentials" %}}).
| `EDGEONE_REGION` | Region |
| `EDGEONE_SESSION_TOKEN` | Access Key token |
| `EDGEONE_TTL` | The TTL of the TXT record used for the DNS challenge in seconds (Default: 60) |
| `EDGEONE_ZONES_MAPPING` | Mapping between DNS zones and site IDs. (ex: 'example.org:id1,example.com:id2') |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here]({{% ref "dns#configuration-and-credentials" %}}).

Some files were not shown because too many files have changed in this diff Show more