Hermes Agent가 작업하는 컴퓨터 화면을 볼 수 있게 해주는 XFCE
에이전트가 일하고 있다는 건 아는데, 지금 뭘 하는지는 텍스트로만 짐작해야 했다. "사이트 확인 중"이라고 찍히면 그런가 보다 하는 수밖에 없었다.
그록봇이 링크를 하나 던져줬다
그록봇을 직접 써보다가 겪은 일이다. 채팅으로 작업을 시켰더니 답변 중에 링크가 하나 나왔다. 눌러보니 그록이 지금 만지고 있는 화면이 그대로 떠 있었다. 브라우저가 열리고 페이지가 넘어가고 클릭이 찍히는 걸 앉아서 지켜봤다.
이게 생각보다 좋았다. 에이전트가 "이 사이트 들어가서 확인하고 있어요"라고 말로 설명하는 것과, 그 화면을 눈으로 보는 건 신뢰가 다르다. 엉뚱한 데를 누르면 바로 알아챌 수 있고, 캡차가 떠서 멈춰 있는 건지 아니면 그냥 느린 건지도 구분이 된다.
그래서 내 Hermes 에이전트한테도 같은 걸 해주고 싶어졌다. 채팅으로 일을 시키면, 링크 하나로 지금 뭘 누르고 있는지 내가 볼 수 있게.
그런데 내 컴퓨터 화면을 보여줄 수는 없었다
에이전트가 브라우저를 조작하려면 어딘가 화면이 있어야 하는데, 그게 내가 쓰는 컴퓨터면 곤란했다. 개인 파일도 있고 로그인해 둔 계정도 많다. 클립보드에 방금 복사한 비밀번호가 남아 있을 수도 있다. 링크로 열어볼 수 있는 화면이라면 더더욱 안 될 일이었다.
그래서 방향을 바꿨다. 에이전트가 쓸 컴퓨터를 하나 따로 만들고, 거기에만 링크를 걸어주기로 했다.
우분투 서버에 XFCE 데스크톱 하나 띄우기
만든 건 AI Agent Desktop이다. 이름 그대로 내 AI 에이전트 전용 데스크톱이고, 우분투 서버 위에 도커 컨테이너 하나로 돌아간다. 화면은 XFCE, 접속은 웹 브라우저로 한다.
services:
desktop:
image: lscr.io/linuxserver/webtop@sha256:5079531...
container_name: ai-agent-desktop
environment:
TITLE: "AI Agent Desktop"
START_DOCKER: "false"
HARDEN_DESKTOP: "true"
volumes:
- ./config:/config
ports:
- "127.0.0.1:3001:3000"
베이스 이미지는 linuxserver/webtop이다. 리눅스 데스크톱을 컨테이너로 띄워서 웹으로 스트리밍해주는 물건인데, 화면 서버 따로 붙이고 VNC 세팅하고 하는 과정을 전부 건너뛸 수 있다.
XFCE를 고른 이유는 단순하다. 가볍고, 브라우저 하나 띄우는 데 필요한 것만 있다. AI Agent가 여기서 할 일은 크로미움 열고 클릭하는 정도라 화려한 데스크톱 환경이 필요 없었다.
링크 하나로 들여다보기
바깥에서 이 화면에 닿는 통로는 Tailscale Serve로 만들었다.
sudo tailscale serve --bg --https=443 --set-path=/agent-desktop/ http://127.0.0.1:3001
이러면 https://duncan-ubuntu.tailb864de.ts.net/agent-desktop/ 주소 하나로 내 Tailnet에 들어와 있는 기기라면 어디서든 AI Agent 화면을 볼 수 있다. 맥북에서도 열리고 아이폰에서도 열린다. 그록봇에서 받았던 그 링크와 같은 역할이다.
AI Agent한테 웹 작업을 시켜놓고 이 링크를 띄워두면, 어느 사이트에 로그인하려는지 어떤 버튼을 눌렀는지 그대로 보인다. 로그 읽으면서 상상하던 것과 완전히 다른 감각이다.
대신 밖으로 새지 않게
화면을 링크로 열어둔 만큼, 이 컨테이너가 서버의 다른 곳으로 넘어갈 길은 다 막아뒀다.
| 항목 | 상태 |
|---|---|
| 호스트 홈 디렉토리 마운트 | 없음 |
| 도커 소켓 마운트 | 없음 |
| 특권 모드(privileged) | 꺼짐 |
| 호스트 네트워크 | 안 씀 (127.0.0.1에만 바인딩) |
| 컨테이너 안 도커 실행 | 꺼짐 |
| 클립보드 동기화 | 꺼짐 |
| 파일 전송 | 꺼짐 |
| 오디오·마이크 | 꺼짐 |
| 공유 링크·협업 세션 | 꺼짐 |
데이터가 남는 곳은 /config 하나뿐이다. 크로미움 프로필 정도가 쌓이고, 컨테이너를 지우면 나머지는 같이 없어진다.
포트도 127.0.0.1:3001로만 열었다. 같은 공유기 안에서도 직접 못 들어오고, Tailscale을 거친 링크가 유일한 입구다. Funnel은 켜지 않았다. 이걸 켜는 순간 인터넷 아무나 볼 수 있는 화면이 된다.
AI Agent한테 손 달아주기
화면이 보이는 것만으로는 반쪽이다. AI Agent가 그 화면에서 실제로 뭔가 해야 지켜볼 거리가 생긴다. 컨테이너 안의 xdotool을 docker exec로 부르는 셸 스크립트 desktopctl을 만들어서, AI Agent가 터미널 명령처럼 쓰게 했다.
./scripts/desktopctl open https://example.com
./scripts/desktopctl click 600 400
./scripts/desktopctl type 'hello world'
./scripts/desktopctl key ctrl+l
./scripts/desktopctl screenshot
스크린샷은 컨테이너 안에서 xwd로 찍고, 호스트로 꺼내서 ffmpeg로 PNG로 바꾸는 식이다.
docker exec --user abc -e "DISPLAY=:1" "$CONTAINER" xwd -root -silent -out "$container_xwd"
docker cp "$CONTAINER:$container_xwd" "$host_xwd"
ffmpeg -y -v error -i "$host_xwd" "$output"
이 스크립트는 ai-agent-desktop 컨테이너만 건드리게 짰다. 다른 컨테이너나 진짜 우분투 세션을 만질 방법이 아예 없다.
비밀번호를 안 건 이유
이 데스크톱에는 로그인 화면이 없다. 링크만 알면 바로 들어가진다. 허술해 보이는데 일부러 그렇게 뒀다.
누가 들어올 수 있는지는 이미 Tailscale이 정한다. 기기 인증도 접근 규칙도 거기서 걸린다. 그 위에 비밀번호를 하나 더 얹으면 화면 한 번 보려고 로그인을 두 번 하는 꼴이 된다. 링크 누르면 바로 화면이 뜨는 감각이 이 구조의 핵심인데, 그걸 스스로 깎을 이유가 없었다.
써보니
로그인이 필요한 사이트를 AI Agent한테 맡길 때 링크를 열어두고 작업을 지켜보는 게 습관이 됐다. 캡차가 뜨면 바로 보이고, 이상한 페이지로 넘어가면 그 자리에서 멈추라고 할 수 있다.
의외로 좋았던 건 마음이 편해졌다는 점이다. 뭔가 잘못돼도 그 컨테이너 안에서 끝난다는 걸 아니까, 예전 같으면 망설였을 작업도 그냥 시켜본다.
다음으로 붙이고 싶은 건 채팅 중에 AI Agent가 "지금 화면 보려면 여기"라고 링크를 알아서 던져주는 흐름이다. 그록봇에서 받았던 경험이 딱 그거였다.
정리
- 시작: 그록봇이 채팅에 던져준 링크로 에이전트 작업 화면을 실시간으로 본 경험
- 만든 것: 우분투 서버에 XFCE 데스크톱 컨테이너 하나, 링크로 접속
- 베이스:
linuxserver/webtop— 화면 서버·VNC 세팅 없이 웹으로 바로 붙음 - 막아둔 것: 호스트 마운트, 도커 소켓, 특권 모드, 클립보드, 파일 전송
- 입구: Tailscale Serve 링크 하나, Funnel 없음
- 조작:
desktopctl로xdotool클릭·입력,xwd+ffmpeg스크린샷
에이전트가 뭘 하는지 말로 듣는 것과 화면으로 보는 건 다르다. 그록봇 덕에 그 차이를 알았고, 이제 AI Agent 화면도 링크 하나로 열린다.
환경: 우분투 서버, 도커(linuxserver/webtop), XFCE, Tailscale Serve