AI가 만든 화면을 확인하려고 서버를 공개해야 했던 문제
AI 코딩 에이전트가 React 화면을 수정한 뒤 브라우저로 확인하려면 의외로 번거로운 연결 작업이 필요하다. 개발 서버는 컨테이너의 5173번 포트에서 실행 중인데, 브라우저는 별도의 클라우드 환경에 있어서 그 주소로 바로 접속할 수 없기 때문이다. 이전에는 외부 공개 URL이나 터널을 만들어 브라우저가 접속하도록 연결하는 방식을 생각하기 쉬웠다.
하지만 임시 미리보기 주소가 인터넷에 노출되면 테스트용 관리자 화면, 아직 검토하지 않은 API, 개발 중인 데이터가 함께 접근 가능한 상태가 될 수 있다. 인증과 접근 제어를 제대로 구성했다면 터널 자체가 곧 취약점이라는 뜻은 아니다. 다만 화면 하나 확인하려고 공개 주소와 권한 정책을 따로 관리해야 하는 부담은 분명히 생긴다.
Cloudflare는 2026년 10월 28일 Agents SDK의 브라우저에 내부 호스트 이름을 연결하는 기능을 발표했다. 에이전트가 사용하는 Browser Run 브라우저에서 preview.internal 같은 이름을 열면, 요청이 공개 인터넷으로 나가지 않고 에이전트가 제공한 개발 서버로 전달된다. 핵심은 브라우저 테스트를 없애는 것이 아니라 테스트할 주소를 공개하지 않아도 된다는 점이다.
preview.internal 요청은 어떤 경로로 전달될까
일반 웹사이트를 열면 브라우저는 공개 DNS와 인터넷을 거쳐 서버에 요청한다. 내부 호스트는 이 경로를 쓰지 않는다. Browser Run이 내부 호스트 요청을 Cloudflare Worker 쪽으로 돌려보내고, 해당 Worker의 Durable Object에서 등록한 fetch 함수가 실제 응답을 만든다. Durable Object는 에이전트의 상태와 브라우저 연결을 유지하는 실행 단위다.
예를 들어 에이전트가 샌드박스에서 Vite 개발 서버를 실행했다고 가정해 보자. 브라우저가 http://preview.internal/을 요청하면 등록된 fetch 함수가 샌드박스의 포트 5173으로 요청을 넘긴다. 반환된 HTML과 자산을 브라우저가 렌더링하므로 에이전트는 실제 화면의 레이아웃과 오류를 확인할 수 있다. 포트 연결 함수는 애플리케이션에서 별도로 구현해야 한다.
연결 대상은 개발 서버만이 아니다. 작업 공간의 정적 파일 폴더를 읽게 하거나 R2 버킷의 파일을 제공할 수 있고, 서비스 바인딩으로 다른 Worker를 연결할 수도 있다. 따라서 단순히 localhost를 다른 이름으로 바꾸는 기능보다 범위가 넓다. 공개 URL과 내부 호스트를 한 브라우저에서 함께 다룰 수 있지만, 보안상 외부 사이트 접근을 허용할지는 따로 결정해야 한다.
Agents SDK 0.31.0부터 설정하는 순서
먼저 기존 Cloudflare Agents 프로젝트에 agents 패키지 0.31.0 이상이 설치돼 있는지 확인한다. 이 버전의 공식 릴리스에는 내부 호스트 지원이 명시돼 있다. 기능은 일반적인 로컬 Chrome의 DNS 설정이 아니라 Cloudflare Browser Run과 Agents SDK를 함께 쓰는 구성에서 제공된다. 다른 브라우저 자동화 서비스에 같은 주소만 넣는다고 동작하지 않는다.
브라우저를 만드는 부분에서 browserRun()의 internalHosts 설정에 preview.internal을 등록한다. 등록 항목에는 설명, 선택적으로 대상 포트의 스키마, 실제 요청을 처리할 fetch 함수를 지정한다. 공식 예제는 Zod 스키마로 포트가 1024 이상인 정수인지 확인하고, fetchSandboxPort()라는 애플리케이션 함수를 통해 해당 포트로 연결한다. 이 함수는 SDK가 자동으로 제공하는 마법의 함수가 아니라 예제 프로젝트에서 구현해야 할 연결 코드다.
Durable Object에서는 InternalHostRouter를 내보내고, browserRun에 router를 전달한 다음 fetchInternalHost()를 Browser 객체에 연결한다. Agent 클래스를 사용하면 해당 메서드는 기본 제공되지만, 일반 DurableObject를 직접 구현한다면 공식 예제처럼 명시해야 한다. 기존에 Pi Durable, AI SDK, TanStack AI를 쓰는 에이전트는 제공되는 브라우저 도구 어댑터를 이용할 수 있고 다른 실행 환경은 browser.session()으로 연결할 수 있다.
마지막으로 샌드박스 안에서 실제 개발 서버가 실행 중인지 확인하고 브라우저 도구에 미리보기 요청을 맡긴다. 이 글의 구성 예시는 공식 문서를 읽고 설명한 것이며 Cloudflare 계정에 배포하거나 Browser Run을 직접 호출해 성공을 측정한 결과는 아니다. 환경마다 샌드박스 포트 전달 함수와 Durable Object 바인딩을 구현해야 한다는 점을 남겨 둬야 한다.
// Cloudflare Agents SDK 0.31.0+의 핵심 구성 형태를 축약한 문서 기반 예시
// 실제 실행에는 Browser binding, Durable Object, 포트 연결 함수가 필요함
const browser = new Browser({
provider: browserRun(env.BROWSER, {
guardrails: { allowedDomains: [] },
internalHosts: {
router: ctx.exports.InternalHostRouter,
hosts: {
"preview.internal": {
description: "Development preview",
target: z.object({ port: z.number().int().min(1024) }),
fetch: (request, { port }) => fetchSandboxPort(port, request),
},
},
},
}),
});에이전트가 포트를 고르게 할 때 생기는 보안 경계
고정된 사이트 하나만 보여 준다면 내부 호스트에 fetch 함수를 직접 지정하면 된다. 여러 프로젝트를 오가는 에이전트라면 target 스키마를 붙여 모델이 연결할 대상을 선택하게 할 수 있다. 예를 들어 모델이 browser.assignHost()를 호출해 preview.internal의 대상 포트를 5173으로 지정하면 이후 같은 호스트로 들어온 요청에 그 포트가 전달된다. 할당은 명시적으로 지우기 전까지 유지되며 브라우저 교체나 재배포 뒤에도 남을 수 있다.
여기서 중요한 점은 모델이 선택할 수 있는 값의 범위다. 대상 포트를 무제한으로 받거나 임의 파일 경로를 그대로 열어 주면 내부 호스트가 의도하지 않은 서비스나 파일에 접근하는 통로가 될 수 있다. 공식 문서는 Zod 등의 스키마로 포트 범위, 폴더 경로와 허용 값을 제한하라고 안내한다. 정적 폴더를 연결할 때는 작업 공간 내부 경로인지 확인하고 상위 디렉터리 이동 문자열을 거부하는 예시도 제공한다.
브라우저의 allowedDomains 제한은 내부 호스트에는 적용되지 않는다. 외부 사이트를 동시에 열 수 있도록 허용하면, HTTP로 열린 외부 페이지가 내부 호스트에 요청을 보낼 수 있는 경우도 고려해야 한다. 내부 서비스에 상태를 변경하는 API가 있다면 Origin을 검사하고, 가능하면 외부 접근을 차단하는 allowedDomains: []를 사용한다. 내부 주소라는 사실만으로 인증과 권한 검사를 생략해서는 안 된다.
웹소켓과 로컬 개발에는 아직 제약이 있다
내부 호스트 이름은 소문자로 된 .internal, .test, .example, .invalid 같은 예약 접미사만 사용할 수 있다. 등록할 때는 preview.internal처럼 호스트 이름만 쓰며 주소 뒤에 :5173을 붙이지 않는다. 브라우저는 HTTP 80번 포트로 접속하고, 내부 라우팅 설정이 실제 샌드박스 포트를 결정한다. 브라우저당 등록 가능한 내부 호스트는 최대 여덟 개다.
현재 내부 호스트는 HTTPS와 WebSocket을 지원하지 않는다. Vite나 다른 프런트엔드 개발 서버가 WebSocket으로 화면을 자동 갱신하는 기능은 이 경로에서 연결되지 않을 수 있다. 따라서 코드 변경 뒤 자동 새로고침만 기다리는 대신 브라우저를 명시적으로 다시 탐색하게 하는 테스트 흐름이 적합하다. 인증 쿠키나 HTTPS 전용 동작을 검증해야 한다면 별도 환경이 필요하다.
또한 이 기능은 Worker가 실제로 배포돼 있어야 동작한다. 로컬 개발에서 브라우저를 시작하면 내부 호스트가 빠지고 경고가 남는다고 공식 문서는 설명한다. 개발 서버는 샌드박스에 있을 수 있지만 요청을 중계하는 Worker는 배포된 상태여야 한다는 뜻이다. 브라우저를 완전히 교체하는 호스트 구성 변경이나 대상 Worker 변경 때에는 세션을 닫고 다시 여는 처리가 필요할 수 있다.
| 항목 | 현재 조건 | 실무 영향 |
|---|---|---|
| SDK | agents 0.31.0 이상 | 기존 패키지 버전 확인 |
| 호스트 수 | 브라우저당 최대 8개 | 여러 프로젝트는 대상 재할당 고려 |
| 프로토콜 | HTTP만 지원 | HTTPS·WebSocket 테스트는 별도 구성 |
| 실행 위치 | 배포된 Worker 필요 | 로컬 전용 테스트와 구분 |
| 외부 접근 | 가드레일 별도 설정 | 내부 호스트도 권한 검사 필요 |
2026년 10월 29일 갱신된 Cloudflare 공식 Browser 문서 기준. 향후 SDK 변경에 따라 달라질 수 있다.
요금은 내부 호스트가 아니라 브라우저 사용량부터 확인
내부 호스트 기능이 생겼다고 Browser Run의 사용료가 사라지는 것은 아니다. Cloudflare의 공개 요금표는 Workers Free에서 하루 10분의 브라우저 시간과 동시 브라우저 세 개를 제공한다고 안내한다. Workers Paid에서는 월 10시간과 평균 동시 브라우저 열 개가 포함되고, 초과 브라우저 시간은 시간당 0.09달러, 추가 동시 브라우저는 개당 월 2달러 기준이다. 요금은 브라우저 사용 방식과 플랜에 따라 달라진다.
이 수치는 Browser Run의 일반 요금표이며 내부 호스트에만 붙는 별도 가격이라는 뜻은 아니다. 에이전트가 호출하는 모델의 추론 비용, Durable Object 실행, 샌드박스나 컨테이너 비용까지 무료로 포함된다는 근거도 없다. 전체 시스템 비용을 계산할 때는 브라우저 사용량과 그 밖의 Cloudflare 서비스 사용량을 나눠 보는 편이 정확하다.
예를 들어 하루에 브라우저를 몇 차례만 열어 화면을 확인하는 개인 프로젝트라면 포함 사용량 안에서 시험해 볼 여지가 있다. 반대로 에이전트가 여러 브랜치의 화면을 장시간 열어 두고 반복 테스트하면 브라우저 시간과 동시 세션 수가 빠르게 늘어난다. 실제 청구 전에는 계정의 Workers 플랜과 Browser Run 사용량 화면을 확인해야 하며, 이 글에서 임의의 월 예상 비용을 보장하지 않는다.
| 항목 | Workers Free | Workers Paid |
|---|---|---|
| 포함 브라우저 시간 | 하루 10분 | 월 10시간 |
| 동시 브라우저 | 3개 | 월평균 10개 |
| 초과 시간 요금 | 추가 이용 불가 | 시간당 $0.09 |
| 초과 동시 이용 | 추가 이용 불가 | 브라우저당 월 $2.00 |
Cloudflare Browser Run 공식 가격표. 브라우저 세션 방식과 다른 서비스 비용은 별도로 확인해야 한다.
어떤 팀에 맞고 언제 기존 터널을 유지할까
이 기능이 특히 유용한 곳은 에이전트가 코드를 고친 직후 브라우저로 결과를 확인하는 반복 작업이다. 같은 Cloudflare Agents 환경 안에서 개발 서버와 브라우저를 관리한다면 공개 URL을 발급하고 폐기하는 과정을 줄일 수 있다. 여러 프런트엔드 미리보기와 내부 API를 에이전트가 선택적으로 살펴보는 경우에도 내부 호스트가 편리하다.
반면 사람에게 링크를 공유해 직접 검수받는 상황이라면 내부 호스트가 공개 미리보기 URL을 대신하지 못한다. 이 이름은 해당 Browser Run 브라우저에서만 접근하도록 설계됐기 때문이다. 외부 테스터가 로그인해 동작을 확인하거나, HTTPS·WebSocket이 반드시 필요한 경우에도 기존 프리뷰 배포나 접근 제어된 터널을 계속 사용하는 편이 낫다.
도입을 판단할 때는 네 가지를 확인하면 된다. 에이전트가 이미 Cloudflare Agents SDK와 Browser Run을 쓰는지, 개발 서버 응답을 Worker의 fetch 함수로 안전하게 연결할 수 있는지, 테스트가 HTTP 화면 확인으로 충분한지, 브라우저와 샌드박스 비용을 감당할 수 있는지다. 해당 조건이 맞으면 0.31.0 이상에서 작은 미리보기 하나부터 검증하고, 그렇지 않다면 기존 도구를 굳이 바꿀 이유는 없다.
내 PC의 localhost:5173을 바로 연결할 수 있나?
아니다. 내부 호스트는 Cloudflare의 Browser Run과 배포된 Worker를 통해 에이전트가 제공하는 응답에 연결한다. 로컬 PC 포트가 자동으로 공개되거나 연결되는 기능은 아니다.
내부 호스트에 HTTPS나 WebSocket을 사용할 수 있나?
2026년 10월 29일 기준 공식 문서는 HTTP만 지원하고 HTTPS와 WebSocket은 지원하지 않는다고 안내한다.
무료 플랜에서 사용할 수 있나?
Browser Run 공식 요금표에는 Workers Free의 하루 10분과 동시 브라우저 3개가 안내돼 있다. 다른 서비스의 이용 조건과 실제 계정 사용 가능 여부는 별도로 확인해야 한다.
