DNS — API v1 i MCP | Dokumentacja Nodea
Moduł DNS udostępnia zarządzanie strefami i rekordami hostowanymi na naszym autorytatywnym klastrze PowerDNS: listowanie stref, podgląd strefy z pełną listą rekordów oraz tworzenie, aktualizację i usuwanie pojedynczych rekordów. Dokument opisuje warstwę REST API v1 (/api/v1/dns) oraz narzędzia MCP z tego modułu.
Uwierzytelnianie i zakresy (scopes)
API v1 uwierzytelnia się tokenem osobistym Passport przez nagłówek Authorization: Bearer <token>. Poziomy dostępu:
infra:read— listowanie stref i podgląd strefy z rekordami (index, show).infra:write— tworzenie, aktualizacja i usuwanie rekordów. Rekord to podrzędna konfiguracja strefy, dlatego jego skasowanie NIE wymagainfra:delete(ten poziom rezerwujemy dla niszczenia całych zasobów, np. urządzeń czy serwerów).
Cały moduł jest dodatkowo bramkowany flagą Pennant features:hosting-suite — wyłączenie pakietu hostingowego ukrywa DNS zarówno w web UI, jak i w API/MCP. Limit zapytań: throttle:api-v1 = 240/min na użytkownika tokenu.
Własność i widoczność (ownership)
Model PowerDnsZone nie ma klasy polityki — dostęp na poziomie wiersza jest twardo zawężony do user_id = użytkownik tokenu. Strefa cudza, systemowa (user_id NULL, wspólna infrastruktura) lub nieznana zwraca zawsze 404 — API nigdy nie potwierdza istnienia cudzej strefy (brak enumeracji między najemcami). Parametr {record} korzysta ze scoped route binding względem {zone}, więc rekord należący do innej strefy zwraca 404 jeszcze przed wejściem do kontrolera.
Zapisy odwzorowują web UI: najpierw zapisywany jest lokalny wiersz (baza jest źródłem prawdy), następnie następuje synchroniczny push do PowerDNS. Błędy transportu są przechwytywane i logowane — nieudany push nie kończy żądania błędem, a stan doreconciliuje zadanie cykliczne.
API v1 — endpointy
| Metoda | Ścieżka | Scope | Opis |
|---|---|---|---|
| GET | /api/v1/dns/zones | infra:read | Lista stref użytkownika, paginowana; z licznikiem rekordów. |
| GET | /api/v1/dns/zones/{zone} | infra:read | Szczegóły strefy wraz z pełną listą rekordów (sort: type, name). |
| POST | /api/v1/dns/zones/{zone}/records | infra:write | Utworzenie rekordu w strefie. Zwraca 201. |
| PATCH | /api/v1/dns/zones/{zone}/records/{record} | infra:write | Częściowa aktualizacja rekordu (tylko przesłane pola). Scoped binding. |
| DELETE | /api/v1/dns/zones/{zone}/records/{record} | infra:write | Usunięcie rekordu (scoped binding). Zwraca 204. |
GET /dns/zones — parametry zapytania
search(string, opcjonalny, max 255) — dopasowanie po nazwie strefy.per_page(int 1–100, domyślnie 20),page(int ≥1).
Odpowiedź: kolekcja DnsZoneResource — pola: id, name, kind, serial (SOA), dnssec (bool), records_count, last_synced_at, created_at, updated_at. W show dochodzi tablica records[] (DnsRecordResource). Konfiguracja wewnętrzna strefy (masters, nsec3param, uchwyt do zdalnego PowerDNS) pozostaje po stronie serwera i nie jest serializowana.
DnsRecordResource — pola rekordu
id, zone_id, name (FQDN), type, content, ttl, priority (nullable), comment (nullable), disabled (bool), created_at, updated_at.
POST/PATCH — parametry ciała rekordu
name(string, max 253) — akceptuje@(apex strefy), gołą etykietę (zostanie dopełniona nazwą strefy) lub pełny FQDN.type(enum) — jeden z:A,AAAA,CNAME,MX,TXT,NS,SRV,CAA,PTR.content(string, max 1000) — adres IP, host docelowy lub wartość tekstowa.ttl(int, 60–604800 s).priority(int, 0–65535, opcjonalny) — dla MX/SRV.comment(string, max 255, opcjonalny).disabled(bool, opcjonalny) — rekord utworzony/oznaczony jako nieserwowany.
POST wymaga kompletu name/type/content/ttl. PATCH jest częściowy — zmienią się wyłącznie przesłane pola (reszta bez zmian), inaczej niż w web UI, gdzie każdorazowo repostowany jest cały rekord.
Kody błędów
401— brak/niepoprawny token.403— brak wymaganego scope.404— nieznana, cudza lub systemowa strefa; rekord z innej strefy (scoped binding).422— walidacja (niedozwolony typ, TTL poza zakresem, zbyt długa nazwa/treść).
Przykłady — API
Lista stref z wyszukiwaniem
curl -s "https://app.nodea.io/api/v1/dns/zones?search=example&per_page=20" \
-H "Authorization: Bearer $NODEA_TOKEN" \
-H "Accept: application/json"
Utworzenie rekordu A
curl -s -X POST https://app.nodea.io/api/v1/dns/zones/42/records \
-H "Authorization: Bearer $NODEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "www",
"type": "A",
"content": "203.0.113.10",
"ttl": 3600
}'
Rekord MX z priorytetem
curl -s -X POST https://app.nodea.io/api/v1/dns/zones/42/records \
-H "Authorization: Bearer $NODEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "@",
"type": "MX",
"content": "mail.example.com",
"ttl": 3600,
"priority": 10
}'
Częściowa aktualizacja (tylko TTL)
curl -s -X PATCH https://app.nodea.io/api/v1/dns/zones/42/records/1001 \
-H "Authorization: Bearer $NODEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "ttl": 300 }'
MCP — narzędzia
Narzędzia MCP dzielą model uwierzytelniania i zakresów z API v1 (Bearer + scope sprawdzany w ensureScope) oraz flagę features:hosting-suite (narzędzie na nieaktywnej fladze znika z tools/list). Strefy i rekordy są adresowane po całkowitych identyfikatorach; brakujący, cudzy i systemowy identyfikator zwracają ten sam błąd (brak enumeracji między najemcami). Odpowiedzi zapisów zawierają flagę synced — false oznacza push odroczony do reconcilera, nie błąd.
| Narzędzie | Scope | Tryb | Opis |
|---|---|---|---|
| dns-zones-list | infra:read | read-only | Lista stref; filtr search, page, per_page (max 50). Zwraca id/nazwę/kind/serial/dnssec/licznik/last_synced. |
| dns-zone-get | infra:read | read-only | Strefa wraz z każdym rekordem (sort type, name). Param: id. |
| dns-record-create | infra:write | zapis | Dodanie rekordu; zone_id, name, type, content, ttl, opcjonalnie priority/comment/disabled. |
| dns-record-update | infra:write | idempotentne (pełny replace) | Podmiana rekordu; name/type/content/ttl wymagane za każdym razem (odczytaj wcześniej przez dns-zone-get). |
| dns-record-delete | infra:write | destrukcyjne | Usunięcie rekordu; wymaga confirm: true. Nazwa przestaje się rozwiązywać natychmiast. |
Przykład — MCP (JSON-RPC)
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "dns-record-create",
"arguments": {
"zone_id": 42,
"name": "www",
"type": "A",
"content": "203.0.113.10",
"ttl": 3600
}
}
}
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "dns-record-delete",
"arguments": { "zone_id": 42, "record_id": 1001, "confirm": true }
}
}