dns01proxy is a server for using DNS-01 challenges to get TLS/SSL certificates from Let's Encrypt, or any ACME-compatible certificate authority, without exposing your DNS credentials to every host that needs a certificate.
It acts as a proxy for DNS-01 challenge requests, allowing hosts to delegate their DNS record updates during ACME validation. This makes it possible to issue certificates to internal or private hosts that can't (or shouldn't) have direct access to your DNS provider or API keys.
dns01proxy is designed to work with:
- acme.sh's
acmeproxy
provider, - lego's
httpreq
DNS provider, and - Caddy's
acmeproxy
DNS provider module.
- Privilege separation. Internal or private hosts can complete DNS-01 challenges without having direct access to DNS API keys. In turn, the private keys for issued certificates stay private to the ACME clients.
- HTTPS built-in, automatic, and always on. dns01proxy uses its configured DNS credentials to automatically get and renew its own TLS/SSL certificate.
- Mandatory client authentication using HTTP Basic Authentication.
- Optional per-client policies for limiting which DNS names each client can get a certificate for.
There are two options for getting dns01proxy.
dns01proxy is built using Caddy, and uses DNS provider modules that are written by the Caddy community. dns01proxy ships a number of binaries, each built with a single DNS module. To install, just download a build of the latest release that matches your DNS provider.
Caution
Always check that you trust the author of the DNS module. The release notes has details about the source of the DNS module in each build.
Alternatively, dns01proxy is also available as a Caddy module, which adds dns01proxy to Caddy as a subcommand, app, and HTTP handler. See the caddy-dns01proxy project for more on this second option.
dns01proxy is configured through a single TOML file. Below is an example
configuration for running at https://dns01proxy.example.com
with Cloudflare
as a DNS provider.
hostnames = ["dns01proxy.example.com"]
listen = [":443"]
[dns.provider]
name = "cloudflare"
api_token = "{env.CF_API_TOKEN}" # Reads from an environment variable.
# One for each user. Password is hashed using `dns01proxy hash-password`.
[[accounts]]
username = "AzureDiamond"
password = "$2a$14$N5bGBXf7zwAW9Ym7IQ/mxOHTGsvFNOTEAiN4/r1LnvfzYCpiWcHOa"
allow_domains = ["private.example.com"]
Each DNS provider has a different set of configuration parameters. See the Caddy documentation link for your provider in the release notes. Caddy documents its modules' options in JSON, but remember that you'll need to configure the module in TOML.
Full structure
# The server's hostnames. Used for obtaining TLS/SSL certificates.
hostnames = ["<hostname>"]
# The sockets on which to listen.
listen = ["<ip_addr:port>"]
# Configures the set of trusted proxies, for accurate logging of client IP
# addresses. This must be an `http.ip_sources` Caddy module. See Caddy's module
# documentation at https://caddyserver.com/docs/modules/
#
# Note that Caddy documents its modules' options in JSON. You'll need to
# configure the module in TOML. For example, to configure
# `http.ip_sources.static`:
#
# [trusted_proxies]
# source = "static"
# ranges = ["10.0.0.1", "192.168.0.1"]
#
[trusted_proxies]
source = "<module_name>"
# ••• # Module-specific configuration goes here.
[dns]
# The TTL to use in DNS TXT records. Optional. Not usually needed.
ttl = "<ttl>" # e.g., "2m"
# Custom DNS resolvers to prefer over system or built-in defaults. Set this to
# a public resolver if you are using split-horizon DNS.
resolvers = ["<resolver>"]
# The DNS provider for publishing DNS-01 responses. This must be a
# `dns.providers` Caddy module that is compiled into your dns01proxy binary.
# See the Caddy documentation link for your provider in the release notes:
# https://github.com/liujed/dns01proxy/releases
#
# Note that Caddy documents its modules' options in JSON. You'll need to
# configure the module in TOML. For example, to configure
# `dns.providers.cloudflare`:
#
# [dns.provider]
# name = "cloudflare"
# api_token = "{env.CF_API_TOKEN}" # Reads from an environment variable.
#
[dns.provider]
name = "<provider_name>"
# ••• # Module-specific configuration goes here.
# Configures HTTP basic authentication and the domains for which each user can
# get TLS/SSL certificates.
[[accounts]]
user_id = "<userID>"
# To hash passwords, use `dns01proxy hash-password`.
password = "<hashed_password>"
# These largely follow Smallstep's domain name rules:
#
# https://smallstep.com/docs/step-ca/policies/#domain-names
#
# Due to a limitation in ACME and DNS-01, allowing a domain also allows
# wildcard certificates for that domain.
allow_domains = ["<domain>"]
deny_domains = ["<domain>"]
If you prefer JSON, then just use the same JSON structure as the configuration
for the dns01proxy
Caddy app.
To run dns01proxy, use the run
subcommand. For example,
dns01proxy run --config /usr/local/etc/dns01proxy.toml
dns01proxy works with acme.sh's
acmeproxy
provider:
export ACMEPROXY_ENDPOINT='https://dns01proxy.example.com'
export ACMEPROXY_USERNAME='AzureDiamond'
export ACMEPROXY_PASSWORD='hunter2'
acme.sh --issue --dns dns_acmeproxy -d example.com
dns01proxy works with lego's
httpreq
DNS
provider:
export HTTPREQ_ENDPOINT='https://dns01proxy.example.com'
export HTTPREQ_USERNAME='AzureDiamond'
export HTTPREQ_PASSWORD='hunter2'
lego --email [email protected] --dns httpreq -d example.com run
dns01proxy works with Caddy's
acmeproxy
DNS
provider module:
{
"endpoint": "https://dns01proxy.example.com",
"username": "AzureDiamond",
"password": "hunter2"
}
dns01proxy is a reimplementation of acmeproxy, which is no longer being developed. Whereas acmeproxy was built on top of lego, dns01proxy uses libdns under the hood, which allows for better compatibility with acme.sh.
acmeproxy.pl is another reimplementation of acmeproxy, written in Perl.