전체 구성
설치는 세 단계(Phase)로 진행되며, 마지막에 검증 스크립트로 마무리합니다. 각 단계는 서로 다른 디렉토리에 독립된 Docker 컨테이너 묶음을 만듭니다.
메인 스택
OpenWebUI · Twilio 전화봇 · Qdrant · OpenAPI 도구를 ~/OpenWebUI에 설치
AI 브라우저 에이전트
Browser Use + Playwright 기반 검색·브라우징 에이전트를 ~/OpenWebUI/browser-agent에 설치
Telegram 브릿지
OpenWebUI의 모델·도구를 Telegram에서 쓰도록 ~/telegram-openwebui-bridge에 연결
4개 스크립트 한눈에
각 파일의 정확한 이름·버전·역할·생성물입니다. 파일명은 실행 명령에 그대로 쓰이니 오타 없이 확인하세요.
start-openwebui-
hardened.sh
메인 설치 — OpenWebUI + Twilio 전화봇
- 설치 위치
- ~/OpenWebUI
- 핵심
- Ollama·Qdrant·Twilio
- 보안
- 21항목
setup-browser-agent-
browser-use-v7-fixed.sh
AI 브라우저 에이전트 + Multi-Agent
- 설치 위치
- ~/OpenWebUI/
browser-agent - 핵심
- Browser Use·Playwright
- 포트
- 8001
setup-telegram-
openwebui-bridge-FINAL.sh
OpenWebUI ↔ Telegram 연동
- 설치 위치
- ~/telegram-
openwebui-bridge - 핵심
- 봇 토큰·화이트리스트
- 보안
- 26항목
verify-install.sh
설치 후 정합성·보안 검증
- 대상
- 위 3개 전체
- 검사
- 컨테이너·포트·패치
- 실행
- 마지막 단계
filter_response 함수 정의가 누락되어
/browse 호출 시 NameError가 발생하던 버그를 바로잡은 버전입니다.
앵커 매칭에 실패해도 함수 정의가 항상 주입되도록 안전장치가 추가되어 있습니다.
사전 준비
Ubuntu 서버와 Docker가 필요합니다. 스크립트가 Ollama와 Docker 설치를 돕지만, 아래 항목은 미리 갖춰두면 설치가 매끄럽습니다.
서버 사양 (권장)
| 항목 | 최소 | 권장 |
|---|---|---|
| OS | Ubuntu 22.04+ | Ubuntu 24.04 LTS |
| CPU | 2 vCPU | 4 vCPU 이상 |
| 메모리 | 4 GB | 8 GB 이상 (브라우저 에이전트 동시 실행 시) |
| 디스크 | 20 GB | 40 GB 이상 |
Docker 설치 확인
$ docker --version Docker version 27.x, build … $ docker compose version Docker Compose version v2.x
두 명령이 버전을 출력하면 준비된 것입니다. docker compose(공백형)가
동작하지 않으면 구버전 docker-compose(하이픈형)로 대체할 수 있습니다.
서버 셋업 · 필수 파일 · Docker · Ollama
클라우드 서버를 새로 받은 직후, 스크립트를 돌리기 전에 갖춰야 할 것들입니다. 4개 설치 스크립트와 도구 파일을 서버에 올리고, Docker·Docker Compose·Ollama를 준비하면 Phase 2부터 막힘없이 진행됩니다.
1. 빈 우분투 기본 준비
방금 설치한 깨끗한 Ubuntu라면 먼저 패키지 목록을 갱신하고, 파일을 받는 데
필요한 git·curl·wget·unzip을 설치합니다.
$ sudo apt update && sudo apt upgrade -y $ sudo apt install -y git curl wget unzip ca-certificates # 작업 폴더 생성 $ mkdir -p ~/install && cd ~/install
2. 필수 파일 다운로드
아래 파일들을 ~/install 한 폴더에 모읍니다. 받는 방법은 세 가지 중 편한 것을 고르면 됩니다.
| 파일 | 역할 | 비고 |
|---|---|---|
start-openwebui-hardened.sh | Phase 2 · 메인 스택 설치 | 가장 먼저 실행 |
setup-browser-agent-browser-use-v7-fixed.sh | AI 브라우저 에이전트 설치 | 네이버·Tavily 키 입력 단계 포함 |
setup-telegram-openwebui-bridge-FINAL.sh | Telegram 브릿지 설치 | Phase 3 |
verify-install.sh | 설치 후 정합성·보안 검증 | 마지막 단계 |
방법 A — Git 저장소에서 clone (권장)
파일들이 Git 저장소에 있다면 한 번에 받습니다.
$ cd ~/install $ git clone https://github.com/<계정>/<저장소>.git . # 비공개 저장소면 토큰 또는 SSH 키로 인증
방법 B — 로컬 PC에서 서버로 직접 전송 (scp)
파일이 내 PC에만 있을 때 사용합니다.
# 로컬 PC 터미널에서 실행 $ scp ./*.sh user@your-server-ip:~/install/
방법 C — 개별 URL에서 직접 받기 (wget)
각 파일의 다운로드 링크가 있을 때 사용합니다.
$ cd ~/install $ wget https://<다운로드주소>/start-openwebui-hardened.sh $ wget https://<다운로드주소>/setup-browser-agent-browser-use-v7-fixed.sh $ wget https://<다운로드주소>/setup-telegram-openwebui-bridge-FINAL.sh $ wget https://<다운로드주소>/verify-install.sh
어떤 방법이든 받은 뒤에는 파일이 다 있는지 확인하고 실행 권한을 줍니다.
$ cd ~/install && ls -al $ chmod +x *.sh
3. Docker · Docker Compose 설치
서버에 Docker가 없다면 공식 설치 스크립트로 한 번에 설치합니다.
설치 후 현재 사용자를 docker 그룹에 넣어야 sudo 없이 실행됩니다.
$ curl -fsSL https://get.docker.com | sh $ sudo usermod -aG docker $USER # 그룹 적용을 위해 로그아웃 후 재접속 (또는 newgrp docker) $ docker --version $ docker compose version
두 명령이 버전을 출력하면 준비된 것입니다. docker compose(공백형)가
동작하지 않으면 구버전 docker-compose(하이픈형)로 대체할 수 있습니다.
4. Ollama 설치 (로컬 LLM)
스크립트가 Ollama 설치를 돕지만, 미리 깔아두면 매끄럽습니다. 설치 후 서비스가 11434 포트에서 동작하는지 확인하고, 필요한 모델을 미리 받아두면 첫 실행이 빨라집니다.
$ curl -fsSL https://ollama.com/install.sh | sh $ ollama --version # 서비스 상태 확인 $ systemctl status ollama --no-pager # 모델 미리 받기 (예시) $ ollama pull llama3.3 $ ollama list
nvidia-container-toolkit을 먼저 설치해야
Docker 컨테이너에서 GPU를 인식합니다. CPU만으로도 동작하지만 추론 속도가 느립니다.
무거운 추론은 Groq 같은 외부 API로 넘기는 구성을 권장합니다.
5. 방화벽 · 포트
모든 서비스는 보안을 위해 127.0.0.1(로컬)에만 바인딩됩니다.
외부 접속은 SSH 터널이나 Cloudflare Tunnel을 통하므로, 클라우드 방화벽에서는
22(SSH)만 열어두면 충분합니다. 필요 포트는 9번 섹션을 참고하세요.
chmod +x 한 스크립트 4개가 한 폴더에 있고, docker compose version과
ollama --version이 정상 출력되면 Phase 2로 넘어갈 준비가 끝난 것입니다.
미리 발급할 API 키
설치 중 입력 시간이 제한(스크립트별 약 180초)되어 있으므로, 필요한 키는 미리 발급해 손에 들고 시작하세요. 모든 키는 선택·필수가 갈립니다.
| 키 | 용도 | 필수 여부 | 발급처 |
|---|---|---|---|
| Groq API Key | LLM 추론 · Multi-Agent | 브라우저 에이전트는 필수 | console.groq.com (무료) |
| 네이버 검색 API (Client ID·Secret) | 한국어 검색 | 선택 (없으면 Tavily로 폴백) | developers.naver.com (무료/일 25,000건) |
| Tavily API Key | 웹 검색 폴백 | 선택 (tvly-로 시작) | app.tavily.com (무료) |
| Twilio 자격증명 | 전화·SMS 봇 | 전화봇 사용 시 필수 | console.twilio.com |
| Telegram Bot Token | Telegram 브릿지 | Phase 3 필수 | @BotFather → /newbot |
| Telegram User ID | 관리자 화이트리스트 | Phase 3 필수 | @userinfobot |
Phase 2 · 메인 스택 설치
start-openwebui-hardened.sh가 OpenWebUI, Twilio 전화봇,
Qdrant 벡터 DB, OpenAPI 도구 서버를 ~/OpenWebUI에 설치합니다.
# 스크립트를 서버에 올린 뒤 실행 권한 부여 $ chmod +x start-openwebui-hardened.sh $ ./start-openwebui-hardened.sh
설치 중 입력값
스크립트가 순서대로 아래를 물어봅니다. 모두 마스킹 처리되며, 빈 비밀번호는
openssl rand로 자동 생성됩니다.
- Groq API Key — 입력하면 Groq 모델 사용, 건너뛰면 OpenWebUI 모델만 사용
- OpenWebUI 관리자 비밀번호 — 비워두면 자동 생성되어 화면에 1회 표시
- Twilio 자격증명 · 전화번호 — 전화/SMS 봇을 쓸 때 입력
- 관리자 PIN (6자리 숫자) — 필수. 취약한 PIN은 거부됨
- 연락처 —
이름,전화번호형식. 건너뛰면 설치 후 음성 명령으로 추가 가능 - SSL 도메인 / Cloudflare Tunnel Token — 외부 HTTPS 접속용(선택)
🎉 설치 완료! 메시지와 함께 접속 주소
(http://localhost:3000 등)가 출력됩니다.
AI 브라우저 에이전트 설치
setup-browser-agent-browser-use-v7-fixed.sh가 Browser Use와 Playwright를
설치하고, browser-agent 컨테이너를 8001 포트로 띄웁니다.
OpenWebUI와 같은 Docker 네트워크에 자동 연결됩니다.
$ chmod +x setup-browser-agent-browser-use-v7-fixed.sh $ ./setup-browser-agent-browser-use-v7-fixed.sh
설치 중 입력값
- OpenWebUI 외부 URL — 예:
https://your-domain.com - OpenWebUI 관리자 이메일 · 비밀번호
- OpenWebUI API 키 — 설정 → 계정 → API Keys에서 생성한 키
- Groq API Key — Multi-Agent 기능에 필요
- 네이버 검색 API Client ID · Client Secret — 한국어 검색용(선택, Enter로 건너뛰면 Tavily로 폴백). developers.naver.com에서 발급
- Tavily API Key — 검색 폴백용(선택,
tvly-로 시작). app.tavily.com에서 발급
llama-3.3-70b-versatile입니다. 이 모델은 흔한 한국어는 잘
처리하지만, 드문 고유명사를 검색어로 만들 때 글자가 깨질 수 있습니다. 검색 품질이 중요하면
create_llm이 지원하는 OpenAI·Anthropic·Google 모델로 전환하는 것을 권장합니다
(환경변수 변경만으로 가능, 재설치 불필요).
Phase 3 · Telegram 브릿지 설치
setup-telegram-openwebui-bridge-FINAL.sh가 OpenWebUI의 모델·도구·RAG를
Telegram에서 그대로 쓸 수 있게 연결합니다. ~/telegram-openwebui-bridge에
설치되며 8443–8445 포트를 사용합니다.
$ chmod +x setup-telegram-openwebui-bridge-FINAL.sh $ ./setup-telegram-openwebui-bridge-FINAL.sh
설치 중 입력값
- Telegram Bot Token — @BotFather에게
/newbot으로 봇 생성 후 받은 토큰 - OpenWebUI API Key — 설정 → 계정 → API Keys에서 발급 (또는 로그인 JWT)
- 관리자 Telegram User ID — @userinfobot으로 확인. 화이트리스트에 등록된 ID만 접근 허용
/start를 보내면 대화가 시작됩니다.
봇 토큰은 AES-256으로 암호화 저장되고, 사용자당 분당 30회 요청 제한이 적용됩니다.
설치 검증
모든 설치가 끝나면 verify-install.sh로 3개 스택의 정합성과
보안 설정을 한 번에 점검합니다.
$ chmod +x verify-install.sh $ ./verify-install.sh … 🎉 모든 항목 검증 통과!
검증 스크립트는 다음을 확인합니다:
- 각 컨테이너의 기동 상태와 포트 바인딩
- 브라우저 에이전트의 Path Traversal 이중 검증, 메모리 스키마 검증 패치 적용 여부
- Telegram 브릿지의 Magic Bytes 검증 등 보안 패치 적용 여부
- 컨테이너 권한 설정(no-new-privileges, cap_drop) 일관성
실패 항목이 있으면 ❌ N개 항목 실패로 개수와 위치를 알려줍니다.
진단 목적상 일부 검사가 실패해도 끝까지 실행되어 전체 결과를 합산합니다.
대시보드 종류
이 프로젝트는 용도가 다른 웹 대시보드 3종을 제공합니다. 모두 보안을 위해
127.0.0.1(로컬)에만 열리며, 외부에서 보려면 SSH 터널을 거쳐야 합니다.
Cloudflare Tunnel 헤더가 감지되면 자동으로 403 차단됩니다.
| 대시보드 | 제공 주체 | 주소 | 주요 내용 |
|---|---|---|---|
| OpenWebUI 관리 화면 | open-webui | localhost:3000 | 모델·사용자·RAG 문서·설정 전반 |
| AI 전화비서 대시보드 | twilio-bot | localhost:5000/dashboard | 통화 이력·AI 요약·대화 내용 |
| Bot 관리 대시보드 | telegram-bridge | localhost:8445/dashboard | 메시지·업로드·차단 통계·로그·비상차단 |
① OpenWebUI 관리 화면 (3000)
메인 웹 인터페이스입니다. 처음 접속 시 관리자 계정을 만들고, 설정 → 관리자 패널에서 모델 추가, 사용자 관리, RAG 문서 관리, 설정 → 계정 → API Keys에서 키 발급을 합니다. 브라우저 에이전트와 Telegram 브릿지 설치에 쓰이는 그 키가 여기서 나옵니다.
② AI 전화비서 대시보드 (5000/dashboard)
Twilio 전화봇의 통화 기록을 보는 화면입니다. 통화 이력, AI가 생성한 통화 요약,
실제 대화 내용을 이름으로 검색하고 최근 20·50·100·200건 단위로 조회할 수 있습니다.
데이터는 /api/call-history JSON API로 공급되며, 둘 다 로컬 접근만 허용됩니다.
$ ssh -L 5000:localhost:5000 user@서버IP # 브라우저에서 열기 http://localhost:5000/dashboard
③ Bot 관리 대시보드 (8445/dashboard)
Telegram 브릿지의 운영 현황 화면입니다. 총 메시지·파일 업로드·음성 처리·차단 시도
통계, 감사 로그, 화이트리스트, 그리고 비상 차단 모드(/emergency) 제어를
제공합니다. Brute-force 방지가 적용되어 로그인 5회 실패 시 해당 IP가 15분 잠깁니다.
$ ssh -L 8445:localhost:8445 user@서버IP http://localhost:8445/dashboard
/admin을 보내면 "웹 대시보드 URL" 버튼으로 위 접속 방법을
그대로 안내해 줍니다. 간단한 통계는 /stats 명령으로 채팅 안에서 바로 볼 수 있습니다.
/browse,
/search, /screenshot, /sessions, /monitors 등)와
헬스체크만 제공합니다. 작업 결과·스크린샷은 다음 섹션의 미디어 폴더에 쌓입니다.
미디어 관리 · 업로드
문서(RAG), 통화 녹음·보고서, 브라우저 결과물 등 종류별로 업로드 경로와 저장 위치가 다릅니다. 업로드는 모두 파일명 정제·크기 제한·형식 검증을 거칩니다.
1. RAG 문서 업로드 (PDF·TXT·CSV·DOCX)
지식 기반 답변에 쓰일 문서는 두 가지 방법으로 올립니다. 일반 사용은 OpenWebUI 화면에서 끌어다 놓으면 되고, 자동화·API 연동 시에는 OpenAPI 도구 서버의 업로드 엔드포인트를 직접 호출합니다. 업로드하면 텍스트 추출 → 스마트 청킹 → Qdrant 벡터 색인까지 자동 진행되며, 같은 파일은 기존 벡터를 지우고 다시 색인합니다.
| 방법 | 경로 | 지원 형식 |
|---|---|---|
| 웹 UI | OpenWebUI(3000) → 문서/지식 업로드 | PDF·TXT·CSV·DOCX |
| API | POST localhost:8000/documents/upload | PDF·TXT·CSV·DOCX |
| 목록 확인 | GET localhost:8000/documents/list | — |
$ curl -X POST http://localhost:8000/documents/upload \ -H "X-Internal-Secret: $INTERNAL_SECRET" \ -F "file=@./manual.pdf"
2. 통화 녹음 · PDF 보고서 (전화봇)
Twilio 전화봇은 통화 녹음(.mp3)과 PDF 보고서를 컨테이너 안
/app/data/recordings·/app/data/reports에 저장합니다.
목록 조회와 다운로드 API가 있으며, 녹음·보고서 기능은 실시간 토글로 켜고 끌 수 있습니다.
| 동작 | 경로 | 비고 |
|---|---|---|
| 녹음 목록 | GET localhost:5000/recordings | API 시크릿 필요 |
| 녹음 다운로드 | GET /recordings/<파일명>.mp3 | 파일명 검증 |
| 보고서 목록 | GET localhost:5000/reports | API 시크릿 필요 |
| 보고서 다운로드 | GET /reports/<파일명>.pdf | 파일명 검증 |
| 기능 켜고 끄기 | POST /toggle/recording · /toggle/pdf-report | 실시간 전환 |
3. Telegram으로 올리기 (파일 · 음성)
Telegram 채팅에서 직접 미디어를 보낼 수 있습니다. PDF·이미지를 보내면 OpenWebUI에 자동 업로드되어 RAG로 색인되고, 음성 메시지를 보내면 Whisper STT로 텍스트 변환 → AI 응답 → TTS 음성 회신까지 이어집니다. 업로드는 20MB로 제한되며, 확장자 위조를 막기 위해 Magic Bytes(파일 시그니처) 검증을 거칩니다.
4. 브라우저 에이전트 결과물
브라우저 에이전트는 작업 산출물을 ~/OpenWebUI/browser-agent/data
아래에 종류별로 쌓습니다. 스크린샷은 data/screenshots,
세션 저장본은 data/sessions, 작업 결과는 data/results,
감사 로그는 data/audit에 보관됩니다. 스크린샷은
POST /screenshot으로 즉석 생성할 수 있습니다.
5. 미디어 업로드 페이지 (사진·동영상·음성·PDF)
드래그앤드롭 업로드 화면(localhost:8000/upload)으로 사진·동영상·음성·PDF를
올릴 수 있습니다. 저장 위치는 컨테이너의 /app/media이며, 이는 호스트의
공유 폴더(예: ~/ai-share)에 마운트됩니다.
apiuser, uid 1002)로 동작합니다.
호스트의 공유 폴더 소유자가 다르면 업로드 시 500 (Permission denied) 오류가
납니다. 첫 사용 전에 폴더 소유권을 컨테이너 사용자에 맞춰 주세요.
# 마운트된 공유 폴더 소유권을 컨테이너 사용자(1002)로 변경 $ sudo chown 1002:1002 /home/<사용자>/ai-share # 하위 폴더(예: photos/홍길동)에도 저장한다면 — 단, 읽기전용 마운트(recordings·reports)는 제외 $ sudo find /home/<사용자>/ai-share -mindepth 1 -maxdepth 1 \ ! -name recordings ! -name reports -exec chown -R 1002:1002 {} + # 적용 확인 — 소유자가 1002로 보이면 정상 $ docker exec openwebui-openapi-tools-1 ls -ld /app/media
/app/media 대상에 연결된 Source 값이 권한을 줄 폴더입니다.
docker inspect openwebui-openapi-tools-1 --format '{{json .Mounts}}'
포트 · 접속 정보
모든 서비스는 보안을 위해 127.0.0.1(로컬)에만 바인딩됩니다.
외부 접속은 SSH 터널이나 Cloudflare Tunnel을 통해야 합니다.
| 서비스 | 컨테이너 | 포트 | 로컬 주소 |
|---|---|---|---|
| OpenWebUI | open-webui | 3000 | http://localhost:3000 |
| Twilio 전화봇 | twilio-bot | 5000 | http://localhost:5000 |
| OpenAPI 도구 | openwebui-openapi-tools | 8000 | http://localhost:8000/docs |
| Qdrant | qdrant | 6333 | http://localhost:6333/dashboard |
| 브라우저 에이전트 | browser-agent | 8001 | http://localhost:8001 |
| Telegram 브릿지 | telegram-openwebui-bridge | 8443–8445 | (웹훅 전용) |
외부 접속 — SSH 터널 (권장)
# OpenWebUI(3000)를 내 PC로 터널링 $ ssh -L 3000:localhost:3000 user@your-server # 이후 브라우저에서 http://localhost:3000 접속
OpenWebUI에 처음 접속하면 관리자 계정을 만들고, 설정 → 계정 → API Keys에서 API 키를 발급할 수 있습니다. 이 키가 브라우저 에이전트와 Telegram 브릿지 설치에 쓰입니다.
문제 해결
컨테이너 상태 확인
$ docker ps $ docker logs browser-agent # 특정 컨테이너 로그 $ docker logs -f browser-agent # 실시간 추적 (Ctrl+C로 종료)
브라우저 에이전트가 500 에러를 낼 때
로그에 NameError: name 'filter_response' is not defined가 보이면,
구버전 스크립트(-fixed가 아닌)로 설치된 경우입니다. 이 가이드의
setup-browser-agent-browser-use-v7-fixed.sh로 재빌드하면 해결됩니다.
$ cd ~/OpenWebUI $ docker compose build browser-agent $ docker compose up -d browser-agent
미디어 업로드가 500 (Permission denied)을 낼 때
업로드 화면(localhost:8000/upload)에서 파일이 "실패"로 뜨고, 로그에
PermissionError: [Errno 13] Permission denied: '/app/media/...'가 보이면
호스트 공유 폴더의 쓰기 권한 문제입니다. 컨테이너는 uid 1002로 동작하므로
마운트된 폴더 소유자를 1002로 맞춰 주면 해결됩니다(형식·크기와 무관, 어떤 파일이든 동일 증상).
$ sudo chown 1002:1002 /home/<사용자>/ai-share $ docker exec openwebui-openapi-tools-1 ls -ld /app/media # 1002 확인
검색어가 깨져서 엉뚱한 결과가 나올 때
이는 코드 버그가 아니라 기본 LLM(llama-3.3-70b-versatile)의 한국어 처리 한계입니다.
한국어 처리가 안정적인 모델로 바꾸면 해결됩니다. docker-compose.yml의 모델
환경변수를 변경하거나, 지원되는 다른 프로바이더의 API 키를 설정하세요. 데이터 삭제나
전체 재설치는 필요하지 않습니다.
~/OpenWebUI의 secrets 폴더와 .env,
그리고 각 스크립트를 백업하세요.