CodeGym /Các khóa học /ChatGPT Apps /Đường hầm “trưởng thành”: dev‑URL ổn định và cập nhật tro...

Đường hầm “trưởng thành”: dev‑URL ổn định và cập nhật trong Dev Mode

ChatGPT Apps
Mức độ , Bài học
Có sẵn

1. Vấn đề “đường hầm ngẫu nhiên”

Khi bạn lần đầu chạy ngrok http 3000 hoặc Cloudflare Quick Tunnel cho nhanh, cảm giác như phép màu: bỗng một cái — http://localhost:3000 của bạn biến thành https://random-1234.tunnelprovider.com. Bạn có thể sao chép URL vào ChatGPT Dev Mode, và GPT vui vẻ tải App của bạn.

Rồi bạn khởi động lại đường hầm… và nhận một tên miền mới. URL cũ trong phần cài đặt Dev‑app của ChatGPT bỗng biến thành “liên kết hỏng”, GPT thông báo “App unavailable”, còn bạn lại phải vào cài đặt, đổi URL, bấm Save, chờ nó cập nhật, và âm thầm “ghét” cả cái stack này.

Để “vọc buổi tối” một lần thì còn chịu được. Nhưng khi bạn:

  • mỗi ngày chỉnh sửa App;
  • muốn cho đồng nghiệp/manager xem phiên bản giữa chừng;
  • song song dựng thêm staging và production,

việc phải kết nối lại Dev Mode mỗi lần URL ngẫu nhiên thay đổi trở thành nỗi khổ thuần túy.

Thêm nữa, nếu trong ứng dụng bạn đã thêm thứ gì đó phụ thuộc vào tên miền (ví dụ OAuth redirect URI hoặc webhook), mỗi URL mới cũng làm chúng hỏng theo. Hệ quả dây chuyền: đổi đường hầm — là phải chỉnh lại cấu hình App, redirect‑URL ở OAuth‑provider và cấu hình webhook‑receiver.

Từ đây nảy ra ý chính của bài: dev‑URL ổn định không phải xa xỉ, mà là công cụ giữ gìn “sức khỏe tinh thần” cho lập trình viên.

Insight

ChatGPT có các timeout rất nghiêm ngặt khi làm việc với ứng dụng của bạn, và ta dễ đánh giá thấp chúng. Lời gọi MCP‑tool có giới hạn thời gian: tối đa 2 phút — sau đó nền tảng sẽ coi như gọi thất bại, dù máy chủ của bạn vẫn đang làm gì đó.

Còn nghiêm hơn với đăng ký ứng dụng (Store hoặc Dev Mode): để đọc manifest, resources và mô tả công cụ, ChatGPT cho khoảng 20 giây. Nếu trong thời gian đó MCP‑server của bạn chưa kịp khởi tạo, trả danh sách tools/resources, v.v., việc đăng ký App sẽ timeout.

Khuyến nghị: mọi khởi tạo nặng nên diễn ra trước khi bạn vào Dev Mode hoặc Store. Làm ấm kết nối DB, nạp config lớn, cache lười,… — nên chạy trước, ví dụ chọc server một lần qua MCP Jam hoặc script nội bộ riêng. Từ góc nhìn nền tảng, MCP‑server phải “ấm” và trả lời trong vài giây, chứ không “thức dậy” ngay lúc đăng ký.

2. “Đường hầm trưởng thành” là gì

Ta cùng chốt lại, “đường hầm trưởng thành” khác gì so với thứ bạn chạy ở đầu khóa.

Chế độ ban đầu (mô‑đun 2) trông như sau:

# Ví dụ với ngrok
ngrok http 3000
# Nhận được: https://random-abc123.ngrok-free.app

Bạn lấy URL dùng một lần này và dán vào Dev Mode. Lần sau chạy ngrok thì URL đã khác, và cấu hình ChatGPT bị lỗi thời.

Trong cách làm “trưởng thành”, bạn có:

  • subdomain tĩnh ở nhà cung cấp đường hầm (hoặc tên miền riêng);
  • cùng một tên miền luôn được chuyển tới localhost:3000 của bạn;
  • bạn có thể khởi động lại đường hầm, máy, router, nhưng URL vẫn không đổi.

Những subdomain tĩnh có sẵn, ví dụ:

  • trong ngrok — một static domain miễn phí theo tài khoản;
  • trong Cloudflare Tunnel — thông qua đường hầm được đặt tên và gắn với tên miền của bạn.

Và ChatGPT‑app trong Dev Mode được cấu hình đúng một URL này và không quấy rầy bạn nữa.

Về mặt hình thức, yêu cầu cho “đường hầm trưởng thành” của chúng ta là:

  • một tên miền công khai HTTPS luôn ổn định;
  • chứng chỉ TLS hợp lệ (nhà cung cấp lo giúp);
  • cấu hình mô tả: “mọi thứ đến https://dev.yourdomain.com hãy chuyển tới http://localhost:3000”;
  • tùy chọn — biện pháp tối thiểu về bảo mật (ít nhất đừng khoe URL trên StackOverflow).

3. Thiết lập dev‑URL ổn định: ví dụ với Cloudflare Tunnel

Trong khóa học, chúng tôi khuyến nghị Cloudflare Tunnel làm công cụ chính, vì nó phù hợp cả dev lẫn các kịch bản nghiêm túc hơn. Ở mô‑đun 2 bạn đã thấy ví dụ cài đặt cơ bản, giờ ta “vặn” thêm để có dev‑URL cố định.

Giả sử ta có ứng dụng học tập GiftGenius và muốn URL ổn định là giftgenius-dev.yourdomain.com.

Các bước tối thiểu (đơn giản, không phụ thuộc UI Cloudflare):

  1. Gắn tên miền vào tài khoản Cloudflare (một lần, qua bảng điều khiển của họ).
  2. Cài cloudflared cục bộ và đăng nhập.
brew install cloudflare/cloudflare/cloudflared   # macOS
cloudflared login                                # sẽ mở trình duyệt để ủy quyền

3. Tạo đường hầm được đặt tên:

cloudflared tunnel create giftgenius-dev

4. Cấu hình route trong ~/.cloudflared/config.yml:

tunnel: giftgenius-dev
credentials-file: /Users/you/.cloudflared/giftgenius-dev.json

ingress:
  - hostname: giftgenius-dev.yourdomain.com
    service: http://localhost:3000  # dev server Next.js của chúng ta
  - service: http_status:404

5. Chạy đường hầm:

cloudflared tunnel run giftgenius-dev

Giờ, miễn là npm run devcloudflared tunnel run đang chạy, Next.js cục bộ của bạn sẵn sàng tại URL cố định https://giftgenius-dev.yourdomain.com. Và chính URL này bạn khai báo trong cài đặt ChatGPT Dev Mode.

Kết nối với ứng dụng của chúng ta

Nếu bạn mở trong trình duyệt URL ứng dụng mà bạn nhập vào ChatGPT khi kết nối Dev‑app:

https://giftgenius-dev.yourdomain.com/mcp

bạn sẽ thấy phản hồi (lỗi) — kiểu như:

{"jsonrpc":"2.0","error":{"code":-32000,"message":"Method not allowed."},"id":null}

Điều đó hoàn toàn bình thường, vì máy chủ ở /mcp không chờ GET. Các phần khác của ứng dụng — widget, MCP endpoint /mcp, các API route — cũng đi qua cùng đường hầm này, bạn không cần mỗi lần nhớ một tên miền mới.

4. Phương án khác: subdomain tĩnh trong ngrok

Nếu bạn đã quen ngrok, có thể “trưởng thành hóa” theo cách tương tự, dùng static domain. Từ 2023 ngrok cho phép ngay cả gói miễn phí ghim một subdomain tĩnh dạng myapp-dev.ngrok-free.app.

Sơ đồ tối thiểu:

# ~/.config/ngrok/ngrok.yml
authtoken: <token của bạn>
tunnels:
  giftgenius-dev:
    addr: 3000
    proto: http
    domain: giftgenius-dev.ngrok-free.app

Chạy:

ngrok start giftgenius-dev

Kết quả, URL https://giftgenius-dev.ngrok-free.app sẽ là cố định, và bạn đưa nó cho ChatGPT Dev Mode làm URL gốc của ứng dụng.

Tư tưởng vẫn vậy:

  • không còn địa chỉ “ngẫu nhiên”;
  • chỉ trạng thái nội bộ của đường hầm thay đổi (chạy/không chạy), chứ không phải tên miền;
  • không cần kết nối lại Dev Mode.

Cloudflare và ngrok ở đây chỉ là “hai vị kem” khác nhau. Có người thích tên miền riêng và kiểm soát DNS “tinh” (Cloudflare), người khác thích “khai báo YAML là xong” (ngrok). Với khóa học, cả hai đều hợp lệ, điều chính yếu — URL ổn định.

5. Sơ đồ: ChatGPT Dev Mode ↔ đường hầm ↔ stack cục bộ

Để hình thức hóa một chút, vẽ một bức tranh.

flowchart TD
    ChatGPT["ChatGPT (Dev Mode)"]
    AppCfg["Dev App (cấu hình: https://giftgenius-dev...)"]
    Tunnel["Đường hầm Cloudflare/ngrok (giftgenius-dev...)"]
    Next["Máy chủ dev Next.js localhost:3000 + MCP handler"]

    ChatGPT --> AppCfg
    AppCfg -->|"trong cấu hình chỉ định https://giftgenius-dev.../.well-known/openai-app"| Tunnel
    Tunnel -->|"Chuyển tiếp HTTPS → HTTP"| Next

ChatGPT không bao giờ biết bạn đang chạy gì trên laptop. Với nó chỉ có một endpoint HTTPS. Đằng sau đó là Vercel, đường hầm cục bộ hay Kubernetes — là việc của bạn. Và trong bài này chúng ta quan tâm chính là sự ổn định của endpoint HTTPS đó cho phát triển cục bộ.

Còn lại là làm sao để bên trong ứng dụng của chúng ta, địa chỉ này cũng là “nguồn chân lý” duy nhất, thay vì rải rác các chuỗi hardcode — phần tiếp theo sẽ nói về điều đó.

6. Biến môi trường và baseURL trong mã

Để mọi thứ chạy trơn tru, hữu ích là xác định một lần trong mã Next.js “URL bên ngoài gốc của ứng dụng” rồi dựa vào nó ở mọi nơi.

Ví dụ, trong thư mục app/lib/config.ts của ứng dụng GiftGenius, ta có thể tạo:

// app/lib/config.ts
export const baseUrl =
  process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000"; // dự phòng (fallback)

export const mcpEndpoint = `${baseUrl}/mcp`;  // URL máy chủ MCP

Còn trong .env.local khi phát triển, chỉ định:

NEXT_PUBLIC_APP_URL=https://giftgenius-dev.yourdomain.com

Khi đó:

  • bên trong widget và mọi liên kết, bạn luôn dùng baseUrl;
  • đối với ChatGPT Dev Mode và trình duyệt, mọi thứ trông nhất quán;
  • nếu ngày mai bạn chuyển sang Vercel staging với tên miền https://giftgenius-staging.vercel.app, chỉ cần đổi biến môi trường.

Điều này đặc biệt quan trọng cho:

  • callback‑URL (ví dụ cho OAuth, webhook handlers);
  • các liên kết bạn hiển thị cho người dùng trong widget (nút “Mở trong trình duyệt” qua openExternal);
  • mọi URL tuyệt đối trong logic ứng dụng.

Hiện ta mới nói về dev‑URL, nhưng ý tưởng kiến trúc “một nguồn chân lý cho baseUrl” cũng áp dụng ngon lành khi bạn chuyển sang staging/production.

7. Cập nhật URL trong ChatGPT Dev Mode

OK, ta đã có tên miền ổn định đẹp đẽ. Sống với nó trong Dev Mode thế nào?

Logic như sau:

  1. Trong cài đặt Dev‑app, bạn chỉ định một lần URL gốc: https://giftgenius-dev.yourdomain.com/
  2. ChatGPT truy cập manifest tại (.well-known/openai-app) và sau đó dùng cùng gốc cho MCP (/mcp), static, v.v.
  3. Nếu bạn chỉ thay đổi mã (React widget, MCP handlers, style), không cần đổi URL. Chỉ cần đường hầm chạy và máy chủ Next.js trả lời.
  4. Nếu bạn đổi chính tên miền (hiếm, ví dụ từ ngrok sang Cloudflare), thì vào Dev Mode cập nhật endpoint một lần.

Trong vài trường hợp, ChatGPT cache manifest nên thay đổi không xuất hiện ngay lập tức. Trong giao diện Dev Mode thường có nút kiểu “Reload configuration / Refresh App”, còn xấu nhất thì tắt rồi kết nối lại App với cùng URL cũng được.

Quan trọng: miễn là bạn không đổi URL, Dev Mode sẽ tự động “bắt” phiên bản mã mới. Tín hiệu chính đối với App là tên miền, không phải commit‑hash.

8. Chuyển đổi giữa dev / staging / prod trong Dev Mode

Tên miền dev ổn định chỉ là bước đầu. Để không chìm trong hỗn loạn URL khi dự án lớn dần, hữu ích là sớm hiểu đường hầm dev gắn thế nào vào sơ đồ môi trường (dev/staging/prod) và Dev Mode. Dù staging/prod sẽ là chủ đề của bài sau về Vercel, Dev Mode đã có thể làm việc với nhiều môi trường.

Để dễ hình dung, tham khảo bảng sau:

Môi trường URL gốc Mã chạy ở đâu
Local
https://giftgenius-dev.yourdomain.com
Next.js cục bộ + MCP qua đường hầm
Staging
https://giftgenius-staging.vercel.app
Vercel Preview / staging deploy
Prod
https://giftgenius.vercel.app
Vercel Production

Có hai cách làm việc với Dev Mode.

Thứ nhất — một Dev‑App, nhưng bạn thỉnh thoảng cập nhật URL trong cài đặt để thử staging hoặc prod (cẩn thận). Cách này hợp giai đoạn đầu, nhưng dễ nhầm: hôm nay test local, mai staging, ngày kia quên chuyển và vô tình gửi qua Dev‑App vào prod.

Cách thứ hai — lành mạnh hơn: nhiều Dev‑app, mỗi cái gắn rõ ràng với một môi trường:

  • GiftGenius Devgiftgenius-dev.yourdomain.com;
  • GiftGenius Staginggiftgenius-staging.vercel.app;
  • GiftGenius (sản phẩm, qua Store) → giftgenius.vercel.app.

Trong khuôn khổ bài này, ta đi từng bước, sắp xếp tối thiểu với dev‑URL. Ở bài sau, bạn sẽ thấy cách gắn Vercel và preview deploy với staging/production một cách logic.

9. Làm việc nhóm: nhiều lập trình viên và một đường hầm

Khi còn một dev‑domain và một lập trình viên “ẩn dật”, đường hầm là bạn tốt. Nhưng khi có cả đội, các đường hầm và môi trường bắt đầu chồng chéo, và quan trọng là đừng biến thành “cuộc chiến giành subdomain”.

Giả sử hai lập trình viên dùng chung một subdomain tĩnh, ví dụ giftgenius-dev.ngrok-free.app. Cả hai đều chạy ngrok start giftgenius-dev trên máy mình. Tốt nhất là một đường hầm không khởi động được (xung đột tên miền), tệ hơn là hai người sẽ “đá” phiên của nhau và ChatGPT lúc vào máy này lúc vào máy kia.

Có vài chiến lược.

Đơn giản nhất — dev‑domain cá nhân:

  • alex.dev.giftgenius.app;
  • maria.dev.giftgenius.app.

Và mỗi người có một Dev‑App trong ChatGPT, ví dụ GiftGenius Dev (Alex)GiftGenius Dev (Maria). Khi đó ai nấy chạy local của mình, không ảnh hưởng người khác.

Cách “đội nhóm” hơn — một endpoint staging chung:

  • Mỗi lập trình viên có đường hầm dev cá nhân (để debug riêng).
  • Thêm một staging trên Vercel, nơi merge các feature branch và nơi Dev‑App chung GiftGenius Staging trỏ tới.

Cách này rất phổ biến ngoài thực tế:

  • tính năng được xây trên local và debug qua đường hầm cá nhân;
  • sau pull‑request và merge, nó được mọi người test qua staging (không cần đường hầm, chỉ cần URL Vercel).

10. Bảo mật đường hầm dev (ngắn gọn, không hoang tưởng)

Đường hầm là cách tiện để đưa máy chủ cục bộ của bạn ra internet. Mà internet, như ta biết, chủ yếu là bot, scanner và những người thích kiểm tra xem bạn có quên mật khẩu admin/admin không.

Những điều cơ bản nên nhớ ngay từ giai đoạn dev:

  • đường hầm cho phép truy cập bên ngoài tới mọi thứ chạy trên cổng đó; đừng đưa cả admin DB, phpMyAdmin hay “CRM thử nghiệm không mật khẩu” lên đó;
  • đừng công khai URL đường hầm trong repo mở hoặc các phòng chat công cộng;
  • tắt đường hầm khi không làm việc (và thỉnh thoảng tắt cả laptop — máy cũng cần nghỉ).

Các biện pháp nghiêm ngặt hơn như Basic Auth, kiểm tra header đặc biệt hoặc token trong URL sẽ bàn trong các mô‑đun bảo mật. Điều quan trọng lúc này: đường hầm là công cụ phát triển, không phải máy chủ bảo vệ. Sản phẩm sẽ chạy trên hosting “đúng nghĩa”, như Vercel, với cơ chế bảo vệ khác — ta sẽ tới đó trong bài sau.

11. Thực hành: thiết lập dev‑URL ổn định cho ứng dụng của chúng ta

Giờ từ lý thuyết và cảnh báo — sang thực hành: gắn tất cả vào ứng dụng Next.js mẫu (Apps SDK) của chúng ta.

Giả sử cấu trúc dự án như sau:

apps/
  web/          # Next.js App + widget
  mcp-server/   # (tùy chọn) MCP tách riêng, hoặc /mcp handler nằm trong web

Trong thực tế bạn có thể đặt MCP ngay trong Next.js, ở app/api/mcp/route.ts, nhưng nguyên tắc là như nhau.

Bước 1. Sửa .env.local

Thêm dev‑URL ổn định của đường hầm:

NEXT_PUBLIC_APP_URL=https://giftgenius-dev.yourdomain.com

Trong mã dev ta đã dùng baseUrl lấy từ biến này (xem trên). Nếu chưa dùng — đây là lúc tách ra.

Bước 2. Chạy dev‑server và đường hầm

cd apps/web
npm run dev          # Next.js trên localhost:3000

# terminal riêng
cloudflared tunnel run giftgenius-dev

Kiểm tra trên trình duyệt xem https://giftgenius-dev.yourdomain.com mở được và hiển thị App của bạn.

Bước 3. Kết nối trong ChatGPT Dev Mode

Trong giao diện ChatGPT (mục dành cho lập trình viên):

  • tạo hoặc chỉnh GiftGenius Dev;
  • ở trường URL/Endpoint, nhập https://giftgenius-dev.yourdomain.com/;
  • lưu.

Sau đó ChatGPT truy cập manifest tại /.well-known/openai-app, rồi bắt đầu chạy App của bạn trên tên miền này.

Giờ bạn có thể:

  • thay đổi mã widget, MCP‑handlers, style;
  • khởi động lại npm run dev;
  • khởi động lại cloudflared tunnel run giftgenius-dev;

không bao giờ phải vào lại cài đặt Dev‑App, miễn là tên miền giữ nguyên.

12. Trông như thế nào trong mã: ví dụ với openExternal

Để khép lại ví dụ liên hệ với bài trước, thêm vào widget nút “Mở giao diện đầy đủ trong trình duyệt”, cũng dùng dev‑URL ổn định.

Giả sử ta có React component widget GiftWidget:

// app/components/GiftWidget.tsx
"use client";

import { baseUrl } from "../lib/config"; // lấy baseUrl từ env

export function GiftWidget() {
  const handleOpenFull = () => {
    window.openai.openExternal({
      // mở trang ứng dụng ở tab riêng
      url: `${baseUrl}/full`,
      label: "Mở giao diện đầy đủ",
    });
  };

  return (
    <div>
      <button onClick={handleOpenFull}>
        Chế độ đầy đủ
      </button>
    </div>
  );
}

Nếu NEXT_PUBLIC_APP_URL trỏ tới đường hầm, thì:

  • khi phát triển cục bộ sẽ mở trang https://giftgenius-dev.yourdomain.com/full;
  • sau khi deploy lên staging — https://giftgenius-staging.vercel.app/full;
  • ở prod — tên miền sản phẩm.

Vẫn là một nguồn chân lý cho tên miền: đổi môi trường, không cần đổi mã.

13. Mini‑chiến lược: nghĩ về đường hầm theo cách “trưởng thành”

Tóm lại thành một mô hình tinh gọn, có thể coi rằng:

  • đường hầm chỉ là sợi dây tạm giữa laptop của bạn và một tên miền công khai ổn định;
  • ChatGPT Dev Mode chỉ biết tên miền, và không quan tâm mã chạy ở đâu;
  • càng ít đổi tên miền, bạn càng ít mất thời gian trong cài đặt ChatGPT và OAuth‑provider;
  • đường hầm dev chỉ là một dòng trong bản đồ môi trường tổng thể của bạn, bên cạnh staging (Vercel preview) và prod (Vercel production).

Bài sau sẽ chỉ ra cách sợi dây này được thay bằng hosting “xịn” trên Vercel, và cách gắn tất cả với nhánh Git, preview deploy và production.

14. Lỗi thường gặp khi làm việc với đường hầm “trưởng thành”

Lỗi số 1: “Tôi đã cấu hình tên miền tĩnh, nhưng vẫn dùng URL ngẫu nhiên”.
Đôi khi lập trình viên tạo được giftgenius-dev.yourdomain.com đẹp đẽ, nhưng theo thói quen vẫn chạy ngrok http 3000 không có config. Kết quả là ChatGPT nhìn vào một tên miền, còn mã chạy sau một tên miền khác. Nếu bạn đã có dev‑URL ổn định — chỉ dùng nó, và chạy đường hầm qua config (đường hầm/ hồ sơ được đặt tên).

Lỗi số 2: Ghi cứng (hardcode) localhost:3000 trong mã.
Gặp khi trong React component hoặc MCP handler viết fetch("http://localhost:3000/api/..."). Ở local còn chạy được, nhưng trong Dev Mode và nhất là staging/prod sẽ hỏng ngay. Luôn đưa URL gốc vào config (baseUrl, NEXT_PUBLIC_APP_URL) và dùng nó ở mọi nơi cần liên kết tuyệt đối.

Lỗi số 3: Liên tục sửa URL trong Dev Mode thay vì dùng đường hầm ổn định.
Nếu bạn nghĩ “thôi được, đổi URL trong cài đặt thêm lần nữa”, — đó là tín hiệu. Cài một subdomain tĩnh ở ngrok/Cloudflare chỉ tốn 10–15 phút một lần, nhưng tiết kiệm hàng giờ trong quá trình phát triển.

Lỗi số 4: Dùng chung tên miền tĩnh trong đội mà không có quy ước.
Hai lập trình viên, một tên miền giftgenius-dev.ngrok-free.app, và ai cũng chạy đường hầm khi thích. Kết quả — xung đột đường hầm, các phản hồi “biến mất một cách huyền bí” trong Dev Mode và debug kiểu “máy tôi chạy mà”. Với đội ngũ, hoặc là domain dev cá nhân cho mỗi người, hoặc một domain staging trên hosting thực sự.

Lỗi số 5: Xem đường hầm như “gần như production”.
Đôi khi ai đó nghĩ: “Nếu tôi có HTTPS ổn định qua đường hầm, hãy để người dùng/thanh toán thật đi qua nó”. Đó là con đường đau khổ: laptop tắt — ứng dụng tắt, mạng rớt — cũng vậy, còn bảo mật thì cùng lắm là tượng trưng. Đường hầm là công cụ dev. Lưu lượng thật dành cho Vercel và hạ tầng trưởng thành — ta sẽ tới trong bài sau.

Lỗi số 6: Quên đồng bộ biến môi trường và Dev Mode.
Thường người ta đổi NEXT_PUBLIC_APP_URL trong .env.local, nhưng quên đổi URL trong Dev Mode (hoặc ngược lại). Kết quả là widget sinh liên kết tới một tên miền, còn ChatGPT gọi tới tên miền khác. Hãy giữ một bảng đơn giản “môi trường ↔ tên miền ↔ App trong ChatGPT” và cập nhật khi thay đổi — rẻ hơn nhiều so với việc đoán URL nào mới là thật.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION