Skip to content

Commit defc4fb

Browse files
committed
Add TOML support to dns01proxy command
1 parent 9bd9b11 commit defc4fb

File tree

5 files changed

+199
-83
lines changed

5 files changed

+199
-83
lines changed

README.md

Lines changed: 167 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -28,93 +28,102 @@ download page](https://caddyserver.com/download).
2828
## Using the command line
2929

3030
This package adds a `dns01proxy` command to Caddy, making it convenient to run
31-
a standalone dns01proxy server. Naturally, because dns01proxy runs on Caddy,
32-
TLS/SSL certificates for the dns01proxy server itself are automatically
33-
obtained and renewed using the configured DNS credentials.
31+
a standalone dns01proxy server. Naturally, because dns01proxy runs on Caddy, it
32+
automatically obtains and renews its own TLS/SSL certificates using the
33+
configured DNS credentials.
3434

3535
To run dns01proxy, just provide a config file:
3636
```
37-
caddy dns01proxy --config dns01proxy.json
37+
caddy dns01proxy --config dns01proxy.toml
3838
```
3939

40-
Here is an example configuration for running at `https://dns01proxy.example.com`
41-
with Cloudflare as a DNS provider. The user's password is hashed using `caddy
42-
hash-password` with the bcrypt algorithm.
43-
```json
44-
{
45-
"hostnames": ["dns01proxy.example.com"],
46-
"listen": [":443"],
47-
"dns": {
48-
"provider": {
49-
"name": "cloudflare",
50-
"api_token": "{env.CF_API_TOKEN}"
51-
}
52-
},
53-
"accounts": [
54-
{
55-
"username": "AzureDiamond",
56-
"password": "$2a$14$N5bGBXf7zwAW9Ym7IQ/mxOHTGsvFNOTEAiN4/r1LnvfzYCpiWcHOa",
57-
"allow_domains": ["private.example.com"]
58-
}
59-
]
60-
}
61-
```
62-
63-
<details>
64-
<summary>Full JSON structure</summary>
65-
66-
```jsonc
67-
{
68-
// The server's hostnames. Used for obtaining TLS/SSL certificates.
69-
"hostnames": ["<hostname>"],
70-
71-
// The sockets on which to listen.
72-
"listen": ["<ip_addr:port>"],
73-
74-
// Configures the set of trusted proxies, for accurate logging of client IP
75-
// addresses.
76-
"trusted_proxies": {
77-
// an http.ip_sources module
78-
"source": "<module_name>",
79-
// •••
80-
},
40+
The example below configures dns01proxy for running at
41+
`https://dns01proxy.example.com` with Cloudflare as a DNS provider.
8142

82-
"dns": {
83-
// The DNS provider for publishing DNS-01 responses.
84-
"provider": {
85-
// A `dns.providers` module.
86-
"name": "<provider_name>",
87-
// •••
88-
},
43+
If you prefer JSON, then just use the same JSON structure as the configuration
44+
for the [`dns01proxy` Caddy app](#configuring-a-dns01proxy-app-in-json).
8945

90-
// The TTL to use in DNS TXT records. Optional. Not usually needed.
91-
"ttl": "<ttl>", // e.g., "2m"
46+
```toml
47+
hostnames = ["dns01proxy.example.com"]
48+
listen = [":443"]
9249

93-
// Custom DNS resolvers to prefer over system or built-in defaults. Set
94-
// this to a public resolver if you are using split-horizon DNS.
95-
"resolvers": ["<resolver>"]
96-
},
97-
98-
// Configures HTTP basic authentication and the domains for which each user
99-
// can get TLS/SSL certificates.
100-
"accounts": [
101-
{
102-
"user_id": "<userID>",
50+
[dns.provider]
51+
name = "cloudflare"
52+
api_token = "{env.CF_API_TOKEN}" # Reads from an environment variable.
10353

104-
// To hash passwords, use `caddy hash-password`.
105-
"password": "<hashed_password>",
54+
# One for each user. Password is hashed using `caddy hash-password` with the
55+
# bcrypt algorithm.
56+
[[accounts]]
57+
username = "AzureDiamond"
58+
password = "$2a$14$N5bGBXf7zwAW9Ym7IQ/mxOHTGsvFNOTEAiN4/r1LnvfzYCpiWcHOa"
59+
allow_domains = ["private.example.com"]
60+
```
10661

107-
// These largely follow Smallstep's domain name rules:
108-
//
109-
// https://smallstep.com/docs/step-ca/policies/#domain-names
110-
//
111-
// Due to a limitation in ACME and DNS-01, allowing a domain also allows
112-
// wildcard certificates for that domain.
113-
"allow_domains": ["<domain>"],
114-
"deny_domains": ["<domain>"]
115-
}
116-
]
117-
}
62+
<details>
63+
<summary>Full structure</summary>
64+
65+
```toml
66+
# The server's hostnames. Used for obtaining TLS/SSL certificates.
67+
hostnames = ["<hostname>"]
68+
69+
# The sockets on which to listen.
70+
listen = ["<ip_addr:port>"]
71+
72+
# Configures the set of trusted proxies, for accurate logging of client IP
73+
# addresses. This must be an `http.ip_sources` Caddy module. See Caddy's module
74+
# documentation at https://caddyserver.com/docs/modules/
75+
#
76+
# Note that Caddy documents its modules' options in JSON. You'll need to
77+
# configure the module in TOML. For example, to configure
78+
# `http.ip_sources.static`:
79+
#
80+
# [trusted_proxies]
81+
# source = "static"
82+
# ranges = ["10.0.0.1", "192.168.0.1"]
83+
#
84+
[trusted_proxies]
85+
source = "<module_name>"
86+
# ••• # Module-specific configuration goes here.
87+
88+
[dns]
89+
# The TTL to use in DNS TXT records. Optional. Not usually needed.
90+
ttl = "<ttl>" # e.g., "2m"
91+
92+
# Custom DNS resolvers to prefer over system or built-in defaults. Set this to
93+
# a public resolver if you are using split-horizon DNS.
94+
resolvers = ["<resolver>"]
95+
96+
# The DNS provider for publishing DNS-01 responses. This must be a
97+
# `dns.providers` Caddy module. See Caddy's module documentation at
98+
# https://caddyserver.com/docs/modules/
99+
#
100+
# Note that Caddy documents its modules' options in JSON. You'll need to
101+
# configure the module in TOML. For example, to configure
102+
# `dns.providers.cloudflare`:
103+
#
104+
# [dns.provider]
105+
# name = "cloudflare"
106+
# api_token = "{env.CF_API_TOKEN}" # Reads from an environment variable.
107+
#
108+
[dns.provider]
109+
name = "<provider_name>"
110+
# ••• # Module-specific configuration goes here.
111+
112+
113+
# Configures HTTP basic authentication and the domains for which each user can
114+
# get TLS/SSL certificates.
115+
[[accounts]]
116+
user_id = "<userID>"
117+
password = "<hashed_password>" # To hash passwords, use `caddy hash-password`.
118+
119+
# These largely follow Smallstep's domain name rules:
120+
#
121+
# https://smallstep.com/docs/step-ca/policies/#domain-names
122+
#
123+
# Due to a limitation in ACME and DNS-01, allowing a domain also allows
124+
# wildcard certificates for that domain.
125+
allow_domains = ["<domain>"]
126+
deny_domains = ["<domain>"]
118127
```
119128

120129
</details>
@@ -249,8 +258,87 @@ a handler similar to the one in the Caddyfile example above.
249258

250259
## Configuring a dns01proxy app in JSON
251260

252-
To configure dns01proxy as a Caddy app, use the same JSON structure as the
253-
configuration file for the [`dns01proxy` command](#using-the-command-line).
261+
Here is a sample configuration for the dns01proxy Caddy app, analogous to the
262+
TOML example for the [`dns01proxy` command](#using-the-command-line).
263+
264+
```json
265+
{
266+
"hostnames": ["dns01proxy.example.com"],
267+
"listen": [":443"],
268+
"dns": {
269+
"provider": {
270+
"name": "cloudflare",
271+
"api_token": "{env.CF_API_TOKEN}"
272+
}
273+
},
274+
"accounts": [
275+
{
276+
"username": "AzureDiamond",
277+
"password": "$2a$14$N5bGBXf7zwAW9Ym7IQ/mxOHTGsvFNOTEAiN4/r1LnvfzYCpiWcHOa",
278+
"allow_domains": ["private.example.com"]
279+
}
280+
]
281+
}
282+
```
283+
284+
<details>
285+
<summary>Full JSON structure</summary>
286+
287+
```jsonc
288+
{
289+
// The server's hostnames. Used for obtaining TLS/SSL certificates.
290+
"hostnames": ["<hostname>"],
291+
292+
// The sockets on which to listen.
293+
"listen": ["<ip_addr:port>"],
294+
295+
// Configures the set of trusted proxies, for accurate logging of client IP
296+
// addresses.
297+
"trusted_proxies": {
298+
// an http.ip_sources module
299+
"source": "<module_name>",
300+
// •••
301+
},
302+
303+
"dns": {
304+
// The DNS provider for publishing DNS-01 responses.
305+
"provider": {
306+
// A `dns.providers` module.
307+
"name": "<provider_name>",
308+
// •••
309+
},
310+
311+
// The TTL to use in DNS TXT records. Optional. Not usually needed.
312+
"ttl": "<ttl>", // e.g., "2m"
313+
314+
// Custom DNS resolvers to prefer over system or built-in defaults. Set
315+
// this to a public resolver if you are using split-horizon DNS.
316+
"resolvers": ["<resolver>"]
317+
},
318+
319+
// Configures HTTP basic authentication and the domains for which each user
320+
// can get TLS/SSL certificates.
321+
"accounts": [
322+
{
323+
"user_id": "<userID>",
324+
325+
// To hash passwords, use `caddy hash-password`.
326+
"password": "<hashed_password>",
327+
328+
// These largely follow Smallstep's domain name rules:
329+
//
330+
// https://smallstep.com/docs/step-ca/policies/#domain-names
331+
//
332+
// Due to a limitation in ACME and DNS-01, allowing a domain also allows
333+
// wildcard certificates for that domain.
334+
"allow_domains": ["<domain>"],
335+
"deny_domains": ["<domain>"]
336+
}
337+
]
338+
}
339+
```
340+
341+
</details>
254342

255343
## Acknowledgements
256344

caddy_config.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package caddydns01proxy
22

33
import (
4+
"encoding/json"
5+
"path/filepath"
6+
"strings"
7+
8+
"github.com/BurntSushi/toml"
49
"github.com/caddyserver/caddy/v2"
510
"github.com/caddyserver/caddy/v2/caddyconfig"
611
"github.com/liujed/caddy-dns01proxy/jsonutil"
@@ -15,9 +20,30 @@ const defaultListen = "127.0.0.1:9095"
1520
// Reads a dns01proxy configuration file and returns a corresponding Caddy
1621
// configuration.
1722
func caddyConfigFromConfigFile(path string) (*caddy.Config, error) {
18-
config, err := jsonutil.UnmarshalFromFile[ConfigFile](path)
19-
if err != nil {
20-
return nil, err
23+
var config ConfigFile
24+
var err error
25+
switch strings.ToLower(filepath.Ext(path)) {
26+
case ".toml":
27+
// Convert TOML to JSON.
28+
rawMap := map[string]any{}
29+
_, err = toml.DecodeFile(path, &rawMap)
30+
if err != nil {
31+
return nil, err
32+
}
33+
rawJSON, err := json.Marshal(rawMap)
34+
if err != nil {
35+
return nil, err
36+
}
37+
err = json.Unmarshal(rawJSON, &config)
38+
if err != nil {
39+
return nil, err
40+
}
41+
42+
default:
43+
config, err = jsonutil.UnmarshalFromFile[ConfigFile](path)
44+
if err != nil {
45+
return nil, err
46+
}
2147
}
2248

2349
// Set default listen sockets.

command.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ var (
2121
ShortName: optionals.Some('c'),
2222
UsageMsg: "read configuration from `FILE`",
2323
Required: true,
24-
FilenameExts: optionals.Some([]string{"json"}),
24+
FilenameExts: optionals.Some([]string{"json", "toml"}),
2525
}
2626

2727
flgDebug = flags.Flag[bool]{

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/liujed/caddy-dns01proxy
33
go 1.24.3
44

55
require (
6+
github.com/BurntSushi/toml v1.4.0
67
github.com/caddyserver/caddy/v2 v2.10.0
78
github.com/caddyserver/certmagic v0.23.0
89
github.com/libdns/libdns v1.1.0

go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
3030
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
3131
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
3232
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
33+
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
3334
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
3435
github.com/KimMachineGun/automemlimit v0.7.1 h1:QcG/0iCOLChjfUweIMC3YL5Xy9C3VBeNmCZHrZfJMBw=
3536
github.com/KimMachineGun/automemlimit v0.7.1/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM=

0 commit comments

Comments
 (0)