1. Il problema dei tunnel «casuali»
Quando avvii per la prima volta ngrok http 3000 o il veloce Cloudflare Quick Tunnel, sembra magia: all’improvviso il tuo http://localhost:3000 si trasforma in https://random-1234.tunnelprovider.com. Puoi copiare l’URL nel ChatGPT Dev Mode e GPT carica felicemente la tua App.
Poi però riavvii il tunnel… e ottieni un nuovo dominio. Il vecchio URL nelle impostazioni dell’app Dev in ChatGPT diventa all’improvviso un «link rotto», GPT scrive onestamente «App unavailable», e tu torni nelle impostazioni, cambi l’URL, premi Save, aspetti che si aggiorni e in silenzio odi tutto lo stack.
Per un «gioco serale» una tantum è tollerabile. Ma quando:
- lavori sull’App ogni giorno;
- vuoi mostrare una versione intermedia a un collega/manager;
- in parallelo allestisci anche staging e production,
riassociare il Dev Mode a ogni nuovo URL casuale diventa pura sofferenza.
Inoltre, se nell’app hai già aggiunto qualcosa che dipende dal dominio (ad esempio un OAuth redirect URI o dei webhook), ogni nuovo URL li rompe a sua volta. Nasce un effetto domino: cambi il tunnel — e devi correggere la configurazione dell’App, il redirect‑URL nel provider OAuth e le impostazioni del ricevitore webhook.
Da qui nasce l’idea chiave della lezione: un dev‑URL stabile non è un lusso, ma un modo per salvaguardare la salute mentale dello sviluppatore.
Insight
ChatGPT ha timeout molto rigidi nell’interazione con la tua applicazione, e sono facili da sottovalutare. MCP‑tool‑call ha un limite di tempo: al massimo 2 minuti — dopo di che la piattaforma considera la chiamata non riuscita, anche se il tuo server sta ancora lavorando.
Ancora più severa è la registrazione dell’app (Store o Dev Mode): per leggere manifest, risorse e descrizioni degli strumenti ChatGPT concede circa 20 secondi. Se in questo tempo il tuo server MCP non è riuscito a inizializzarsi, restituire l’elenco di tools/resources ecc., la registrazione dell’App cadrà in timeout.
Raccomandazione: tutta l’inizializzazione pesante deve avvenire prima di andare in Dev Mode o nello Store. Il warm‑up delle connessioni al DB, il caricamento di grandi config, le cache lazy — è meglio farli in anticipo, ad esempio chiamando una volta il server tramite MCP Jam o uno script interno dedicato. Dal punto di vista della piattaforma il server MCP deve essere «caldo» e rispondere in pochi secondi, non «svegliarsi» durante la registrazione.
2. Che cos’è un tunnel «da grandi»
Fissiamo in chiaro in cosa un tunnel «da grandi» differisce da quello che hai avviato a inizio corso.
La modalità iniziale (modulo 2) era così:
# Esempio con ngrok
ngrok http 3000
# Otteniamo: https://random-abc123.ngrok-free.app
Prendevi questo URL usa e getta e lo incollavi nel Dev Mode. Al successivo avvio di ngrok l’URL era già diverso e la configurazione di ChatGPT diventava obsoleta.
Nell’approccio «da grandi» hai:
- un sottodominio statico presso il provider del tunnel (o un tuo dominio);
- sempre lo stesso dominio instradato al tuo localhost:3000;
- puoi riavviare tunnel, macchina, router, ma l’URL resta invariato.
Questi sottodomini statici sono disponibili, ad esempio:
- in ngrok — dominio statico gratuito per account;
- in Cloudflare Tunnel — tramite tunnel nominato e collegamento al tuo dominio.
E l’app ChatGPT in Dev Mode è configurata esattamente su quell’unico URL e non ti disturba più.
Dal punto di vista formale, i requisiti per il nostro tunnel «da grandi» sono:
- sempre lo stesso dominio pubblico HTTPS stabile;
- certificato TLS valido (il provider se ne occupa per noi);
- una config che descrive: «tutto ciò che arriva su https://dev.yourdomain.com, instradalo su http://localhost:3000»;
- opzionalmente — misure minime di sicurezza (almeno non esporre l’URL su StackOverflow).
3. Configuriamo un dev‑URL stabile: esempio con Cloudflare Tunnel
Nel corso consigliamo Cloudflare Tunnel come strumento principale, perché si adatta bene sia al dev sia a scenari più seri. Già nel modulo 2 hai visto un esempio di configurazione di base, ora «completiamo» il tutto fino a un dev‑URL permanente.
Supponiamo di avere l’app didattica GiftGenius e di volere l’URL stabile giftgenius-dev.yourdomain.com.
Passi minimi (semplificati, senza riferimenti alla UI di Cloudflare):
- Collega il dominio all’account Cloudflare (una volta, dal loro pannello).
- Installa cloudflared in locale ed effettua il login.
brew install cloudflare/cloudflare/cloudflared # macOS
cloudflared login # aprirà il browser per l'autorizzazione
3. Creiamo un tunnel nominato:
cloudflared tunnel create giftgenius-dev
4. Configuriamo il routing in ~/.cloudflared/config.yml:
tunnel: giftgenius-dev
credentials-file: /Users/you/.cloudflared/giftgenius-dev.json
ingress:
- hostname: giftgenius-dev.yourdomain.com
service: http://localhost:3000 # il nostro server Next.js in dev
- service: http_status:404
5. Avviamo il tunnel:
cloudflared tunnel run giftgenius-dev
Ora, finché sono attivi npm run dev e cloudflared tunnel run, il tuo Next.js locale è raggiungibile all’URL permanente https://giftgenius-dev.yourdomain.com. Ed è proprio questo che indichi nelle impostazioni del ChatGPT Dev Mode.
Come si collega alla nostra applicazione
Se apri nel browser l’URL della tua app, quello che inserisci in ChatGPT durante il collegamento dell’app Dev:
https://giftgenius-dev.yourdomain.com/mcp
vedrai una risposta (errore) — qualcosa di questo tipo:
{"jsonrpc":"2.0","error":{"code":-32000,"message":"Method not allowed."},"id":null}
È assolutamente normale, perché il server su /mcp non si aspetta una richiesta GET. Tutte le altre parti dell’app — widget, endpoint MCP /mcp, rotte API — passano dallo stesso tunnel: non devi ricordare ogni volta un nuovo dominio.
4. Alternativa: sottodominio stabile in ngrok
Se ti sei già abituato a ngrok, puoi «farlo crescere» allo stesso modo utilizzando un dominio statico. Dal 2023 ngrok offre, anche nel piano gratuito, la possibilità di fissare un sottodominio statico del tipo myapp-dev.ngrok-free.app.
Schema minimo:
# ~/.config/ngrok/ngrok.yml
authtoken: <il tuo token>
tunnels:
giftgenius-dev:
addr: 3000
proto: http
domain: giftgenius-dev.ngrok-free.app
Avvio:
ngrok start giftgenius-dev
Di conseguenza l’URL https://giftgenius-dev.ngrok-free.app sarà permanente, e lo fornisci al ChatGPT Dev Mode come URL di base dell’app.
La filosofia è la stessa:
- niente indirizzi «casuali»;
- cambia solo lo stato interno del tunnel (avviato/non avviato), non il dominio;
- non serve riconnettere il Dev Mode.
Cloudflare e ngrok, in questo senso, sono solo gusti diversi di gelato. Alcuni preferiscono i propri domini e il controllo DNS «fine» (Cloudflare), altri prediligono «configuri lo YAML ed è pronto» (ngrok). Per il corso entrambi gli approcci sono validi; l’importante è l’URL stabile.
5. Schema: ChatGPT Dev Mode ↔ tunnel ↔ stack locale
Per formalizzare un po’ quello che succede, disegniamo un diagramma.
flowchart TD
ChatGPT["ChatGPT (Dev Mode)"]
AppCfg["Dev App (config: https://giftgenius-dev...)"]
Tunnel["Tunnel Cloudflare/ngrok (giftgenius-dev...)"]
Next["Server Next.js di dev localhost:3000 + gestore MCP"]
ChatGPT --> AppCfg
AppCfg -->|"nel config è indicato https://giftgenius-dev.../.well-known/openai-app"| Tunnel
Tunnel -->|"Proxy HTTPS → HTTP"| Next
ChatGPT non sa mai cosa stai eseguendo sul tuo laptop. Per lui esiste un solo endpoint HTTPS. Cosa ci sia dietro — Vercel, tunnel locale, Kubernetes — è affar tuo. In questa lezione ci interessa proprio la stabilità di questo endpoint HTTPS per lo sviluppo locale.
Resta da fare in modo che all’interno della nostra applicazione questo indirizzo sia anch’esso un’unica «fonte di verità», e non si disperda in stringhe hardcoded — a questo è dedicata la sezione seguente.
6. Variabili d’ambiente e baseURL nel codice
Perché tutto funzioni senza sorprese, è utile definire una volta nel codice di Next.js l’«URL esterno di base dell’applicazione» e basarsi sempre su quello.
Ad esempio, nella cartella app/lib/config.ts della nostra app GiftGenius possiamo creare:
// app/lib/config.ts
export const baseUrl =
process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000"; // fallback
export const mcpEndpoint = `${baseUrl}/mcp`; // URL del server MCP
E in .env.local in sviluppo indicare:
NEXT_PUBLIC_APP_URL=https://giftgenius-dev.yourdomain.com
Allora:
- all’interno del widget e di qualsiasi link usi sempre baseUrl;
- per ChatGPT Dev Mode e per il browser tutto appare coerente;
- se domani passi a un Vercel staging con dominio https://giftgenius-staging.vercel.app, basta cambiare solo la variabile d’ambiente.
È particolarmente importante per:
- callback‑URL (ad esempio per OAuth, gestori webhook);
- i link che mostri all’utente nel widget (pulsante «Apri nel browser» tramite openExternal);
- qualsiasi URL assoluto nella logica dell’applicazione.
Per ora parliamo solo del dev‑URL, ma l’idea architetturale «un’unica fonte di verità per il baseUrl» funziona benissimo e si porta senza problemi anche su staging/production.
7. Aggiornare l’URL in ChatGPT Dev Mode
Ok, ci siamo fatti un bel dominio stabile. Come conviverci nel Dev Mode?
La logica è questa:
- Nelle impostazioni dell’app Dev indichi una volta l’URL radice: https://giftgenius-dev.yourdomain.com/
- ChatGPT vi accede per il manifest (.well-known/openai-app) e poi usa la stessa radice per accedere a MCP (/mcp), statici, ecc.
- Se cambi solo il codice (widget React, handler MCP, stili), non serve cambiare l’URL. Basta che il tunnel sia avviato e il server Next.js risponda.
- Se cambi il dominio (raramente, ad esempio da ngrok a Cloudflare), devi entrare una volta nel Dev Mode e aggiornare l’endpoint.
In alcuni casi ChatGPT mette in cache il manifest e le modifiche potrebbero non comparire subito. Nell’interfaccia del Dev Mode di solito c’è un pulsante tipo «Reload configuration / Refresh App», ma nel peggiore dei casi aiuta anche un semplice «disconnettere e riconnettere l’App allo stesso URL».
Importante: finché non cambi l’URL, il Dev Mode «aggancia» automaticamente le nuove versioni del codice. Il trigger principale per l’App è il dominio, non l’hash del commit.
8. Commutare tra dev / staging / prod in Dev Mode
Un dominio dev stabile è solo il primo gradino. Per non affogare nel caos degli URL man mano che il progetto cresce, è utile capire subito come il tunnel di dev si inserisce nello schema complessivo degli ambienti (dev/staging/prod) e del Dev Mode. Sebbene staging e prod siano tema della prossima lezione su Vercel, il Dev Mode già ora può lavorare con più ambienti.
Per capire meglio, ecco una tabella:
| Ambiente | URL di base | Dove gira il codice |
|---|---|---|
| Local | |
Next.js locale + MCP tramite tunnel |
| Staging | |
Vercel Preview / deploy di staging |
| Prod | |
Vercel Production |
Ci sono due modalità di lavoro con il Dev Mode.
La prima — un’unica Dev‑App, ma di tanto in tanto aggiorni il suo URL nelle impostazioni per provare lo staging o la prod (con cautela). Va bene nelle fasi iniziali, ma è facile confondersi: oggi testavi il locale, domani lo staging, dopodomani ti dimentichi di cambiare e per sbaglio mandi richieste tramite la Dev‑App alla produzione.
La seconda — più sana: più app Dev, ognuna con un chiaro collegamento all’ambiente:
- GiftGenius Dev → giftgenius-dev.yourdomain.com;
- GiftGenius Staging → giftgenius-staging.vercel.app;
- GiftGenius (di produzione, tramite Store) → giftgenius.vercel.app.
In questa lezione procediamo passo dopo passo, mettendo ordine almeno nel dev‑URL. Nella prossima vedrai come collegare logicamente Vercel e i deploy di preview a staging/production.
9. Lavoro in team: più sviluppatori e un solo tunnel
Finché abbiamo un solo dominio dev e un solo sviluppatore introverso, il tunnel è il tuo amico personale. Ma appena arriva un team al progetto, tunnel e ambienti iniziano a incrociarsi: è importante non scatenare una «guerra per un solo sottodominio».
Supponiamo che due sviluppatori decidano di usare lo stesso sottodominio statico, poniamo giftgenius-dev.ngrok-free.app. Entrambi avviano ngrok start giftgenius-dev. Nel migliore dei casi uno dei tunnel non partirà (conflitto di dominio), nel peggiore — vi «soffierete» a vicenda la sessione, e ChatGPT a volte arriverà da uno, a volte dall’altro.
Ci sono diverse strategie.
La più semplice — domini dev personali:
- alex.dev.giftgenius.app;
- maria.dev.giftgenius.app.
E a ciascuno la propria Dev‑App in ChatGPT, ad esempio GiftGenius Dev (Alex) e GiftGenius Dev (Maria). Così ognuno lavora in locale senza disturbare il vicino.
Un approccio più «di squadra» — endpoint di staging comune:
- Tutti gli sviluppatori hanno un tunnel dev personale (per il debug individuale).
- In più c’è lo staging su Vercel, dove confluiscono le feature branch e a cui punta la Dev‑App comune GiftGenius Staging.
Questo approccio è spesso usato nei team reali:
- la feature nasce in locale e viene verificata tramite il tunnel personale;
- dopo il pull‑request e il merge viene testata da tutti via staging (senza tunnel, semplicemente tramite l’URL Vercel).
10. Sicurezza del tunnel di dev (breve e senza paranoia)
Il tunnel è un modo comodo per esporre il tuo server locale su Internet. E Internet, come sappiamo, è fatto in gran parte di bot, scanner e persone che amano verificare se ti sei dimenticato la password admin/admin.
Cose basilari da ricordare già in fase di dev:
- il tunnel dà accesso esterno a tutto quello che sta su quella porta; non esporre anche admin DB, phpMyAdmin e «la mia CRM di test senza password»;
- non pubblicare l’URL del tunnel in repository e chat pubbliche;
- spegni il tunnel quando non lavori (e spegni anche il laptop ogni tanto — ha bisogno di riposo pure lui).
Misure più serie come Basic Auth, verifica di header speciali o token nell’URL le vedremo nei moduli sulla sicurezza. Ora conta una cosa sola: il tunnel è uno strumento di sviluppo, non un server protetto. La produzione vivrà su un hosting serio, come Vercel, con altri meccanismi di protezione.
11. Pratica: configuriamo un dev‑URL stabile per la nostra app
Dalla teoria e dagli avvertimenti — alla pratica: colleghiamo tutto questo alla nostra app didattica su Next.js (template Apps SDK).
Supponiamo che la struttura del progetto sia questa:
apps/
web/ # App Next.js + widget
mcp-server/ # (opzionale) MCP separato oppure handler /mcp in web
In pratica puoi tenere MCP direttamente in Next.js, in app/api/mcp/route.ts, ma il principio è lo stesso.
Passo 1. Modifichiamo .env.local
Aggiungiamo il dev‑URL stabile del tunnel:
NEXT_PUBLIC_APP_URL=https://giftgenius-dev.yourdomain.com
Nel codice di dev abbiamo già usato baseUrl da questa variabile (vedi sopra). Se non lo hai fatto — è il momento di estrarlo.
Passo 2. Avviamo il server di dev e il tunnel
cd apps/web
npm run dev # Next.js su localhost:3000
# terminale separato
cloudflared tunnel run giftgenius-dev
Verifichiamo nel browser che https://giftgenius-dev.yourdomain.com si apra e mostri la tua App.
Passo 3. Colleghiamo in ChatGPT Dev Mode
Nell’interfaccia di ChatGPT (sezione sviluppatori):
- crea o modifica GiftGenius Dev;
- nel campo URL/Endpoint inserisci https://giftgenius-dev.yourdomain.com/;
- salva.
Dopo questo ChatGPT accede al manifest in /.well-known/openai-app, quindi avvia la tua App sopra quel dominio.
Ora puoi:
- modificare il codice del widget, gli handler MCP, gli stili;
- riavviare npm run dev;
- riavviare cloudflared tunnel run giftgenius-dev;
e al tempo stesso non toccare più le impostazioni della Dev‑App, finché il dominio resta lo stesso.
12. Come appare nella logica del codice: esempio con openExternal
Per chiudere il cerchio con quanto scritto nelle lezioni precedenti, aggiungiamo nel widget un pulsante «Apri l’interfaccia completa nel browser», che userà anch’esso il dev‑URL stabile.
Supponiamo di avere il componente React del widget GiftWidget:
// app/components/GiftWidget.tsx
"use client";
import { baseUrl } from "../lib/config"; // prendiamo baseUrl da env
export function GiftWidget() {
const handleOpenFull = () => {
window.openai.openExternal({
// apriamo la pagina dell'app in una nuova scheda
url: `${baseUrl}/full`,
label: "Apri l'interfaccia completa",
});
};
return (
<div>
<button onClick={handleOpenFull}>
Modalità completa
</button>
</div>
);
}
Se NEXT_PUBLIC_APP_URL punta al tunnel, allora:
- in sviluppo locale si aprirà la pagina https://giftgenius-dev.yourdomain.com/full;
- dopo il deploy su staging — https://giftgenius-staging.vercel.app/full;
- in prod — il dominio di produzione.
Ancora una volta — un’unica fonte di verità per il dominio: cambiamo l’ambiente, ma non cambiamo il codice.
13. Mini‑strategia: come pensare al tunnel «da grandi»
Riassumendo in un semplice modello mentale, puoi considerare che:
- il tunnel è semplicemente un cavo temporaneo tra il tuo laptop e un dominio pubblico stabile;
- ChatGPT Dev Mode conosce solo il dominio, e non gli importa dove gira fisicamente il codice;
- più raramente cambi il dominio, meno tempo passi nelle impostazioni di ChatGPT e dei provider OAuth;
- il tunnel di dev è solo una riga nella tua mappa degli ambienti, accanto a staging (Vercel preview) e prod (Vercel production).
La prossima lezione mostrerà come questo cavo viene sostituito da un hosting completo su Vercel e come collegare il tutto ai rami Git, ai deploy di preview e alla produzione.
14. Errori tipici con un tunnel «da grandi»
Errore n. 1: «Ho configurato un dominio statico, ma continuo a usare URL casuali».
A volte lo sviluppatore crea una volta il bell’giftgenius-dev.yourdomain.com, ma per abitudine avvia ngrok http 3000 senza config. Il risultato è che ChatGPT guarda un dominio, ma il codice gira dietro un altro. Se hai già impostato un dev‑URL stabile — usa solo quello e avvia il tunnel tramite config (tunnel/profilo nominato).
Errore n. 2: localhost:3000 hardcoded nel codice.
Capita quando in un componente React o in un handler MCP si scrive fetch("http://localhost:3000/api/..."). In locale magari funziona, ma in Dev Mode e ancor più su staging/prod si rompe subito. Estrai sempre l’URL di base nella config (baseUrl, NEXT_PUBLIC_APP_URL) e usalo ovunque servano link assoluti.
Errore n. 3: Modificare continuamente l’URL nel Dev Mode invece di usare un tunnel stabile.
Se ti accorgi di pensare «ok, cambio ancora l’URL nelle impostazioni, pazienza», — è un campanello d’allarme. Configurare un sottodominio statico in ngrok/Cloudflare richiede una volta 10–15 minuti, ma risparmia ore durante lo sviluppo.
Errore n. 4: Dominio statico condiviso dal team senza regole.
Due sviluppatori, un dominio giftgenius-dev.ngrok-free.app, e entrambi avviano il tunnel quando vogliono. Risultato — conflitto di tunnel, risposte che «misteriosamente» spariscono nel Dev Mode e debug in stile «a me funzionava». Per il team: o domini dev personali per tutti, o un dominio di staging su un hosting reale.
Errore n. 5: Trattare il tunnel come «quasi produzione».
A volte qualcuno pensa: «Se ho un HTTPS stabile via tunnel, facciamo passare traffico reale/pagamenti». È strada verso il dolore: spegni il laptop — l’app muore, cade la connessione — idem, e la sicurezza è al massimo simbolica. Il tunnel è uno strumento di dev. Il traffico di produzione è per Vercel e altra infrastruttura «da grandi», che affronteremo nella prossima lezione.
Errore n. 6: Dimenticare di sincronizzare variabili d’ambiente e Dev Mode.
Spesso si modifica NEXT_PUBLIC_APP_URL in .env.local, ma ci si dimentica di aggiornare l’URL nel Dev Mode (o viceversa). Il risultato è che il widget genera link verso un dominio, mentre ChatGPT si rivolge a un altro. Tieni una tabellina «ambiente ↔ dominio ↔ App in ChatGPT» e aggiornala quando cambi qualcosa — costa meno che indovinare quale URL sia quello giusto.
GO TO FULL VERSION