Post

Pi-Server 만들기 2편: ttyd로 웹 Bash 띄우기

SSH가 막힌 환경에서도 브라우저로 접속 가능한 웹 터미널을 구축하기 위한 ttyd 설치 및 설정 과정.

Pi-Server 만들기 2편: ttyd로 웹 Bash 띄우기

🧩 Pi-Server 만들기 2편: ttyd로 웹 Bash 띄우기

1. ttyd 방식을 선택한 이유

처음엔 SSH로만 접속할 생각이었다. 하지만 싸지방(군대 PC방) 환경에서는 CMD나 Ubuntu 터미널이 막혀 있어서 SSH는 사실상 불가능했다. 결국, 브라우저만 있으면 접속 가능한 웹 터미널이 답이었다.

처음 떠올린 건 code-server였다. VS Code 환경을 그대로 웹으로 띄우는 방식이라 보안성과 접근성이 뛰어나지만, 문제는 “너무 무겁다.” Pi-server는 코드 작성용 IDE가 아니라 항상 켜져 있는 런타임 환경이기 때문에, 굳이 code-server처럼 리소스를 많이 잡아먹는 건 맞지 않았다.

그래서 다음 후보는 Node.js 기반의 Wetty였다. 보안성과 접근성 면에서 ttyd보다 낫다는 평이 있었고, Node 환경에서 돌아간다는 점도 익숙했다.

하지만 막상 빌드해보니 의존성 지옥 시작이었다. Python 관련 패키지가 엮여 있었고, Node의 무거운 빌드 패키지까지 추가되면서 설치 속도도 답답했다. 그래도 참고 빌드를 마친 후 웹에 띄워봤는데…

404. F12 눌러보니 경로 이슈로 계속 에러.

렌더링이 안 되는 이유를 찾아보다가 이걸 고치다간 32시간 제한 안에 프로젝트를 끝낼 수 없겠다고 판단. 결국 Wetty는 포기. 지금 생각해도 그 선택은 나쁘지 않았다. Wetty 자체가 생각보다 꽤 무겁고, 라즈베리파이에 올리기엔 부담이 컸다.

그래서 C 기반의 ttyd로 최종 결정했다. 보안적인 우려는 컸지만, 일단은 Cloudflare Zero Trust에서 인증을 추가하는 방향으로 커버하기로 했다. 이 시점에서 약간 흔들리긴 했다 — “보안이 해결되지 않으면 이건 서버라기보다 자살행위다…” 하지만 프로젝트의 목적은 ‘가능한 빠르게 완성하는 실험용 서버 구축’이었다.


2. Wetty 시도기 (그리고 포기까지)

당시 설치 명령은 대충 이런 식이었다:

1
2
3
sudo apt update
sudo apt install -y nodejs npm python3
sudo npm install -g wetty

설치 후 실행도 해봤다:

1
npx wetty --port 3000 --base /

브라우저에서 http://<REDACTED_LOCAL_IP>:3000 접속! 그런데 화면은 까맣고, “404 Not Found”만 떠 있었다.

F12(개발자 도구)로 보니 계속 “경로를 찾을 수 없다”는 메시지가 반복됐다. 문제는 Wetty의 정적 파일 경로 설정이 Node 버전에 따라 미묘하게 다르고, 내가 깔려 있던 Node 버전(20.x대)에서는 경로 구조가 달라져서 발생한 문제였다.

고쳐보려 했지만, 빌드 과정도 길고, 종속성도 꼬여서 결국 포기했다. 다시 정리하자면:

  • Node.js 기반이라 의존성이 복잡함
  • Python3까지 요구해서 설치 과정 길어짐
  • 실행은 되지만 렌더링 오류 발생 (404, 경로 문제)
  • 빌드/패키지 문제로 프로젝트 시간 초과 위험

결론: 깔끔하게 전부 제거.

1
2
3
sudo npm uninstall -g wetty
sudo apt purge -y nodejs npm python3
sudo apt autoremove -y

3. ttyd 구축 과정

이제 정말 “가볍고 단순한” 웹 터미널이 필요했다. 그래서 선택한 게 ttyd였다 — C 기반으로 가볍고, 설정도 간단하다.

설치는 다음과 같이 진행했다:

1
2
3
4
5
6
7
sudo apt update
sudo apt install -y build-essential cmake git libjson-c-dev libwebsockets-dev
git clone https://github.com/tsl0922/ttyd.git
cd ttyd
mkdir build && cd build
cmake ..
make && sudo make install

설치가 끝났다면 이제 실행 테스트:

1
./ttyd -p 3000 -c <user>:<pass> --writable --check-origin /usr/bin/bash

여기서 사용된 옵션 의미는 다음과 같다.

옵션설명
-p 3000포트 번호 지정
-c user:pass접속 비밀번호 설정 (기본 인증)
--writable터미널 내 입력 가능
--check-origin다른 도메인에서 접근 차단 (보안 강화용)
/usr/bin/bash실행할 쉘 지정

이 설정으로 웹 브라우저에서 http://<REDACTED_LOCAL_IP>:3000 접속 시 브라우저 창에 내 Bash 터미널이 그대로 떠 있었다. 로그인 창까지 뜨는 모습은 진짜 뿌듯했다.

“드디어 내가 집 밖에서도 내 서버를 조작할 수 있게 됐다.”

물론 보안이 완벽하진 않다. 그래서 이후 단계(3편)에서는 Cloudflare Tunnel + Zero Trust 인증을 붙여서 github 계정으로 로그인해야만 접근 가능한 터널 구조를 완성할 예정이다.


4. 정리

이번 편에서는 Wetty에서의 실패와 ttyd 구축 성공기를 다뤘다. 결국엔 “단순함이 최고의 보안이다”라는 걸 다시 느꼈다. 코드는 간단했고, 실행은 가벼웠으며, 브라우저 하나로 완전히 작동했다.

다음 편에서는 드디어 Cloudflare Tunnel 연결 및 Zero Trust 설정을 통해 보안이 강화된 24시간 원격 접근 서버로 발전시킨다.


← 이전 글: Pi-Server 만들기 1편: 아키텍처 굽기와 SSH 연결 → 다음 글: Pi-Server 만들기 3편: Cloudflare Tunnel 연결

This post is licensed under CC BY 4.0 by the author.