SSD Nodes Learn Hosting plans →
Przewodniki Matt ConnorAutor: Matt Connor · Zaktualizowano 2026-08-28

Samodzielny hosting OpenBot AI na VPS: konfiguracja

Dowiedz się, jak uruchomić OpenBot AI na własnym VPS. Każdy agent otrzymuje osobny kontener i przegladarkę Chromium. Sprawdź, jak brama zarządza akcjami i ile RAM zużywa bot.

Co zyskujesz, hostując samodzielnie współpracowników OpenBot AI

Samodzielne hostowanie współpracowników OpenBot AI polega na uruchomieniu jednego serwera bramy oraz jednego kontenera na każdego bota na sprzęcie, którym zarządzasz. Każdy kontener bota posiada własną przeglądarkę Chromium oraz dedykowany wolumen obszaru roboczego z profilem przeglądarki, który jest zachowywany między sesjami. Każde działanie podejmowane przez bota na komputerze, w pliku, na serwerze MCP (model context protocol) lub w komponencie interfejsu użytkownika przechodzi przez tę bramę, która weryfikuje je zgodnie z polityką przed wykonaniem i rejestruje po jego zakończeniu. Jeśli pętla agenta, którą otacza brama, jest wciąż nieznanym obszarem, ścieżka szkoleniowa w uczenie się agentów AI od podstaw pozwoli Ci samodzielnie napisać prostą wersję, zanim przekażesz botowi przeglądarkę i swoje dane logowania.

OpenBot jest publikowany przez CopilotKit na licencji MIT pod adresem github.com/CopilotKit/openbot. Pierwsze otagowane wydanie, v0.0.1, zostało opublikowane 17 sierpnia 2026 roku, a projekt określa się jako wersję alfa w fazie aktywnego rozwoju. Należy traktować go jako przemyślany projekt z wczesnymi niedociągnięciami.

Ciekawa część tej architektury jest jednocześnie jej kosztownym elementem. Przeglądarka dla każdego agenta to koszt pamięci, o którym większość osób zapomina podczas planowania, dlatego przed instalacją należy odpowiednio dobrać zasoby.

W jaki sposób bramka podejmuje każdą decyzję

Serwer API na porcie 3001 stanowi jedyną ścieżkę dostępu do komputera bota. Zanim zostanie wykonana akcja w przeglądarce, bramka ustala cel na podstawie zrzutu strony, ocenia reguły polityki CEL (common expression language) w odniesieniu do kontekstu, zapisuje wiersz audytu zawierający decyzję i dopiero wtedy wywołuje kontener. Jeśli po tym kroku wykonanie zakończy się niepowodzeniem, zapisywany jest drugi wiersz. Dokumentacja jasno określa granicę: komputer nie decyduje o polityce, to bramka serwera stanowi granicę akcji. Ten podział posiada nazwę poza OpenBot, ponieważ pętla, definicje narzędzi, sprawdzanie uprawnień oraz stan sesji tworzą razem mechanizm otaczający model, a niniejsza bramka stanowi połowę tego mechanizmu odpowiedzialną za uprawnienia.

Polityka opiera się na domyślnej odmowie (deny-by-default), a reguły odmowy są oceniane przed regułami zezwalającymi. Kierunek niepowodzenia ma większe znaczenie niż składnia reguły. Brakująca polityka nie zezwala na nic, a uszkodzona reguła skutkuje zablokowaniem, niezależnie od tego, czy jest to reguła odmowy, czy zezwolenia. Dzięki temu błąd w polityce skutkuje zablokowaniem bota, a nie jego niekontrolowanym działaniem na Twoich kontach. Ta warstwa zarządza tym, co bot robi, a nie tym, co odczytuje. Strona zawierająca instrukcje skierowane do agenta pozostaje zatem odrębnym problemem, co stanowi tę samą powierzchnię ataku typu prompt injection, z którą masz do czynienia, gdy przekazujesz agentowi wyniki z własnej instancji SearXNG.

Ścieżka audytu znajduje się w PostgreSQL, dzięki czemu przetrwa restart. Przekazanie kontroli jest rejestrowane jako computer.help_requested, computer.control_taken oraz computer.control_released; w ten sposób można sprawdzić, kiedy bot prosi o pomoc człowieka oraz kiedy człowiek odzyskuje kontrolę. Sekrety są rejestrowane jako liczba znaków, nigdy jako wartości. Operacje na plikach rejestrują ścieżkę oraz rozmiar, nigdy zawartość. Jeśli wymagasz tej samej granicy kontroli bez przeglądarki w tle, artykuł gating AI agent actions behind approvals omawia ten węższy przypadek.

Koszt jednego bota w pamięci RAM i na dysku

Projekt publikuje zmierzone wartości dla pojedynczego bota na architekturze arm64. Są to jedyne liczby dotyczące rozmiaru, jakie udostępnia OpenBot. Opisują one jednego bota na jednej architekturze, więc należy traktować je jako punkt wyjścia, a nie jako plan wydajnościowy.

ChartOpenBot published resource figures, one Bot on arm64 (August 2026)
The data behind this chart
[
  {
    "label": "Measured, one Bot",
    "memory_gb": 0.55,
    "disk_gb": 5.3,
    "vcpu": 0.06
  },
  {
    "label": "Documented minimum",
    "memory_gb": 2,
    "disk_gb": 8,
    "vcpu": 1
  },
  {
    "label": "Documented recommended",
    "memory_gb": 4,
    "disk_gb": 10,
    "vcpu": 2
  }
]

Szczytowe zużycie pamięci dla jednego bota zmierzono na poziomie 0.55 GB, podczas gdy udokumentowane minimum wynosi 2 GB, a zalecana wartość to 4 GB. Różnica między pomiarem a minimum stanowi margines na wzrost zapotrzebowania Chromium pod obciążeniem, ponieważ zużycie pamięci przez przeglądarkę zależy od otwartych stron, a nie od procesu w stanie spoczynku. Zużycie procesora w stanie bezczynności jest bliskie zeru i wynosi 0.06 rdzenia w górnej granicy pomiaru, więc to nie CPU jest głównym kosztem. Jest nim dysk. Sam obraz zajmuje 5.3 GB, przy zalecanej objętości wolumenu 10 GB. Obraz jest tak duży, ponieważ zawiera pliki binarne Playwright dla Firefox i WebKit obok Chromium.

Żadna z tych wartości nie określa kosztu działania kilku botów jednocześnie, a projekt nie publikuje takich danych. Udokumentowane minimum to liczba, którą projekt bezpiecznie podaje, a nie wynik obserwacji pod obciążeniem. Dlatego właśnie wybór między PhotoPrism a Immich sprowadza się do zmierzonego zużycia pamięci RAM, a nie do wartości publikowanych. Przeprowadź własne pomiary. Uruchom jednego bota, przydziel mu rzeczywiste zadanie z otwartą stroną i monitoruj kontener podczas pracy.

docker stats --no-stream
free -m

Przyjmij wartość z kolumny MEM USAGE dla kontenera bota jako koszt jednostkowy, dodaj do tego wymagania gateway oraz PostgreSQL, a następnie pomnóż wynik przez liczbę botów, które mają działać jednocześnie. Nawet bezczynny bot utrzymuje proces przeglądarki, więc mnożnik dotyczy wszystkich istniejących botów, a nie tylko tych aktualnie zajętych. Obliczenia są identyczne z tymi, które stosuje się przy doborze RAM i CPU dla agenta programistycznego na VPS, a kwestie związane z przeglądarką omówiono w uruchamianiu przeglądarki bez interfejsu graficznego dla agentów na VPS.

Jeden szczegół dotyczący Chromium wpływa na małe plany. OpenBot uruchamia Chromium z flagą --disable-dev-shm-usage, dzięki czemu przeglądarka zapisuje dane w /tmp zamiast w /dev/shm. Pozwala to uniknąć awarii występujących na hostach z małym /dev/shm i przenosi obciążenie na główny system plików. Jest to kolejny powód, dla którego zalecana przestrzeń dyskowa jest większa niż sam obraz.

Jak samodzielnie hostować OpenBot na VPS?

Wymagane są Docker, Bun 1.3 lub nowszy, projekt CopilotKit Intelligence oraz klucz API modelu. Dokumentacja programistyczna wymaga również obecności lsof, python3 oraz curl w systemie. Należy sklonować oznaczoną wersję (tagged release) zamiast main, ponieważ main w projektach w fazie alfa zmienia się bez ostrzeżenia.

git clone --branch v0.0.1 https://github.com/CopilotKit/openbot.git
cd openbot
cp .env.example .env

Przygotuj projekt Intelligence. Te trzy polecenia zapisują klucz środowiskowy oraz token licencyjny w pliku środowiskowym.

npx --yes copilotkit@latest login
npx --yes copilotkit@latest project select
npx --yes copilotkit@latest license --write

Wygeneruj klucz szyfrujący przechowywane dane uwierzytelniające i umieść wynik w .env jako KEY_ENCRYPTION_KEY. Dodaj swój OPENAI_API_KEY w tym samym pliku lub ustaw BOT_PROVIDER na anthropic lub google wraz z pasującym kluczem.

openssl rand -base64 32

Następnie przeprowadź instalację i uruchomienie.

bun install
bash scripts/start.sh

scripts/start.sh uruchamia usługi Docker, wykonuje migracje bazy danych, startuje serwer oraz aplikację, a także sprawdza ich stan. Po zakończeniu operacji aplikacja odpowiada na porcie 3010, a API na porcie 3001. Skrypt zgłasza konflikty portów i pomija już działające usługi, więc jego ponowne uruchomienie jest bezpieczne.

Przetestuj działanie z poziomu serwera przed wystawieniem usług na zewnątrz.

curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3010
ss -ltnp | grep -E ':(3010|3001|4100|4500|5432)'

200 w odpowiedzi na pierwsze polecenie oznacza, że aplikacja działa. Drugie polecenie wskazuje, do jakich adresów przypisane są te porty, co jest kluczową informacją w przypadku VPS. Wiersz zawierający 127.0.0.1:3001 oznacza dostępność wyłącznie lokalną. Wiersz zawierający 0.0.0.0:3001 oznacza, że usługa jest dostępna dla każdego, kto posiada trasę sieciową do serwera.

Pojedynczy obraz kontenera

Dokumentacja wdrożeniowa udostępnia również pojedynczy obraz zawierający aplikację, API oraz Chromium, działający na porcie 3001.

docker build -t openbot .
docker run -p 127.0.0.1:3001:3001 --env-file .env \
  -e EMBEDDED_POSTGRES=on -v openbot-data:/var/lib/postgresql/data openbot

EMBEDDED_POSTGRES=on uruchamia PostgreSQL wewnątrz kontenera i wykonuje migracje podczas startu. Nazwany wolumen przechowuje historię audytu po ponownym wdrożeniu; bez niego każda przebudowa powoduje utratę tej historii. Jeśli wskażesz DATABASE_URL na zewnętrzną bazę danych, musi być na niej włączone rozszerzenie vector. Usługi zarządzane, takie jak RDS, Cloud SQL oraz Azure Database, obsługują to rozszerzenie, jednak żadna z nich nie włącza go automatycznie. W rezultacie migracja na świeżej bazie danych zakończy się niepowodzeniem, ponieważ typ kolumny vector jeszcze nie istnieje.

W przypadku zewnętrznej bazy danych należy uruchamiać migracje jako krok procesu wydawniczego.

docker run --rm --env-file .env openbot \
  sh -c "cd /app/server && bun x drizzle-kit migrate --config=drizzle.config.ts"

Ten obraz celowo nie publikuje portu przeglądarki. Pomija również supervisor, ponieważ wymaga on dostępu do gniazda Docker, czego nie oferują platformy typu serverless. Bez supervisora każdy bot współdzieli jedną przeglądarkę, a tym samym jeden zestaw danych logowania, co eliminuje izolację uzasadniającą stosowanie osobnych kontenerów dla każdego bota. Jeśli powodem korzystania z tego rozwiązania jest potrzeba odrębnych logowań dla każdego bota, należy uruchomić stos compose z ustawionymi zmiennymi COMPUTER_SUPERVISOR_URL oraz SUPERVISOR_TOKEN na hoście, na którym akceptuje się związane z tym ryzyko. Proces mający dostęp do gniazda Docker może uruchomić uprzywilejowany kontener, co w praktyce oznacza uzyskanie uprawnień root na hoście. Jest to istotny powód, aby utrzymywać OpenBot na dedykowanej maszynie, zgodnie z zasadą udostępniania agentom programistycznym tymczasowej maszyny wirtualnej.

Dlaczego OPENBOT_SINGLE_USER jest ustawieniem dla laptopa

.env.example jest dostarczany z OPENBOT_SINGLE_USER=true. To ustawienie traktuje każde żądanie jako żądanie administratora i całkowicie pomija logowanie. Na laptopie jest to udogodnienie, ponieważ jedynym klientem, który może uzyskać dostęp do portu, jesteś Ty. Na serwerze VPS oznacza to, że pierwsza osoba, która połączy się z portem 3010, staje się administratorem systemu przechowującego zaszyfrowane poświadczenia i obsługującego przeglądarkę już zalogowaną na Twoje konta.

Istnieją dwa poprawne sposoby uruchomienia tej aplikacji. Zachowaj OPENBOT_SINGLE_USER=true, powiąż wszystkie porty z 127.0.0.1 i uzyskuj dostęp do aplikacji wyłącznie przez tunel SSH lub prywatny interfejs sieciowy.

ssh -N -L 3010:127.0.0.1:3010 -L 3001:127.0.0.1:3001 you@your-vps

Aplikacja jest wtedy dostępna pod adresem http://localhost:3010 w Twojej przeglądarce, co jest uznawane za bezpieczny kontekst, dzięki czemu pliki cookie logowania oraz funkcje przeglądarki wymagane przez podgląd na żywo działają poprawnie. Drugim sposobem jest wyłączenie trybu jednouserowego i skonfigurowanie rzeczywistego dostawcy tożsamości. Obsługiwane są Google, Microsoft Entra, Okta, SAML oraz OIDC. Każdy dostawca wymaga również BETTER_AUTH_SECRET o długości co najmniej 32 znaków, BETTER_AUTH_URL ustawionego na publiczny bazowy adres URL API dla wywołań zwrotnych OAuth, INITIAL_ADMIN_EMAILS oraz TRUSTED_ORIGINS. Poświadczenia dostawcy muszą być kompletne, ponieważ niepełna konfiguracja dostawcy wstrzymuje uruchomienie aplikacji zamiast powrotu do otwartego dostępu. Jeśli powodem dodawania kont jest chęć posiadania przez każdego członka zespołu własnego agenta zamiast własnej przeglądarki, OneCLI został zaprojektowany w ten sposób od podstaw, z jednym odizolowanym agentem dla każdej osoby i kluczami modelu przechowywanymi w jednej bramie.

Jeśli aplikacja jest dostępna pod publiczną nazwą domenową, należy umieścić przed nią TLS (transport layer security). Strona serwowana przez zwykłe http:// na czymkolwiek innym niż localhost nie stanowi bezpiecznego kontekstu, dlatego pliki cookie oznaczone jako Secure nie są zapisywane, a logowanie kończy się niepowodzeniem, co wygląda jak błąd w OpenBot.

Zabezpieczanie portów niskiego poziomu

Notatka dotycząca bezpieczeństwa OpenBot wskazuje, że punkty końcowe usług niskiego poziomu są chronione tokenami, powinny pozostać prywatne i nie należy ich używać do omijania bramy. Tokeny stanowią drugą linię ochrony. Pierwszą jest uniemożliwienie dostępu do portu.

Komputer agenta nasłuchuje na porcie 4100 i wymaga COMPUTER_TOKEN. Punkty końcowe bota nasłuchują na portach 4200 oraz 4201. Nadzorca nasłuchuje na porcie 4500 na hoście oraz 4300 wewnątrz kontenera. PostgreSQL nasłuchuje na porcie 5432. Żaden z tych portów nie powinien być dostępny na publicznym interfejsie; w przypadku wdrożenia dla jednego użytkownika dotyczy to również aplikacji oraz API.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verbose

Istnieje pułapka, w którą wpadają osoby zakładające, że firewall jest wystarczający. Publikacja portu kontenera za pomocą -p 3001:3001 powoduje, że Docker instaluje regułę DNAT. W rezultacie ruch jest obsługiwany w ścieżce FORWARD i nigdy nie przechodzi przez łańcuch INPUT, który podlega domyślnej polityce odmowy ufw. Port pozostaje otwarty, mimo że ufw status nadal wyświetla Status: active. Powiąż opublikowany port z interfejsem loopback bezpośrednio w mapowaniu, używając -p 127.0.0.1:3001:3001, lub ustaw adres hosta w pliku compose. Weryfikację przeprowadź za pomocą ss -ltnp, a nie ufw status. Ta pułapka nie jest specyficzna dla OpenBot, dlatego wykonaj taką samą kontrolę dla każdego innego kontenera opublikowanego na serwerze, w tym dla usługi udostępniającej bibliotekę Jellyfin przebudowaną na wypożyczalnię kaset wideo z lat 90.

OpenBot nie jest rozwiązaniem typu offline

Uwzględnij to przed zaplanowaniem wdrożenia. OpenBot jest zależny od projektu CopilotKit Intelligence, który przechowuje trwałe wątki oraz historię konwersacji poza Twoim serwerem. Podczas uruchamiania serwer weryfikuje INTELLIGENCE_API_URL, INTELLIGENCE_GATEWAY_WS_URL, INTELLIGENCE_API_KEY oraz COPILOTKIT_LICENSE_TOKEN; wszystkie cztery muszą być obecne jednocześnie, w przeciwnym razie proces startowy zakończy się niepowodzeniem. Według stanu na sierpień 2026 dostępny jest plan darmowy, a samą usługę Intelligence można hostować samodzielnie, więc pełne wdrożenie lokalne jest możliwe, choć wymaga więcej pracy niż zakłada przewodnik typu quickstart.

Modele stanowią drugą zewnętrzną zależność. Pakiet nie zawiera żadnych gotowych rozwiązań. BOT_PROVIDER akceptuje openai, anthropic lub google, a OPENAI_BASE_URL wskazuje ścieżkę OpenAI na dowolny kompatybilny punkt końcowy. W tym miejscu znajduje się uruchamianie Ollama na VPS w celu samodzielnego hostowania LLM, jeśli wymagane jest, aby tokeny pozostały na własnym sprzęcie. Sterowanie przeglądarką stawia wysokie wymagania modelowi, dlatego przed podjęciem decyzji należy przetestować model lokalny w rzeczywistym zadaniu.

Uruchomienie jednej repliki na obecnym etapie

Brama buforuje migawki stron w pamięci procesu serwera. Przy dwóch replikach migawka wykonana przez jeden proces jest niewidoczna dla drugiego, co powoduje sporadyczne błędy typu element-not-found, które wyglądają na losowe. Dokumentacja wdrożeniowa jest jednoznaczna: należy uruchomić pojedynczą replikę i ograniczyć maksymalną liczbę instancji w platformie do 1. To ograniczenie przestanie obowiązywać, gdy buforowanie migawek zostanie przeniesione do bazy danych. Do tego czasu skalowanie OpenBot odbywa się poprzez zwiększenie zasobów maszyny, a nie dodawanie kolejnych jednostek. Izolacja między botami nadal jest zapewniana przez kontenery przypisane do poszczególnych botów, w taki sam sposób, w jaki piaskownice agentów self-hosted chronią przed skutkami błędów jednego agenta w odniesieniu do pozostałych.

Tryby awarii i ich objawy

Proces uruchamiania kończy się natychmiast po wypełnieniu .env. Serwer weryfikuje konfigurację przed rozpoczęciem obsługi jakichkolwiek żądań. Niekompletny blok Intelligence, brakujący KEY_ENCRYPTION_KEY lub dostawca OAuth z identyfikatorem klienta bez klucza tajnego powodują przerwanie uruchamiania zamiast cichej degradacji usług. Należy odczytać pierwszy błąd, poprawić wskazane pole i uruchomić proces ponownie.

Migracje kończą się niepowodzeniem w zarządzanej bazie danych. Rozszerzenie vector nie jest domyślnie włączone, przez co migracja odwołuje się do typu kolumny nieobsługiwanego przez PostgreSQL. Należy połączyć się jako superużytkownik, wykonać CREATE EXTENSION vector;, a następnie ponownie uruchomić krok migracji.

Aplikacja ładuje się, ale logowanie nie jest utrzymywane. Usługa jest udostępniana przez zwykłe http:// na publicznym adresie, co nie stanowi bezpiecznego kontekstu, przez co plik cookie Secure jest odrzucany. Należy wdrożyć TLS przed aplikacją lub użyć tunelu SSH, aby przeglądarka wykryła localhost.

Boty współdzielą loginy, które powinny być odrębne. Supervisor nie działa, więc nie ma odizolowanego środowiska dla każdego bota i wszystkie korzystają ze współdzielonej przeglądarki. Należy potwierdzić, że COMPUTER_SUPERVISOR_URL jest ustawione oraz że supervisor ma dostęp do gniazda Docker.

Bot zatrzymuje się i prosi o pomoc. Jest to zamierzone działanie systemu. Ścieżka audytu rejestruje computer.help_requested, użytkownik przejmuje kontrolę na ekranie na żywo, a przekazanie uprawnień jest rejestrowane po obu stronach.

FAQ

Czy pozostawienie włączonej opcji OPENBOT_SINGLE_USER jest bezpieczne w przypadku wdrożenia na VPS?

Tylko wtedy, gdy bramka nie jest dostępna z Internetu. OPENBOT_SINGLE_USER=true akceptuje każde żądanie jako administratora bez logowania, więc każdy, kto może otworzyć port, przejmuje kontrolę nad wdrożeniem, przechowywanymi poświadczeniami oraz zalogowaną przeglądarką. Jest to dopuszczalne, gdy każdy port jest powiązany z 127.0.0.1, a dostęp do aplikacji uzyskuje się przez tunel SSH lub prywatny interfejs sieciowy. Na publicznym interfejsie należy wyłączyć tę opcję i skonfigurować Google, Microsoft Entra, Okta lub OIDC wraz z BETTER_AUTH_SECRET, BETTER_AUTH_URL, INITIAL_ADMIN_EMAILS oraz TRUSTED_ORIGINS.

Ile pamięci RAM potrzebuje jeden bot OpenBot?

Opublikowane dane projektu dla pojedynczego bota na architekturze arm64 wskazują szczytowe zużycie pamięci na poziomie 0.55 GB, przy czym 2 GB jest udokumentowanym minimum, a 4 GB wartością zalecaną. Nie ma opublikowanych danych dla wielu botów jednocześnie, ponieważ każdy z nich utrzymuje własną instancję Chromium. Należy uruchomić jednego bota w ramach rzeczywistego zadania, odczytać zużycie pamięci kontenera w docker stats, dodać zużycie bramki i bazy danych, a następnie pomnożyć wynik przez liczbę botów, które mają działać jednocześnie.

Czy do samodzielnego hostowania OpenBot potrzebuję konta CopilotKit?

Tak. OpenBot jest zależny od projektu CopilotKit Intelligence w zakresie trwałych wątków i pamięci, a serwer odmawia uruchomienia, jeśli nie ustawiono adresu URL Intelligence API, adresu URL WebSocket bramki, klucza API oraz tokena licencyjnego. Na sierpień 2026 dostępny jest plan darmowy, a Intelligence można hostować samodzielnie, więc zależność od hostowanej usługi można usunąć przy dodatkowym nakładzie pracy. Należy również dostarczyć własny klucz API modelu, ponieważ żaden model nie jest dostarczany wraz z OpenBot.

Dlaczego każdy bot otrzymuje własną przeglądarkę zamiast współdzielić jedną?

Ponieważ profil przeglądarki stanowi tożsamość. Współdzielona przeglądarka oznacza współdzielone pliki cookie i sesje, więc bot zalogowany na konto powoduje, że każdy bot jest zalogowany na to samo konto. Kontenery przypisane do poszczególnych botów zapewniają każdemu pracownikowi własny profil i własne dane logowania. Kosztem jest pamięć, ponieważ instancja Chromium na bota jest największym pojedynczym elementem wpływającym na zapotrzebowanie na zasoby.

Które porty OpenBot powinny być otwarte na firewallu?

Żaden z portów niskiego poziomu. Agent-computer na 4100, punkty końcowe botów na 4200 i 4201, nadzorca na 4500 oraz PostgreSQL na 5432 powinny pozostać prywatne. Projekt zabezpiecza je tokenami i zaleca, aby w każdym przypadku pozostały niedostępne z zewnątrz. Należy publikować tylko to, co jest niezbędne dla użytkownika, pamiętając, że port kontenera opublikowany za pomocą -p 3001:3001 jest dostępny niezależnie od reguły ufw default-deny, ponieważ reguła DNAT w Dockerze kieruje ten ruch ścieżką FORWARD zamiast INPUT.