---
title: "Podłączanie serwerów wtyczką nodeaD — API v1 | Dokumentacja Nodea"
description: "Reference przycisku „Połącz z panelem nodea”: przepływ OAuth z PKCE i ekranem zgody, scope fleet:enroll, endpoint POST /api/v1/fleet/enrollments, biała lista env agenta i kody błędów."
url: "https://nodea.pl/pl/dokumentacja-api/fleet-enrollments"
lang: "pl"
updated: "2026-10-27"
---

# Podłączanie serwerów wtyczką nodeaD — API v1 | Dokumentacja Nodea

> Jak wtyczka nodeaD dla DirectAdmin, cPanel i WHM podłącza istniejący serwer do panelu: OAuth z PKCE i obowiązkową zgodą, jednorazowy scope fleet:enroll, endpoint enrollmentu, pakiet startowy agenta, przejęcie działającego agenta z potwierdzeniem mailem, historia podłączeń, przeniesienie haseł baz i kody błędów.

**Podłączanie serwerów wtyczką nodeaD** to przycisk „Połącz z panelem nodea” we wtyczce nodeaD dla **DirectAdmin**, **cPanel** i **WHM**. Administrator serwera klika przycisk, loguje się w panelu Nodea, wybiera konto oraz **istniejący** serwer z panelu, a wtyczka dostaje jednorazowy pakiet startowy agenta i sama kończy rejestrację. Dokument opisuje przepływ OAuth, endpoint POST /api/v1/fleet/enrollments, kształt odpowiedzi i kody błędów. Z tej ścieżki korzysta wyłącznie wtyczka nodeaD — **nie ma odpowiednika w MCP** ani w tokenach osobistych.

## Uwierzytelnianie i scope fleet:enroll

- Klient OAuth: **„nodeaD server plugin”**, stały identyfikator 019ea33a-c0de-7000-8b1a-000000000002, klient publiczny (bez sekretu), wymagane **PKCE S256**, wyłącznie grant authorization\_code (bez refresh tokenu).
- Jedyny dopuszczalny scope to fleet:enroll — żądanie z jakimkolwiek innym zakresem (albo bez niego) kończy się 403 jeszcze przed ekranem zgody. Żaden inny klient (także zarejestrowany dynamicznie przez DCR) nie może żądać fleet:enroll.
- Scope fleet:enroll **nie jest dostępny dla tokenów osobistych** i nie pojawia się w ustawieniach Tokenów API.
- Token klienta wtyczki działa **wyłącznie** na POST /api/v1/fleet/enrollments. Każda inna trasa /api/\* (także GET /api/v1/me) i serwer MCP /mcp (także whoami) odpowiadają 403 z kodem token\_restricted.
- Token dostępowy jest **jednorazowy**: po udanym wywołaniu endpointu panel unieważnia go (razem z ewentualnymi refresh tokenami). Ponowienie tym samym tokenem dostaje 401.
- Ścieżka działa na hoście aplikacji (https://app.nodea.io, za Cloudflare) — bez mTLS. Adres panelu po stronie wtyczki jest stały, z nadpisaniem w konfiguracji do testów (https://dev-app.nodea.io).

## Przepływ krok po kroku

1. Wtyczka generuje state (co najmniej 43 znaki \[A-Za-z0-9\_-\], ≥ 32 losowe bajty), code\_verifier i code\_challenge (S256) oraz pokazuje **kod parowania** wyliczony ze state: XXXX-XXXX = pierwsze 8 znaków SHA-256(state) wielkimi literami.
2. Wtyczka otwiera w przeglądarce GET /oauth/authorize z parametrami OAuth i danymi serwera (tabela niżej).
3. Panel pokazuje **obowiązkowy ekran zgody** (nigdy nie jest pomijany): kod parowania, dane serwera opisane jako *niezweryfikowane — podane przez serwer*, wybór konta i **istniejącego** serwera. Serwer z agentem o tym samym odcisku maszyny albo z tą samą nazwą hosta jest oznaczony jako pasujący i pokazany na górze listy — to tylko podpowiedź: panel niczego nie zaznacza sam, serwer zawsze wybiera użytkownik. Gdy w koncie nie ma serwerów do podłączenia, ekran mówi to wprost i nie pozwala zatwierdzić.
4. Po „Autoryzuj” panel zapisuje wybór przy skrócie state (ważny **15 minut**, przypięty do użytkownika i klienta) i przekierowuje na relay /oauth/desktop/callback. Wtyczka odbiera kod z GET /api/oauth/desktop/code?state=… (jednorazowo, 120 s).
5. Wtyczka wymienia kod w POST /oauth/token (grant\_type=authorization\_code, client\_id, redirect\_uri, code\_verifier, code).
6. Wtyczka woła POST /api/v1/fleet/enrollments z tokenem i dostaje pakiet startowy agenta.
7. Wtyczka zapisuje /etc/nodead/ca-bundle.pem, /etc/default/nodead (z obiektu env) i /etc/nodead/bootstrap.env, po czym agent woła istniejące POST /api/fleet/enroll (bez zmian) w ciągu 5 minut.

### Parametry GET /oauth/authorize

ParametrWymaganyReguła response\_typetakcode client\_idtak019ea33a-c0de-7000-8b1a-000000000002 redirect\_uritakhttps://app.nodea.io/oauth/desktop/callback (adres panelu danego środowiska + /oauth/desktop/callback) scopetakdokładnie fleet:enroll statetak43–512 znaków \[A-Za-z0-9\_-\] code\_challenge, code\_challenge\_methodtakPKCE, metoda S256 nodead\_hostnametaknazwa hosta, do 253 znaków, litery, cyfry, . i -; panel zapisuje ją małymi literami nodead\_ipstakadresy IPv4/IPv6 rozdzielone przecinkami, 1–16 pozycji, bez powtórzeń, łącznie do 1024 znaków nodead\_paneltakdirectadmin | cpanel | whm nodead\_fingerprinttakSHA-256 maszyny od nodeaD: 64 znaki \[0-9a-f\] nodead\_versionniedo 64 znaków \[0-9A-Za-z.+\_-\]

Nieprawidłowe dane serwera = ekran z komunikatem błędu i bez możliwości zatwierdzenia.

## Kto może podłączyć serwer

- **Konto**: konto, którego jesteś właścicielem, albo konto, w którym masz uprawnienie manageproducts. Konta zamknięte nie są pokazywane.
- **Tylko istniejące serwery**: wtyczka podłącza wyłącznie serwery, które już są w panelu (VM, serwer dedykowany, host operatora albo inny istniejący rekord). Panel nie tworzy nowych serwerów — zgoda bez wskazania istniejącego serwera kończy się 422 z kodem foreign\_servers\_disabled.
- **Istniejący serwer**: serwer wybranego konta, którym możesz zarządzać (VM konta albo serwer, którego właścicielem jest właściciel konta). Hypervisory Proxmox nie są dostępne — mają własną ścieżkę agenta.
- Host, który ma **zarejestrowanego agenta w innym koncie**, nie zostanie przejęty — najpierw trzeba odłączyć agenta („Odłącz agenta” na stronie serwera) w tamtym koncie. Panel rozpoznaje taki host po odcisku maszyny, a także po zgłoszonej nazwie hosta (pełna nazwa z kropką) i publicznych adresach IP porównanych **wyłącznie z danymi zweryfikowanymi przez panel**: adresem serwera, adresem VM, głównym adresem serwera dedykowanego oraz inwentarzem agenta przesłanym przez mTLS (nazwa hosta porównywana jest tylko z nazwą z tego inwentarza) — nigdy z nazwą serwera wpisaną w panelu (nie jest weryfikowana) ani z nazwą hosta i adresami zgłoszonymi wcześniej przez wtyczkę. Liczą się tylko agenci, którzy się zarejestrowali (mają certyfikat). Odpowiedź 409 server\_connected\_elsewhere nie ujawnia, o które konto chodzi.
- Hosty operatora (współdzielone hosty hostingowe) można podłączyć do wybranego konta; zachowują oznaczenie hosta operatora, nie zmieniają statusu po podłączeniu, a klucze SSH klientów nie są na nie wysyłane.
- **Status serwera**: zwykły serwer w statusie „nowy” przechodzi w „połączony” przy pierwszym kontakcie nowego agenta (pierwsza telemetria z inwentarzem). Host operatora nigdy nie zmienia statusu; serwery w innych statusach zostają bez zmian.

## Endpoint POST /api/v1/fleet/enrollments

Scope fleet:enroll, flaga funkcji servers, limit **10 żądań na minutę** na użytkownika (oprócz globalnego throttle:api-v1). Token musi pochodzić od klienta wtyczki nodeaD. Adres źródłowy połączenia z tym endpointem decyduje o przeniesieniu haseł baz danych (sekcja „Ponowne podłączenie”) — wtyczka powinna wołać endpoint z samego serwera. Ten sam adres decyduje, czy zastąpienie działającego agenta wymaga potwierdzenia właściciela konta (sekcja „Przejęcie działającego agenta”).

### Treść żądania (JSON)

PoleTypReguła statestringten sam state co w /oauth/authorize (22–512 znaków) hostnamestringjak nodead\_hostname; musi być taki sam jak na ekranie zgody (bez rozróżniania wielkości liter) ipsstring\[\]1–16 adresów IP, bez powtórzeń machine\_fingerprintstring64 znaki \[0-9a-f\]; musi być taki sam jak na ekranie zgody panel\_typestringdirectadmin | cpanel | whm; musi być taki sam jak na ekranie zgody agent\_versionstringdo 64 znaków \[0-9A-Za-z.+\_-\] capabilitiesstring\[\]do 128 pozycji, każda do 64 znaków \[a-z0-9\_.-\] (może być pusta lista) curl -X POST https://app.nodea.io/api/v1/fleet/enrollments \\ -H "Authorization: Bearer \<token z /oauth/token\>" \\ -H "Content-Type: application/json" \\ -d '{"state":"…","hostname":"da1.example.com","ips":\["203.0.113.10"\], "machine\_fingerprint":"a3f1…","panel\_type":"directadmin", "agent\_version":"0.2.0-nodeaD+1a2b3c4d5e6f","capabilities":\["agent.ping"\]}'

### Odpowiedź 201 Created

{ "data": { "agent\_uuid": "8b1d…", "server\_id": "9c2e…", "wrapping\_token": "s.xxxxx", "expires\_at": "2026-10-26T12:05:00+00:00", "ca\_bundle": "-----BEGIN CERTIFICATE-----\\n…", "control\_plane\_url": "https://fleet.nodea.io:9443", "env": { "CONTROL\_PLANE\_URL": "https://fleet.nodea.io:9443", "REVERB\_WS\_URL": "wss://app.nodea.io:443", "REVERB\_APP\_KEY": "…", "NODEAD\_REVERB\_ORIGIN": "…", "NODEAD\_LOG\_LEVEL": "info" }, "db\_secrets": "transferred" } }

- wrapping\_token — jednorazowy token OpenBao ważny **5 minut** (expires\_at); trafia do BAO\_WRAPPING\_TOKEN w /etc/nodead/bootstrap.env razem z AGENT\_UUID, CONTROL\_PLANE\_URL i CA\_BUNDLE\_PATH=/etc/nodead/ca-bundle.pem. Panel nigdy go nie zapisuje ani nie loguje. Odpowiedź ma nagłówek Cache-Control: no-store.
- ca\_bundle — łańcuch CA control plane tego środowiska (do /etc/nodead/ca-bundle.pem).
- control\_plane\_url (i CONTROL\_PLANE\_URL w env) — adres mTLS floty, uzgodniony z nodea-fw: panel app.nodea.io zwraca adres z hostem fleet.nodea.io, panel dev-app.nodea.io — z hostem dev-app.nodea.io. Zawsze https, port dowolny (dziś 9443), bez ścieżki, query i danych logowania w adresie. Inny host dla danego panelu = wtyczka odmawia zapisania pakietu. Zmiana nazwy floty (bao.fleet\_control\_plane\_url / FLEET\_CONTROL\_PLANE\_URL) wymaga wcześniejszego wydania nodeaD i uzgodnienia z nodea-fw.
- env — zawartość /etc/default/nodead, filtrowana białą listą endpointu (kontrakt z nodea-fw, runner/env.go); wartości z konfiguracji środowiska, do którego się logujesz. Wymagane: Opcjonalne (tylko gdy panel je generuje; dziś NODEAD\_REVERB\_ORIGIN i NODEAD\_LOG\_LEVEL): Odpowiedź **nigdy** nie zawiera: CA\_BUNDLE\_PATH, NODEAD\_HOME, NODEAD\_STATE\_DIR, NODEAD\_SECRETS\_DIR, NODEAD\_SELF\_BINARY\_PATH, NODEAD\_TELEMETRY\_DISK\_PATH, NODEAD\_SELF\_UPDATE (dla żadnego hosta w tej ścieżce), NODEAD\_ZFS\_KMS\_\*, NODEAD\_PVE\_TRYB, NODEAD\_SECRETS\_ROTATION\_ENABLED.
  - CONTROL\_PLANE\_URL — adres mTLS control plane floty;
  - REVERB\_WS\_URL — adres WebSocket (Reverb) panelu;
  - REVERB\_APP\_KEY — klucz aplikacji Reverb.
  - NODEAD\_REVERB\_ORIGIN — nagłówek Origin połączenia WebSocket agenta;
  - NODEAD\_LOG\_LEVEL — poziom logowania (info);
  - NODEAD\_TELEMETRY\_INTERVAL, NODEAD\_WAF\_EVENTS\_INTERVAL, NODEAD\_UPDATE\_CHECK\_INTERVAL, NODEAD\_RENEW\_CHECK\_INTERVAL, NODEAD\_RENEW\_THRESHOLD, NODEAD\_ENROLL\_RETRY\_INTERVAL.
- db\_secrets — co stało się z hasłami baz danych poprzedniego agenta: none (nie było czego przenosić), transferred (przeniesione na nowego agenta), not\_transferred (warunek bezpieczeństwa niespełniony — hasła baz trzeba ustawić ponownie), transfer\_failed (błąd kopii — stare hasła zostały nietknięte, hasła baz trzeba ustawić ponownie).

### Ponowne podłączenie tego samego hosta

Podłączenie zawsze trafia do **wybranego, istniejącego rekordu serwera** — panel nie tworzy duplikatu i nie zmienia adresu serwera. Poprzedni agent dostaje stan „odwołany”, a jego certyfikat zostaje unieważniony. Od serwera jest odpinany dopiero po udanym przeniesieniu haseł baz (albo gdy nie miał haseł) — przy odmowie lub błędzie przeniesienia zostaje przypięty, żeby usunięcie serwera wyczyściło jego hasła, a późniejsze legalne podłączenie mogło je jeszcze przenieść. Niezarejestrowany jeszcze agent z wcześniejszej próby jest używany ponownie. Dwa równoległe podłączenia tego samego serwera nie zostawią dwóch aktywnych agentów: drugie dostaje 409 enrollment\_in\_progress.

**Hasła baz danych** zapisane dla poprzedniego agenta (także agenta odłączonego przyciskiem „Odłącz agenta”) przechodzą na nowego agenta **tylko wtedy, gdy nowa maszyna jest wiarygodnie tą samą maszyną**:

- adres źródłowy połączenia z POST /api/v1/fleet/enrollments jest jednym z głównych adresów IP serwera w panelu (adres serwera, adres VM albo główny adres serwera dedykowanego) — tego adresu nie da się podać w treści żądania, więc obca maszyna (np. po wyłudzeniu zgody) go nie spełni;
- jeśli poprzedni agent miał zapisany odcisk maszyny, musi on być równy zgłoszonemu.

Po przejęciu **potwierdzonym przez właściciela konta** (sekcja niżej) warunek adresu nie obowiązuje — właściciel świadomie przekazuje hasła nowej maszynie; warunek odcisku obowiązuje nadal.

Gdy warunek jest spełniony, panel kopiuje hasła, sprawdza kopię odczytem i dopiero wtedy usuwa skopiowane wpisy starego agenta (db\_secrets: transferred). Gdy nie — niczego nie kopiuje ani nie usuwa, stare hasła zostają nietknięte, zdarzenie trafia do dziennika aktywności (kv\_not\_transferred z powodem), a odpowiedź ma db\_secrets: not\_transferred: hasła baz danych trzeba ustawić ponownie w panelu. Odłączenie bez ponownego podłączenia: „Odłącz agenta” na stronie serwera — może to zrobić także właściciel konta na hoście operatora; każde odłączenie jest szczegółowo zapisywane w dzienniku aktywności.

### Przejęcie działającego agenta — potwierdzenie mailem

Gdy wybrany serwer ma **zarejestrowanego, nieodwołanego agenta**, a adres źródłowy żądania **nie** jest głównym adresem IP serwera w panelu, panel nie zastępuje agenta od razu (ochrona przed zgodą wyłudzoną phishingiem):

1. Endpoint odpowiada 202 Accepted i **niczego nie zużywa** (ani wyboru, ani tokenu): { "message": "…", "code": "takeover\_confirmation\_required", "data": { "takeover\_id": "0b7c…", "expires\_at": "2026-10-26T13:00:00+00:00", "retry\_after": 15 } } Odpowiedź ma też nagłówek Retry-After równy data.retry\_after (pełne sekundy, 5–60).
2. **Właściciel konta** serwera dostaje e-mail (w swoim języku): kto, kiedy i z jakiego adresu IP chce podłączyć serwer, zgłoszona nazwa hosta i adresy, ostrzeżenie o phishingu oraz linki „Potwierdź przejęcie” i „To nie ja — odrzuć”. Jeśli podłącza ktoś inny niż właściciel, dostaje ten sam e-mail informacyjnie, bez linków decyzji.
3. Link jest podpisany i jednorazowy, ważny **60 minut** (nie dłużej niż token OAuth wtyczki). Prowadzi do strony w panelu, która wymaga zalogowania jako właściciel konta z prawem zarządzania serwerem; samo otwarcie linku niczego nie zatwierdza — decyduje dopiero przycisk. Te same przyciski są w sekcji agenta na stronie serwera.
4. Wtyczka ponawia **ten sam** POST (ten sam token i state) co retry\_after sekund: dopóki przejęcie czeka — 202; po potwierdzeniu — zwykłe 201 (agent zastąpiony, hasła baz przenoszone mimo innego adresu, jeśli zgadza się odcisk); po odrzuceniu — 403 takeover\_rejected; po wygaśnięciu — 410 takeover\_expired. Wybór ze zgody żyje tak długo jak oczekujące przejęcie.
5. Przejęcie staje się **nieaktualne** (ponowienie → 410 takeover\_expired, trzeba zacząć od nowa), gdy serwer zostanie w międzyczasie podłączony inną drogą (z głównego adresu IP serwera albo innym dokończonym przejęciem) albo gdy agent, którego dotyczyło, w chwili ponowienia nie jest już bieżącym agentem serwera (np. został odłączony lub zastąpiony).
6. Jeśli między sprawdzeniem a samym podłączeniem na serwerze zarejestruje się agent, a żądanie nie przyszło z głównego adresu IP serwera, endpoint odpowiada 409 enrollment\_in\_progress i niczego nie zużywa — ponowienie dostaje wtedy 202 i wymaga potwierdzenia właściciela.
7. Na serwer czeka naraz najwyżej jedno przejęcie — kolejne żądanie innej zgody dostaje 409 takeover\_pending. Ponowienia podlegają limitowi 10 żądań na minutę.

Podłączenie z głównego adresu IP serwera (albo serwera bez zarejestrowanego agenta) działa jak dotąd, bez e-maila.

### Historia podłączeń

Sekcja agenta na stronie serwera pokazuje historię: podłączenia wtyczką, przejęcia (oczekujące, potwierdzone, odrzucone, wygasłe, nieaktualne, wykonane) i odłączenia — kto, kiedy, z jakiego adresu IP, wynik i czy hasła baz przeniesiono. Klient i administrator widzą tę samą listę; potwierdzić albo odrzucić oczekujące przejęcie może tylko właściciel konta.

## Kody błędów

Błędy mają kopertę {"message": "…", "code": "…"}, błędy walidacji (422) — {"message": "…", "errors": {…}}. Odmowy 4xx i 503 niczego nie zużywają — token i wybór zostają ważne do wygaśnięcia (wybór 15 min, token 1 h).

StatuscodeKiedy 202takeover\_confirmation\_requiredserwer ma działającego agenta, a żądanie nie przyszło z adresu IP serwera — właściciel konta dostał e-mail; ponów ten sam POST po retry\_after s (pola data.takeover\_id, data.expires\_at, data.retry\_after) 401—brak tokenu, token odwołany lub już użyty 403—token bez scope'a fleet:enroll 403invalid\_clienttoken nie pochodzi od klienta wtyczki nodeaD 403server\_forbiddenmiędzy zgodą a wywołaniem utracono prawo do konta lub serwera 403takeover\_rejectedwłaściciel konta odrzucił przejęcie agenta 404enrollment\_not\_foundbrak zatwierdzonej zgody dla tego state, użytkownika i klienta 403token\_restrictedtoken klienta wtyczki użyty na innej trasie niż POST /api/v1/fleet/enrollments (dowolna inna trasa /api/\*, /mcp) 409enrollment\_usedzgoda została już wykorzystana 409enrollment\_mismatchnazwa hosta, odcisk albo panel różnią się od zatwierdzonych 409server\_connected\_elsewherehost ma zarejestrowanego agenta w innym koncie (po odcisku maszyny, nazwie hosta albo publicznym IP zweryfikowanym przez panel) 409enrollment\_in\_progressten sam serwer jest właśnie podłączany innym żądaniem albo w międzyczasie zarejestrował się na nim agent — ponów za chwilę 409fingerprint\_conflictwybrano serwer, a maszyna ma aktywnego agenta na innym serwerze tego konta 409pve\_host\_unsupportedwybrany serwer jest hypervisorem Proxmox 409takeover\_pendinginne przejęcie agenta tego serwera czeka już na potwierdzenie właściciela 410enrollment\_expiredzgoda wygasła (15 min) 410takeover\_expiredprzejęcie nie zostało potwierdzone w ciągu 60 minut albo jest nieaktualne (agent serwera zmienił się w międzyczasie) — rozpocznij połączenie od nowa 422foreign\_servers\_disabledzgoda nie wskazuje istniejącego serwera — wtyczka podłącza tylko serwery już obecne w panelu 422—walidacja pól (errors) 429—limit zapytań 503control\_plane\_unavailableusługa rejestracji agentów (OpenBao) chwilowo niedostępna — ponów

## Powiązane

- [Serwery — API v1 i MCP | Dokumentacja Nodea](https://nodea.pl/pl/dokumentacja-api/servers)
- [API Nodea v1 — wprowadzenie: base URL, tokeny, scope'y, limity | Nodea](https://nodea.pl/pl/dokumentacja-api/overview)
- [Klucze SSH — API v1 i MCP | Dokumentacja Nodea](https://nodea.pl/pl/dokumentacja-api/ssh-keys)

---

Wersje językowe: [en](https://nodea.io/en/api-docs/fleet-enrollments.md)  
Spis treści witryny: [llms.txt](https://nodea.pl/pl/llms.txt)
