Repository: go-acme/lego (language: go)

Issue:
Support for provider: dnshome.de
### Welcome

- [X] Yes, I've searched similar issues on GitHub and didn't find any.
- [X] Yes, the DNS provider exposes a public API.
- [X] Yes, I know that the lego maintainers don't have an account in all DNS providers in the world.
- [ ] Yes, I'm able to create a pull request and be able to maintain the implementation.
- [X] Yes, I'm able to test an implementation if someone creates a pull request to add the support of this DNS provider.

### How do you use lego?

Binary

### Link to the DNS provider

https://www.dnshome.de

### Link to the API documentation

https://github.com/acmesh-official/acme.sh/blob/master/dnsapi/dns_dnshome.sh

### Additional Notes

Hi,

unfortunately, I'm not able to "transcribe" an existing acme.sh plugin for dnshome.de to use it with LEGO.

The existing (tested / working) script can be found here:
https://github.com/acmesh-official/acme.sh/blob/master/dnsapi/dns_dnshome.sh

Is anybody able to help me integrating this provider?

Thanks in advance and best regards,
David


Discussion / hints:
Hello,

can you provide a link to the API documentation (not a link to acmesh)?
Unfortunately, the acme.sh script was the only document containing API I was able to find...

There is no further information on the provider's homepage either.

My idea was to use the acme script in order to "translate" it into a LEGO plugin - however, I don't possess sufficient programming / scripting skills in order to do so 😔 
I'm currently trying to get the API works but I have an error: `error - no valid acme txt record`
I found the problem there is a min size (12 characters) for the TXT value, weird API...

Fix patch:
diff --git a/README.md b/README.md
index f4a5f97bf5..80f2f0130a 100644
--- a/README.md
+++ b/README.md
@@ -54,29 +54,29 @@ Detailed documentation is available [here](https://go-acme.github.io/lego/dns).
 | [Azure](https://go-acme.github.io/lego/dns/azure/)                              | [Bindman](https://go-acme.github.io/lego/dns/bindman/)                          | [Bluecat](https://go-acme.github.io/lego/dns/bluecat/)                          | [Checkdomain](https://go-acme.github.io/lego/dns/checkdomain/)                  |
 | [Civo](https://go-acme.github.io/lego/dns/civo/)                                | [CloudDNS](https://go-acme.github.io/lego/dns/clouddns/)                        | [Cloudflare](https://go-acme.github.io/lego/dns/cloudflare/)                    | [ClouDNS](https://go-acme.github.io/lego/dns/cloudns/)                          |
 | [CloudXNS](https://go-acme.github.io/lego/dns/cloudxns/)                        | [ConoHa](https://go-acme.github.io/lego/dns/conoha/)                            | [Constellix](https://go-acme.github.io/lego/dns/constellix/)                    | [deSEC.io](https://go-acme.github.io/lego/dns/desec/)                           |
-| [Designate DNSaaS for Openstack](https://go-acme.github.io/lego/dns/designate/) | [Digital Ocean](https://go-acme.github.io/lego/dns/digitalocean/)               | [DNS Made Easy](https://go-acme.github.io/lego/dns/dnsmadeeasy/)                | [DNSimple](https://go-acme.github.io/lego/dns/dnsimple/)                        |
-| [DNSPod (deprecated)](https://go-acme.github.io/lego/dns/dnspod/)               | [Domain Offensive (do.de)](https://go-acme.github.io/lego/dns/dode/)            | [Domeneshop](https://go-acme.github.io/lego/dns/domeneshop/)                    | [DreamHost](https://go-acme.github.io/lego/dns/dreamhost/)                      |
-| [Duck DNS](https://go-acme.github.io/lego/dns/duckdns/)                         | [Dyn](https://go-acme.github.io/lego/dns/dyn/)                                  | [Dynu](https://go-acme.github.io/lego/dns/dynu/)                                | [EasyDNS](https://go-acme.github.io/lego/dns/easydns/)                          |
-| [Epik](https://go-acme.github.io/lego/dns/epik/)                                | [Exoscale](https://go-acme.github.io/lego/dns/exoscale/)                        | [External program](https://go-acme.github.io/lego/dns/exec/)                    | [freemyip.com](https://go-acme.github.io/lego/dns/freemyip/)                    |
-| [G-Core Labs](https://go-acme.github.io/lego/dns/gcore/)                        | [Gandi Live DNS (v5)](https://go-acme.github.io/lego/dns/gandiv5/)              | [Gandi](https://go-acme.github.io/lego/dns/gandi/)                              | [Glesys](https://go-acme.github.io/lego/dns/glesys/)                            |
-| [Go Daddy](https://go-acme.github.io/lego/dns/godaddy/)                         | [Google Cloud](https://go-acme.github.io/lego/dns/gcloud/)                      | [Hetzner](https://go-acme.github.io/lego/dns/hetzner/)                          | [Hosting.de](https://go-acme.github.io/lego/dns/hostingde/)                     |
-| [Hosttech](https://go-acme.github.io/lego/dns/hosttech/)                        | [HTTP request](https://go-acme.github.io/lego/dns/httpreq/)                     | [Hurricane Electric DNS](https://go-acme.github.io/lego/dns/hurricane/)         | [HyperOne](https://go-acme.github.io/lego/dns/hyperone/)                        |
-| [IBM Cloud (SoftLayer)](https://go-acme.github.io/lego/dns/ibmcloud/)           | [IIJ DNS Platform Service](https://go-acme.github.io/lego/dns/iijdpf/)          | [Infoblox](https://go-acme.github.io/lego/dns/infoblox/)                        | [Infomaniak](https://go-acme.github.io/lego/dns/infomaniak/)                    |
-| [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/)            | [Internet.bs](https://go-acme.github.io/lego/dns/internetbs/)                   | [INWX](https://go-acme.github.io/lego/dns/inwx/)                                | [Ionos](https://go-acme.github.io/lego/dns/ionos/)                              |
-| [iwantmyname](https://go-acme.github.io/lego/dns/iwantmyname/)                  | [Joker](https://go-acme.github.io/lego/dns/joker/)                              | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/)               | [Liara](https://go-acme.github.io/lego/dns/liara/)                              |
-| [Linode (v4)](https://go-acme.github.io/lego/dns/linode/)                       | [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/)                     | [Loopia](https://go-acme.github.io/lego/dns/loopia/)                            | [LuaDNS](https://go-acme.github.io/lego/dns/luadns/)                            |
-| [Manual](https://go-acme.github.io/lego/dns/manual/)                            | [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/)                         | [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/)                | [Name.com](https://go-acme.github.io/lego/dns/namedotcom/)                      |
-| [Namecheap](https://go-acme.github.io/lego/dns/namecheap/)                      | [Namesilo](https://go-acme.github.io/lego/dns/namesilo/)                        | [NearlyFreeSpeech.NET](https://go-acme.github.io/lego/dns/nearlyfreespeech/)    | [Netcup](https://go-acme.github.io/lego/dns/netcup/)                            |
-| [Netlify](https://go-acme.github.io/lego/dns/netlify/)                          | [Nicmanager](https://go-acme.github.io/lego/dns/nicmanager/)                    | [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/)                        | [Njalla](https://go-acme.github.io/lego/dns/njalla/)                            |
-| [NS1](https://go-acme.github.io/lego/dns/ns1/)                                  | [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/)                   | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/)                 | [OVH](https://go-acme.github.io/lego/dns/ovh/)                                  |
-| [Porkbun](https://go-acme.github.io/lego/dns/porkbun/)                          | [PowerDNS](https://go-acme.github.io/lego/dns/pdns/)                            | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/)                      | [reg.ru](https://go-acme.github.io/lego/dns/regru/)                             |
-| [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/)                          | [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/)                  | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/)                 | [Scaleway](https://go-acme.github.io/lego/dns/scaleway/)                        |
-| [Selectel](https://go-acme.github.io/lego/dns/selectel/)                        | [Servercow](https://go-acme.github.io/lego/dns/servercow/)                      | [Simply.com](https://go-acme.github.io/lego/dns/simply/)                        | [Sonic](https://go-acme.github.io/lego/dns/sonic/)                              |
-| [Stackpath](https://go-acme.github.io/lego/dns/stackpath/)                      | [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/)           | [TransIP](https://go-acme.github.io/lego/dns/transip/)                          | [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/)                   |
-| [Ultradns](https://go-acme.github.io/lego/dns/ultradns/)                        | [Variomedia](https://go-acme.github.io/lego/dns/variomedia/)                    | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/)                          | [Vercel](https://go-acme.github.io/lego/dns/vercel/)                            |
-| [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/)                 | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/)                        | [VK Cloud](https://go-acme.github.io/lego/dns/vkcloud/)                         | [Vscale](https://go-acme.github.io/lego/dns/vscale/)                            |
-| [Vultr](https://go-acme.github.io/lego/dns/vultr/)                              | [WEDOS](https://go-acme.github.io/lego/dns/wedos/)                              | [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/)                 | [Yandex PDD](https://go-acme.github.io/lego/dns/yandex/)                        |
-| [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/)                           | [Zonomi](https://go-acme.github.io/lego/dns/zonomi/)                            |                                                                                 |                                                                                 |
+| [Designate DNSaaS for Openstack](https://go-acme.github.io/lego/dns/designate/) | [Digital Ocean](https://go-acme.github.io/lego/dns/digitalocean/)               | [DNS Made Easy](https://go-acme.github.io/lego/dns/dnsmadeeasy/)                | [dnsHome.de](https://go-acme.github.io/lego/dns/dnshomede/)                     |
+| [DNSimple](https://go-acme.github.io/lego/dns/dnsimple/)                        | [DNSPod (deprecated)](https://go-acme.github.io/lego/dns/dnspod/)               | [Domain Offensive (do.de)](https://go-acme.github.io/lego/dns/dode/)            | [Domeneshop](https://go-acme.github.io/lego/dns/domeneshop/)                    |
+| [DreamHost](https://go-acme.github.io/lego/dns/dreamhost/)                      | [Duck DNS](https://go-acme.github.io/lego/dns/duckdns/)                         | [Dyn](https://go-acme.github.io/lego/dns/dyn/)                                  | [Dynu](https://go-acme.github.io/lego/dns/dynu/)                                |
+| [EasyDNS](https://go-acme.github.io/lego/dns/easydns/)                          | [Epik](https://go-acme.github.io/lego/dns/epik/)                                | [Exoscale](https://go-acme.github.io/lego/dns/exoscale/)                        | [External program](https://go-acme.github.io/lego/dns/exec/)                    |
+| [freemyip.com](https://go-acme.github.io/lego/dns/freemyip/)                    | [G-Core Labs](https://go-acme.github.io/lego/dns/gcore/)                        | [Gandi Live DNS (v5)](https://go-acme.github.io/lego/dns/gandiv5/)              | [Gandi](https://go-acme.github.io/lego/dns/gandi/)                              |
+| [Glesys](https://go-acme.github.io/lego/dns/glesys/)                            | [Go Daddy](https://go-acme.github.io/lego/dns/godaddy/)                         | [Google Cloud](https://go-acme.github.io/lego/dns/gcloud/)                      | [Hetzner](https://go-acme.github.io/lego/dns/hetzner/)                          |
+| [Hosting.de](https://go-acme.github.io/lego/dns/hostingde/)                     | [Hosttech](https://go-acme.github.io/lego/dns/hosttech/)                        | [HTTP request](https://go-acme.github.io/lego/dns/httpreq/)                     | [Hurricane Electric DNS](https://go-acme.github.io/lego/dns/hurricane/)         |
+| [HyperOne](https://go-acme.github.io/lego/dns/hyperone/)                        | [IBM Cloud (SoftLayer)](https://go-acme.github.io/lego/dns/ibmcloud/)           | [IIJ DNS Platform Service](https://go-acme.github.io/lego/dns/iijdpf/)          | [Infoblox](https://go-acme.github.io/lego/dns/infoblox/)                        |
+| [Infomaniak](https://go-acme.github.io/lego/dns/infomaniak/)                    | [Internet Initiative Japan](https://go-acme.github.io/lego/dns/iij/)            | [Internet.bs](https://go-acme.github.io/lego/dns/internetbs/)                   | [INWX](https://go-acme.github.io/lego/dns/inwx/)                                |
+| [Ionos](https://go-acme.github.io/lego/dns/ionos/)                              | [iwantmyname](https://go-acme.github.io/lego/dns/iwantmyname/)                  | [Joker](https://go-acme.github.io/lego/dns/joker/)                              | [Joohoi's ACME-DNS](https://go-acme.github.io/lego/dns/acme-dns/)               |
+| [Liara](https://go-acme.github.io/lego/dns/liara/)                              | [Linode (v4)](https://go-acme.github.io/lego/dns/linode/)                       | [Liquid Web](https://go-acme.github.io/lego/dns/liquidweb/)                     | [Loopia](https://go-acme.github.io/lego/dns/loopia/)                            |
+| [LuaDNS](https://go-acme.github.io/lego/dns/luadns/)                            | [Manual](https://go-acme.github.io/lego/dns/manual/)                            | [MyDNS.jp](https://go-acme.github.io/lego/dns/mydnsjp/)                         | [MythicBeasts](https://go-acme.github.io/lego/dns/mythicbeasts/)                |
+| [Name.com](https://go-acme.github.io/lego/dns/namedotcom/)                      | [Namecheap](https://go-acme.github.io/lego/dns/namecheap/)                      | [Namesilo](https://go-acme.github.io/lego/dns/namesilo/)                        | [NearlyFreeSpeech.NET](https://go-acme.github.io/lego/dns/nearlyfreespeech/)    |
+| [Netcup](https://go-acme.github.io/lego/dns/netcup/)                            | [Netlify](https://go-acme.github.io/lego/dns/netlify/)                          | [Nicmanager](https://go-acme.github.io/lego/dns/nicmanager/)                    | [NIFCloud](https://go-acme.github.io/lego/dns/nifcloud/)                        |
+| [Njalla](https://go-acme.github.io/lego/dns/njalla/)                            | [NS1](https://go-acme.github.io/lego/dns/ns1/)                                  | [Open Telekom Cloud](https://go-acme.github.io/lego/dns/otc/)                   | [Oracle Cloud](https://go-acme.github.io/lego/dns/oraclecloud/)                 |
+| [OVH](https://go-acme.github.io/lego/dns/ovh/)                                  | [Porkbun](https://go-acme.github.io/lego/dns/porkbun/)                          | [PowerDNS](https://go-acme.github.io/lego/dns/pdns/)                            | [Rackspace](https://go-acme.github.io/lego/dns/rackspace/)                      |
+| [reg.ru](https://go-acme.github.io/lego/dns/regru/)                             | [RFC2136](https://go-acme.github.io/lego/dns/rfc2136/)                          | [RimuHosting](https://go-acme.github.io/lego/dns/rimuhosting/)                  | [Sakura Cloud](https://go-acme.github.io/lego/dns/sakuracloud/)                 |
+| [Scaleway](https://go-acme.github.io/lego/dns/scaleway/)                        | [Selectel](https://go-acme.github.io/lego/dns/selectel/)                        | [Servercow](https://go-acme.github.io/lego/dns/servercow/)                      | [Simply.com](https://go-acme.github.io/lego/dns/simply/)                        |
+| [Sonic](https://go-acme.github.io/lego/dns/sonic/)                              | [Stackpath](https://go-acme.github.io/lego/dns/stackpath/)                      | [Tencent Cloud DNS](https://go-acme.github.io/lego/dns/tencentcloud/)           | [TransIP](https://go-acme.github.io/lego/dns/transip/)                          |
+| [UKFast SafeDNS](https://go-acme.github.io/lego/dns/safedns/)                   | [Ultradns](https://go-acme.github.io/lego/dns/ultradns/)                        | [Variomedia](https://go-acme.github.io/lego/dns/variomedia/)                    | [VegaDNS](https://go-acme.github.io/lego/dns/vegadns/)                          |
+| [Vercel](https://go-acme.github.io/lego/dns/vercel/)                            | [Versio.[nl/eu/uk]](https://go-acme.github.io/lego/dns/versio/)                 | [VinylDNS](https://go-acme.github.io/lego/dns/vinyldns/)                        | [VK Cloud](https://go-acme.github.io/lego/dns/vkcloud/)                         |
+| [Vscale](https://go-acme.github.io/lego/dns/vscale/)                            | [Vultr](https://go-acme.github.io/lego/dns/vultr/)                              | [WEDOS](https://go-acme.github.io/lego/dns/wedos/)                              | [Yandex Cloud](https://go-acme.github.io/lego/dns/yandexcloud/)                 |
+| [Yandex PDD](https://go-acme.github.io/lego/dns/yandex/)                        | [Zone.ee](https://go-acme.github.io/lego/dns/zoneee/)                           | [Zonomi](https://go-acme.github.io/lego/dns/zonomi/)                            |                                                                                 |
 
 <!-- END DNS PROVIDERS LIST -->
 
diff --git a/cmd/zz_gen_cmd_dnshelp.go b/cmd/zz_gen_cmd_dnshelp.go
index a18feaae80..fbfc6aa6b0 100644
--- a/cmd/zz_gen_cmd_dnshelp.go
+++ b/cmd/zz_gen_cmd_dnshelp.go
@@ -34,6 +34,7 @@ func allDNSCodes() string {
 		"desec",
 		"designate",
 		"digitalocean",
+		"dnshomede",
 		"dnsimple",
 		"dnsmadeeasy",
 		"dnspod",
@@ -572,6 +573,20 @@ func displayDNSHelp(w io.Writer, name string) error {
 		ew.writeln()
 		ew.writeln(`More information: https://go-acme.github.io/lego/dns/digitalocean`)
 
+	case "dnshomede":
+		// generated from: providers/dns/dnshomede/dnshomede.toml
+		ew.writeln(`Configuration for dnsHome.de.`)
+		ew.writeln(`Code:	'dnshomede'`)
+		ew.writeln(`Since:	'v4.10.0'`)
+		ew.writeln()
+
+		ew.writeln(`Credentials:`)
+		ew.writeln(`	- "DNSHOMEDE_TOKENS":	TXT record names and tokens`)
+		ew.writeln()
+
+		ew.writeln()
+		ew.writeln(`More information: https://go-acme.github.io/lego/dns/dnshomede`)
+
 	case "dnsimple":
 		// generated from: providers/dns/dnsimple/dnsimple.toml
 		ew.writeln(`Configuration for DNSimple.`)
diff --git a/docs/content/dns/zz_gen_dnshomede.md b/docs/content/dns/zz_gen_dnshomede.md
new file mode 100644
index 0000000000..54cb3bd196
--- /dev/null
+++ b/docs/content/dns/zz_gen_dnshomede.md
@@ -0,0 +1,56 @@
+---
+title: "dnsHome.de"
+date: 2019-03-03T16:39:46+01:00
+draft: false
+slug: dnshomede
+dnsprovider:
+  since:    "v4.10.0"
+  code:     "dnshomede"
+  url:      "https://www.dnshome.de"
+---
+
+<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
+<!-- providers/dns/dnshomede/dnshomede.toml -->
+<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
+
+
+Configuration for [dnsHome.de](https://www.dnshome.de).
+
+
+<!--more-->
+
+- Code: `dnshomede`
+- Since: v4.10.0
+
+
+Here is an example bash command using the dnsHome.de provider:
+
+```bash
+DNSHOMEDE_CREDENTIALS=sub.example.org:password \
+lego --email you@example.com --dns dnshomede --domains example.org --domains '*.example.org' run
+
+DNSHOMEDE_CREDENTIALS=my.example.org:password1,demo.example.org:password2 \
+lego --email you@example.com --dns dnshomede --domains my.example.org --domains demo.example.org
+```
+
+
+
+
+## Credentials
+
+| Environment Variable Name | Description |
+|-----------------------|-------------|
+| `DNSHOMEDE_TOKENS` | TXT record names and tokens |
+
+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" >}}).
+
+
+
+
+
+
+
+<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
+<!-- providers/dns/dnshomede/dnshomede.toml -->
+<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. -->
diff --git a/docs/data/zz_cli_help.toml b/docs/data/zz_cli_help.toml
index c02f0739f6..d9926c2ad5 100644
--- a/docs/data/zz_cli_help.toml
+++ b/docs/data/zz_cli_help.toml
@@ -125,7 +125,7 @@ To display the documentation for a specific DNS provider, run:
   $ lego dnshelp -c code
 
 Supported DNS providers:
-  acme-dns, alidns, allinkl, arvancloud, auroradns, autodns, azure, bindman, bluecat, checkdomain, civo, clouddns, cloudflare, cloudns, cloudxns, conoha, constellix, desec, designate, digitalocean, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dynu, easydns, edgedns, epik, exec, exoscale, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, hetzner, hostingde, hosttech, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, iwantmyname, joker, liara, lightsail, linode, liquidweb, loopia, luadns, manual, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla, ns1, oraclecloud, otc, ovh, pdns, porkbun, rackspace, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, servercow, simply, sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, vscale, vultr, wedos, yandex, yandexcloud, zoneee, zonomi
+  acme-dns, alidns, allinkl, arvancloud, auroradns, autodns, azure, bindman, bluecat, checkdomain, civo, clouddns, cloudflare, cloudns, cloudxns, conoha, constellix, desec, designate, digitalocean, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, dreamhost, duckdns, dyn, dynu, easydns, edgedns, epik, exec, exoscale, freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, hetzner, hostingde, hosttech, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, infomaniak, internetbs, inwx, ionos, iwantmyname, joker, liara, lightsail, linode, liquidweb, loopia, luadns, manual, mydnsjp, mythicbeasts, namecheap, namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla, ns1, oraclecloud, otc, ovh, pdns, porkbun, rackspace, regru, rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, servercow, simply, sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio, vinyldns, vkcloud, vscale, vultr, wedos, yandex, yandexcloud, zoneee, zonomi
 
 More information: https://go-acme.github.io/lego/dns
 """
diff --git a/providers/dns/dns_providers.go b/providers/dns/dns_providers.go
index e6d50312cd..a0343fb784 100644
--- a/providers/dns/dns_providers.go
+++ b/providers/dns/dns_providers.go
@@ -25,6 +25,7 @@ import (
 	"github.com/go-acme/lego/v4/providers/dns/desec"
 	"github.com/go-acme/lego/v4/providers/dns/designate"
 	"github.com/go-acme/lego/v4/providers/dns/digitalocean"
+	"github.com/go-acme/lego/v4/providers/dns/dnshomede"
 	"github.com/go-acme/lego/v4/providers/dns/dnsimple"
 	"github.com/go-acme/lego/v4/providers/dns/dnsmadeeasy"
 	"github.com/go-acme/lego/v4/providers/dns/dnspod"
@@ -159,6 +160,8 @@ func NewDNSChallengeProviderByName(name string) (challenge.Provider, error) {
 		return designate.NewDNSProvider()
 	case "digitalocean":
 		return digitalocean.NewDNSProvider()
+	case "dnshomede":
+		return dnshomede.NewDNSProvider()
 	case "dnsimple":
 		return dnsimple.NewDNSProvider()
 	case "dnsmadeeasy":
diff --git a/providers/dns/dnshomede/dnshomede.go b/providers/dns/dnshomede/dnshomede.go
new file mode 100644
index 0000000000..6d8e6a143b
--- /dev/null
+++ b/providers/dns/dnshomede/dnshomede.go
@@ -0,0 +1,148 @@
+// Package dnshomede implements a DNS provider for solving the DNS-01 challenge using dnsHome.de.
+package dnshomede
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+	"strings"
+	"time"
+
+	"github.com/go-acme/lego/v4/challenge/dns01"
+	"github.com/go-acme/lego/v4/platform/config/env"
+	"github.com/go-acme/lego/v4/providers/dns/dnshomede/internal"
+)
+
+// Environment variables names.
+const (
+	envNamespace = "DNSHOMEDE_"
+
+	EnvCredentials = envNamespace + "CREDENTIALS"
+
+	EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
+	EnvPollingInterval    = envNamespace + "POLLING_INTERVAL"
+	EnvHTTPTimeout        = envNamespace + "HTTP_TIMEOUT"
+	EnvSequenceInterval   = envNamespace + "SEQUENCE_INTERVAL"
+)
+
+// Config is used to configure the creation of the DNSProvider.
+type Config struct {
+	Credentials        map[string]string
+	PropagationTimeout time.Duration
+	PollingInterval    time.Duration
+	SequenceInterval   time.Duration
+	HTTPClient         *http.Client
+}
+
+// NewDefaultConfig returns a default configuration for the DNSProvider.
+func NewDefaultConfig() *Config {
+	return &Config{
+		PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 20*time.Minute),
+		PollingInterval:    env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
+		SequenceInterval:   env.GetOrDefaultSecond(EnvSequenceInterval, 2*time.Minute),
+		HTTPClient: &http.Client{
+			Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
+		},
+	}
+}
+
+// DNSProvider implements the challenge.Provider interface.
+type DNSProvider struct {
+	config *Config
+	client *internal.Client
+}
+
+// NewDNSProvider returns a DNSProvider instance configured for dnsHome.de.
+// Credentials must be passed in the environment variable: DNSHOMEDE_CREDENTIALS.
+func NewDNSProvider() (*DNSProvider, error) {
+	config := NewDefaultConfig()
+	values, err := env.Get(EnvCredentials)
+	if err != nil {
+		return nil, fmt.Errorf("dnshomede: %w", err)
+	}
+
+	credentials, err := parseCredentials(values[EnvCredentials])
+	if err != nil {
+		return nil, fmt.Errorf("dnshomede: %w", err)
+	}
+
+	config.Credentials = credentials
+
+	return NewDNSProviderConfig(config)
+}
+
+func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
+	if config == nil {
+		return nil, errors.New("dnshomede: the configuration of the DNS provider is nil")
+	}
+
+	if len(config.Credentials) == 0 {
+		return nil, errors.New("dnshomede: missing credentials")
+	}
+
+	for domain, password := range config.Credentials {
+		if domain == "" {
+			return nil, fmt.Errorf(`dnshomede: missing domain: "%s:%s"`, domain, password)
+		}
+
+		if password == "" {
+			return nil, fmt.Errorf(`dnshomede: missing password: "%s:%s"`, domain, password)
+		}
+	}
+
+	client := internal.NewClient(config.Credentials)
+
+	return &DNSProvider{config: config, client: client}, nil
+}
+
+// Present updates a TXT record to fulfill the dns-01 challenge.
+func (d *DNSProvider) Present(domain, _, keyAuth string) error {
+	fqdn, value := dns01.GetRecord(domain, keyAuth)
+
+	err := d.client.Add(dns01.UnFqdn(fqdn), value)
+	if err != nil {
+		return fmt.Errorf("dnshomede: %w", err)
+	}
+
+	return nil
+}
+
+// CleanUp updates the TXT record matching the specified parameters.
+func (d *DNSProvider) CleanUp(domain, _, keyAuth string) error {
+	fqdn, value := dns01.GetRecord(domain, keyAuth)
+
+	err := d.client.Remove(dns01.UnFqdn(fqdn), value)
+	if err != nil {
+		return fmt.Errorf("dnshomede: %w", err)
+	}
+
+	return nil
+}
+
+// Timeout returns the timeout and interval to use when checking for DNS propagation.
+// Adjusting here to cope with spikes in propagation times.
+func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
+	return d.config.PropagationTimeout, d.config.PollingInterval
+}
+
+// Sequential All DNS challenges for this provider will be resolved sequentially.
+// Returns the interval between each iteration.
+func (d *DNSProvider) Sequential() time.Duration {
+	return d.config.SequenceInterval
+}
+
+func parseCredentials(raw string) (map[string]string, error) {
+	credentials := make(map[string]string)
+
+	credStrings := strings.Split(strings.TrimSuffix(raw, ","), ",")
+	for _, credPair := range credStrings {
+		data := strings.Split(credPair, ":")
+		if len(data) != 2 {
+			return nil, fmt.Errorf("invalid credential pair: %q", credPair)
+		}
+
+		credentials[strings.TrimSpace(data[0])] = strings.TrimSpace(data[1])
+	}
+
+	return credentials, nil
+}
diff --git a/providers/dns/dnshomede/dnshomede.toml b/providers/dns/dnshomede/dnshomede.toml
new file mode 100644
index 0000000000..0598f38fb9
--- /dev/null
+++ b/providers/dns/dnshomede/dnshomede.toml
@@ -0,0 +1,22 @@
+Name = "dnsHome.de"
+Description = ''''''
+URL = "https://www.dnshome.de"
+Code = "dnshomede"
+Since = "v4.10.0"
+
+Example = '''
+DNSHOMEDE_CREDENTIALS=sub.example.org:password \
+lego --email you@example.com --dns dnshomede --domains example.org --domains '*.example.org' run
+
+DNSHOMEDE_CREDENTIALS=my.example.org:password1,demo.example.org:password2 \
+lego --email you@example.com --dns dnshomede --domains my.example.org --domains demo.example.org
+'''
+
+[Configuration]
+  [Configuration.Credentials]
+    DNSHOMEDE_CREDENTIALS = "Comma-separated list of domain:password credential pairs"
+  [Configuration.Addtional]
+    DNSHOMEDE_POLLING_INTERVAL = "Time between DNS propagation checks"
+    DNSHOMEDE_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation; defaults to 300s (5 minutes)"
+    DNSHOMEDE_SEQUENCE_INTERVAL = "Time between sequential requests"
+    DNSHOMEDE_HTTP_TIMEOUT = "API request timeout"
diff --git a/providers/dns/dnshomede/internal/client.go b/providers/dns/dnshomede/internal/client.go
new file mode 100644
index 0000000000..175b12e81b
--- /dev/null
+++ b/providers/dns/dnshomede/internal/client.go
@@ -0,0 +1,118 @@
+package internal
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+	"strings"
+	"sync"
+	"time"
+)
+
+const (
+	removeAction = "rm"
+	addAction    = "add"
+)
+
+const successCode = "successfully"
+
+const defaultBaseURL = "https://www.dnshome.de/dyndns.php"
+
+// Client the dnsHome.de client.
+type Client struct {
+	HTTPClient *http.Client
+	baseURL    string
+
+	credentials map[string]string
+	credMu      sync.Mutex
+}
+
+// NewClient Creates a new Client.
+func NewClient(credentials map[string]string) *Client {
+	return &Client{
+		HTTPClient:  &http.Client{Timeout: 10 * time.Second},
+		baseURL:     defaultBaseURL,
+		credentials: credentials,
+	}
+}
+
+// Add adds a TXT record.
+// only one TXT record for ACME is allowed, so it will update the "current" TXT record.
+func (c *Client) Add(hostname, value string) error {
+	domain := strings.TrimPrefix(hostname, "_acme-challenge.")
+
+	c.credMu.Lock()
+	password, ok := c.credentials[domain]
+	c.credMu.Unlock()
+
+	if !ok {
+		return fmt.Errorf("domain %s not found in credentials, check your credentials map", domain)
+	}
+
+	return c.do(url.UserPassword(domain, password), addAction, value)
+}
+
+// Remove removes a TXT record.
+// only one TXT record for ACME is allowed, so it will remove "all" the TXT records.
+func (c *Client) Remove(hostname, value string) error {
+	domain := strings.TrimPrefix(hostname, "_acme-challenge.")
+
+	c.credMu.Lock()
+	password, ok := c.credentials[domain]
+	c.credMu.Unlock()
+
+	if !ok {
+		return fmt.Errorf("domain %s not found in credentials, check your credentials map", domain)
+	}
+
+	return c.do(url.UserPassword(domain, password), removeAction, value)
+}
+
+func (c *Client) do(userInfo *url.Userinfo, action, value string) error {
+	if len(value) < 12 {
+		return fmt.Errorf("the TXT value must have more than 12 characters: %s", value)
+	}
+
+	apiEndpoint, err := url.Parse(c.baseURL)
+	if err != nil {
+		return err
+	}
+
+	apiEndpoint.User = userInfo
+
+	query := apiEndpoint.Query()
+	query.Set("acme", action)
+	query.Set("txt", value)
+	apiEndpoint.RawQuery = query.Encode()
+
+	req, err := http.NewRequest(http.MethodPost, apiEndpoint.String(), http.NoBody)
+	if err != nil {
+		return err
+	}
+
+	resp, err := c.HTTPClient.Do(req)
+	if err != nil {
+		return err
+	}
+	defer func() { _ = resp.Body.Close() }()
+
+	if resp.StatusCode != http.StatusOK {
+		all, _ := io.ReadAll(resp.Body)
+		return fmt.Errorf("%d: %s", resp.StatusCode, string(all))
+	}
+
+	all, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return err
+	}
+
+	output := string(all)
+
+	if !strings.HasPrefix(output, successCode) {
+		return errors.New(output)
+	}
+
+	return nil
+}
diff --git a/providers/dns/dnshomede/internal/readme.md b/providers/dns/dnshomede/internal/readme.md
new file mode 100644
index 0000000000..008b1508e3
--- /dev/null
+++ b/providers/dns/dnshomede/internal/readme.md
@@ -0,0 +1,37 @@
+# dnshome.de API
+
+## Add TXT record
+
+```
+https://<subdomain>:<subdomain_password>@www.dnshome.de/dyndns.php?acme=add&txt=<txtvalue>
+```
+
+- `<subdomain>`: the subdomain (ex: `lego.dnshome.de`).
+- `<subdomain_password>`: the subdomain password.
+- `<txtvalue>`: the value of the TXT record (12 characters minimum)
+
+Only one TXT record can be used for a subdomain.
+
+Always returns StatusOK (200)
+
+If the API call works the first word of the response body is `successfully`.
+
+Can be a POST or a GET, the HTTP method doesn't seem to have an impact.
+
+## Remove TXT record
+
+```
+https://<subdomain>:<subdomain_password>@www.dnshome.de/dyndns.php?acme=rm&txt=<txtvalue>
+```
+
+- `<subdomain>`: the subdomain (ex: `lego.dnshome.de`).
+- `<subdomain_password>`: the subdomain password.
+- `<txtvalue>`: the value of the TXT record (12 characters minimum) (IGNORED)
+
+Only one TXT record can be used for a subdomain.
+
+Always returns StatusOK (200)
+
+If the API call works the first word of the response body is `successfully`.
+
+Can be a POST or a GET, the HTTP method doesn't seem to have an impact.


Test patch:
diff --git a/providers/dns/dnshomede/dnshomede_test.go b/providers/dns/dnshomede/dnshomede_test.go
new file mode 100644
index 0000000000..6b79912e8c
--- /dev/null
+++ b/providers/dns/dnshomede/dnshomede_test.go
@@ -0,0 +1,165 @@
+package dnshomede
+
+import (
+	"testing"
+
+	"github.com/go-acme/lego/v4/platform/tester"
+	"github.com/stretchr/testify/require"
+)
+
+const envDomain = envNamespace + "DOMAIN"
+
+var envTest = tester.NewEnvTest(EnvCredentials).WithDomain(envDomain)
+
+func TestNewDNSProvider(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		envVars  map[string]string
+		expected string
+	}{
+		{
+			desc: "success",
+			envVars: map[string]string{
+				EnvCredentials: "example.org:123",
+			},
+		},
+		{
+			desc: "success multiple domains",
+			envVars: map[string]string{
+				EnvCredentials: "example.org:123,example.com:456,example.net:789",
+			},
+		},
+		{
+			desc: "invalid credentials",
+			envVars: map[string]string{
+				EnvCredentials: ",",
+			},
+			expected: `dnshomede: invalid credential pair: ""`,
+		},
+		{
+			desc: "missing password",
+			envVars: map[string]string{
+				EnvCredentials: "example.org:",
+			},
+			expected: `dnshomede: missing password: "example.org:"`,
+		},
+		{
+			desc: "missing domain",
+			envVars: map[string]string{
+				EnvCredentials: ":123",
+			},
+			expected: `dnshomede: missing domain: ":123"`,
+		},
+		{
+			desc: "invalid credentials, partial",
+			envVars: map[string]string{
+				EnvCredentials: "example.org:123,example.net",
+			},
+			expected: `dnshomede: invalid credential pair: "example.net"`,
+		},
+		{
+			desc: "missing credentials",
+			envVars: map[string]string{
+				EnvCredentials: "",
+			},
+			expected: "dnshomede: some credentials information are missing: DNSHOMEDE_CREDENTIALS",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			defer envTest.RestoreEnv()
+			envTest.ClearEnv()
+
+			envTest.Apply(test.envVars)
+
+			p, err := NewDNSProvider()
+
+			if test.expected == "" {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestNewDNSProviderConfig(t *testing.T) {
+	testCases := []struct {
+		desc     string
+		creds    map[string]string
+		expected string
+	}{
+		{
+			desc:  "success",
+			creds: map[string]string{"example.org": "123"},
+		},
+		{
+			desc: "success multiple domains",
+			creds: map[string]string{
+				"example.org": "123",
+				"example.com": "456",
+				"example.net": "789",
+			},
+		},
+		{
+			desc:     "missing credentials",
+			expected: "dnshomede: missing credentials",
+		},
+		{
+			desc:     "missing domain",
+			creds:    map[string]string{"": "123"},
+			expected: `dnshomede: missing domain: ":123"`,
+		},
+		{
+			desc:     "missing password",
+			creds:    map[string]string{"example.org": ""},
+			expected: `dnshomede: missing password: "example.org:"`,
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			config := NewDefaultConfig()
+			config.Credentials = test.creds
+
+			p, err := NewDNSProviderConfig(config)
+
+			if test.expected == "" {
+				require.NoError(t, err)
+				require.NotNil(t, p)
+				require.NotNil(t, p.config)
+			} else {
+				require.EqualError(t, err, test.expected)
+			}
+		})
+	}
+}
+
+func TestLivePresent(t *testing.T) {
+	if !envTest.IsLiveTest() {
+		t.Skip("skipping live test")
+	}
+
+	envTest.RestoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
+
+	err = provider.Present(envTest.GetDomain(), "", "123d==")
+	require.NoError(t, err)
+}
+
+func TestLiveCleanUp(t *testing.T) {
+	if !envTest.IsLiveTest() {
+		t.Skip("skipping live test")
+	}
+
+	envTest.RestoreEnv()
+	provider, err := NewDNSProvider()
+	require.NoError(t, err)
+
+	err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
+	require.NoError(t, err)
+}
diff --git a/providers/dns/dnshomede/internal/client_test.go b/providers/dns/dnshomede/internal/client_test.go
new file mode 100644
index 0000000000..305d83cb30
--- /dev/null
+++ b/providers/dns/dnshomede/internal/client_test.go
@@ -0,0 +1,112 @@
+package internal
+
+import (
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestClient_Add(t *testing.T) {
+	txtValue := "123456789012"
+
+	mux := http.NewServeMux()
+	mux.HandleFunc("/", handlerMock(addAction, txtValue))
+	server := httptest.NewServer(mux)
+
+	credentials := map[string]string{
+		"example.org": "secret",
+	}
+
+	client := NewClient(credentials)
+	client.HTTPClient = server.Client()
+	client.baseURL = server.URL
+
+	err := client.Add("example.org", txtValue)
+	require.NoError(t, err)
+}
+
+func TestClient_Add_error(t *testing.T) {
+	txtValue := "123456789012"
+
+	mux := http.NewServeMux()
+	mux.HandleFunc("/", handlerMock(addAction, txtValue))
+	server := httptest.NewServer(mux)
+
+	credentials := map[string]string{
+		"example.com": "secret",
+	}
+
+	client := NewClient(credentials)
+	client.HTTPClient = server.Client()
+	client.baseURL = server.URL
+
+	err := client.Add("example.org", txtValue)
+	require.Error(t, err)
+}
+
+func TestClient_Remove(t *testing.T) {
+	txtValue := "ABCDEFGHIJKL"
+
+	mux := http.NewServeMux()
+	mux.HandleFunc("/", handlerMock(removeAction, txtValue))
+	server := httptest.NewServer(mux)
+
+	credentials := map[string]string{
+		"example.org": "secret",
+	}
+
+	client := NewClient(credentials)
+	client.HTTPClient = server.Client()
+	client.baseURL = server.URL
+
+	err := client.Remove("example.org", txtValue)
+	require.NoError(t, err)
+}
+
+func TestClient_Remove_error(t *testing.T) {
+	txtValue := "ABCDEFGHIJKL"
+
+	mux := http.NewServeMux()
+	mux.HandleFunc("/", handlerMock(removeAction, txtValue))
+	server := httptest.NewServer(mux)
+
+	credentials := map[string]string{
+		"example.com": "secret",
+	}
+
+	client := NewClient(credentials)
+	client.HTTPClient = server.Client()
+	client.baseURL = server.URL
+
+	err := client.Remove("example.org", txtValue)
+	require.Error(t, err)
+}
+
+func handlerMock(action, value string) http.HandlerFunc {
+	return func(rw http.ResponseWriter, req *http.Request) {
+		rw.WriteHeader(http.StatusOK)
+
+		query := req.URL.Query()
+
+		if query.Get("acme") != action {
+			_, _ = rw.Write([]byte("nochg 1234:1234:1234:1234:1234:1234:1234:1234"))
+			return
+		}
+
+		txtValue := query.Get("txt")
+		if len(txtValue) < 12 {
+			_, _ = rw.Write([]byte("error - no valid acme txt record"))
+			return
+		}
+
+		if txtValue != value {
+			http.Error(rw, fmt.Sprintf("got: %q, expected: %q", txtValue, value), http.StatusBadRequest)
+			return
+		}
+
+		_, _ = fmt.Fprintf(rw, "%s %s", successCode, txtValue)
+	}
+}