1. Проблема «випадкових» тунелів
Коли ви вперше запускаєте ngrok http 3000 або швидкий Cloudflare Quick Tunnel, усе здається магією: раз — і ваш http://localhost:3000 перетворюється на https://random-1234.tunnelprovider.com. Ви копіюєте URL у ChatGPT Dev Mode — і GPT охоче завантажує ваш застосунок.
А потім ви перезапускаєте тунель… і отримуєте новий домен. Старий URL у налаштуваннях dev‑застосунку в ChatGPT раптом стає «битим посиланням». GPT чесно пише «App unavailable», а ви знову йдете в налаштування, змінюєте URL, тиснете Save, чекаєте, доки все оновиться, — і щоразу дратуєтеся через усю цю купу кроків.
Для разового «погратися ввечері» це ще терпимо. Але якщо ви:
- щодня допрацьовуєте застосунок;
- хочете показати проміжну версію колезі або менеджеру;
- паралельно налаштовуєте staging і production,
то перепідʼєднувати Dev Mode під кожен новий випадковий URL швидко перетворюється на суцільні муки.
До того ж, якщо ви вже додали в застосунок щось, що залежить від домену (наприклад, redirect URI для OAuth або вебхуки), кожен новий URL ламає і це. Виникає каскад: змінили тунель — і доводиться правити конфігурацію застосунку, redirect URI в OAuth‑провайдері та налаштування обробника вебхуків.
Звідси й ключова ідея лекції: стабільний dev‑URL — не розкіш, а спосіб берегти психічне здоровʼя розробника.
Інсайт
У ChatGPT діють доволі суворі часові обмеження на роботу з вашим застосунком, і їх легко недооцінити. Для MCP‑tool‑call є ліміт: максимум 2 хвилини. Після цього платформа вважає виклик невдалим — навіть якщо ваш сервер і далі щось робить.
Ще суворіші обмеження діють під час реєстрації застосунку (Store або Dev Mode): на читання маніфесту, ресурсів і описів інструментів ChatGPT дає близько 20 секунд. Якщо за цей час ваш MCP‑сервер не встиг ініціалізуватися й повернути список tools/resources тощо, реєстрація застосунку завершиться тайм‑аутом.
Рекомендація: усю важку ініціалізацію виконайте до того, як іти в Dev Mode або Store. Прогрівання зʼєднань із БД, завантаження великих конфігів, «ледачі» кеші — усе це краще зробити заздалегідь. Наприклад, один раз звернутися до сервера через MCP Jam або запустити окремий внутрішній скрипт. Для платформи MCP‑сервер має бути «теплим» і відповідати за секунди, а не «прокидатися» під час реєстрації.
2. Що таке «дорослий» тунель
Зафіксуймо, чим «дорослий» тунель відрізняється від того, що ви запускали на початку курсу.
Ранній підхід (модуль 2) виглядав так:
# Приклад на ngrok
ngrok http 3000
# Отримуємо: https://random-abc123.ngrok-free.app
Ви брали цей одноразовий URL і вставляли в Dev Mode. Під час наступного запуску ngrok URL уже інший — і конфігурація ChatGPT застаріває.
У «дорослому» підході у вас:
- є статичний піддомен у тунель‑провайдера (або власний домен);
- один і той самий домен завжди проксіюється на ваш localhost:3000;
- ви можете перезапускати тунель, машину й роутер, але URL залишатиметься тим самим.
Такі статичні піддомени доступні, наприклад:
- у ngrok — один безкоштовний статичний домен на обліковий запис;
- у Cloudflare Tunnel — через іменований тунель і привʼязку до власного домену.
І ChatGPT‑застосунок у Dev Mode налаштований рівно на цей один URL — і більше вам не доводиться про це думати.
З формального погляду вимоги до нашого «дорослого» тунелю такі:
- стабільно один і той самий публічний HTTPS‑домен;
- дійсний TLS‑сертифікат (провайдер забезпечує це за нас);
- конфігурація, яка описує: «усе, що прийшло на https://dev.yourdomain.com, спрямуй на http://localhost:3000»;
- за потреби — мінімальні заходи безпеки (хоча б не світити URL на Stack Overflow).
3. Налаштовуємо стабільний dev‑URL: приклад із Cloudflare Tunnel
У курсі ми рекомендуємо Cloudflare Tunnel як основний інструмент, тому що він добре підходить і для dev, і для складніших сценаріїв. У модулі 2 ви вже бачили приклад базового налаштування — тепер «доведемо» його до постійного dev‑URL.
Припустімо, у нас навчальний застосунок GiftGenius, і ми хочемо стабільний URL giftgenius-dev.yourdomain.com.
Мінімальні кроки (спрощено, без привʼязки до UI Cloudflare):
- Привʼязуємо домен до акаунта Cloudflare (один раз, через їхню панель).
- Встановлюємо cloudflared локально та входимо в обліковий запис.
brew install cloudflare/cloudflare/cloudflared # macOS
cloudflared login # відкриє браузер для авторизації
Крок 3. Створюємо іменований тунель:
cloudflared tunnel create giftgenius-dev
Крок 4. Налаштовуємо маршрут у ~/.cloudflared/config.yml:
tunnel: giftgenius-dev
credentials-file: /Users/you/.cloudflared/giftgenius-dev.json
ingress:
- hostname: giftgenius-dev.yourdomain.com
service: http://localhost:3000 # наш Next.js dev-сервер
- service: http_status:404
Крок 5. Запускаємо тунель:
cloudflared tunnel run giftgenius-dev
Тепер, доки працюють npm run dev і cloudflared tunnel run, ваш локальний Next.js доступний за постійним URL https://giftgenius-dev.yourdomain.com. Саме його ви зазначаєте в налаштуваннях ChatGPT Dev Mode.
Як це повʼязується з нашим застосунком
Якщо ви відкриєте в браузері URL застосунку, який вводите в ChatGPT під час підключення dev‑застосунку:
https://giftgenius-dev.yourdomain.com/mcp
ви побачите відповідь (помилку) — щось на кшталт:
{"jsonrpc":"2.0","error":{"code":-32000,"message":"Method not allowed."},"id":null}
Це абсолютно нормально, адже сервер на /mcp не очікує GET-запиту. Усі інші частини застосунку — віджет, MCP‑ендпойнт /mcp, API‑роути — працюють через цей самий тунель. Вам не потрібно щоразу запамʼятовувати новий домен.
4. Альтернатива: стабільний піддомен у ngrok
Якщо ви вже звикли до ngrok, його можна «зробити дорослим» приблизно так само — використовуючи статичний домен. Із 2023 року ngrok навіть на безкоштовному плані дає змогу закріпити один статичний піддомен на кшталт myapp-dev.ngrok-free.app.
Мінімальна схема:
# ~/.config/ngrok/ngrok.yml
authtoken: <ваш токен>
tunnels:
giftgenius-dev:
addr: 3000
proto: http
domain: giftgenius-dev.ngrok-free.app
Запуск:
ngrok start giftgenius-dev
У результаті URL https://giftgenius-dev.ngrok-free.app буде постійним — і саме його ви даєте ChatGPT Dev Mode як базовий URL застосунку.
Філософія та сама:
- жодних «випадкових» адрес;
- змінюється лише внутрішній стан тунелю (запущено/не запущено), а не домен;
- Dev Mode не потрібно перепідʼєднувати.
Cloudflare і ngrok у цьому сенсі — просто різні «смаки морозива». Дехто любить власні домени та «тонкий» контроль DNS (Cloudflare), інші надають перевагу підходу «написали YAML — і готово» (ngrok). Для курсу обидва варіанти підходять; головне — стабільний URL.
5. Схема: ChatGPT Dev Mode ↔ тунель ↔ локальний стек
Щоб трохи формалізувати те, що відбувається, намалюємо схему.
flowchart TD
ChatGPT["ChatGPT (Dev Mode)"]
AppCfg["Dev App (конфіг: httрs://giftgenius-dev...)"]
Tunnel["Тунель Cloudflare/ngrok (giftgenius-dev...)"]
Next["Next.js dev-сервер localhost:3000 + MCP обробник"]
ChatGPT --> AppCfg
AppCfg -->|"у конфігурації вказано https://giftgenius-dev.../.well-known/openai-app"| Tunnel
Tunnel -->|"HTTPS → HTTP проксіювання"| Next
ChatGPT ніколи не знає, що ви там робите на ноутбуці. Для нього існує лише один HTTPS‑ендпойнт. Що саме за ним — Vercel, локальний тунель, Kubernetes — уже ваша справа. А в цій лекції нас цікавить саме стабільність цього HTTPS‑ендпойнта для локальної розробки.
Залишилося зробити так, щоб усередині застосунку ця адреса теж була єдиним «джерелом правди», а не розʼїжджалася по жорстко прописаних рядках. Саме цьому й присвячено наступний розділ.
6. Змінні середовища та baseUrl у коді
Щоб усе працювало без сюрпризів, корисно один раз визначити в коді Next.js «базовий зовнішній URL застосунку» — і далі спиратися лише на нього.
Наприклад, у папці app/lib/config.ts у нашому застосунку GiftGenius можна завести:
// app/lib/config.ts
export const baseUrl =
process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000"; // fallback
export const mcpEndpoint = `${baseUrl}/mcp`; // URL MCP-сервера
А в .env.local під час розробки вказати:
NEXT_PUBLIC_APP_URL=https://giftgenius-dev.yourdomain.com
Тоді:
- усередині віджета та будь‑яких посилань ви завжди використовуєте baseUrl;
- для ChatGPT Dev Mode і браузера все виглядає послідовно;
- якщо завтра ви переїдете на Vercel staging із доменом https://giftgenius-staging.vercel.app, достатньо змінити лише змінну середовища.
Це особливо важливо для:
- callback‑URL (наприклад, для OAuth і webhook‑обробників);
- посилань, які ви показуєте користувачеві у віджеті (кнопка «Відкрити в браузері» через openExternal);
- будь‑яких абсолютних URL у логіці застосунку.
Поки ми говоримо лише про dev‑URL, але сама архітектурна ідея «одне джерело правди для baseUrl» чудово працює й так само спокійно переїде з вами на staging/production.
7. Оновлення URL у ChatGPT Dev Mode
Гаразд, ми зробили собі стабільний домен. Як тепер із ним жити в Dev Mode?
Логіка така:
- У налаштуваннях dev‑застосунку ви один раз вказуєте кореневий URL: https://giftgenius-dev.yourdomain.com/
- ChatGPT звертається до нього по маніфест (.well-known/openai-app) і далі використовує той самий корінь для звернення до MCP (/mcp), статичних файлів тощо.
- Якщо ви змінюєте лише код (React‑віджет, MCP‑обробники, стилі), URL змінювати взагалі не потрібно. Достатньо, щоб тунель був запущений і Next.js‑сервер відповідав.
- Якщо ви змінюєте сам домен (рідко — наприклад, переходите з ngrok на Cloudflare), потрібно один раз зайти в Dev Mode і змінити ендпойнт.
У деяких випадках ChatGPT кешує маніфест, і зміни в ньому можуть зʼявлятися не миттєво. В інтерфейсі Dev Mode зазвичай є кнопка на кшталт «Reload configuration / Refresh App», але в найгіршому сценарії допоможе навіть просте «відʼєднати й знову підʼєднати застосунок за тим самим URL».
Важливо: доки ви не змінюєте URL, Dev Mode автоматично «підхоплює» нові версії коду. Основний тригер для застосунку — домен, а не хеш коміту.
8. Перемикання між dev / staging / prod у Dev Mode
Стабільний dev‑домен — це лише перша сходинка. Щоб не загубитися в хаосі URL‑адрес у міру зростання проєкту, корисно відразу розуміти, як dev‑тунель вписується в загальну схему середовищ (dev/staging/prod) і Dev Mode. Хоча staging і prod — тема радше наступної лекції про Vercel, Dev Mode вже зараз уміє працювати з кількома середовищами.
Щоб легше було стежити за подальшими міркуваннями, корисна така таблиця:
| Середовище | Базовий URL | Де працює код |
|---|---|---|
| Local | |
Локальний Next.js + MCP через тунель |
| Staging | |
Vercel Preview / staging‑деплой |
| Prod | |
Vercel Production |
Варіантів роботи з Dev Mode — два.
Перший: один dev‑застосунок, але ви час від часу оновлюєте в його налаштуваннях URL, щоб перевірити staging або prod (обережно). Такий підхід годиться на ранніх стадіях, але його легко переплутати: сьогодні ви тестували локальне середовище, завтра — staging, післязавтра забули перемкнутися — і випадково надсилаєте через dev‑застосунок запити в prod.
Другий — здоровіший: кілька dev‑застосунків, кожен із чіткою привʼязкою до середовища:
- GiftGenius Dev → giftgenius-dev.yourdomain.com;
- GiftGenius Staging → giftgenius-staging.vercel.app;
- GiftGenius (бойовий, через Store) → giftgenius.vercel.app.
У межах цієї лекції ми крок за кроком наводимо лад хоча б у dev‑URL. У наступній лекції ви побачите, як логічно привʼязати Vercel і preview‑деплої до staging/production.
9. Робота в команді: кілька розробників і один тунель
Поки у вас один dev‑домен і один розробник, тунель — ваш особистий інструмент. Але щойно в проєкті зʼявляється команда, тунелі та середовища починають перетинатися. Тут важливо не влаштувати «війну за один піддомен».
Уявімо, що два розробники вирішили використовувати один і той самий статичний піддомен, скажімо giftgenius-dev.ngrok-free.app. Обидва запускають у себе ngrok start giftgenius-dev. У кращому разі один тунель просто не підніметься (конфлікт домену), у гіршому — ви будете по черзі «перебивати» одне одному сесію, і ChatGPT то потраплятиме до одного, то до іншого.
Є кілька стратегій.
Найпростіша — персональні dev‑домени:
- alex.dev.giftgenius.app;
- maria.dev.giftgenius.app.
І кожному — свій dev‑застосунок у ChatGPT, наприклад GiftGenius Dev (Alex) і GiftGenius Dev (Maria). Тоді кожен спокійно працює локально й не заважає колезі.
Більш «командний» шлях — спільний staging‑ендпойнт:
- У всіх розробників є особистий dev‑тунель (для персонального налагодження).
- Плюс є staging на Vercel, куди зливаються feature‑гілки і куди дивиться спільний dev‑застосунок GiftGenius Staging.
Такий підхід часто трапляється в реальних командах:
- функціональність народжується локально й налагоджується через особистий тунель;
- після pull‑request і злиття вона тестується всіма через staging (без тунелів — просто через Vercel URL).
10. Безпека dev‑тунелю (коротко й без параної)
Тунель — це зручний спосіб вивести ваш локальний сервер в інтернет. А інтернет, як ми знаємо, здебільшого складається з ботів, сканерів і людей, які люблять перевіряти, чи не забули ви пароль admin/admin.
Базові речі, про які варто памʼятати вже на етапі dev:
- тунель дає зовнішній доступ до всього, що висить на цьому порту; не виносьте туди ще й адмінку БД, phpMyAdmin і «мою тестову CRM без пароля»;
- не публікуйте URL тунелю у відкритих репозиторіях і чатах;
- вимикайте тунель, коли не працюєте (і ноутбук також іноді вимикайте — йому теж потрібен відпочинок).
Більш серйозні заходи на кшталт Basic Auth, перевірки спецзаголовків або токена в URL ми розбиратимемо вже в модулях про безпеку. Зараз важливо лише одне: тунель — інструмент розробки, а не захищений сервер. Бойове середовище житиме на нормальному хостингу, на кшталт Vercel, з іншими механізмами захисту.
11. Практика: налаштовуємо стабільний dev‑URL для нашого застосунку
Тепер від теорії та застережень — до практики: давайте привʼяжемо все це до нашого навчального застосунку на Next.js (шаблон Apps SDK).
Припустімо, структура проєкту виглядає так:
apps/
web/ # Next.js App + віджет
mcp-server/ # (необов’язково) окремий MCP, або /mcp-обробник у web
На практиці ви можете тримати MCP прямо в Next.js — у app/api/mcp/route.ts, але принцип той самий.
Крок 1. Правимо .env.local
Додайте туди стабільний dev‑URL тунелю:
NEXT_PUBLIC_APP_URL=https://giftgenius-dev.yourdomain.com
У dev‑коді ми вже використовували baseUrl із цієї змінної (див. вище). Якщо ви цього ще не зробили — саме час винести й підʼєднати.
Крок 2. Запускаємо dev‑сервер і тунель
cd apps/web
npm run dev # Next.js на localhost:3000
# окремий термінал
cloudflared tunnel run giftgenius-dev
Перевірте в браузері, що https://giftgenius-dev.yourdomain.com відкривається й показує ваш застосунок.
Крок 3. Підключаємо в ChatGPT Dev Mode
В інтерфейсі ChatGPT (секція для розробників):
- створюємо або редагуємо GiftGenius Dev;
- у полі URL/Endpoint вказуємо https://giftgenius-dev.yourdomain.com/;
- зберігаємо.
Після цього ChatGPT звертається до маніфесту за шляхом /.well-known/openai-app, а потім починає запускати ваш застосунок поверх цього домену.
Тепер ви можете:
- міняти код віджета, MCP‑обробники, стилі;
- перезапускати npm run dev;
- перезапускати cloudflared tunnel run giftgenius-dev;
і при цьому більше ніколи не заходити в налаштування dev‑застосунку, доки домен залишається тим самим.
12. Як це виглядає в логіці коду: приклад із openExternal
Щоб завершити приклад тим, що ми вже писали в попередніх лекціях, додамо у віджет кнопку «Відкрити повний інтерфейс у браузері». Вона також використовуватиме стабільний dev‑URL.
Припустімо, у нас є React‑компонент віджета GiftWidget:
// app/components/GiftWidget.tsx
"use client";
import { baseUrl } from "../lib/config"; // беремо baseUrl з env
export function GiftWidget() {
const handleOpenFull = () => {
window.openai.openExternal({
// відкриваємо сторінку застосунку в окремій вкладці
url: `${baseUrl}/full`,
label: "Відкрити повний інтерфейс",
});
};
return (
<div>
<button onClick={handleOpenFull}>
Повний режим
</button>
</div>
);
}
Якщо NEXT_PUBLIC_APP_URL вказує на тунель, то:
- під час локальної розробки відкриється сторінка https://giftgenius-dev.yourdomain.com/full;
- після деплою на staging — https://giftgenius-staging.vercel.app/full;
- у prod — бойовий домен.
І знову — одне джерело правди для домену: змінюємо середовище, але не змінюємо код.
13. Міні‑стратегія: як думати про тунель «по‑дорослому»
Якщо звести все до простої ментальної моделі, то можна вважати, що:
- тунель — це просто тимчасовий провід між вашим ноутбуком і стабільним публічним доменом;
- ChatGPT Dev Mode знає лише домен — і йому байдуже, де фізично працює код;
- що рідше ви змінюєте домен, то менше часу проводите в налаштуваннях ChatGPT і OAuth‑провайдерів;
- dev‑тунель — це лише один рядок у вашій загальній карті середовищ, поруч зі staging (Vercel preview) і prod (Vercel production).
Наступна лекція якраз покаже, як цей «провід» замінюється повноцінним хостингом на Vercel і як повʼязати все це з Git‑гілками, preview‑деплоями та production.
14. Типові помилки під час роботи з «дорослим» тунелем
Помилка № 1: «Я налаштував статичний домен, але все одно продовжую використовувати випадкові URL».
Іноді розробник один раз робить красивий giftgenius-dev.yourdomain.com, але за звичкою запускає ngrok http 3000 без конфігурації. У результаті ChatGPT дивиться на один домен, а код працює через інший. Якщо ви вже зробили стабільний dev‑URL — використовуйте лише його й запускайте тунель через конфігурацію (іменований тунель або профіль).
Помилка № 2: Жорстко прописаний localhost:3000 у коді.
Це трапляється, коли в React‑компоненті або MCP‑обробнику пишуть fetch("http://localhost:3000/api/..."). Локально ще якось працює, але в Dev Mode і тим більше на staging/prod ламається миттєво. Завжди виносьте базовий URL у конфіг (baseUrl, NEXT_PUBLIC_APP_URL) і використовуйте його всюди, де потрібні абсолютні посилання.
Помилка № 3: Постійна правка URL у Dev Mode замість стабільного тунелю.
Якщо ви ловите себе на думці «ну гаразд, іще раз поміняю URL у налаштуваннях — що вже там», — це сигнал. Налаштування статичного піддомену в ngrok або Cloudflare займає один раз 10–15 хвилин, зате економить години під час розробки.
Помилка № 4: Спільний статичний домен на команду без правил.
Два розробники, один домен giftgenius-dev.ngrok-free.app, і обидва запускають тунель, коли заманеться. Результат — конфлікт тунелів, «містично» зникаючі відповіді в Dev Mode і налагодження в стилі «у мене ж працювало». Для команди завжди або особисті dev‑домени, або один staging‑домен на реальному хостингу.
Помилка № 5: Тунель як «майже продакшн».
Іноді хтось вирішує: «Ну якщо в мене стабільний HTTPS‑URL через тунель, давайте пускати через нього справжніх користувачів або платежі». Це шлях до болю: вимкнули ноутбук — застосунок «упав», зник інтернет — те саме, а безпека в кращому разі символічна. Тунель — це dev‑інструмент. Для production‑трафіку призначені Vercel та інша доросла інфраструктура, до якої ми дістанемося в наступній лекції.
Помилка № 6: Забута синхронізація змін середовища і Dev Mode.
Часто змінюють NEXT_PUBLIC_APP_URL у .env.local, але забувають змінити URL у Dev Mode (або навпаки). У результаті віджет генерує посилання на один домен, а ChatGPT звертається до іншого. Ведіть просту табличку «середовище ↔ домен ↔ застосунок у ChatGPT» і оновлюйте її під час змін — це дешевше, ніж гадати, який URL зараз справжній.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ