-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add DNS provider for SelfHost.(de|eu) (#2278)
Co-authored-by: Dominik Menke <git@dmke.org>
- Loading branch information
Showing
13 changed files
with
1,018 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
--- | ||
title: "SelfHost.(de|eu)" | ||
date: 2019-03-03T16:39:46+01:00 | ||
draft: false | ||
slug: selfhostde | ||
dnsprovider: | ||
since: "v4.19.0" | ||
code: "selfhostde" | ||
url: "https://www.selfhost.de" | ||
--- | ||
|
||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. --> | ||
<!-- providers/dns/selfhostde/selfhostde.toml --> | ||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. --> | ||
|
||
|
||
Configuration for [SelfHost.(de|eu)](https://www.selfhost.de). | ||
|
||
|
||
<!--more--> | ||
|
||
- Code: `selfhostde` | ||
- Since: v4.19.0 | ||
|
||
|
||
Here is an example bash command using the SelfHost.(de|eu) provider: | ||
|
||
```bash | ||
SELFHOSTDE_USERNAME=xxx \ | ||
SELFHOSTDE_PASSWORD=yyy \ | ||
SELFHOSTDE_RECORDS_MAPPING=my.example.com:123 \ | ||
lego --email you@example.com --dns selfhostde --domains my.example.org run | ||
``` | ||
|
||
|
||
|
||
|
||
## Credentials | ||
|
||
| Environment Variable Name | Description | | ||
|-----------------------|-------------| | ||
| `SELFHOSTDE_PASSWORD` | Password | | ||
| `SELFHOSTDE_RECORDS_MAPPING` | Record IDs mapping with domains (ex: example.com:123:456,example.org:789,foo.example.com:147) | | ||
| `SELFHOSTDE_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 | | ||
|--------------------------------|-------------| | ||
| `SELFHOSTDE_HTTP_TIMEOUT` | API request timeout | | ||
| `SELFHOSTDE_POLLING_INTERVAL` | Time between DNS propagation check | | ||
| `SELFHOSTDE_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation | | ||
| `SELFHOSTDE_TTL` | The TTL of the TXT record used for the DNS challenge | | ||
|
||
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" %}}). | ||
|
||
SelfHost.de doesn't have an API to create or delete TXT records, | ||
there is only an "unofficial" and undocumented endpoint to update an existing TXT record. | ||
|
||
So, before using lego to request a certificate for a given domain or wildcard (such as `my.example.org` or `*.my.example.org`), | ||
you must create: | ||
|
||
- one TXT record named `_acme-challenge.my.example.org` if you are **not** using wildcard for this domain. | ||
- two TXT records named `_acme-challenge.my.example.org` if you are using wildcard for this domain. | ||
|
||
After that you must edit the TXT record(s) to get the ID(s). | ||
|
||
You then must prepare the `SELFHOSTDE_RECORDS_MAPPING` environment variable with the following format: | ||
|
||
``` | ||
<domain_A>:<record_id_A1>:<record_id_A2>,<domain_B>:<record_id_B1>:<record_id_B2>,<domain_C>:<record_id_C1>:<record_id_C2> | ||
``` | ||
|
||
where each group of domain + record ID(s) is separated with a comma (`,`), | ||
and the domain and record ID(s) are separated with a colon (`:`). | ||
|
||
For example, if you want to create or renew a certificate for `my.example.org`, `*.my.example.org`, and `other.example.org`, | ||
you would need: | ||
|
||
- two separate records for `_acme-challenge.my.example.org` | ||
- and another separate record for `_acme-challenge.other.example.org` | ||
|
||
The resulting environment variable would then be: `SELFHOSTDE_RECORDS_MAPPING=my.example.com:123:456,other.example.com:789` | ||
|
||
|
||
|
||
|
||
|
||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. --> | ||
<!-- providers/dns/selfhostde/selfhostde.toml --> | ||
<!-- THIS DOCUMENTATION IS AUTO-GENERATED. PLEASE DO NOT EDIT. --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package internal | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"time" | ||
|
||
"github.com/go-acme/lego/v4/providers/dns/internal/errutils" | ||
) | ||
|
||
const defaultBaseURL = "https://selfhost.de/cgi-bin/api.pl" | ||
|
||
// Client the SelfHost client. | ||
type Client struct { | ||
username string | ||
password string | ||
|
||
baseURL string | ||
HTTPClient *http.Client | ||
} | ||
|
||
// NewClient Creates a new Client. | ||
func NewClient(username, password string) *Client { | ||
return &Client{ | ||
username: username, | ||
password: password, | ||
baseURL: defaultBaseURL, | ||
HTTPClient: &http.Client{Timeout: 5 * time.Second}, | ||
} | ||
} | ||
|
||
// UpdateTXTRecord updates content of an existing TXT record. | ||
func (c *Client) UpdateTXTRecord(ctx context.Context, recordID, content string) error { | ||
endpoint, err := url.Parse(c.baseURL) | ||
if err != nil { | ||
return fmt.Errorf("parse URL: %w", err) | ||
} | ||
|
||
query := endpoint.Query() | ||
query.Set("username", c.username) | ||
query.Set("password", c.password) | ||
query.Set("rid", recordID) | ||
query.Set("content", content) | ||
|
||
endpoint.RawQuery = query.Encode() | ||
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil) | ||
if err != nil { | ||
return fmt.Errorf("new HTTP request: %w", err) | ||
} | ||
|
||
resp, err := c.HTTPClient.Do(req) | ||
if err != nil { | ||
return errutils.NewHTTPDoError(req, err) | ||
} | ||
|
||
defer func() { _ = resp.Body.Close() }() | ||
|
||
if resp.StatusCode/100 != 2 { | ||
return errutils.NewUnexpectedResponseStatusCodeError(req, resp) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package internal | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"net/http/httptest" | ||
"net/url" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func setupTest(t *testing.T) (*Client, *http.ServeMux) { | ||
t.Helper() | ||
|
||
mux := http.NewServeMux() | ||
server := httptest.NewServer(mux) | ||
t.Cleanup(server.Close) | ||
|
||
client := NewClient("user", "secret") | ||
serverURL, err := url.Parse(server.URL) | ||
require.NoError(t, err) | ||
|
||
client.baseURL = serverURL.String() | ||
|
||
return client, mux | ||
} | ||
|
||
func TestClient_UpdateTXTRecord(t *testing.T) { | ||
client, mux := setupTest(t) | ||
|
||
mux.HandleFunc("GET /", func(rw http.ResponseWriter, req *http.Request) { | ||
query := req.URL.Query() | ||
|
||
fields := map[string]string{ | ||
"username": "user", | ||
"password": "secret", | ||
"rid": "123456", | ||
"content": "txt", | ||
} | ||
|
||
for k, v := range fields { | ||
value := query.Get(k) | ||
if value != v { | ||
http.Error(rw, fmt.Sprintf("%s: unexpected value: %s (%s)", k, value, v), http.StatusBadRequest) | ||
return | ||
} | ||
} | ||
}) | ||
|
||
err := client.UpdateTXTRecord(context.Background(), "123456", "txt") | ||
require.NoError(t, err) | ||
} | ||
|
||
func TestClient_UpdateTXTRecord_error(t *testing.T) { | ||
client, mux := setupTest(t) | ||
|
||
mux.HandleFunc("GET /", func(rw http.ResponseWriter, _ *http.Request) { | ||
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) | ||
}) | ||
|
||
err := client.UpdateTXTRecord(context.Background(), "123456", "txt") | ||
require.Error(t, err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# SelfHost.(de|eu) | ||
|
||
SelfHost doesn't provide an official API documentation and there are no endpoints for create a TXT record or delete a TXT record. | ||
|
||
## More | ||
|
||
The documentation found at https://kirk.selfhost.de/cgi-bin/selfhost?p=document&name=api (PDF) describes the DynDNS/ddns API endpoint and is not used by our client. |
Oops, something went wrong.