Skip to content

Conversation

@ldez
Copy link
Member

@ldez ldez commented Oct 6, 2025

  • adds a description to your PR
  • have a homogeneous design with the other providers
  • add tests (units)
  • add tests ("live")
  • add a provider descriptor
  • generate CLI help, documentation, and readme.
  • be able to do: (and put the output of this command to a comment)
    make build
    rm -rf .lego
    
    OCTENIUM_API_KEY="xxx" \
    lego --email you@example.com --dns octenium -d '*.example.com' -d example.com -s https://acme-staging-v02.api.letsencrypt.org/directory run
    Note that the wildcard domain is important.
  • pass the linter
  • do go mod tidy

Closes #2660

Ping @abdeldjalil-fellah, can you run the command (with your domain, email, credentials, etc.)?

How to test this PR?
  1. You need Go
  2. Check out the PR:
    git clone https://github.com/ldez/lego.git
    cd lego
    git checkout feat/dns/octenium
  3. Compile lego:
    • if you have make: make build
    • if you don't have make: go build -o dist/lego ./cmd/lego
  4. Run the following command with your information (email, domain, credentials):
    OCTENIUM_API_KEY="xxx" \
    ./dist/lego --email you@example.com --dns octenium -d '*.example.com' -d example.com  -s https://acme-staging-v02.api.letsencrypt.org/directory run
    The wildcard domain is important
  5. Before each run of the command, you should clean your local environment:
    rm -rf .lego

@ldez ldez mentioned this pull request Oct 6, 2025
5 tasks
@abdeldjalil-fellah
Copy link

abdeldjalil-fellah commented Oct 6, 2025

Details
Your account credentials have been saved in your
configuration directory at "/opt/custom/tmp/.lego/accounts".

You should make a secure backup of this folder now. This
configuration directory will also contain certificates and
private keys obtained from the ACME server so making regular
backups of this folder is ideal.
2025/10/06 14:53:20 [INFO] [*.example.com, example.com] acme: Obtaining bundled SAN certificate
2025/10/06 14:53:21 [INFO] [*.example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232921003/19613955073
2025/10/06 14:53:21 [INFO] [example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232921003/19613955083
2025/10/06 14:53:21 [INFO] [*.example.com] acme: use dns-01 solver
2025/10/06 14:53:21 [INFO] [example.com] acme: Could not find solver for: tls-alpn-01
2025/10/06 14:53:21 [INFO] [example.com] acme: Could not find solver for: http-01
2025/10/06 14:53:21 [INFO] [example.com] acme: use dns-01 solver
2025/10/06 14:53:21 [INFO] [*.example.com] acme: Preparing to solve DNS-01
2025/10/06 14:53:21 [INFO] [example.com] acme: Preparing to solve DNS-01
2025/10/06 14:53:21 [INFO] [*.example.com] acme: Cleaning DNS-01 challenge
2025/10/06 14:53:21 [WARN] [*.example.com] acme: cleaning up failed: octenium: unknown domain ID for '_acme-challenge.example.com.'
2025/10/06 14:53:21 [INFO] [example.com] acme: Cleaning DNS-01 challenge
2025/10/06 14:53:21 [WARN] [example.com] acme: cleaning up failed: octenium: unknown domain ID for '_acme-challenge.example.com.'
2025/10/06 14:53:21 [INFO] Deactivating auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232921003/19613955073
2025/10/06 14:53:22 [INFO] Deactivating auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232921003/19613955083
2025/10/06 14:53:22 Could not obtain certificates:
        error: one or more domains had a problem:
[*.example.com] [*.example.com] acme: error presenting token: octenium: get domain ID: list domains: unable to unmarshal response: [status code: 200] body: {"api-status":"success","api-response":{"domains":{"30012":{"domain-name":"example.com","registration-date":"21\/08\/2025","expiration-date":"-","status":"active"}}}} error: json: cannot unmarshal object into Go struct field APIResponse[[]github.com/go-acme/lego/v4/providers/dns/octenium/internal.DomainsResponse].api-response of type []internal.DomainsResponse
[example.com] [example.com] acme: error presenting token: octenium: get domain ID: list domains: unable to unmarshal response: [status code: 200] body: {"api-status":"success","api-response":{"domains":{"30012":{"domain-name":"example.com","registration-date":"21\/08\/2025","expiration-date":"-","status":"active"}}}} error: json: cannot unmarshal object into Go struct field APIResponse[[]github.com/go-acme/lego/v4/providers/dns/octenium/internal.DomainsResponse].api-response of type []internal.DomainsResponse
root@srv02:/opt/custom/tmp#

@ldez
Copy link
Member Author

ldez commented Oct 6, 2025

Based on the log, the API documentation is wrong. I updated the implementation.
Can you pull, build, and run again?

@abdeldjalil-fellah
Copy link

Details
2025/10/06 17:47:09 [INFO] [*.example.com, example.com] acme: Obtaining bundled SAN certificate
2025/10/06 17:47:10 [INFO] [*.example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232956043/19615944203
2025/10/06 17:47:10 [INFO] [example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232956043/19615944213
2025/10/06 17:47:10 [INFO] [*.example.com] acme: use dns-01 solver
2025/10/06 17:47:10 [INFO] [example.com] acme: Could not find solver for: tls-alpn-01
2025/10/06 17:47:10 [INFO] [example.com] acme: Could not find solver for: http-01
2025/10/06 17:47:10 [INFO] [example.com] acme: use dns-01 solver
2025/10/06 17:47:10 [INFO] [*.example.com] acme: Preparing to solve DNS-01
2025/10/06 17:47:11 [INFO] [example.com] acme: Preparing to solve DNS-01
2025/10/06 17:47:11 [INFO] [*.example.com] acme: Cleaning DNS-01 challenge
2025/10/06 17:47:11 [WARN] [*.example.com] acme: cleaning up failed: octenium: list records: unexpected status: error
2025/10/06 17:47:11 [INFO] [example.com] acme: Cleaning DNS-01 challenge
2025/10/06 17:47:11 [WARN] [example.com] acme: cleaning up failed: octenium: list records: unexpected status: error
2025/10/06 17:47:11 [INFO] Deactivating auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232956043/19615944203
2025/10/06 17:47:11 [INFO] Deactivating auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232956043/19615944213
2025/10/06 17:47:12 Could not obtain certificates:
        error: one or more domains had a problem:
[*.example.com] [*.example.com] acme: error presenting token: octenium: add record: unable to unmarshal response: [status code: 200] body: {"api-status":"error","api-response":[],"api-error":"missing required fields (type, name, ttl)"} error: json: cannot unmarshal array into Go struct field APIResponse[github.com/go-acme/lego/v4/providers/dns/octenium/internal.AddRecordResponse].api-response of type internal.AddRecordResponse
[example.com] [example.com] acme: error presenting token: octenium: add record: unable to unmarshal response: [status code: 200] body: {"api-status":"error","api-response":[],"api-error":"missing required fields (type, name, ttl)"} error: json: cannot unmarshal array into Go struct field APIResponse[github.com/go-acme/lego/v4/providers/dns/octenium/internal.AddRecordResponse].api-response of type internal.AddRecordResponse

@ldez
Copy link
Member Author

ldez commented Oct 6, 2025

So the documentation is very weak...

I improved the parsing of the response, but I already set all the required fields.

I added some debug logs, can you try again?

@ldez ldez added the waiting-for/contrib-feedback Awaiting feedback from the contributor. label Oct 6, 2025
@abdeldjalil-fellah
Copy link

abdeldjalil-fellah commented Oct 6, 2025

Yes, I noticed that the docs need many improvments and fixes, and I contacted them about that.

Details
2025/10/06 21:00:46 [INFO] [*.example.com, example.com] acme: Obtaining bundled SAN certificate
2025/10/06 21:00:46 [INFO] [*.example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232987453/19618036173
2025/10/06 21:00:46 [INFO] [example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232987453/19618036183
2025/10/06 21:00:46 [INFO] [*.example.com] acme: use dns-01 solver
2025/10/06 21:00:46 [INFO] [example.com] acme: Could not find solver for: tls-alpn-01
2025/10/06 21:00:46 [INFO] [example.com] acme: Could not find solver for: http-01
2025/10/06 21:00:46 [INFO] [example.com] acme: use dns-01 solver
2025/10/06 21:00:46 [INFO] [*.example.com] acme: Preparing to solve DNS-01
GET /domains?domain-name=example.com HTTP/1.1
Host: api.panel.octenium.com
Accept: application/json


POST /domains/dns-records/add?name=_acme-challenge.example.com.&order-id=30012&ttl=120&type=TXT&value=d4qTWt-ApiZ1hGJ3tTJbnfQOpkjXJAr6dhQRxhZHdOY HTTP/1.1
Host: api.panel.octenium.com
Accept: application/json


2025/10/06 21:00:47 [INFO] [example.com] acme: Preparing to solve DNS-01
GET /domains?domain-name=example.com HTTP/1.1
Host: api.panel.octenium.com
Accept: application/json


2025/10/06 21:00:47 [INFO] [*.example.com] acme: Cleaning DNS-01 challenge
POST /domains/dns-records/list?order-id=30012&types%5B%5D=TXT HTTP/1.1
Host: api.panel.octenium.com
Accept: application/json


2025/10/06 21:00:47 [WARN] [*.example.com] acme: cleaning up failed: octenium: list records: unexpected status code: [status code: 429] body: Too many requests
2025/10/06 21:00:47 [INFO] [example.com] acme: Cleaning DNS-01 challenge
2025/10/06 21:00:47 [WARN] [example.com] acme: cleaning up failed: octenium: unknown domain ID for '_acme-challenge.example.com.'
2025/10/06 21:00:47 [INFO] Deactivating auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232987453/19618036173
2025/10/06 21:00:48 [INFO] Deactivating auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz/232987453/19618036183
2025/10/06 21:00:48 Could not obtain certificates:
        error: one or more domains had a problem:
[*.example.com] [*.example.com] acme: error presenting token: octenium: add record: unexpected status: error: missing required fields (type, name, ttl)
[example.com] [example.com] acme: error presenting token: octenium: get domain ID: list domains: unexpected status code: [status code: 429] body: Too many requests

@ldez
Copy link
Member Author

ldez commented Oct 6, 2025

add record: unexpected status: error: missing required fields (type, name, TTL)

As you can see the query parameters are set:

POST /domains/dns-records/add?name=_acme-challenge.example.com.&order-id=30012&ttl=120&type=TXT&value=d4qTWt-ApiZ1hGJ3tTJbnfQOpkjXJAr6dhQRxhZHdOY HTTP/1.1

And bonus:

unexpected status code: [status code: 429] body: Too many requests

The API is rate-limited, but there is no documentation about that...

@ldez
Copy link
Member Author

ldez commented Oct 6, 2025

Maybe it's because there is a non-documented min TTL.

I increased the default TTL.

@ldez
Copy link
Member Author

ldez commented Oct 6, 2025

I found the doc about rate limits:

Rate Limit: Octenium safeguards the API against bursts of incoming traffic based on the request's IP address to ensure stability for all users. If your application sends more than 20 requests per second, the API may return HTTP status code 429.

lego is doing 4 calls per domain, then 8 for 2 domains (base + wildcard).

So I think, either you run lego several times or the doc is wrong again.

Note that 20 req/s is very limited.

@abdeldjalil-fellah
Copy link

abdeldjalil-fellah commented Oct 7, 2025

After the last commit, the rate limit issue is resolved, but there is still "error: missing order-id." Waiting for them to fix it.

Details
2025/10/07 06:51:01 [INFO] [*.example.com, example.com] acme: Obtaining bundled SAN certificate
2025/10/07 06:51:01 [INFO] [*.example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/233066073/19623727673
2025/10/07 06:51:01 [INFO] [example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/233066073/19623727683
2025/10/07 06:51:01 [INFO] [*.example.com] acme: use dns-01 solver
2025/10/07 06:51:01 [INFO] [example.com] acme: Could not find solver for: tls-alpn-01
2025/10/07 06:51:01 [INFO] [example.com] acme: Could not find solver for: http-01
2025/10/07 06:51:01 [INFO] [example.com] acme: use dns-01 solver
2025/10/07 06:51:01 [INFO] [*.example.com] acme: Preparing to solve DNS-01
GET /domains?domain-name=example.com HTTP/1.1
Host: api.panel.octenium.com
Accept: application/json


POST /domains/dns-records/add?name=_acme-challenge.example.com.&order-id=30012&ttl=300&type=TXT&value=Cs9UHYNCXawnZgNaEELSSrXvbZ__bCTie5yd6C7wHnQ HTTP/1.1
Host: api.panel.octenium.com
Accept: application/json


2025/10/07 06:51:02 [INFO] [example.com] acme: Preparing to solve DNS-01
GET /domains?domain-name=example.com HTTP/1.1
Host: api.panel.octenium.com
Accept: application/json


POST /domains/dns-records/add?name=_acme-challenge.example.com.&order-id=30012&ttl=300&type=TXT&value=m3l-bR2OVzD7RSRapJ3Rpl5cfmfGw2iNtqTclgnrl5s HTTP/1.1
Host: api.panel.octenium.com
Accept: application/json


2025/10/07 06:51:02 [INFO] [*.example.com] acme: Cleaning DNS-01 challenge
POST /domains/dns-records/list?order-id=30012&types%5B%5D=TXT HTTP/1.1
Host: api.panel.octenium.com
Accept: application/json


2025/10/07 06:51:02 [WARN] [*.example.com] acme: cleaning up failed: octenium: list records: unexpected status: error: missing order-id
2025/10/07 06:51:02 [INFO] [example.com] acme: Cleaning DNS-01 challenge
POST /domains/dns-records/list?order-id=30012&types%5B%5D=TXT HTTP/1.1
Host: api.panel.octenium.com
Accept: application/json


2025/10/07 06:51:03 [WARN] [example.com] acme: cleaning up failed: octenium: list records: unexpected status: error: missing order-id
2025/10/07 06:51:03 [INFO] Deactivating auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz/233066073/19623727673
2025/10/07 06:51:03 [INFO] Deactivating auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz/233066073/19623727683
2025/10/07 06:51:04 Could not obtain certificates:
        error: one or more domains had a problem:
[*.example.com] [*.example.com] acme: error presenting token: octenium: add record: unexpected status: error: missing required fields (type, name, ttl)
[example.com] [example.com] acme: error presenting token: octenium: add record: unexpected status: error: missing required fields (type, name, ttl)

@abdeldjalil-fellah

This comment was marked as off-topic.

@ldez
Copy link
Member Author

ldez commented Oct 7, 2025

I updated the implementation, can you try again?

@abdeldjalil-fellah
Copy link

Now all requests are ok, but another error occurred

Details
2025/10/07 08:33:16 [INFO] [*.example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:33:18 [INFO] [example.com] acme: Trying to solve DNS-01
2025/10/07 08:33:18 [INFO] [example.com] acme: Checking DNS record propagation. [nameservers=127.0.0.53:53]
2025/10/07 08:33:20 [INFO] Wait for propagation [timeout: 1m0s, interval: 2s]
2025/10/07 08:33:20 [INFO] [example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:33:35 [INFO] [example.com] The server validated our request
2025/10/07 08:33:35 [INFO] [*.example.com] acme: Cleaning DNS-01 challenge
2025/10/07 08:33:41 [INFO] [example.com] acme: Cleaning DNS-01 challenge
2025/10/07 08:33:47 [INFO] Deactivating auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz/233081073/19624682923
2025/10/07 08:33:48 [INFO] Skipping deactivating of valid auth: https://acme-staging-v02.api.letsencrypt.org/acme/authz/233081073/19624682933
2025/10/07 08:33:48 Could not obtain certificates:
        error: one or more domains had a problem:
[*.example.com] propagation: time limit exceeded: last error: authoritative nameservers: NS ns1.octenium.net.:53 returned NXDOMAIN for _acme-challenge.example.com.

@abdeldjalil-fellah
Copy link

Adding --dns.resolvers 1.1.1.1 works:

2025/10/07 08:39:32 [INFO] [*.example.com, example.com] acme: Obtaining bundled SAN certificate
2025/10/07 08:39:33 [INFO] [*.example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/233082073/19624758353
2025/10/07 08:39:33 [INFO] [example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/233082073/19624758363
2025/10/07 08:39:33 [INFO] [*.example.com] acme: use dns-01 solver
2025/10/07 08:39:33 [INFO] [example.com] acme: Could not find solver for: tls-alpn-01
2025/10/07 08:39:33 [INFO] [example.com] acme: Could not find solver for: http-01
2025/10/07 08:39:33 [INFO] [example.com] acme: use dns-01 solver
2025/10/07 08:39:33 [INFO] [*.example.com] acme: Preparing to solve DNS-01
2025/10/07 08:39:36 [INFO] [example.com] acme: Preparing to solve DNS-01
2025/10/07 08:39:39 [INFO] [*.example.com] acme: Trying to solve DNS-01
2025/10/07 08:39:39 [INFO] [*.example.com] acme: Checking DNS record propagation. [nameservers=1.1.1.1:53]
2025/10/07 08:39:41 [INFO] Wait for propagation [timeout: 1m0s, interval: 2s]
2025/10/07 08:39:42 [INFO] [*.example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:39:45 [INFO] [*.example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:39:47 [INFO] [*.example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:39:49 [INFO] [*.example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:39:52 [INFO] [*.example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:39:54 [INFO] [*.example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:39:57 [INFO] [*.example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:39:59 [INFO] [*.example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:40:01 [INFO] [*.example.com] acme: Waiting for DNS record propagation.
2025/10/07 08:40:10 [INFO] [*.example.com] The server validated our request
2025/10/07 08:40:10 [INFO] [example.com] acme: Trying to solve DNS-01
2025/10/07 08:40:10 [INFO] [example.com] acme: Checking DNS record propagation. [nameservers=1.1.1.1:53]
2025/10/07 08:40:12 [INFO] Wait for propagation [timeout: 1m0s, interval: 2s]
2025/10/07 08:40:20 [INFO] [example.com] The server validated our request
2025/10/07 08:40:20 [INFO] [*.example.com] acme: Cleaning DNS-01 challenge
2025/10/07 08:40:27 [INFO] [example.com] acme: Cleaning DNS-01 challenge
2025/10/07 08:40:34 [INFO] [*.example.com, example.com] acme: Validations succeeded; requesting certificates
2025/10/07 08:40:34 [INFO] Wait for certificate [timeout: 30s, interval: 500ms]
2025/10/07 08:40:34 [INFO] [*.example.com] Server responded with a certificate.

@ldez ldez removed the waiting-for/user-tests Need users to test functionality label Oct 7, 2025
@ldez ldez removed the waiting-for/contrib-feedback Awaiting feedback from the contributor. label Oct 7, 2025
@ldez ldez marked this pull request as ready for review October 7, 2025 11:35
@ldez ldez added this to the unreleased milestone Oct 7, 2025
@ldez ldez requested a review from dmke October 7, 2025 11:37
Copy link
Member

@dmke dmke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ldez ldez merged commit a3f3c62 into go-acme:master Oct 7, 2025
11 of 13 checks passed
@ldez ldez deleted the feat/dns/octenium branch October 7, 2025 14:41
@ldez ldez modified the milestones: unreleased, v4.27 Oct 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

Support for provider: Octenium

3 participants