← back to the garden

MD

Serviço Próprio de DNS Autoritativo

Uma arquitetura prática para criar um serviço independente de DNS autoritativo com PowerDNS, PostgreSQL, painel web, API, receitas DNS, ACME, backup e monitoramento.

  • dns
  • infraestrutura
  • homelab
  • powerdns
  • automação
  • indie-web

Serviço próprio de DNS autoritativo

Este documento organiza a ideia de criar um serviço próprio de DNS autoritativo: nameservers próprios, painel simples, API de automação, receitas prontas e operação segura.

A proposta é bonita, útil e tecnicamente viável. Mas o ponto central é simples: DNS é infraestrutura crítica. Se for feito com preguiça, não vira independência; vira uma máquina elegante de derrubar os próprios serviços.

Resumo rápido

Campo Decisão recomendada
Tipo de serviço DNS autoritativo, não resolver recursivo
Software DNS PowerDNS Authoritative
Banco PostgreSQL
Nameservers ns1 e ns2 em VPS diferentes
Painel Web simples, com validações fortes
Automação API própria + tokens com escopo
Certificados DNS-01 para wildcard via Certbot/Caddy
Monitoramento Uptime Kuma, Prometheus, Grafana e exporters
MVP Domínio laboratório, nunca domínio crítico

DNS próprio é liberdade, mas também responsabilidade operacional. O MVP precisa provar estabilidade antes de tocar em domínio importante.


Para que serve este projeto

Este projeto serve para criar um serviço próprio de hospedagem DNS autoritativa.

Na prática, ele permite que uma pessoa, empresa, comunidade ou projeto controle diretamente os registros DNS dos seus domínios usando nameservers próprios, em vez de depender totalmente de provedores externos para responder oficialmente por esses registros.

Exemplo com domínio fictício:

krikri.zone

Em um provedor DNS comum, os nameservers de krikri.zone poderiam ser algo como:

ns1.provedor.example
ns2.provedor.example

Neste projeto, a ideia é ter nameservers próprios:

ns1.krikri.zone
ns2.krikri.zone

ou, em uma arquitetura mais separada:

ns1.dns.krikri.zone
ns2.dns.krikri.zone

A partir daí, esses servidores passam a responder oficialmente por registros como:

krikri.zone.              A      203.0.113.10
www.krikri.zone.          CNAME  krikri.zone.
mail.krikri.zone.         A      203.0.113.20
krikri.zone.              MX     10 mail.krikri.zone.
_acme-challenge.krikri.zone. TXT "token-de-validacao"

O serviço não é um resolver público como 1.1.1.1, 8.8.8.8 ou 9.9.9.9.

Ele é um servidor DNS autoritativo, ou seja, responde oficialmente pelas zonas delegadas a ele.

Em termos simples:

Resolver público:
  usado por pessoas e computadores para perguntar "qual é o IP deste domínio?"

Servidor autoritativo:
  usado pela internet para descobrir a resposta oficial de um domínio.

Este projeto quer resolver o segundo caso.


Objetivo do projeto

O objetivo é construir uma plataforma própria de DNS autoritativo com:

  1. nameservers próprios;
  2. painel web simples;
  3. API para automação;
  4. suporte a zonas DNS;
  5. criação, edição e remoção de registros;
  6. receitas DNS prontas;
  7. integração com certificados TLS via DNS-01;
  8. logs de auditoria;
  9. backup e rollback;
  10. monitoramento dos nameservers.

O diferencial não deve ser apenas “ter DNS próprio”. Isso, sozinho, não é produto.

O diferencial real deve ser:

  • simplicidade;
  • controle;
  • independência;
  • receitas prontas;
  • interface humana;
  • automação segura;
  • integração com fediverse, e-mail, certificados, sites indie e infraestrutura pessoal;
  • explicação clara de erros DNS;
  • operação suficientemente robusta para não derrubar os próprios domínios.

Conceito central

A versão mínima do projeto deve permitir:

  1. cadastrar domínios/zonas;
  2. criar, editar e remover registros DNS;
  3. hospedar zonas em nameservers próprios;
  4. gerar API tokens;
  5. permitir automação ACME/DNS-01 para certificados wildcard;
  6. aplicar receitas DNS prontas;
  7. registrar logs de auditoria;
  8. monitorar saúde dos nameservers;
  9. fazer backup das zonas;
  10. evitar erros clássicos de configuração DNS.

Exemplo de uso com krikri.zone:

1. O domínio krikri.zone é registrado normalmente em um registrador.
2. No registrador, são criados glue records para ns1.krikri.zone e ns2.krikri.zone.
3. Os nameservers do domínio são alterados para ns1.krikri.zone e ns2.krikri.zone.
4. O painel do serviço passa a controlar a zona krikri.zone.
5. Registros A, AAAA, CNAME, MX, TXT, CAA e outros são gerenciados pelo painel/API.
6. Certificados wildcard podem ser emitidos automaticamente com desafio DNS-01.

Público-alvo possível

Inicialmente, o público-alvo deve ser o próprio operador do serviço.

Ou seja: primeiro construir para uso pessoal, em domínios não críticos.

Depois, se o serviço ficar estável, poderia atender:

  • administradores de homelab;
  • donos de pequenos sites;
  • projetos indie web;
  • usuários de fediverse;
  • operadores de e-mail próprio;
  • pequenos provedores;
  • comunidades como pubnix;
  • pessoas que querem fugir de painéis DNS inchados;
  • pessoas que querem receitas prontas para configurar domínios.

Para uso comercial amplo, o nível de responsabilidade sobe muito. DNS é infraestrutura crítica. Um erro pode derrubar sites, e-mails, certificados e serviços federados.

Para o exemplo krikri.zone, o projeto deve começar como ferramenta interna/laboratório. Só depois de estabilidade real, backup testado, monitoramento e rollback funcional faria sentido pensar em uso por terceiros.


Nomes possíveis

Algumas ideias de nome:

Krikri DNS
Zone Garden
DNS Garden
Krikri Zones
Krikri Zonekeeper

A estética pode seguir uma linha:

  • indie web;
  • old web;
  • terminal;
  • pubnix;
  • “cozinha” de receitas DNS;
  • jardim de zonas;
  • laboratório DNS;
  • personagem assistente explicando erros.

Uma boa direção seria algo como:

Zone Garden — um jardim de zonas DNS com receitas prontas, automação segura e painel simples.

Ou:

Krikri DNS — DNS hosting autoritativo para projetos indie, fediverse, e-mail próprio e certificados wildcard.


Conceitos técnicos fundamentais

1 DNS autoritativo

Um servidor DNS autoritativo é aquele que responde oficialmente por uma zona.

Exemplo:

krikri.zone

Se o domínio estiver delegado para:

ns1.krikri.zone
ns2.krikri.zone

então esses nameservers respondem oficialmente por registros como:

www.krikri.zone
mail.krikri.zone
_acme-challenge.krikri.zone

2 Resolver recursivo

Não confundir com resolver recursivo.

Resolvers como:

1.1.1.1
8.8.8.8
9.9.9.9

são usados por clientes para consultar a internet. Eles perguntam aos servidores autoritativos e devolvem a resposta ao usuário.

Este projeto não é sobre criar um resolver público. É sobre hospedar DNS autoritativo.

3 Nameserver próprio

Exemplo:

ns1.krikri.zone
ns2.krikri.zone

Esses hosts precisam apontar para IPs públicos de servidores que rodam software DNS autoritativo.

4 Glue records

Se o nameserver está dentro do próprio domínio que ele ajuda a resolver, é preciso criar glue records no registrador.

Exemplo:

krikri.zone

Nameservers:
ns1.krikri.zone
ns2.krikri.zone

Problema circular:

Para saber o IP de ns1.krikri.zone, eu preciso consultar krikri.zone. Mas para consultar krikri.zone, eu preciso saber onde está ns1.krikri.zone.

Solução: no registrador do domínio, cadastrar hosts de nameserver:

ns1.krikri.zone → IP_DA_VPS_1
ns2.krikri.zone → IP_DA_VPS_2

Isso são os glue records.

5 Zona DNS

Uma zona é o conjunto de registros de um domínio.

Exemplo de zona:

$ORIGIN krikri.zone.
$TTL 3600
@       IN SOA ns1.krikri.zone. hostmaster.krikri.zone. (
            2026062701 ; serial
            3600       ; refresh
            900        ; retry
            1209600    ; expire
            3600       ; minimum
)
@       IN NS  ns1.krikri.zone.
@       IN NS  ns2.krikri.zone.
@       IN A   203.0.113.10
www     IN CNAME krikri.zone.
mail    IN A   203.0.113.20
@       IN MX  10 mail.krikri.zone.

BIND 9 vs PowerDNS

Existem duas rotas principais.


1 Rota A: BIND 9

BIND 9 é uma opção clássica para servidores DNS autoritativos. Ele trabalha muito bem com arquivos de zona e é excelente para aprendizado profundo de DNS.

Vantagens:

  • tradicional;
  • muito documentado;
  • estável;
  • arquivos de zona legíveis;
  • ótimo para aprendizado profundo de DNS;
  • compatível com praticamente tudo.

Desvantagens:

  • menos confortável para virar produto web;
  • edição concorrente de arquivos de zona exige cuidado;
  • reload/reconfiguração precisa ser bem controlado;
  • automação de DNSSEC pode ficar mais delicada;
  • painel próprio exige mais cola operacional;
  • auditoria e histórico exigem implementação adicional.

BIND pode ser usado com dynamic update via RFC 2136, mas a experiência de construir um painel e uma API completos em cima dele é menos direta do que com PowerDNS.


2 Rota B: PowerDNS Authoritative

Para este projeto, a recomendação principal é usar PowerDNS Authoritative com PostgreSQL.

Vantagens:

  • tem API HTTP/JSON oficial;
  • trabalha muito bem com banco SQL;
  • é mais amigável para painel web;
  • facilita auditoria;
  • facilita automação;
  • facilita replicação;
  • facilita integração com backend próprio;
  • suporta DNSSEC;
  • é mais adequado para produto.

Desvantagens:

  • menos “old-school” que BIND;
  • exige banco de dados;
  • exige entender bem o modelo de dados;
  • painel próprio precisa validar regras DNS corretamente.

Recomendação honesta:

Para um serviço próprio com painel web, API, receitas e automação, PowerDNS + PostgreSQL é a melhor escolha inicial.


Arquitetura recomendada

Arquitetura inicial:

                 ┌───────────────────────────┐
                 │ app.dns.krikri.zone    │
                 │ Painel Web + API própria  │
                 └────────────┬──────────────┘
                              │
                              ▼
                 ┌───────────────────────────┐
                 │ PostgreSQL                │
                 │ users/zones/records/logs  │
                 └────────────┬──────────────┘
                              │
                              ▼
        ┌─────────────────────────────────────────┐
        │ PowerDNS Authoritative                  │
        │ ns1 + ns2 lendo banco/replicação        │
        └─────────────────────────────────────────┘
                              │
                              ▼
                         Internet DNS

Arquitetura com dois servidores:

┌──────────────────────────────────────┐
│ VPS 1                                │
│                                      │
│ ns1.krikri.zone                    │
│ PowerDNS Authoritative               │
│ PostgreSQL primary                   │
│ API/painel opcional                  │
└──────────────────────────────────────┘

┌──────────────────────────────────────┐
│ VPS 2                                │
│                                      │
│ ns2.krikri.zone                    │
│ PowerDNS Authoritative               │
│ PostgreSQL replica ou AXFR           │
└──────────────────────────────────────┘

┌──────────────────────────────────────┐
│ VPS 3 opcional                       │
│                                      │
│ painel web                           │
│ worker de receitas                   │
│ backups                              │
│ monitoramento                        │
└──────────────────────────────────────┘

Não usar ns1 e ns2 no mesmo servidor. Isso só simula redundância, mas não entrega redundância real.

Errado:

ns1.krikri.zone → 203.0.113.10
ns2.krikri.zone → 203.0.113.10

Correto:

ns1.krikri.zone → 203.0.113.10
ns2.krikri.zone → 198.51.100.20

Ideal:

ns1.krikri.zone → VPS A / provedor A / região A
ns2.krikri.zone → VPS B / provedor B / região B

Componentes do sistema

1 Nameservers

Responsáveis por responder consultas DNS autoritativas.

Sugestão:

ns1.krikri.zone
ns2.krikri.zone

Software recomendado:

PowerDNS Authoritative

Alternativa:

BIND 9

2 Banco de dados

Recomendado:

PostgreSQL

Funções:

  • armazenar zonas;
  • armazenar registros;
  • armazenar usuários;
  • armazenar tokens de API;
  • armazenar logs;
  • armazenar receitas aplicadas;
  • armazenar histórico de alterações.

3 Painel web

Funções:

  • login;
  • listagem de zonas;
  • criação de zona;
  • listagem de registros;
  • editor de registros;
  • aplicação de receitas;
  • gerenciamento de API keys;
  • visualização de logs;
  • verificação de propagação DNS;
  • tela de ajuda contextual.

4 API própria

Funções:

  • criar zonas;
  • listar zonas;
  • criar registros;
  • editar registros;
  • apagar registros;
  • aplicar receitas;
  • criar/remover TXT de desafio ACME;
  • consultar logs.

5 Worker de automação

Responsável por tarefas assíncronas:

  • aplicar receitas complexas;
  • validar propagação;
  • rodar checagens periódicas;
  • renovar estados;
  • gerar backups;
  • atualizar serial de zonas, se necessário;
  • verificar integridade dos nameservers.

6 Monitoramento

Monitorar:

  • porta 53 UDP;
  • porta 53 TCP;
  • resposta SOA;
  • resposta NS;
  • latência de consulta;
  • divergência entre ns1 e ns2;
  • erros de API;
  • falhas de replicação;
  • expiração de zonas secundárias;
  • status do PostgreSQL;
  • uso de disco;
  • uso de memória;
  • carga do servidor.

Ferramentas possíveis:

Uptime Kuma
Prometheus
Grafana
node_exporter
blackbox_exporter
PowerDNS exporter

7 Backups

Backup obrigatório de:

  • banco PostgreSQL;
  • configuração do PowerDNS;
  • secrets/API tokens com hash;
  • arquivos de configuração;
  • snapshots das zonas;
  • logs importantes.

Política recomendada:

backup diário local
backup diário remoto
retenção de 7 dias
retenção semanal de 4 semanas
retenção mensal de 6 meses

Modelo de dados sugerido

Se usar PowerDNS, parte do modelo de dados vem do próprio schema do PowerDNS. Mesmo assim, o painel próprio deve ter tabelas de aplicação.

1 Usuários

CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    email TEXT NOT NULL UNIQUE,
    password_hash TEXT NOT NULL,
    name TEXT,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

2 Zonas da aplicação

CREATE TABLE app_zones (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id),
    name TEXT NOT NULL UNIQUE,
    status TEXT NOT NULL DEFAULT 'active',
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

3 Tokens de API

CREATE TABLE api_tokens (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id),
    zone_id BIGINT REFERENCES app_zones(id),
    name TEXT NOT NULL,
    token_hash TEXT NOT NULL,
    scopes JSONB NOT NULL DEFAULT '[]',
    allowed_names JSONB NOT NULL DEFAULT '[]',
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    last_used_at TIMESTAMPTZ
);

4 Logs de auditoria

CREATE TABLE audit_logs (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT REFERENCES users(id),
    zone_id BIGINT REFERENCES app_zones(id),
    action TEXT NOT NULL,
    old_value JSONB,
    new_value JSONB,
    ip INET,
    user_agent TEXT,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

5 Receitas aplicadas

CREATE TABLE applied_recipes (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id),
    zone_id BIGINT NOT NULL REFERENCES app_zones(id),
    recipe_name TEXT NOT NULL,
    recipe_version TEXT NOT NULL,
    applied_records JSONB NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

API mínima

1 Zonas

GET    /api/zones
POST   /api/zones
GET    /api/zones/:zone
DELETE /api/zones/:zone

2 Registros

GET    /api/zones/:zone/records
POST   /api/zones/:zone/records
PUT    /api/zones/:zone/records/:id
DELETE /api/zones/:zone/records/:id

3 Receitas

GET    /api/recipes
GET    /api/recipes/:recipe
POST   /api/zones/:zone/apply-recipe

4 Tokens

GET    /api/tokens
POST   /api/tokens
DELETE /api/tokens/:id

5 ACME / LEGO

POST /api/lego/present
POST /api/lego/cleanup

Payload para present:

{
  "fqdn": "_acme-challenge.krikri.zone.",
  "value": "token-do-letsencrypt",
  "ttl": 120
}

Payload para cleanup:

{
  "fqdn": "_acme-challenge.krikri.zone.",
  "value": "token-do-letsencrypt"
}

Autenticação:

Authorization: Bearer TOKEN

Regras obrigatórias:

  • token precisa pertencer ao usuário;
  • token precisa ter escopo ACME;
  • token precisa estar limitado à zona correta;
  • token não deve conseguir editar registros fora de _acme-challenge;
  • token não deve conseguir apagar registros não criados por ele, salvo regra explícita;
  • todas as ações devem gerar log.

Integração com certificados TLS

Uma das funções mais úteis do serviço é permitir emissão de certificados wildcard via DNS-01.

Exemplo:

*.krikri.zone

Fluxo:

Caddy/Certbot pede certificado wildcard
  ↓
Let's Encrypt exige TXT em _acme-challenge.dominio.com
  ↓
Caddy/Certbot chama API do serviço DNS
  ↓
Serviço cria TXT no PowerDNS
  ↓
Let's Encrypt consulta o TXT
  ↓
Certificado é emitido
  ↓
Serviço remove o TXT

1 Hook Certbot: auth

Exemplo conceitual:

#!/usr/bin/env bash
set -euo pipefail

: "${KRIKRIDNS_API_BASE:?Missing KRIKRIDNS_API_BASE}"
: "${KRIKRIDNS_API_TOKEN:?Missing KRIKRIDNS_API_TOKEN}"

domain="${CERTBOT_DOMAIN:?Missing CERTBOT_DOMAIN}"
value="${CERTBOT_VALIDATION:?Missing CERTBOT_VALIDATION}"

fqdn="_acme-challenge.${domain}"
fqdn="${fqdn%.}."

curl -fsS \
  -H "Authorization: Bearer ${KRIKRIDNS_API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d "{\"fqdn\":\"${fqdn}\",\"value\":\"${value}\",\"ttl\":120}" \
  "${KRIKRIDNS_API_BASE%/}/api/lego/present"

2 Hook Certbot: cleanup

#!/usr/bin/env bash
set -euo pipefail

: "${KRIKRIDNS_API_BASE:?Missing KRIKRIDNS_API_BASE}"
: "${KRIKRIDNS_API_TOKEN:?Missing KRIKRIDNS_API_TOKEN}"

domain="${CERTBOT_DOMAIN:?Missing CERTBOT_DOMAIN}"
value="${CERTBOT_VALIDATION:?Missing CERTBOT_VALIDATION}"

fqdn="_acme-challenge.${domain}"
fqdn="${fqdn%.}."

curl -fsS \
  -H "Authorization: Bearer ${KRIKRIDNS_API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d "{\"fqdn\":\"${fqdn}\",\"value\":\"${value}\"}" \
  "${KRIKRIDNS_API_BASE%/}/api/lego/cleanup"

3 Caddy provider futuro

Mais tarde, pode ser criado um provider libdns.

Exemplo de configuração desejada no Caddy:

{
    acme_dns krikridns {
        api_base_url https://dns.krikri.zone/api/lego/
        api_token {$KRIKRIDNS_API_TOKEN}
        ttl 120
    }
}

*.krikri.zone {
    tls {
        dns krikridns
    }
    reverse_proxy 127.0.0.1:8080
}

Receitas DNS

As receitas são o grande diferencial do produto.

Em vez de exigir que o usuário saiba exatamente quais registros criar, o sistema oferece ações prontas.

1 Receita: domínio que não envia nem recebe e-mail

Objetivo: impedir abuso de spoofing em um domínio sem e-mail.

Registros:

@              MX   0 .
@              TXT  "v=spf1 -all"
*._domainkey   TXT  "v=DKIM1; p="
_dmarc         TXT  "v=DMARC1; p=reject; adkim=s; aspf=s;"

2 Receita: proteção básica de e-mail

Registros:

@       TXT  "v=spf1 include:provedor.example -all"
_dmarc  TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc@krikri.zone"

DKIM dependeria do provedor.

3 Receita: Google Workspace

Criar MX padrão do Google:

@  MX  1   ASPMX.L.GOOGLE.COM.
@  MX  5   ALT1.ASPMX.L.GOOGLE.COM.
@  MX  5   ALT2.ASPMX.L.GOOGLE.COM.
@  MX  10  ALT3.ASPMX.L.GOOGLE.COM.
@  MX  10  ALT4.ASPMX.L.GOOGLE.COM.

Também preparar SPF:

@ TXT "v=spf1 include:_spf.google.com -all"

4 Receita: Fastmail

Criar os registros necessários para Fastmail, incluindo MX, SPF, DKIM e DMARC, conforme valores fornecidos pela conta do usuário.

5 Receita: Resend

Criar registros de envio transacional:

SPF
DKIM
DMARC
CNAME de tracking, se aplicável

Os valores devem ser preenchidos com base no painel do Resend.

6 Receita: GoToSocial / Fediverse

Criar registros comuns:

@      A      IP_DO_SERVIDOR
www    CNAME  @

Opcionalmente, documentar uso de WebFinger, ActivityPub e proxies.

7 Receita: Ghost

Criar registros:

@      A      IP_DO_SERVIDOR
www    CNAME  @

Ou, se hospedagem externa exigir:

www    CNAME  host-do-provedor.example.

8 Receita: Bluesky handle

Criar TXT para handle do Bluesky:

_atproto TXT "did=did:plc:..."

9 Receita: Matrix

Criar registros .well-known não é DNS puro, mas DNS pode ajudar com delegation via SRV, dependendo do modelo usado.

Possível receita:

_matrix._tcp.krikri.zone SRV 10 5 8448 matrix.krikri.zone.

10 Receita: CAA para Let's Encrypt

@ CAA 0 issue "letsencrypt.org"
@ CAA 0 iodef "mailto:admin@krikri.zone"

11 Receita: wildcard ACME

Criar API token limitado a:

_acme-challenge.krikri.zone

Escopo:

acme:dns01

Permissões:

create TXT
delete own TXT

Validações obrigatórias

DNS tem regras chatas. O painel deve proteger o usuário de erros comuns.

1 CNAME não pode coexistir com outros registros

Inválido:

blog A     203.0.113.10
blog CNAME krikri.zone.

Também inválido:

blog CNAME krikri.zone.
blog TXT   "teste"

Se um hostname tem CNAME, ele não deve ter outros tipos de registro.

2 MX precisa de prioridade

Inválido:

@ MX mail.krikri.zone.

Correto:

@ MX 10 mail.krikri.zone.

3 SRV precisa de formato correto

Formato:

_service._proto.name TTL IN SRV priority weight port target

Exemplo:

_matrix._tcp.krikri.zone. 3600 IN SRV 10 5 8448 matrix.krikri.zone.

4 CAA precisa ser validado

Exemplo:

@ CAA 0 issue "letsencrypt.org"

5 TXT pode precisar de chunking

TXT muito grande pode precisar ser dividido em múltiplas strings dentro do mesmo registro.

6 Impedir edição fora da zona

Se o usuário controla:

krikri.zone

A API não pode aceitar:

_acme-challenge.outrodominio.com

7 TTL mínimo e máximo

Definir limites:

TTL mínimo: 60 ou 120 segundos
TTL padrão: 3600 segundos
TTL máximo: 86400 ou 604800 segundos

8 Proteção de SOA e NS

O usuário comum não deve conseguir apagar acidentalmente:

SOA
NS principais

A edição desses registros precisa ser controlada.


Segurança

1 API tokens com escopo

Nunca usar token global para tudo.

Tipos de token:

read-only
zone-admin
record-editor
acme-dns01
recipe-runner

Token ACME deve ser extremamente limitado.

Exemplo:

{
  "scope": "acme:dns01",
  "zone": "krikri.zone",
  "allowed_names": [
    "_acme-challenge.krikri.zone."
  ],
  "allowed_types": ["TXT"]
}

2 Hash de tokens

Nunca armazenar token puro.

Guardar apenas hash:

sha256/token hash com salt adequado

Mostrar o token ao usuário apenas uma vez.

3 Logs de auditoria

Registrar:

  • usuário;
  • IP;
  • user-agent;
  • ação;
  • zona;
  • registro anterior;
  • registro novo;
  • horário.

4 Rate limiting

Aplicar limite em:

  • login;
  • criação de registros;
  • chamadas ACME;
  • criação de tokens;
  • endpoints públicos.

5 2FA

Para qualquer serviço DNS com painel web, 2FA é recomendável.

Mínimo:

TOTP

6 Backups e rollback

Toda alteração de zona deve poder ser revertida.

Ideal:

histórico de versões da zona
botão “restaurar versão anterior”
exportação BIND zone file

DNSSEC

DNSSEC é útil, mas adiciona complexidade.

Recomendação:

  1. não ativar DNSSEC no MVP;
  2. implementar DNSSEC depois que o básico estiver estável;
  3. automatizar rotação de chaves;
  4. documentar claramente DS records no registrador;
  5. criar alertas para erro de validação.

Erro em DNSSEC pode deixar o domínio aparentemente “fora do ar” para resolvers validadores.

DNSSEC mal operado é pior do que DNS sem DNSSEC.


UX do painel

Telas mínimas:

Dashboard
Zonas
Registros
Receitas
API Keys
Logs
Verificador DNS
Configurações
Ajuda

1 Dashboard

Mostrar:

  • quantidade de zonas;
  • total de registros;
  • status de ns1;
  • status de ns2;
  • últimos logs;
  • alertas;
  • receitas sugeridas.

2 Tela de zona

Exemplo:

Zona: krikri.zone
Status: ativa
Nameservers esperados:
- ns1.krikri.zone
- ns2.krikri.zone

Delegação detectada:
- ns1.krikri.zone
- ns2.krikri.zone

SOA serial: 2026062701
Última alteração: 2026-06-27 14:32

3 Editor de registros

Tabela:

Nome | Tipo | Valor | TTL | Prioridade | Ações

4 Explicação de erros

Exemplo de erro útil:

Você tentou criar um CNAME em blog.krikri.zone, mas esse nome já possui um registro A.

DNS não permite CNAME coexistindo com outros registros no mesmo hostname.

Escolha uma opção:
1. apagar o registro A e criar CNAME;
2. manter o A;
3. criar o CNAME em outro subdomínio.

Isso é muito melhor do que:

Invalid record

5 Receitas com prévia

Antes de aplicar uma receita, mostrar exatamente o que será criado:

Esta receita criará:

@              MX   0 .
@              TXT  "v=spf1 -all"
*._domainkey   TXT  "v=DKIM1; p="
_dmarc         TXT  "v=DMARC1; p=reject; adkim=s; aspf=s;"

Botões:

[Aplicar]
[Cancelar]

Stack sugerida

1 DNS

PowerDNS Authoritative

2 Banco

PostgreSQL

3 Backend

Boas opções:

Go
Python/FastAPI
Node.js/NestJS
PHP/Laravel

Escolha recomendada:

Python/FastAPI ou Go

Para produtividade rápida:

Python/FastAPI

Para binário simples e performance:

Go

4 Frontend

Opções:

HTML server-side simples
SvelteKit
Next.js
Django templates
Laravel Blade

Recomendação pragmática:

SvelteKit ou templates server-side simples

Não precisa virar uma SPA monstruosa.

5 Proxy

Caddy

ou:

Nginx

6 Monitoramento

Uptime Kuma
Prometheus
Grafana

7 Deploy

Opções:

Docker Compose
Systemd direto
Ansible

Para MVP:

Docker Compose

Para produção mais controlada:

Ansible + systemd + backups

Estrutura de repositório sugerida

krikri-dns/
├── README.md
├── docs/
│   ├── architecture.md
│   ├── api.md
│   ├── recipes.md
│   ├── security.md
│   └── operations.md
├── backend/
│   ├── app/
│   ├── migrations/
│   ├── tests/
│   └── pyproject.toml
├── frontend/
│   ├── src/
│   └── package.json
├── deploy/
│   ├── docker-compose.yml
│   ├── pdns/
│   ├── postgres/
│   └── caddy/
├── scripts/
│   ├── certbot-auth.sh
│   ├── certbot-cleanup.sh
│   ├── backup.sh
│   └── healthcheck.sh
└── recipes/
    ├── no-email-domain.yml
    ├── google-workspace.yml
    ├── resend.yml
    ├── gotosocial.yml
    ├── ghost.yml
    └── letsencrypt-caa.yml

Formato de receita

Exemplo em YAML:

id: no-email-domain
name: Domínio sem e-mail
version: "1.0"
description: Protege um domínio que não envia nem recebe e-mail.
records:
  - name: "@"
    type: "MX"
    priority: 0
    content: "."
    ttl: 3600
  - name: "@"
    type: "TXT"
    content: "v=spf1 -all"
    ttl: 3600
  - name: "*._domainkey"
    type: "TXT"
    content: "v=DKIM1; p="
    ttl: 3600
  - name: "_dmarc"
    type: "TXT"
    content: "v=DMARC1; p=reject; adkim=s; aspf=s;"
    ttl: 3600
warnings:
  - "Use esta receita apenas se o domínio realmente não envia nem recebe e-mail."

Receita com variáveis:

id: resend
name: Resend
version: "1.0"
description: Configura registros básicos para envio via Resend.
variables:
  - id: dkim_name
    label: Nome do DKIM
    required: true
  - id: dkim_value
    label: Valor do DKIM
    required: true
records:
  - name: "@"
    type: "TXT"
    content: "v=spf1 include:amazonses.com -all"
    ttl: 3600
  - name: "{{ dkim_name }}"
    type: "TXT"
    content: "{{ dkim_value }}"
    ttl: 3600
  - name: "_dmarc"
    type: "TXT"
    content: "v=DMARC1; p=quarantine;"
    ttl: 3600

Plano de implementação

Fase 0: decisão de domínio

Escolher domínio base para nameservers.

Sugestões:

krikri.zone
krikri.zone
runv.club

Evitar usar domínio crítico no começo.

Não começar com:

portalidea.com.br
krikri.zone
murad.social

Fase 1: laboratório DNS

Objetivo: rodar PowerDNS Authoritative em uma VPS.

Entregáveis:

  • PowerDNS instalado;
  • PostgreSQL instalado;
  • zona de teste criada;
  • registros A/TXT/CNAME funcionando;
  • consulta via dig funcionando.

Exemplo de teste:

dig @IP_DA_VPS krikri.zone SOA
dig @IP_DA_VPS www.krikri.zone A
dig @IP_DA_VPS krikri.zone TXT

Fase 2: segundo nameserver

Objetivo: ter ns1 e ns2 reais.

Entregáveis:

  • VPS 2 configurada;
  • PowerDNS no segundo servidor;
  • replicação ou AXFR funcionando;
  • glue records no registrador;
  • domínio de teste delegado.

Fase 3: painel mínimo

Objetivo: CRUD básico de zonas e registros.

Entregáveis:

  • login;
  • listar zonas;
  • criar zona;
  • listar registros;
  • criar registro;
  • editar registro;
  • apagar registro;
  • log básico.

Fase 4: API ACME

Objetivo: permitir DNS-01 automático.

Entregáveis:

  • criação de API token;
  • endpoint /api/lego/present;
  • endpoint /api/lego/cleanup;
  • hook Certbot;
  • teste com certificado wildcard;
  • logs.

Fase 5: receitas

Objetivo: transformar DNS em ações prontas.

Entregáveis:

  • receita domínio sem e-mail;
  • receita Google Workspace;
  • receita Resend;
  • receita CAA Let's Encrypt;
  • receita GoToSocial;
  • receita Ghost;
  • prévia antes de aplicar;
  • log de aplicação.

Fase 6: monitoramento

Objetivo: tratar DNS como infraestrutura crítica.

Entregáveis:

  • Uptime Kuma monitorando porta 53 UDP/TCP;
  • checagem de SOA em ns1 e ns2;
  • alerta de divergência;
  • backup diário;
  • dashboard básico.

Fase 7: uso real controlado

Objetivo: colocar domínio não crítico em produção.

Entregáveis:

  • domínio secundário usando nameservers próprios;
  • registros reais;
  • certificado wildcard via API;
  • monitoramento por 30 dias;
  • teste de restore.

Fase 8: expansão

Objetivo: avaliar abertura para terceiros.

Entregáveis:

  • multiusuário seguro;
  • 2FA;
  • limites por usuário;
  • billing, se comercial;
  • termos de uso;
  • documentação pública;
  • status page.

Comandos úteis de teste

Consultar SOA

dig @ns1.krikri.zone krikri.zone SOA +short

Consultar NS

dig krikri.zone NS +short

Consultar contra nameserver específico

dig @ns1.krikri.zone www.krikri.zone A

Ver caminho de delegação

dig krikri.zone +trace

Testar TXT ACME

dig _acme-challenge.krikri.zone TXT +short

Comparar ns1 e ns2

dig @ns1.krikri.zone krikri.zone SOA +short
dig @ns2.krikri.zone krikri.zone SOA +short

Testar porta 53 TCP

dig @ns1.krikri.zone krikri.zone SOA +tcp

Riscos

1 Derrubar domínios próprios

Se nameservers falham, os domínios ficam inacessíveis.

Impacto:

  • sites fora;
  • e-mails falhando;
  • certificados não renovando;
  • fediverse quebrado;
  • serviços internos indisponíveis.

2 Erro de zona

Um registro errado pode quebrar serviço crítico.

Mitigação:

  • validação forte;
  • histórico;
  • rollback;
  • preview antes de aplicar receitas.

3 Falha de replicação

ns1 e ns2 podem responder dados diferentes.

Mitigação:

  • monitorar SOA serial;
  • alertar divergência;
  • testar AXFR/replicação.

4 Token vazado

Token API vazado pode permitir alteração de DNS.

Mitigação:

  • escopos mínimos;
  • token ACME limitado;
  • hash de tokens;
  • rotação;
  • logs;
  • rate limit.

5 DNSSEC mal configurado

DNSSEC quebrado pode fazer o domínio sumir para resolvers validadores.

Mitigação:

  • não ativar DNSSEC no MVP;
  • implementar só depois;
  • automatizar DS/KSK/ZSK com cuidado.

O que não fazer

Não fazer:

usar uma VPS só para ns1 e ns2
colocar domínios críticos no primeiro teste
ativar DNSSEC cedo demais
não ter backup
não ter monitoramento
não ter rollback
não validar CNAME/MX/SRV/CAA
usar token global para ACME
armazenar API token puro
editar zona sem log

Não migrar inicialmente:

portalidea.com.br
krikri.zone
murad.social
serviços com e-mail crítico

Usar primeiro:

domínio laboratório
domínio descartável
subdomínio experimental

MVP recomendado

O MVP mais sensato:

PowerDNS Authoritative
PostgreSQL
2 VPS
ns1/ns2 reais
painel simples
API ACME
receitas básicas
monitoramento
backup

Escopo do MVP:

  • login simples;
  • uma conta admin;
  • criação manual de zonas;
  • CRUD de registros;
  • API token ACME;
  • Certbot hook;
  • receita “domínio sem e-mail”;
  • receita “CAA Let's Encrypt”;
  • checagem ns1/ns2;
  • exportação de zona.

Não incluir no MVP:

  • billing;
  • DNSSEC;
  • multiusuário público;
  • marketplace de receitas;
  • Caddy plugin próprio;
  • interface ultra sofisticada;
  • suporte a todos os tipos obscuros de DNS.

Roadmap sugerido

Versão 0.1

  • PowerDNS + PostgreSQL;
  • uma zona de teste;
  • CRUD via painel/admin;
  • deploy em uma VPS.

Versão 0.2

  • segundo nameserver;
  • delegação real;
  • monitoramento básico;
  • backup.

Versão 0.3

  • API ACME;
  • Certbot hooks;
  • wildcard funcionando.

Versão 0.4

  • receitas YAML;
  • receita domínio sem e-mail;
  • receita CAA;
  • preview de alterações.

Versão 0.5

  • logs de auditoria;
  • rollback;
  • validações fortes.

Versão 0.6

  • UI melhor;
  • documentação pública;
  • verificador DNS;
  • onboarding de domínio.

Versão 1.0

  • multiusuário seguro;
  • 2FA;
  • tokens com escopo;
  • backups testados;
  • status page;
  • pronto para domínios próprios não críticos.

Pós-1.0

  • DNSSEC;
  • Caddy provider;
  • billing;
  • convites;
  • abertura para terceiros;
  • marketplace de receitas;
  • assistente explicativo.

Ideia de posicionamento

Descrição curta:

Um serviço de DNS autoritativo simples e independente, com receitas prontas para e-mail, certificados, fediverse e projetos indie.

Descrição mais longa:

Um painel DNS autoritativo para pessoas que querem controlar seus próprios domínios sem depender totalmente de provedores grandes. Ele combina nameservers próprios, API, automação de certificados wildcard, receitas DNS prontas e explicações claras para evitar erros comuns.

Tom do produto:

simples
indie
técnico
humano
sem firula corporativa
com personalidade

Frase possível:

DNS sem drama para gente que hospeda coisas estranhas na internet.

Outra:

Um jardim de zonas DNS para projetos indie, fediverse, e-mail próprio e certificados wildcard.


Veredito final

A ideia é boa, mas deve ser tratada como infraestrutura crítica.

Construir um serviço desses é totalmente viável. A parte técnica não é absurda. O perigo está na operação: DNS é silencioso, mas quando falha, derruba tudo que depende dele.

A melhor estratégia é:

  1. começar com domínio laboratório;
  2. usar PowerDNS + PostgreSQL;
  3. ter dois nameservers reais;
  4. criar painel mínimo;
  5. implementar API ACME;
  6. adicionar receitas;
  7. monitorar tudo;
  8. testar backup e rollback;
  9. só depois pensar em terceiros.

A arquitetura recomendada é:

PowerDNS Authoritative
PostgreSQL
API própria
Painel web simples
Receitas YAML
Tokens com escopo
Integração Certbot/Caddy
2 VPS reais para ns1/ns2
Monitoramento e backup

O erro seria tentar transformar isso imediatamente em SaaS público.

O caminho inteligente é fazer primeiro como ferramenta própria, usar em domínios secundários, endurecer a operação e só então decidir se vale oferecer para outras pessoas.

DNS próprio é bonito, elegante e poderoso. Mas também é uma maneira sofisticada de derrubar os próprios serviços se for feito com preguiça.


Referências úteis

Links técnicos e documentação