6. From PowerDNS Authoritative Server 3.3.1 to 3.4.0

6.1. Database schema
6.2. Configuration option changes
[Note]Note

If you are coming from 2.9.x, please also read Section 1, “From PowerDNS Authoritative Server 2.9.x to 3.0”, Section 2, “From PowerDNS Authoritative Server 3.0 to 3.1”, Section 3, “From PowerDNS Authoritative Server 3.1 to 3.2” and Section 4, “From PowerDNS Authoritative Server 3.2 to 3.3” and Section 5, “From PowerDNS Authoritative Server 3.3 to 3.3.1”.

6.1. Database schema

[Warning]Warning

The default database schema has changed. The database update below is mandatory.

If custom queries are in use, they probably need an update.

For gmysql backend with nodnssec schema:

/* Uncomment next line for versions <= 3.1 */
/* DROP INDEX rec_name_index ON records; */

ALTER TABLE records ADD disabled TINYINT(1) DEFAULT 0;
ALTER TABLE records MODIFY content VARCHAR(64000) DEFAULT NULL;
ALTER TABLE records ADD ordername VARCHAR(255) BINARY DEFAULT NULL;
ALTER TABLE records ADD auth TINYINT(1) DEFAULT 1;
ALTER TABLE records MODIFY type VARCHAR(10);
ALTER TABLE supermasters MODIFY ip VARCHAR(64) NOT NULL;
ALTER TABLE supermasters MODIFY account VARCHAR(40) NOT NULL;
ALTER TABLE supermasters ADD PRIMARY KEY(ip, nameserver);

CREATE INDEX recordorder ON records (domain_id, ordername);


CREATE TABLE domainmetadata (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  kind                  VARCHAR(32),
  content               TEXT,
  PRIMARY KEY(id)
) Engine=InnoDB;

CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);


CREATE TABLE cryptokeys (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  flags                 INT NOT NULL,
  active                TINYINT(1),
  content               TEXT,
  PRIMARY KEY(id)
) Engine=InnoDB;

CREATE INDEX domainidindex ON cryptokeys(domain_id);


CREATE TABLE tsigkeys (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255),
  algorithm             VARCHAR(50),
  secret                VARCHAR(255),
  PRIMARY KEY(id)
) Engine=InnoDB;

CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);


CREATE TABLE comments (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) NOT NULL,
  comment               VARCHAR(64000) NOT NULL,
  PRIMARY KEY(id)
) Engine=InnoDB;

CREATE INDEX comments_domain_id_idx ON comments (domain_id);
CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);

For gmysql backend with dnssec schema:

/* Uncomment next 3 lines for versions <= 3.1 */
/* DROP INDEX rec_name_index ON records; */
/* DROP INDEX orderindex ON records; */
/* CREATE INDEX recordorder ON records (domain_id, ordername); */

ALTER TABLE records ADD disabled TINYINT(1) DEFAULT 0 AFTER change_date;
ALTER TABLE records MODIFY content VARCHAR(64000) DEFAULT NULL;
ALTER TABLE records MODIFY ordername VARCHAR(255) BINARY DEFAULT NULL;
ALTER TABLE records MODIFY auth TINYINT(1) DEFAULT 1;
ALTER TABLE records MODIFY type VARCHAR(10);
ALTER TABLE supermasters MODIFY ip VARCHAR(64) NOT NULL;
ALTER TABLE supermasters ADD PRIMARY KEY(ip, nameserver);
ALTER TABLE supermasters MODIFY account VARCHAR(40) NOT NULL;
ALTER TABLE domainmetadata MODIFY kind VARCHAR(32);
ALTER TABLE tsigkeys MODIFY algorithm VARCHAR(50);
ALTER TABLE domainmetadata ENGINE=InnoDB;
ALTER TABLE cryptokeys ENGINE=InnoDB;
ALTER TABLE tsigkeys ENGINE=InnoDB;

DROP INDEX domainmetaidindex ON domainmetadata;
CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);

CREATE TABLE comments (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) NOT NULL,
  comment               VARCHAR(64000) NOT NULL,
  PRIMARY KEY(id)
) Engine=InnoDB;

CREATE INDEX comments_domain_id_idx ON comments (domain_id);
CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);

For gpgsql backend with nodnssec schema:

/* Uncomment next line for versions <= 3.3 */
/* ALTER TABLE domains ADD CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))); */

ALTER TABLE records ADD disabled BOOL DEFAULT 'f';
ALTER TABLE records ALTER COLUMN content TYPE VARCHAR(65535);
ALTER TABLE records ADD ordername VARCHAR(255);
ALTER TABLE records ADD auth BOOL DEFAULT 't';
ALTER TABLE records ALTER COLUMN type TYPE VARCHAR(10);
ALTER TABLE supermasters ALTER COLUMN ip TYPE INET USING ip::INET;
ALTER TABLE supermasters ALTER COLUMN account SET DEFAULT NOT NULL;
ALTER TABLE supermasters ADD CONSTRAINT supermasters_pkey PRIMARY KEY (ip, nameserver);

CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops);


CREATE TABLE domainmetadata (
 id                     SERIAL PRIMARY KEY,
 domain_id              INT REFERENCES domains(id) ON DELETE CASCADE,
 kind                   VARCHAR(32),
 content                TEXT
);

CREATE INDEX domainidmetaindex ON domainmetadata(domain_id);


CREATE TABLE cryptokeys (
 id                     SERIAL PRIMARY KEY,
 domain_id              INT REFERENCES domains(id) ON DELETE CASCADE,
 flags                  INT NOT NULL,
 active                 BOOL,
 content                TEXT
);

CREATE INDEX domainidindex ON cryptokeys(domain_id);


CREATE TABLE tsigkeys (
 id                     SERIAL PRIMARY KEY,
 name                   VARCHAR(255),
 algorithm              VARCHAR(50),
 secret                 VARCHAR(255),
 constraint c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);

CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);


CREATE TABLE comments (
  id                    SERIAL PRIMARY KEY,
  domain_id             INT NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  comment               VARCHAR(65535) NOT NULL,
  CONSTRAINT domain_exists
  FOREIGN KEY(domain_id) REFERENCES domains(id)
  ON DELETE CASCADE,
  CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);

CREATE INDEX comments_domain_id_idx ON comments (domain_id);
CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);

For gpgsql backend with dnssec schema:

/* Uncomment next 2 lines for versions <= 3.3 */
/* ALTER TABLE domains ADD CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))); */
/* ALTER TABLE tsigkeys ADD CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))); */

ALTER TABLE records ADD disabled BOOL DEFAULT 'f';
ALTER TABLE records ALTER COLUMN content TYPE VARCHAR(65535);
ALTER TABLE records ALTER COLUMN auth SET DEFAULT 't';
ALTER TABLE records ALTER COLUMN type TYPE VARCHAR(10);
ALTER TABLE supermasters ALTER COLUMN ip TYPE INET USING ip::INET;
ALTER TABLE supermasters ALTER COLUMN account SET DEFAULT NOT NULL;
ALTER TABLE supermasters ADD CONSTRAINT supermasters_pkey PRIMARY KEY (ip, nameserver);
ALTER TABLE domainmetadata ALTER COLUMN kind TYPE VARCHAR(32);
ALTER TABLE tsigkeys ALTER COLUMN algorithm TYPE VARCHAR(50);

CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops);
DROP INDEX IF EXISTS orderindex;


CREATE TABLE comments (
  id                    SERIAL PRIMARY KEY,
  domain_id             INT NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  comment               VARCHAR(65535) NOT NULL,
  CONSTRAINT domain_exists
  FOREIGN KEY(domain_id) REFERENCES domains(id)
  ON DELETE CASCADE,
  CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);

CREATE INDEX comments_domain_id_idx ON comments (domain_id);
CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);

For gsqlite3 backend with nodnssec schema:

ALTER TABLE records ADD disabled BOOL DEFAULT 0;
ALTER TABLE records ADD ordername VARCHAR(255);
ALTER TABLE records ADD auth BOOL DEFAULT 1;

CREATE INDEX orderindex ON records(ordername);


CREATE TABLE domainmetadata (
  id                    INTEGER PRIMARY KEY,
  domain_id             INT NOT NULL,
  kind                  VARCHAR(32) COLLATE NOCASE,
  content               TEXT
);

CREATE INDEX domainmetaidindex on domainmetadata(domain_id);


CREATE TABLE cryptokeys (
  id                    INTEGER PRIMARY KEY,
  domain_id             INT NOT NULL,
  flags                 INT NOT NULL,
  active                BOOL,
  content               TEXT
);

CREATE INDEX domainidindex ON cryptokeys(domain_id);


CREATE TABLE tsigkeys (
  id                    INTEGER PRIMARY KEY,
  name                  VARCHAR(255) COLLATE NOCASE,
  algorithm             VARCHAR(50) COLLATE NOCASE,
  secret                VARCHAR(255)
);

CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);


CREATE TABLE comments (
  id                    INTEGER PRIMARY KEY,
  domain_id             INTEGER NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  comment               VARCHAR(65535) NOT NULL
);

CREATE INDEX comments_domain_id_index ON comments (domain_id);
CREATE INDEX comments_nametype_index ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);


BEGIN TRANSACTION;
  CREATE TEMPORARY TABLE supermasters_backup (
    ip                  VARCHAR(64) NOT NULL,
    nameserver          VARCHAR(255) NOT NULL COLLATE NOCASE,
    account             VARCHAR(40) DEFAULT NULL
  );

  INSERT INTO supermasters_backup SELECT ip, nameserver, account FROM supermasters;
  UPDATE supermasters_backup SET account='' WHERE account IS NULL;
  DROP TABLE supermasters;

  CREATE TABLE supermasters (
    ip                  VARCHAR(64) NOT NULL,
    nameserver          VARCHAR(255) NOT NULL COLLATE NOCASE,
    account             VARCHAR(40) NOT NULL
  );
  CREATE UNIQUE INDEX ip_nameserver_pk ON supermasters(ip, nameserver);

  INSERT INTO supermasters SELECT ip, nameserver, account FROM supermasters_backup;
  DROP TABLE supermasters_backup;
COMMIT;

For gsqlite3 backend with dnssec schema:

CREATE TABLE comments (
  id                    INTEGER PRIMARY KEY,
  domain_id             INTEGER NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  comment               VARCHAR(65535) NOT NULL
);

CREATE INDEX comments_domain_id_index ON comments (domain_id);
CREATE INDEX comments_nametype_index ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);


BEGIN TRANSACTION;
  CREATE TEMPORARY TABLE records_backup(
    id                  INTEGER PRIMARY KEY,
    domain_id           INTEGER DEFAULT NULL,
    name                VARCHAR(255) DEFAULT NULL,
    type                VARCHAR(10) DEFAULT NULL,
    content             VARCHAR(65535) DEFAULT NULL,
    ttl                 INTEGER DEFAULT NULL,
    prio                INTEGER DEFAULT NULL,
    change_date         INTEGER DEFAULT NULL,
    ordername           VARCHAR(255),
    auth                BOOL DEFAULT 1
  );

  INSERT INTO records_backup SELECT id,domain_id,name,type,content,ttl,prio,change_date,ordername,auth FROM records;
  DROP TABLE records;

  CREATE TABLE records (
    id                  INTEGER PRIMARY KEY,
    domain_id           INTEGER DEFAULT NULL,
    name                VARCHAR(255) DEFAULT NULL,
    type                VARCHAR(10) DEFAULT NULL,
    content             VARCHAR(65535) DEFAULT NULL,
    ttl                 INTEGER DEFAULT NULL,
    prio                INTEGER DEFAULT NULL,
    change_date         INTEGER DEFAULT NULL,
    disabled            BOOLEAN DEFAULT 0,
    ordername           VARCHAR(255),
    auth                BOOL DEFAULT 1
  );

  CREATE INDEX rec_name_index ON records(name);
  CREATE INDEX nametype_index ON records(name,type);
  CREATE INDEX domain_id ON records(domain_id);
  CREATE INDEX orderindex ON records(ordername);

  INSERT INTO records SELECT id,domain_id,name,type,content,ttl,prio,change_date,0,ordername,auth FROM records_backup;
  DROP TABLE records_backup;
COMMIT;


BEGIN TRANSACTION;
  CREATE TEMPORARY TABLE supermasters_backup (
    ip                  VARCHAR(64) NOT NULL,
    nameserver          VARCHAR(255) NOT NULL COLLATE NOCASE,
    account             VARCHAR(40) DEFAULT NULL
  );

  INSERT INTO supermasters_backup SELECT ip,nameserver,account FROM supermasters;
  UPDATE supermasters_backup SET account='' WHERE account IS NULL;
  DROP TABLE supermasters;

  CREATE TABLE supermasters (
    ip                  VARCHAR(64) NOT NULL,
    nameserver          VARCHAR(255) NOT NULL COLLATE NOCASE,
    account             VARCHAR(40) NOT NULL
  );
  CREATE UNIQUE INDEX ip_nameserver_pk ON supermasters(ip, nameserver);

  INSERT INTO supermasters SELECT ip,nameserver,account FROM supermasters_backup;
  DROP TABLE supermasters_backup;
COMMIT;


BEGIN TRANSACTION;
  CREATE TABLE domainmetadata_backup (
    id INTEGER PRIMARY KEY,
    domain_id INT NOT NULL,
    kind VARCHAR(32) COLLATE NOCASE,
    content TEXT
  );

  INSERT INTO domainmetadata_backup SELECT id,domain_id,kind,content FROM domainmetadata;
  DROP TABLE domainmetadata;

  CREATE TABLE domainmetadata (
    id INTEGER PRIMARY KEY,
    domain_id INT NOT NULL,
    kind VARCHAR(32) COLLATE NOCASE,
    content TEXT
  );
  CREATE INDEX domainmetaidindex ON domainmetadata(domain_id);

  INSERT INTO domainmetadata SELECT id,domain_id,kind,content FROM domainmetadata_backup;
  DROP TABLE domainmetadata_backup;
COMMIT;

For goracle backend:

ALTER TABLE records ADD disabled INT DEFAULT 0;
ALTER TABLE records MODIFY auth INT DEFAULT 1;

UPDATE records SET auth=1 WHERE auth IS NULL;

ALTER TABLE domainmetadata MODIFY kind VARCHAR2(32);
        

6.2. Configuration option changes

New options

allow-dnsupdate-from

A global setting to allow DNS update from these IP ranges.

also-notify

When notifying a domain, also notify these nameservers

carbon-interval

Number of seconds between carbon (graphite) updates

carbon-ourname

If set, overrides our reported hostname for carbon stats

carbon-server

If set, send metrics in carbon (graphite) format to this server

disable-axfr-rectify

Disable the rectify step during an outgoing AXFR. Only required for regression testing.

experimental-api-readonly

If the JSON API should disallow data modification

experimental-api-key

Static API authentication key, must be sent in the X-API-Key header. Required for any API usage.

experimental-dname-processing

If we should support DNAME records

experimental-dnsupdate

Enable/Disable DNS update (RFC2136) support. Default is no.

forward-dnsupdate

A global setting to allow DNS update packages that are for a Slave domain, to be forwarded to the master.

max-signature-cache-entries

Maximum number of signatures cache entries

local-address-nonexist-fail

Fail to start if one or more of the local-address's do not exist on this server

local-ipv6-nonexist-fail

Fail to start if one or more of the local-ipv6 addresses do not exist on this server

max-nsec3-iterations

Limit the number of NSEC3 hash iterations

only-notify

Only send AXFR NOTIFY to these IP addresses or netmasks

reuseport

Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket

udp-truncation-threshold

Maximum UDP response size before we truncate

webserver-allow-from

Webserver access is only allowed from these subnets

Removed options

add-superfluous-nsec3-for-old-bind

Add superfluous NSEC3 record to positive wildcard response

edns-subnet-option-number

EDNS option number to use

fancy-records

Process URL and MBOXFW records

log-failed-updates

If PDNS should log failed update requests

smtpredirector

Our smtpredir MX host

urlredirector

Where we send hosts to that need to be url redirected

wildcard-url

Process URL and MBOXFW records

soa-serial-offset=...

If your database contains single-digit SOA serials and you need to host .DE domains, this setting can help placate their 6-digit SOA serial requirements. Suggested value is to set this to 1000000 which adds 1000000 to all SOA Serials under that offset.

Options with changed default values

allow-axfr-ips

Allow zonetransfers only to these subnets

old value: 0.0.0.0/0,::/0

new value: 127.0.0.0/8,::1

gpgsql-dbname, gpgsql-user

These now default to empty, instead of 'powerdns'.

log-dns-details

If PDNS should log DNS non-erroneous details

old value:

new value: no

module-dir

The default location has changed from libdir to pkglibdir. pkglibdir is defined as '$(libdir)/pdns'