--- title: Serviço Próprio de DNS Autoritativo date: 2026-06-27 summary: 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. tags: [dns, infraestrutura, homelab, powerdns, automação, indie-web] flowerColor: "#d8f3dc" --- # 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: ```txt krikri.zone ``` Em um provedor DNS comum, os nameservers de `krikri.zone` poderiam ser algo como: ```txt ns1.provedor.example ns2.provedor.example ``` Neste projeto, a ideia é ter nameservers próprios: ```txt ns1.krikri.zone ns2.krikri.zone ``` ou, em uma arquitetura mais separada: ```txt ns1.dns.krikri.zone ns2.dns.krikri.zone ``` A partir daí, esses servidores passam a responder oficialmente por registros como: ```txt 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: ```txt 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`: ```txt 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: ```txt 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: ```txt krikri.zone ``` Se o domínio estiver delegado para: ```txt ns1.krikri.zone ns2.krikri.zone ``` então esses nameservers respondem oficialmente por registros como: ```txt www.krikri.zone mail.krikri.zone _acme-challenge.krikri.zone ``` ### 2 Resolver recursivo Não confundir com resolver recursivo. Resolvers como: ```txt 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: ```txt 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: ```txt 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: ```txt 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: ```zone $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: ```txt ┌───────────────────────────┐ │ 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: ```txt ┌──────────────────────────────────────┐ │ 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: ```txt ns1.krikri.zone → 203.0.113.10 ns2.krikri.zone → 203.0.113.10 ``` Correto: ```txt ns1.krikri.zone → 203.0.113.10 ns2.krikri.zone → 198.51.100.20 ``` Ideal: ```txt 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: ```txt ns1.krikri.zone ns2.krikri.zone ``` Software recomendado: ```txt PowerDNS Authoritative ``` Alternativa: ```txt BIND 9 ``` ### 2 Banco de dados Recomendado: ```txt 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: ```txt 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: ```txt 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 ```sql 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 ```sql 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 ```sql 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 ```sql 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 ```sql 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 ```txt GET /api/zones POST /api/zones GET /api/zones/:zone DELETE /api/zones/:zone ``` ### 2 Registros ```txt GET /api/zones/:zone/records POST /api/zones/:zone/records PUT /api/zones/:zone/records/:id DELETE /api/zones/:zone/records/:id ``` ### 3 Receitas ```txt GET /api/recipes GET /api/recipes/:recipe POST /api/zones/:zone/apply-recipe ``` ### 4 Tokens ```txt GET /api/tokens POST /api/tokens DELETE /api/tokens/:id ``` ### 5 ACME / LEGO ```txt POST /api/lego/present POST /api/lego/cleanup ``` Payload para `present`: ```json { "fqdn": "_acme-challenge.krikri.zone.", "value": "token-do-letsencrypt", "ttl": 120 } ``` Payload para `cleanup`: ```json { "fqdn": "_acme-challenge.krikri.zone.", "value": "token-do-letsencrypt" } ``` Autenticação: ```txt 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: ```txt *.krikri.zone ``` Fluxo: ```txt 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: ```bash #!/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 ```bash #!/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: ```caddyfile { 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: ```txt @ 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 @ 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: ```txt @ 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 @ 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: ```txt 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: ```txt @ A IP_DO_SERVIDOR www CNAME @ ``` Opcionalmente, documentar uso de WebFinger, ActivityPub e proxies. ### 7 Receita: Ghost Criar registros: ```txt @ A IP_DO_SERVIDOR www CNAME @ ``` Ou, se hospedagem externa exigir: ```txt www CNAME host-do-provedor.example. ``` ### 8 Receita: Bluesky handle Criar TXT para handle do Bluesky: ```txt _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: ```txt _matrix._tcp.krikri.zone SRV 10 5 8448 matrix.krikri.zone. ``` ### 10 Receita: CAA para Let's Encrypt ```txt @ CAA 0 issue "letsencrypt.org" @ CAA 0 iodef "mailto:admin@krikri.zone" ``` ### 11 Receita: wildcard ACME Criar API token limitado a: ```txt _acme-challenge.krikri.zone ``` Escopo: ```txt acme:dns01 ``` Permissões: ```txt 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: ```txt blog A 203.0.113.10 blog CNAME krikri.zone. ``` Também inválido: ```txt 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: ```txt @ MX mail.krikri.zone. ``` Correto: ```txt @ MX 10 mail.krikri.zone. ``` ### 3 SRV precisa de formato correto Formato: ```txt _service._proto.name TTL IN SRV priority weight port target ``` Exemplo: ```txt _matrix._tcp.krikri.zone. 3600 IN SRV 10 5 8448 matrix.krikri.zone. ``` ### 4 CAA precisa ser validado Exemplo: ```txt @ 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: ```txt krikri.zone ``` A API não pode aceitar: ```txt _acme-challenge.outrodominio.com ``` ### 7 TTL mínimo e máximo Definir limites: ```txt 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: ```txt 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: ```txt read-only zone-admin record-editor acme-dns01 recipe-runner ``` Token ACME deve ser extremamente limitado. Exemplo: ```json { "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: ```txt 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: ```txt TOTP ``` ### 6 Backups e rollback Toda alteração de zona deve poder ser revertida. Ideal: ```txt 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: ```txt 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: ```txt 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: ```txt Nome | Tipo | Valor | TTL | Prioridade | Ações ``` ### 4 Explicação de erros Exemplo de erro útil: ```txt 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: ```txt Invalid record ``` ### 5 Receitas com prévia Antes de aplicar uma receita, mostrar exatamente o que será criado: ```txt 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: ```txt [Aplicar] [Cancelar] ``` --- ## Stack sugerida ### 1 DNS ```txt PowerDNS Authoritative ``` ### 2 Banco ```txt PostgreSQL ``` ### 3 Backend Boas opções: ```txt Go Python/FastAPI Node.js/NestJS PHP/Laravel ``` Escolha recomendada: ```txt Python/FastAPI ou Go ``` Para produtividade rápida: ```txt Python/FastAPI ``` Para binário simples e performance: ```txt Go ``` ### 4 Frontend Opções: ```txt HTML server-side simples SvelteKit Next.js Django templates Laravel Blade ``` Recomendação pragmática: ```txt SvelteKit ou templates server-side simples ``` Não precisa virar uma SPA monstruosa. ### 5 Proxy ```txt Caddy ``` ou: ```txt Nginx ``` ### 6 Monitoramento ```txt Uptime Kuma Prometheus Grafana ``` ### 7 Deploy Opções: ```txt Docker Compose Systemd direto Ansible ``` Para MVP: ```txt Docker Compose ``` Para produção mais controlada: ```txt Ansible + systemd + backups ``` --- ## Estrutura de repositório sugerida ```txt 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: ```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: ```yaml 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: ```txt krikri.zone krikri.zone runv.club ``` Evitar usar domínio crítico no começo. Não começar com: ```txt 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: ```bash 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 ```bash dig @ns1.krikri.zone krikri.zone SOA +short ``` ### Consultar NS ```bash dig krikri.zone NS +short ``` ### Consultar contra nameserver específico ```bash dig @ns1.krikri.zone www.krikri.zone A ``` ### Ver caminho de delegação ```bash dig krikri.zone +trace ``` ### Testar TXT ACME ```bash dig _acme-challenge.krikri.zone TXT +short ``` ### Comparar ns1 e ns2 ```bash dig @ns1.krikri.zone krikri.zone SOA +short dig @ns2.krikri.zone krikri.zone SOA +short ``` ### Testar porta 53 TCP ```bash 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: ```txt 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: ```txt portalidea.com.br krikri.zone murad.social serviços com e-mail crítico ``` Usar primeiro: ```txt domínio laboratório domínio descartável subdomínio experimental ``` --- ## MVP recomendado O MVP mais sensato: ```txt 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: ```txt 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 é: ```txt 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 - Caddy DNS providers / libdns: - PowerDNS Authoritative Server: - PowerDNS HTTP API: - PowerDNS PostgreSQL backend: - BIND 9 documentation: - Certbot manual hooks: - Let's Encrypt DNS-01 challenge: