내 프로덕션 배포 경로는 이미 어느 정도 정해져 있다. 코드는 GitHub에 두고, 보호된 workflow가 배포 시점을 결정하며, Self-hosted Runner는 검토된 절차만 서버에서 실행한다. PanelAlpha Engine의 Show HN을 보고 궁금했던 것은 AI가 배포를 도울 수 있느냐가 아니었다. 애플리케이션 수명주기를 MCP 제어 평면에 맡기면 기존 Runner와 어떤 관계가 되는지 확인하고 싶었다.

별도의 Ubuntu 24.04.2 VPS에서 PanelAlpha Engine v2.1.1을 시험했다. 이 글의 QA 시점에는 이 버전이 프로젝트의 GitHub latest release였다. 1 vCPU, 1.9 GiB RAM, 50 GB 디스크 환경에서 설치는 두 시간이 넘도록 Engine 단계에 머물렀다. 마지막으로 기록된 진행률은 70%였고, 이후 실험은 직접 중단했다.

이 결과가 PanelAlpha를 설치할 수 없다는 증거는 아니다. 확인한 것은 가벼운 AI 명령 실행기가 아니라 Docker, 네트워크, 방화벽, 프로젝트 격리, 백업과 모니터링까지 다루는 Hosting Control Plane이라는 점이다. 설치가 끝나지 않았어도 기존 Self-hosted Runner를 대체할 도구인지 다시 판단할 근거는 얻었다.

프로덕션 Runner 대신 깨끗한 VPS에서 시작했다

실험 전 VPS에는 Docker가 없었고 docker version은 종료 코드 127을 반환했다. iptables와 nft 명령도 없었으며, 수신 대기 포트는 사실상 SSH와 chrony뿐이었다. 이 기준 상태 덕분에 이후 Docker와 방화벽의 변화가 기존 설정의 잔재인지 설치 과정의 결과인지 구분할 수 있었다.

PanelAlpha의 설치 문서도 새 전용 Debian / Ubuntu VPS를 권장한다. 설치 프로그램 소스에는 systemd-resolved, /etc/resolv.conf, Docker 네트워크와 호스트 방화벽 처리 경로가 있다. 기존 블로그 Runner나 다른 프로덕션 서버에는 설치하지 않았다.

실행 전에는 bootstrap을 파일로 내려받고 SHA-256을 계산했다. curl | sh로 바로 실행하지 않았다.

$ curl -fsSL https://get.panelalpha.com/engine -o panelalpha-installer.sh
$ sha256sum panelalpha-installer.sh
5d3c436269e09f8a813073691f61ad18329c0b87a818cb7fc3481344ac8e2496

시험 버전은 v2.1.1로 고정했다.

$ bash /root/panelalpha-installer.sh --engine-version v2.1.1 --no-tui

첫 시도는 일찍 멈췄다. Git이 없어서 설치 프로그램이 추가하려 했지만, 필요한 의존 패키지를 설치할 수 없었다. 실제 로그는 다음과 같다.

git : Depends: liberror-perl but it is not installable
E: Unable to correct problems, you have held broken packages.
[ERROR] Failed to install git (required to fetch the installer).

이 시도의 종료 코드는 1이었다. 아직 호스트 의존성을 준비하는 단계였으므로 PanelAlpha 핵심 설치의 실패로 분류하지 않았다. 이후 검증에서는 대규모 시스템 패키지 업그레이드가 진행됐고, 한 번은 종료 코드 141로 끝났다. 다시 진행한 뒤에야 Engine 설치가 이미지, 네트워크와 방화벽 단계에 도달했다.

처음 예상과 달랐던 부분도 있다. 소스에는 systemd-resolved와 resolv.conf를 변경하는 경로가 있지만, 이 VPS에는 처음부터 systemd-resolved.service가 없었고 resolver 파일도 외부 DNS를 사용했다. 따라서 이번 실행 전후에는 DNS 파일의 변화를 관찰하지 않았다. 소스에 구현된 기능과 이 호스트에서 실제로 일어난 일은 따로 설명해야 한다.

70%에서 멈췄지만 호스트는 이미 바뀌어 있었다

실험을 끝내기 전에 호스트 상태를 다시 수집했다. Docker Engine 29.8.2는 설치됐지만, PanelAlpha 진행률 파일은 여전히 다음 상태였다.

step: Installing PanelAlpha engine
progress: 70

docker ps -a는 비어 있었다. 이를 ‘백그라운드 컨테이너 10개가 실행 중’이라고 설명할 근거는 없다. 직접 확인한 것은 composer, DNS proxy, Exim, metrics, Pure-FTPd, SFTP를 포함한 PanelAlpha 이미지 6개였다. 가장 큰 composer 이미지의 disk usage는 Docker 기준 795 MB였다.

네트워크 변화는 더 뚜렷했다. 기준 상태에는 iptables / nft 도구가 없었지만, 이후에는 UFW / Docker 규칙과 PA-BUILD-EGRESS, PA-PUBLISHED, PA-TENANT-INPUT, PA-TENANT-NET 등의 체인이 생겼다. 반면 수신 대기 포트는 여전히 SSH와 chrony뿐이었다. Engine 자체는 외부 요청을 처리할 준비가 되지 않았다.

종료 시 eth1의 누적 RX 값은 1,508,426,817 bytes였다. 이 수치를 ‘PanelAlpha가 1.5 GB를 다운로드했다’는 주장으로 바꾸지는 않는다. 기준 파일에 RX 값이 없어서 시스템 업그레이드, SSH와 다른 트래픽을 제외할 수 없기 때문이다. 확인한 범위는 몇 시간 동안 진행된 새 VPS 설치에서 애플리케이션 배포가 시작되기도 전에 네트워크, Docker 이미지와 호스트 방화벽이 크게 바뀌었다는 사실이다.

평소 GitHub Runner + Docker Compose를 쓰는 방식과는 느낌이 달랐다. Runner는 GitHub workflow가 구동하는 실행 경로이고, PanelAlpha는 애플리케이션 호스팅 제어 평면 전체를 구축한다. 프로젝트 격리, 도메인, 데이터베이스, 파일, 백업과 모니터링까지 담당한다면 더 많은 기반이 필요한 것은 자연스럽다.

결국 중단한 이유는 ‘PanelAlpha가 좋지 않다’는 결론을 내리기 위해서가 아니었다. 시간을 더 들여 억지로 설치를 완료해도 처음의 선택 문제에 답하기 어려워졌기 때문이다. 이 1C2G 호스트에서는 제어 평면의 콜드 스타트와 호스트 변경 자체가 이미 고려할 비용이었다. 프로젝트 배포 성공, 실패한 배포에서 이전 버전 유지 여부, 백업 복원은 시험하지 못했다. 공식 설명을 직접 실행한 결과처럼 취급하지 않는다.

modify 권한도 신중하게 봐야 하는 이유

MCP 서버 구동까지 도달하지는 않았지만, 고정 버전 소스 감사는 남겨 두었다. v2.1.1의 ToolPolicy는 세 가지 모드에 HTTP 메서드 상한을 설정한다.

권한 모드허용 메서드
readonlyGET
modifyGET, POST, PUT, PATCH
fullGET, POST, PUT, PATCH, DELETE

겉으로는 modify가 ‘수정은 되지만 위험한 삭제는 금지’라는 의미처럼 보인다. 생성된 MCP 도구까지 보면 이 해석만으로는 부족하다.

project_delete는 DELETE이므로 modify의 메서드 상한을 통과하지 않는다. 그러나 backup_restore와 project_push는 모두 POST이며 IsDestructive 표시가 있다. 이 verb ceiling 계층만 보면 modify 범위에 들어갈 수 있다.

이를 무단 접근 취약점으로 결론 내린 것은 아니다. Engine은 도구 등록 전에 toolset, denylist와 TokenAbilities 토큰 범위도 적용하고, 백업 복원에는 confirm=true도 요구한다. 실제 토큰으로 동적 거부 테스트를 완료하지 않았으므로 이 보호가 우회되는지에 대한 실행 증거는 없다.

여기서 얻은 설계상의 주의점은 더 단순하다. DELETE를 금지해도 중요한 상태 덮어쓰기가 사라지지는 않는다. 백업 복원, staging을 live로 반영하거나 프로젝트를 재구축하는 작업도 POST일 수 있다. Coding Agent를 연결한다면 readonly부터 시작하고 toolset과 denylist를 명시적으로 제한하겠다. 세 권한 이름만으로 판단하지는 않는다.

백업과 telemetry 역시 이번에는 소스와 공식 문서 범위에 머물렀다. Backups 문서는 내장 일정 기능이 없으므로 외부 cron 등의 스케줄러가 필요하고, 복원이 현재 프로젝트 상태를 덮어쓴다고 설명한다. Telemetry 문서는 pae telemetry:disable과 PANELALPHA_MONITORING=을 비워 두는 설정을 구분한다. 전자는 6시간 간격 상태 점검을 중단하고, 후자는 로컬 점검을 유지하되 모니터링 엔드포인트로 보고서를 보내지 않는다는 설명이다. 직접 실행한 것은 아니므로 v2.1.1 문서상의 사실과 이번 실험 결과를 혼동하지 않는다.

지금은 Self-hosted Runner를 유지한다

기존 ChatGPT Web + GitHub + Self-hosted Runner 흐름과 함께 놓고 보니 ‘무엇이 무엇을 대체하는가’라는 질문 자체가 너무 좁았다.

GitHub Self-hosted RunnerPanelAlpha Engine
주된 역할GitHub workflow가 통제하는 job 실행애플리케이션과 서버 호스팅 수명주기 관리
핵심 상태Git commit, workflow, releaseEngine 내부 프로젝트 및 호스팅 상태
AI 연결 방식Agent가 코드나 workflow를 수정하고 GitHub가 실행Agent가 MCP / API로 제어 평면을 직접 조작
호스트 개입workflow가 수행하는 작업에 따름설치부터 Docker, 네트워크와 방화벽 기반 구축
이번 검증 범위기존 프로덕션 경로를 계속 사용 중설치 70% 및 일부 호스트 변경까지만

내 블로그, 작은 서비스와 몇 개의 자체 호스팅 프로젝트에는 GitHub + Self-hosted Runner + Docker Compose를 유지하겠다. Runner가 더 안전하거나 더 빠르다고 증명한 것은 아니다. 이미 source of truth, PR 검토와 배포 경로에 맞춰져 있고, 새 고권한 Hosting Control Plane이 추가하는 상태와 기반 비용을 상쇄할 이유가 아직 없다는 판단이다.

반대로 수십 개의 앱을 관리하면서 도메인, 데이터베이스, 파일, 백업과 격리를 통합하고, 제약된 인터페이스로 Coding Agent가 이 자원을 관리해야 한다면 PanelAlpha의 위치는 더 타당하다. 더 화려한 docker compose up이 아니라, 기존 hosting panel을 Agent가 호출할 수 있는 인프라 API로 바꾸려는 접근이다.

이번에는 설치 단계에서 끝났지만, 내 선택에는 충분했다. 완전히 동작하는 PanelAlpha의 사용성을 답하지는 못했어도, 검토된 코드를 몇 대의 서버에 안정적으로 배포하려는 목적만으로 AI 조작 경험을 위해 VPS 제어 평면 전체를 추가할 이유는 없다고 판단했다.

다음에는 자원이 더 넉넉한 새 VPS에서 먼저 readonly / modify / full MCP 거부 매트릭스를 완성하겠다. 이후 실패한 배포, 원격 백업 복원과 telemetry의 실제 동작을 시험할 것이다. 그 결과가 있어야 설치 경험을 넘어 장기적인 AI 운영 진입점으로 적합한지 이야기할 수 있다.