1. Problem „losowych” tuneli
Gdy pierwszy raz uruchamiasz ngrok http 3000 albo szybki Cloudflare Quick Tunnel, wygląda to jak magia: bach – i twój http://localhost:3000 zamienił się w https://random-1234.tunnelprovider.com. Można skopiować URL do ChatGPT Dev Mode i GPT z radością ładuje twój App.
A potem restartujesz tunel… i dostajesz nową domenę. Stary URL w ustawieniach aplikacji Dev w ChatGPT nagle zamienia się w „martwy link”, GPT uczciwie pisze „App unavailable”, a ty znów idziesz do ustawień, zmieniasz URL, klikasz Save, czekasz aż się odświeży – i w ciszy nienawidzisz cały ten stos.
Dla jednorazowego „pobawić się wieczorem” to da się znieść. Ale gdy:
- codziennie doszlifowujesz App;
- chcesz pokazać wersję pośrednią koledze/managerowi;
- równolegle uruchamiasz jeszcze staging i production,
podpinanie Dev Mode pod każdy nowy losowy URL staje się czystą udręką.
Dodatkowo, jeśli już dodałeś do aplikacji coś zależnego od domeny (np. OAuth redirect URI lub webhooki), każdy nowy URL psuje i to. Pojawia się efekt domina: zmieniłeś tunel – i trzeba poprawiać konfigurację App, redirect‑URL u dostawcy OAuth oraz ustawienia odbiornika webhooków.
Z tego wynika główna myśl wykładu: stabilny dev‑URL to nie luksus, lecz sposób na zachowanie zdrowia psychicznego programisty.
Insight
ChatGPT ma bardzo rygorystyczne timeouty przy pracy z twoją aplikacją i łatwo je zlekceważyć. MCP-tool-call ma limit czasu: maksymalnie 2 minuty — po tym czasie platforma po prostu uznaje wywołanie za nieudane, nawet jeśli twój serwer coś jeszcze robi.
Jeszcze ostrzej jest z rejestracją aplikacji (Store lub Dev Mode): na odczyt manifestu, zasobów i opisów narzędzi ChatGPT daje około 20 sekund. Jeśli w tym czasie twój serwer MCP nie zdąży się zainicjalizować, oddać listy tools/resources itp., rejestracja App odpadnie przez timeout.
Rekomendacja: cała ciężka inicjalizacja powinna wydarzyć się zanim wejdziesz w Dev Mode lub Store. Rozgrzanie połączeń z bazą, wczytanie dużych konfiguracji, leniwe cache — najlepiej wykonać to wcześniej, np. raz „szturchnąć” serwer przez MCP Jam lub osobny skrypt wewnętrzny. Z punktu widzenia platformy serwer MCP ma być „ciepły” i odpowiadać w sekundy, a nie „budzić się” podczas rejestracji.
2. Czym jest „dorosły” tunel
Ustalmy, czym „dorosły” tunel różni się od tego, co uruchamiałeś na początku kursu.
Wczesny tryb (moduł 2) wyglądał tak:
# Przykład na ngrok
ngrok http 3000
# Otrzymujemy: https://random-abc123.ngrok-free.app
Brałeś ten jednorazowy URL i wstawiałeś go do Dev Mode. Przy następnym uruchomieniu ngrok URL już jest inny i konfiguracja ChatGPT się dezaktualizuje.
W „dorosłym” podejściu masz:
- statyczny subdomen u dostawcy tunelu (albo własną domenę);
- ta sama domena zawsze jest przekierowana na twój localhost:3000;
- możesz restartować tunel, maszynę, router, ale URL pozostaje ten sam.
Takie statyczne subdomeny są dostępne na przykład:
- w ngrok — darmowy static domain na konto;
- w Cloudflare Tunnel — przez nazwany tunel i powiązanie z własną domeną.
A aplikacja ChatGPT w Dev Mode jest ustawiona dokładnie na ten jeden URL i więcej cię nie niepokoi.
Z formalnego punktu widzenia wymagania dla naszego „dorosłego” tunelu są takie:
- stale ta sama publiczna domena HTTPS;
- ważny certyfikat TLS (dostawca robi to za nas);
- konfiguracja opisująca: „wszystko, co przyszło na https://dev.yourdomain.com, przekaż na http://localhost:3000”;
- opcjonalnie — minimalne środki bezpieczeństwa (choćby nie świecić URL na StackOverflow).
3. Konfigurujemy stabilny dev‑URL: przykład z Cloudflare Tunnel
W kursie polecamy Cloudflare Tunnel jako główne narzędzie, bo dobrze sprawdza się i w dev, i w poważniejszych scenariuszach. Już w module 2 widziałeś przykład podstawowej konfiguracji, teraz „dokręcamy” to do stałego dev‑URL.
Załóżmy, że mamy aplikację szkoleniową GiftGenius i chcemy stabilny URL giftgenius-dev.yourdomain.com.
Minimalne kroki (w skrócie, bez wiązania z UI Cloudflare):
- Podpinamy domenę do konta Cloudflare (raz, przez ich panel).
- Instalujemy cloudflared lokalnie i logujemy się.
brew install cloudflare/cloudflare/cloudflared # macOS
cloudflared login # otworzy przeglądarkę do autoryzacji
3. Tworzymy nazwany tunel:
cloudflared tunnel create giftgenius-dev
4. Ustawiamy trasę w ~/.cloudflared/config.yml:
tunnel: giftgenius-dev
credentials-file: /Users/you/.cloudflared/giftgenius-dev.json
ingress:
- hostname: giftgenius-dev.yourdomain.com
service: http://localhost:3000 # nasz serwer deweloperski Next.js
- service: http_status:404
5. Uruchamiamy tunel:
cloudflared tunnel run giftgenius-dev
Teraz, gdy działają npm run dev i cloudflared tunnel run, twój lokalny Next.js jest dostępny pod stałym adresem https://giftgenius-dev.yourdomain.com. I właśnie jego podajesz w ustawieniach ChatGPT Dev Mode.
Jak to spina się z naszą aplikacją
Jeśli otworzysz w przeglądarce URL twojej aplikacji, który wpisujesz w ChatGPT przy podłączaniu aplikacji Dev:
https://giftgenius-dev.yourdomain.com/mcp
zobaczysz odpowiedź (błąd) — coś w tym rodzaju:
{"jsonrpc":"2.0","error":{"code":-32000,"message":"Method not allowed."},"id":null}
To całkowicie normalne, bo serwer pod /mcp nie oczekuje żądania GET. Wszystkie inne części aplikacji — widżet, endpoint MCP /mcp, trasy API — jadą tym samym tunelem; nie musisz pamiętać za każdym razem nowej domeny.
4. Alternatywa: statyczny subdomen w ngrok
Jeśli przyzwyczaiłeś się do ngrok, można go „uszlachetnić” podobnie, używając static domain. Od 2023 roku ngrok daje nawet na darmowym planie możliwość przypięcia jednego statycznego subdomenu typu myapp-dev.ngrok-free.app.
Minimalny schemat:
# ~/.config/ngrok/ngrok.yml
authtoken: <twój token>
tunnels:
giftgenius-dev:
addr: 3000
proto: http
domain: giftgenius-dev.ngrok-free.app
Uruchomienie:
ngrok start giftgenius-dev
W efekcie URL https://giftgenius-dev.ngrok-free.app będzie stały i ten sam podajesz ChatGPT Dev Mode jako bazowy URL aplikacji.
Filozofia taka sama:
- zero „losowych” adresów;
- zmienia się tylko wewnętrzny stan tunelu (uruchomiony/nieuruchomiony), a nie domena;
- Dev Mode nie wymaga przepinania.
Cloudflare i ngrok to w tym sensie tylko różne smaki lodów. Niektórzy wolą własne domeny i „cienką” kontrolę DNS (Cloudflare), inni preferują „zrób YAML — i gotowe” (ngrok). Dla kursu oba podejścia są poprawne, najważniejsze — stabilny URL.
5. Schemat: ChatGPT Dev Mode ↔ tunel ↔ lokalny stack
Aby nieco sformalizować, narysujmy obrazek.
flowchart TD
ChatGPT["ChatGPT (Dev Mode)"]
AppCfg["Dev App (config: https://giftgenius-dev...)"]
Tunnel["Tunel Cloudflare/ngrok (giftgenius-dev...)"]
Next["Next.js serwer dev localhost:3000 + MCP handler"]
ChatGPT --> AppCfg
AppCfg -->|"w konfiguracji wskazano https://giftgenius-dev.../.well-known/openai-app"| Tunnel
Tunnel -->|"HTTPS → HTTP proxy"| Next
ChatGPT nigdy nie wie, co kręcisz na laptopie. Dla niego istnieje tylko jeden endpoint HTTPS. Co jest za nim — Vercel, lokalny tunel, Kubernetes — to już twoja sprawa. I w tej lekcji interesuje nas przede wszystkim stabilność tego endpointu HTTPS dla lokalnego developmentu.
Pozostaje sprawić, by wewnątrz naszej aplikacji ten adres też był jednym „źródłem prawdy”, a nie rozjeżdżał się po hard‑codowanych stringach — temu poświęcony jest następny rozdział.
6. Zmienne środowiskowe i baseURL w kodzie
Aby to wszystko działało bez niespodzianek, warto raz zdefiniować w kodzie Next.js „bazowy zewnętrzny URL aplikacji” i dalej opierać się tylko na nim.
Na przykład, w folderze app/lib/config.ts w naszej aplikacji GiftGenius można dodać:
// app/lib/config.ts
export const baseUrl =
process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000"; // fallback
export const mcpEndpoint = `${baseUrl}/mcp`; // URL serwera MCP
A w .env.local podczas developmentu wskazać:
NEXT_PUBLIC_APP_URL=https://giftgenius-dev.yourdomain.com
Wtedy:
- wewnątrz widżetu i dowolnych linków zawsze używasz baseUrl;
- dla ChatGPT Dev Mode i przeglądarki wszystko wygląda spójnie;
- jeśli jutro przeniesiesz się na Vercel staging z domeną https://giftgenius-staging.vercel.app, wystarczy zmienić tylko zmienną środowiskową.
To szczególnie ważne dla:
- callback‑URL (np. dla OAuth, handlerów webhooków);
- linków pokazywanych użytkownikowi w widżecie (przycisk „Otwórz w przeglądarce” przez openExternal);
- wszelkich absolutnych URL w logice aplikacji.
Na razie mówimy tylko o dev‑URL, ale sama idea architektoniczna „jedno źródło prawdy dla baseUrl” świetnie działa i spokojnie przeniesie się z tobą na staging/production.
7. Aktualizacja URL w ChatGPT Dev Mode
OK, mamy ładną stabilną domenę. Jak teraz z nią żyć w Dev Mode?
Logika jest taka:
- W ustawieniach aplikacji Dev raz podajesz URL bazowy: https://giftgenius-dev.yourdomain.com/
- ChatGPT pobiera z niego manifest (.well-known/openai-app) i dalej używa tych samych korzeni do odwołań do MCP (/mcp), statyki itd.
- Jeśli zmieniasz tylko kod (widżet React, MCP‑handlers, style), URL nie wymaga żadnych zmian. Wystarczy, że tunel jest uruchomiony i serwer Next.js odpowiada.
- Jeśli zmieniasz samą domenę (rzadko, np. z ngrok na Cloudflare), trzeba raz wejść do Dev Mode i podmienić endpoint.
W niektórych przypadkach ChatGPT keszuje manifest i zmiany mogą nie pojawić się natychmiast. W interfejsie Dev Mode zwykle jest przycisk w rodzaju „Reload configuration / Refresh App”, a w najgorszym scenariuszu pomoże nawet banalne „odłącz i podłącz App pod tym samym URL”.
Ważne: dopóki nie zmieniasz URL, Dev Mode automatycznie „podchwyci” nowe wersje kodu. Głównym wyzwalaczem dla App jest domena, a nie commit‑hash.
8. Przełączanie między dev / staging / prod w Dev Mode
Stabilna domena dev to dopiero pierwszy stopień. Żeby nie utonąć w chaosie adresów URL wraz ze wzrostem projektu, warto od razu rozumieć, jak tunel dev wpisuje się w ogólny schemat środowisk (dev/staging/prod) i Dev Mode. Chociaż staging i prod to temat raczej następnego wykładu o Vercel, Dev Mode już teraz potrafi pracować z kilkoma środowiskami.
Dla zrozumienia dalszych rozważań przyda się taka tabela:
| Środowisko | URL bazowy | Gdzie działa kod |
|---|---|---|
| Local | |
Lokalny Next.js + MCP przez tunel |
| Staging | |
Vercel Preview / wdrożenie staging |
| Prod | |
Vercel Production |
Są dwa warianty pracy z Dev Mode.
Pierwszy — jedno Dev‑App, ale co jakiś czas aktualizujesz w jego ustawieniach URL, by poklikać staging albo prod (ostrożnie). Takie podejście nadaje się na wczesnych etapach, ale łatwo się pomylić: dziś testowałeś lokalnie, jutro staging, pojutrze zapomniałeś przełączyć i przez Dev‑App przypadkiem leci ruch do produkcji.
Drugi — zdrowszy: kilka aplikacji Dev, każda z wyraźnym powiązaniem ze środowiskiem:
- GiftGenius Dev → giftgenius-dev.yourdomain.com;
- GiftGenius Staging → giftgenius-staging.vercel.app;
- GiftGenius (produkcyjna, przez Store) → giftgenius.vercel.app.
W ramach tej lekcji idziemy krok po kroku, porządkując przynajmniej dev‑URL. W następnej lekcji zobaczysz, jak sensownie powiązać Vercel i preview‑deploye ze staging/production.
9. Praca zespołowa: wielu developerów i jeden tunel
Dopóki mamy jedną domenę dev i jednego introwertycznego developera, tunel to twój osobisty przyjaciel. Ale gdy tylko w projekcie pojawia się zespół, tunele i środowiska zaczynają się krzyżować — i tu ważne, by nie zrobić „wojny o jeden subdomen”.
Wyobraźmy sobie, że dwóch developerów postanowiło używać tego samego statycznego subdomenu, powiedzmy giftgenius-dev.ngrok-free.app. Oboje uruchamiają u siebie ngrok start giftgenius-dev. W najlepszym wypadku jeden tunel po prostu nie wstanie (konflikt domeny), w najgorszym — będziecie sobie na zmianę „przebijać” sesję, a ChatGPT raz trafi do jednego, raz do drugiego.
Jest tu kilka strategii.
Najprostsza — personalne domeny dev:
- alex.dev.giftgenius.app;
- maria.dev.giftgenius.app.
I do tego osobne Dev‑App w ChatGPT, np. GiftGenius Dev (Alex) i GiftGenius Dev (Maria). Wtedy każdy spokojnie kręci lokalnie i nie przeszkadza sąsiadowi.
Bardziej „zespołowa” droga — wspólny endpoint staging:
- Każdy developer ma osobny tunel dev (do własnego debugowania).
- Do tego jest staging na Vercel, gdzie lądują scalone feature‑gałęzie i na który patrzy wspólny Dev‑App GiftGenius Staging.
Takie podejście często spotyka się w realnych zespołach:
- funkcja rodzi się lokalnie i jest debugowana przez osobisty tunel;
- po pull‑requeście i mergu jest testowana przez wszystkich na staging (bez tuneli, po prostu przez URL Vercel).
10. Bezpieczeństwo tunelu dev (krótko i bez paranoi)
Tunel to wygodny sposób, by wystawić twój lokalny serwer do internetu. A internet, jak wiemy, składa się głównie z botów, skanerów i ludzi, którzy lubią sprawdzać, czy nie zostawiłeś hasła admin/admin.
Podstawy, o których warto pamiętać już na etapie dev:
- tunel daje zewnętrzny dostęp do wszystkiego, co wisi na tym porcie; nie wystawiaj tam dodatkowo panelu DB, phpMyAdmin ani „mojego testowego CRM bez hasła”;
- nie publikuj URL tunelu w otwartych repozytoriach i czatach;
- wyłączaj tunel, gdy nie pracujesz (i laptopa też czasem wyłącz — też potrzebuje odpoczynku).
Poważniejsze środki jak Basic Auth, weryfikacja specjalnych nagłówków czy token w URL omówimy w modułach o bezpieczeństwie. Ważne teraz jedno: tunel to narzędzie developmentu, a nie zabezpieczony serwer. Produkcja będzie żyła na normalnym hostingu, jak Vercel, z innymi mechanizmami ochrony.
11. Praktyka: ustawiamy stabilny dev‑URL dla naszej aplikacji
Teraz od teorii i ostrzeżeń — do praktyki: powiążmy to z naszą aplikacją szkoleniową na Next.js (szablon Apps SDK).
Załóżmy, że struktura projektu wygląda tak:
apps/
web/ # Next.js App + widżet
mcp-server/ # (opcjonalnie) osobny MCP albo handler /mcp w web
W praktyce możesz trzymać MCP wprost w Next.js, w app/api/mcp/route.ts, ale zasada jest ta sama.
Krok 1. Edytujemy .env.local
Dodajemy stabilny dev‑URL tunelu:
NEXT_PUBLIC_APP_URL=https://giftgenius-dev.yourdomain.com
W kodzie dev już używaliśmy baseUrl z tej zmiennej (zob. wyżej). Jeśli nie — najwyższy czas wydzielić.
Krok 2. Uruchamiamy serwer dev i tunel
cd apps/web
npm run dev # Next.js na localhost:3000
# osobne okno terminala
cloudflared tunnel run giftgenius-dev
Sprawdzamy w przeglądarce, że https://giftgenius-dev.yourdomain.com się otwiera i pokazuje twój App.
Krok 3. Podpinamy w ChatGPT Dev Mode
W interfejsie ChatGPT (sekcja dla deweloperów):
- tworzymy lub edytujemy GiftGenius Dev;
- w polu URL/Endpoint podajemy https://giftgenius-dev.yourdomain.com/;
- zapisujemy.
Po tym ChatGPT odwołuje się do manifestu pod ścieżką /.well-known/openai-app, a następnie zaczyna uruchamiać twój App nad tą domeną.
Teraz możesz:
- zmieniać kod widżetu, MCP‑handlers, style;
- restartować npm run dev;
- restartować cloudflared tunnel run giftgenius-dev;
i przy tym już nigdy nie grzebać w ustawieniach Dev‑App, dopóki domena pozostaje ta sama.
12. Jak to wygląda w logice kodu: przykład z openExternal
Aby spiąć przykład z tym, co pisaliśmy w poprzednich lekcjach, dodajmy w widżecie przycisk „Otwórz pełny interfejs w przeglądarce”, który też będzie używał stabilnego dev‑URL.
Załóżmy, że mamy komponent React widżetu GiftWidget:
// app/components/GiftWidget.tsx
"use client";
import { baseUrl } from "../lib/config"; // bierzemy baseUrl z env
export function GiftWidget() {
const handleOpenFull = () => {
window.openai.openExternal({
// otwieramy stronę aplikacji w osobnej karcie
url: `${baseUrl}/full`,
label: "Otwórz pełny interfejs",
});
};
return (
<div>
<button onClick={handleOpenFull}>
Pełny tryb
</button>
</div>
);
}
Jeśli NEXT_PUBLIC_APP_URL wskazuje na tunel, to:
- podczas lokalnego developmentu otworzy się strona https://giftgenius-dev.yourdomain.com/full;
- po wdrożeniu na staging — https://giftgenius-staging.vercel.app/full;
- w prod — domena produkcyjna.
I znów — jedno źródło prawdy dla domeny: zmieniamy środowisko, ale nie zmieniamy kodu.
13. Mini‑strategia: jak myśleć o tunelu „po dorosłemu”
Sprowadzając wszystko do prostej mentalnej mapy, można przyjąć, że:
- tunel to po prostu tymczasowy przewód między twoim laptopem a stabilną publiczną domeną;
- ChatGPT Dev Mode zna tylko domenę i nie obchodzi go, gdzie fizycznie działa kod;
- im rzadziej zmieniasz domenę, tym mniej czasu spędzasz w ustawieniach ChatGPT i dostawców OAuth;
- tunel dev to tylko jeden wiersz na mapie środowisk, obok staging (Vercel preview) i prod (Vercel production).
Kolejny wykład pokaże właśnie, jak ten przewód zastępuje pełnoprawny hosting na Vercel i jak to wszystko powiązać z gałęziami Git, preview‑deployami i produkcją.
14. Typowe błędy przy pracy z „dorosłym” tunelem
Błąd nr 1: „Skonfigurowałem statyczną domenę, ale i tak używam losowych URL”.
Czasem developer raz zrobi ładne giftgenius-dev.yourdomain.com, ale z przyzwyczajenia uruchamia ngrok http 3000 bez configa. W rezultacie ChatGPT patrzy na jedną domenę, a kod działa za drugą. Jeśli już zrobiłeś stabilny dev‑URL — używaj tylko jego i uruchamiaj tunel przez config (nazwany tunel/profil).
Błąd nr 2: Twardo zhard‑codowany localhost:3000 w kodzie.
Zdarza się, gdy w komponencie React lub handlerze MCP piszą fetch("http://localhost:3000/api/..."). Lokalnie jeszcze jakoś działa, ale w Dev Mode, a tym bardziej na staging/prod, psuje się natychmiast. Zawsze wynoś URL bazowy do configu (baseUrl, NEXT_PUBLIC_APP_URL) i używaj go wszędzie, gdzie potrzebne są absolutne linki.
Błąd nr 3: Ciągła ręczna zmiana URL w Dev Mode zamiast stabilnego tunelu.
Jeśli łapiesz się na myśli „no dobrze, jeszcze raz zmienię URL w ustawieniach”, — to sygnał ostrzegawczy. Ustawienie statycznego subdomenu w ngrok/Cloudflare zajmuje raz 10–15 minut, a oszczędza godziny w trakcie developmentu.
Błąd nr 4: Wspólna statyczna domena dla zespołu bez zasad.
Dwóch developerów, jedna domena giftgenius-dev.ngrok-free.app i obaj uruchamiają tunel, kiedy chcą. Efekt — konflikt tuneli, „mistycznie” znikające odpowiedzi w Dev Mode i debugowanie w stylu „u mnie działało”. Dla zespołu zawsze albo osobiste domeny dev, albo jeden staging‑domen na realnym hostingu.
Błąd nr 5: Tunel jako „prawie produkcja”.
Czasem ktoś wpada na pomysł: „Skoro mam stabilny HTTPS‑URL przez tunel, puśćmy przez to prawdziwych użytkowników/płatności”. To droga do bólu: wyłączysz laptop — aplikacja padnie, internet się urwie — to samo, a bezpieczeństwo co najwyżej symboliczne. Tunel to narzędzie dev. Dla ruchu produkcyjnego są Vercel i inna „dorosła” infrastruktura, do której dojdziemy w kolejnym wykładzie.
Błąd nr 6: Zapomniana synchronizacja zmiennych środowiskowych i Dev Mode.
Często zmienia się NEXT_PUBLIC_APP_URL w .env.local, ale zapomina zmienić URL w Dev Mode (albo odwrotnie). W efekcie widżet generuje linki do jednej domeny, a ChatGPT odwołuje się do innej. Trzymaj prostą tabelkę „środowisko ↔ domena ↔ App w ChatGPT” i aktualizuj ją przy zmianach — to tańsze niż zgadywanie, który URL jest teraz „tym prawdziwym”.
GO TO FULL VERSION