PendingDNS

Lightweight API driven Authoritative DNS server. Extracted from Project Pending.

Source can be found from Github.

Features

Limitations

Requirements

Usage

$ npm install --production
$ npm start

Run as SystemD service

If you want to run PendingDNS as a SystemD service, then there's an example service file with comments.

1. Setup commands

As root run the following commands to set up PendingDNS:

$ cd /opt
$ git clone git://github.com/postalsys/pending-dns.git
$ cd pending-dns
$ npm install --production
$ cp systemd/pending-dns.service /etc/systemd/system
$ cp config/default.toml /etc/pending-dns.toml

2. Configuration

Edit the configuration file /etc/pending-dns.toml and make sure that you have correct configuration.

Also make sure that /etc/systemd/system/pending-dns.service looks correct.

3. Start

Run the following commands as root

$ systemctl enable pending-dns
$ systemctl start pending-dns

General Name Server setup

Conflicts on port 53

There might be already a recursive DNS server listening on 127.0.0.1:53 (or more commonly, SystemD stub resolver on 127.0.0.53:53) so you can't bind your DNS server to 0.0.0.0. Instead bind directly to your outbound interface, you can usually find these by running ip a.

$ ip a
  …
  inet 172.31.41.89/20 brd 172.31.47.255 scope global ens5
  …
[dns]
  port = 53
  host = "172.31.41.89"

Glue records

If you want to use PendingDNS as an authoritative DNS server for your domains then you need at least 2 instances of the server.

Additionally you need to set up both A and so-called GLUE records for the domain names of your name servers. Not all DNS providers allow to set GLUE records.

Here's an example how A records are set up for ns01.pendingdns.com and ns02.pendingdns.com that manage domains hosted on Project Pending:

Registrar and DNS provider for these domains is OVH but you can use any registrar with GLUE support


And the corresponding GLUE records:


Without proper setup domain registrars do not allow your name server domain names to be used. Here's an example for a successful name server setup:

API

You can see the entire API docs from the swagger page at http://127.0.0.1:5080/docs

List Zone entries

GET /v1/zone/{zone}/records

$ curl -X GET "http://127.0.0.1:5080/v1/zone/mailtanker.com/records"
{
    "zone": "mailtanker.com",
    "records": [
        {
            "id": "Y29tLm1haWx0YW5rZXIBQQEzc3lKWkkzbGo",
            "type": "A",
            "address": "18.203.150.145"
        },
        {
            "id": "Y29tLm1haWx0YW5rZXIud3d3AUNOQU1FAXhhV1lnbnFaMA",
            "type": "CNAME",
            "subdomain": "www",
            "target": "mailtanker.com"
        }
    ]
}

NB! system records (NS, SOA) have id=null and these records can not be modified over API

Create new Resource Record

POST /v1/zone/{zone}/records

$ curl -X POST "http://127.0.0.1:5080/v1/zone/mailtanker.com/records" -H "Content-Type: application/json" -d '{
    "subdomain": "www",
    "type": "CNAME",
    "target": "@"
}'
{
    "zone": "mailtanker.com",
    "record": "Y29tLm1haWx0YW5rZXIud3d3AUNOQU1FAXhhV1lnbnFaMA"
}

All record types have the following properties

Type specific options

A

AAAA

CNAME

ANAME

TXT

MX

NS

CAA

URL

Modify existing Resource Record

PUT /v1/zone/{zone}/records/{record}

$ curl -X PUT "http://127.0.0.1:5080/v1/zone/mailtanker.com/records/Y29tLm1haWx0YW5rZXIud3d3AUNOQU1FAXhhV1lnbnFaMA" -H "Content-Type: application/json" -d '{
    "subdomain": "www",
    "type": "CNAME",
    "target": "example.com"
}'
{
    "zone": "mailtanker.com",
    "record": "Y29tLm1haWx0YW5rZXIud3d3AUNOQU1FAXhhV1lnbnFaMA"
}

NB! resulting record ID might be different from the original ID

Delete Resource Record

DELETE /v1/zone/{zone}/records/{record}

$ curl -X DELETE "http://127.0.0.1:5080/v1/zone/mailtanker.com/records/Y29tLm1haWx0YW5rZXIBQQFjT2NWd0d6bE4"
{
    "zone": "mailtanker.com",
    "record": "Y29tLm1haWx0YW5rZXIBQQFjT2NWd0d6bE4",
    "deleted": true
}

Generate Certificate

This API endpoint requests a new certificate from Let's Encrypt or returns a previously generated one.

Certificates can only be requested for domains that:

  1. have at least one resource record set for their zone (not important which kind)
  2. have correctly pointed NS records to your PendingDNS servers
$ curl -X POST "http://127.0.0.1:5080/v1/acme" -H "Content-Type: application/json" -d '{
    "domains": [
        "mailtanker.com",
        "*.mailtanker.com"
    ]
}'
{
    "dnsNames": ["*.mailtanker.com", "mailtanker.com"],
    "key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIB...",
    "cert": "-----BEGIN CERTIFICATE-----\nMIIFaT...\n",
    "validFrom": "2020-06-03T18:50:52.000Z",
    "expires": "2020-09-01T18:50:52.000Z"
}

Acknowledgments

License

MIT