Sign In

[Guide] OpenClaw 페어링과 기기 관리, CLI 스크립트로 스마트하게 해결하기

도커(Docker)로 OpenClaw를 운영하다 보면 가장 당혹스러운 순간이 있습니다. 브라우저에서 연결을 하려고 하면 출력되는 이 메시지 때문이죠.
disconnected (1008): pairing required
이 에러는 기기 인증 세션이 만료되었거나 보안상의 이유로 새로운 페어링 승인이 필요할 때 발생합니다. 하지만 매번 이 에러를 해결하기 위해 복잡한 도커 명령어를 치고, 긴 ID를 복사하는 과정은 매우 번거롭습니다. 특히 터미널 창 너비에 따라 ID가 두 줄로 쪼개져 보일 때는 수동 관리가 거의 불가능해집니다.
이를 깔끔하게 해결해 줄 대화형 CLI 매니저 활용법을 소개합니다.

1. 왜 이 스크립트가 필요한가요?

접속 즉시 대응: 브라우저에서 1008 에러를 마주했을 때, 스크립트 실행 후 1번 메뉴만으로 즉시 재인증을 마칠 수 있습니다.
줄바꿈 이슈 해결: 터미널 너비 때문에 64자리 Device ID가 쪼개져 출력되어도 awkpaste 로직으로 완벽하게 병합해 인식합니다.
직관적인 UI: 복잡한 UUID 대신 번호(1, 2...) 입력만으로 승인과 해제를 제어합니다.
환경 맞춤형: 로컬(127.0.0.1)은 물론 개인 도메인 주소까지 유연하게 대응합니다.

2. 주요 기능 및 사용법

① Pairing Required (1008) 해결하기

브라우저에서 에러가 뜨면 당황하지 말고 스크립트를 실행한 뒤 [1] Pair Device를 선택하세요.
1.
대시보드 토큰을 실시간으로 추출해 접속 URL을 생성합니다.
2.
안내된 주소로 브라우저에서 접속하여 페어링 요청을 보냅니다.
3.
스크립트가 'Pending' 목록을 불러오면 번호를 눌러 즉시 승인(Approve)합니다.

② 페어링 끊기 및 기기 관리 (Unpair)

불필요하게 쌓인 기존 기기 목록을 확인하고, 특정 기기만 골라 연결을 끊거나 clean 명령으로 모든 세션을 초기화하여 보안 상태를 유지합니다.

③ 실시간 상태 보기 (Status)

현재 페어링된 기기 수, 각 기기의 역할(Role) 및 접속 IP를 깔끔한 표 형태로 한눈에 모니터링합니다.

3. 관리 스크립트 전문 (oc-manager.sh)

아래 코드를 복사하여 서버에 저장한 후 실행하세요.
#!/bin/bash BOLD='\033[1m' DIM='\033[2m' GREEN='\033[0;32m' CYAN='\033[0;36m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' DEFAULT_HOST="[http://127.0.0.1:18789](http://127.0.0.1:18789)" function show_header() { clear echo -e "${CYAN}${BOLD}" echo " ╭─────────────────────────────────────────────────────────╮" echo " │ │" echo " │ ◆ OpenClaw CLI Management System │" echo " │ │" printf " │ Gateway › %-40s │\n" "${DEFAULT_HOST}" echo " │ │" echo " ╰─────────────────────────────────────────────────────────╯" echo -e "${NC}" } # 1. 페어링 하기 function action_pairing() { show_header echo -e " ${BOLD}[ 새로운 기기 페어링 ]${NC}\n" echo -en " ${DIM}도메인 입력 (엔터 시 ${DEFAULT_HOST}):${NC} " read USER_INPUT BASE_URL=${USER_INPUT:-$DEFAULT_HOST} echo -e "\n ${YELLOW}▸${NC} 토큰 추출 중..." DASH_LOG=$(docker compose run --rm openclaw-cli dashboard --no-open 2>&1) TOKEN_PART=$(echo "$DASH_LOG" | grep -oE "#token=[a-zA-Z0-9]+") if [ -z "$TOKEN_PART" ]; then echo -e "\n ${RED}✗ 토큰 추출 실패.${NC}" read -p " 엔터를 누르면 돌아갑니다." return fi [[ "${BASE_URL}" != */ ]] && BASE_URL="${BASE_URL}/" echo -e "\n ${GREEN}✓ 접속 주소:${NC} ${BOLD}${BASE_URL}${TOKEN_PART}${NC}" echo -e "\n ${DIM}브라우저 접속 후 엔터를 누르세요.${NC}" read RAW_LIST=$(docker compose exec -T openclaw-gateway node dist/index.js devices list 2>/dev/null) declare -A P_MAP I=0 echo -e "\n ${CYAN}${BOLD}[ Pending 기기 목록 ]${NC}" echo -e " ${DIM}─────────────────────────────────────────${NC}" while read -r ID; do I=$((I+1)) P_MAP[$I]=$ID echo -e " ${GREEN}[$I]${NC} $ID" done < <(echo "$RAW_LIST" | grep -oE "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") if [ $I -eq 0 ]; then echo -e "\n ${DIM}대기 중인 기기가 없습니다.${NC}" sleep 1 return fi echo -e " ${DIM}─────────────────────────────────────────${NC}" echo -en "\n ${DIM}승인: 번호 / 거부: r+번호${NC}\n ${BOLD}›${NC} " read ACT if [[ "$ACT" == r* ]]; then docker compose exec -T openclaw-gateway node dist/index.js devices reject "${P_MAP[${ACT#r}]}" echo -e "\n ${RED}✗ 거부 완료.${NC}" else docker compose exec -T openclaw-gateway node dist/index.js devices approve "${P_MAP[$ACT]}" echo -e "\n ${GREEN}✓ 승인 완료.${NC}" fi sleep 1 } # 2. 페어링 끊기 function action_manage() { show_header echo -e " ${BOLD}[ 페어링 끊기 ]${NC}\n" RAW_LIST=$(docker compose exec -T openclaw-gateway node dist/index.js devices list 2>/dev/null) PAIRED_BLOCK=$(echo "$RAW_LIST" | sed -n '/Paired/,$p') DEVICE_ROWS=$( echo "$PAIRED_BLOCK" \ | awk -F'│' 'NF>2 { dev=$2; role=$3; gsub(/^[[:space:]]+|[[:space:]]+$/, "", dev); gsub(/^[[:space:]]+|[[:space:]]+$/, "", role); if (dev ~ /^[0-9a-f]+$/) print dev ":" role }' ) CLEAN_PAIRS=$( echo "$DEVICE_ROWS" | paste - - | awk -F'\t' '{ split($1, a, ":"); split($2, b, ":"); print a[1] b[1] ":" a[2] }' ) declare -A ID_MAP declare -A ROLE_MAP I=0 echo -e " ${CYAN}${BOLD}[ 연결된 기기 목록 ]${NC}" echo -e " ${DIM}─────────────────────────────────────────${NC}" while IFS=: read -r ID ROLE; do if [ -n "$ID" ]; then I=$((I+1)) ID_MAP[$I]=$ID ROLE_MAP[$I]=${ROLE:-operator} echo -e " ${GREEN}[$I]${NC} ${ID:0:16}...${ID: -8} ${DIM}(${ROLE:-operator})${NC}" fi done < <(echo "$CLEAN_PAIRS") if [ $I -eq 0 ]; then echo -e "\n ${DIM}연결된 기기가 없습니다.${NC}" read -p " 엔터를 누르면 돌아갑니다." return fi echo -e " ${DIM}─────────────────────────────────────────${NC}" echo -e " ${DIM}번호: 해제 | clean: 전체삭제 | q: 취소${NC}" echo -en " ${BOLD}›${NC} " read ACT if [[ "$ACT" == "clean" ]]; then docker compose exec -T openclaw-gateway node dist/index.js devices clear --yes echo -e "\n ${GREEN}✓ 전체 해제 완료.${NC}" elif [[ "$ACT" != "q" && -n "${ID_MAP[$ACT]}" ]]; then docker compose exec -T openclaw-gateway node dist/index.js devices remove "${ID_MAP[$ACT]}" echo -e "\n ${GREEN}✓ 해제 완료.${NC}" fi sleep 1 } # 메인 루프 while true; do show_header echo -e " ${BOLD}Select an action:${NC}" echo "" echo -e " ${GREEN}${BOLD}1${NC} Pair Device ${DIM}새로운 기기 페어링${NC}" echo -e " ${RED}${BOLD}2${NC} Unpair Device ${DIM}페어링 끊기${NC}" echo -e " ${CYAN}${BOLD}3${NC} Status ${DIM}현재 상태 보기${NC}" echo -e " ${DIM}4 Exit 종료${NC}" echo "" echo -e " ${DIM}──────────────────────────────────────────${NC}" echo -en " ${BOLD}›${NC} " read MENU case $MENU in 1) action_pairing ;; 2) action_manage ;; 3) show_header echo -e " ${BOLD}[ 현재 기기 상태 ]${NC}\n" RAW=$(docker compose exec -T openclaw-gateway node dist/index.js devices list 2>/dev/null) PAIRED_COUNT=$(echo "$RAW" | grep -oE 'Paired \([0-9]+\)') echo -e " ${CYAN}${BOLD}${PAIRED_COUNT:-Paired (0)}${NC}" echo -e " ${DIM}─────────────────────────────────────────────────────${NC}" printf " ${BOLD}%-26s %-10s %-15s${NC}\n" "Device ID" "Role" "IP" echo -e " ${DIM}─────────────────────────────────────────────────────${NC}" echo "$RAW" | sed -n '/Paired/,$p' \ | awk -F'│' 'NF>2 { dev=$2; role=$3; ip=$6; gsub(/^[[:space:]]+|[[:space:]]+$/, "", dev); gsub(/^[[:space:]]+|[[:space:]]+$/, "", role); gsub(/^[[:space:]]+|[[:space:]]+$/, "", ip); if (dev ~ /^[0-9a-f]+$/) print dev ":" role ":" ip }' \ | paste - - \ | awk -F'\t' '{ split($1, a, ":"); split($2, b, ":"); id = a[1] b[1]; role = (a[2] != "" ? a[2] : b[2]); ip = (a[3] != "" ? a[3] : b[3]); short = substr(id,1,10) "..." substr(id,length(id)-7); printf " %-26s %-10s %-15s\n", short, role, ip }' echo -e " ${DIM}─────────────────────────────────────────────────────${NC}" echo "" read -p " 엔터를 누르면 돌아갑니다." ;; 4) clear; exit 0 ;; esac done //Script by Thomasjeong

4. 사용 방법

1.
스크립트 생성: vi oc-manager.sh
2.
코드 붙여넣기: 위 코드를 복사해 넣습니다.
3.
권한 부여: chmod +x oc-manager.sh
4.
실행: ./oc-manager.sh

마치며

이 스크립트는 단순한 자동화를 넘어, CLI 환경에서 발생할 수 있는 데이터 파싱 오류를 창의적으로 해결한 결과물입니다. OpenClaw를 사용하는 다른 개발자들에게도 큰 도움이 될 것입니다.
oc-manager.sh10.04KB