Parkexcute — 셀프 호스팅 PaaS
GitHub 저장소를 연결해 Docker 애플리케이션을 배포하는 플랫폼입니다. 자체 서버에서 빌드와 HTTPS 설정, 배포 로그, 환경변수와 워크스페이스를 관리할 수 있습니다.
프로젝트 소개
Parkexcute는 GitHub 저장소를 연결해 웹 애플리케이션을 배포할 수 있는 셀프 호스팅 PaaS입니다. 연결한 브랜치에 코드를 푸시하면 Docker 이미지를 빌드하고 컨테이너를 실행합니다. 배포 주소와 HTTPS 설정도 함께 관리할 수 있습니다.
개인 프로젝트를 배포할 때마다 프록시, 인증서, 실행 환경을 따로 설정하는 과정을 줄이고 싶어 시작했습니다. 사용자는 대시보드에서 저장소와 환경변수를 설정하고, 배포 이력과 빌드 로그를 확인하거나 이전 버전으로 롤백할 수 있습니다.
기획부터 백엔드, 프론트엔드, 인프라와 운영까지 혼자 개발했습니다. 초기 개발 기간은 약 4개월이며, 베타 사용자 4명이 자신의 프로젝트를 배포해 이용했습니다.

시스템 구성
대시보드는 Next.js, API 서버는 Express와 TypeScript로 구성했습니다. 프로젝트와 배포 정보는 PostgreSQL에 저장하고, Redis는 작업 큐와 배포 로그에 사용합니다.
| 영역 | 기술과 역할 |
|---|---|
| 대시보드 | Next.js 15, Tailwind CSS, shadcn/ui, Radix |
| 상태 관리 | TanStack Query로 서버 데이터 조회, Zustand로 UI 상태 관리 |
| API | Express, TypeScript, Zod |
| 데이터 | PostgreSQL, Prisma |
| 배포 작업 | BullMQ, Redis, Dockerode, Docker |
| 라우팅·HTTPS | Traefik, Let's Encrypt |
| 웹 터미널 | Socket.io, xterm.js |
| Dockerfile 생성 | Google Gemini |
| 저장소 구성 | pnpm Workspace, Turborepo |
GitHub Webhook / Next.js 대시보드
|
Express API
/ \
PostgreSQL BullMQ / Redis
|
DeploymentWorker
|
Docker Engine
|
Traefik / HTTPS
오래 걸리는 빌드와 컨테이너 실행은 HTTP 요청 안에서 처리하지 않고 작업 큐에 넣습니다. API는 배포 요청을 받고, 워커가 저장소 복제부터 컨테이너 실행까지 이어서 처리하는 구조입니다.
로그인과 프로젝트 설정
GitHub OAuth로 로그인하면 저장소를 선택해 프로젝트를 만들 수 있습니다. 서버는 OAuth 코드를 토큰으로 교환하고 GitHub 프로필을 조회한 뒤 사용자 정보를 저장합니다. GitHub 토큰은 AES-256-GCM으로 암호화해 보관하고, 서비스 로그인에는 별도의 JWT Access Token과 Refresh Token을 사용합니다.

새 프로젝트는 저장소 선택, 템플릿 선택, 설정, 완료의 네 단계로 만듭니다. 빌드·실행 명령과 포트, 환경변수를 지정할 수 있고, Dockerfile은 템플릿을 사용하거나 직접 편집할 수 있습니다. 저장소를 분석해 Dockerfile을 생성하는 AI 기능도 이 과정에 포함되어 있습니다.

프로젝트 목록에는 배포 상태, 커밋 해시와 메시지, 공개 URL을 표시합니다. 상세 화면에서는 현재 실행 중인 배포와 이전 배포 이력을 확인할 수 있습니다.


배포 처리
GitHub 웹훅으로 푸시를 받으면 연결된 프로젝트와 브랜치를 확인하고 배포 작업을 생성합니다. DeploymentWorker는 다음 순서로 작업합니다.
- 프로젝트 설정과 암호화된 환경변수를 읽습니다.
- 저장소를 복제하고 배포할 커밋을 확인합니다.
- Dockerfile로 이미지를 빌드하거나 Docker Compose 구성을 실행합니다.
- 기존 컨테이너를 정리하고 새 컨테이너를 실행합니다.
- 컨테이너 정보와 배포 상태를 저장합니다.
배포 상태는 대기, 빌드, 실행 준비, 실행 중으로 바뀌며, 오류가 발생하면 실패 상태와 로그를 남깁니다. 워커 하나의 동시 처리 수는 2개로 설정했습니다. 큐에는 최대 3회 시도와 지수 백오프 설정을 두었습니다.
애플리케이션 컨테이너에는 Traefik 라벨을 연결합니다. Traefik이 이 설정을 읽어 요청을 해당 컨테이너로 보내고, Let's Encrypt를 통해 HTTPS 인증서를 관리합니다. 컨테이너마다 프록시 설정 파일을 따로 작성하는 대신 배포 설정에 라우팅 정보를 포함하는 방식입니다.
워크스페이스의 전체 배포를 모아 보는 화면도 제공합니다. 프로젝트별로 페이지를 옮기지 않고 진행 중이거나 실패한 배포를 확인할 수 있습니다.

배포 로그와 웹 터미널
빌드 화면에서는 저장소 복제, 이미지 빌드, 컨테이너 실행 과정의 로그를 볼 수 있습니다. 실패한 배포도 같은 화면에서 오류 메시지를 확인할 수 있도록 구성했습니다.


워커는 로그에 타임스탬프를 붙여 Redis 리스트에 저장합니다. 키는 deployment:{id}:logs이며, 로그를 추가할 때 24시간 TTL을 설정합니다.
DeploymentWorker
-> Redis 리스트에 로그 추가
-> 로그 조회 API
-> TanStack Query
-> 배포 로그 화면
화면은 로그를 200개씩 가져옵니다. 첫 페이지만 열려 있을 때는 2초 간격으로 다시 조회하고, 이전 로그를 펼친 상태에서는 자동 갱신을 멈춥니다.
웹 터미널은 배포 로그와 별도 경로입니다. Socket.io의 /terminal 네임스페이스로 연결하고, xterm.js에서 컨테이너의 터미널 입출력을 주고받습니다.
저장소 분석과 Dockerfile 생성
프로젝트 설정 파일을 Gemini에 전달하면 Dockerfile과 감지한 언어·프레임워크, 권장 포트, 빌드·실행 명령을 받을 수 있습니다. 생성한 Dockerfile은 프로젝트 설정 화면에서 확인하고 수정할 수 있습니다.
분석할 파일은 미리 정한 경로에서 가져옵니다. JavaScript 프로젝트의 package.json과 lock 파일, Python의 requirements.txt와 pyproject.toml, Go의 go.mod, Rust의 Cargo.toml 등이 대상입니다. 프로젝트 하위 디렉터리를 지정한 경우에는 루트의 워크스페이스 설정도 함께 확인합니다.
입력과 응답 처리
파일 본문은 길이를 제한하고, 일부 지시문 패턴을 치환한 뒤 프롬프트에 넣습니다. 파일당 입력 길이는 문자열의 length 기준 50,000으로 제한합니다.
const MAX_SIZE = 50000;
if (content.length > MAX_SIZE) {
content = content.substring(0, MAX_SIZE) + '\n... (truncated)';
}
시스템 지침과 분석 대상 파일을 구분하기 위해 파일 내용은 <PROJECT_FILES> 태그 안에 배치합니다. 프롬프트에는 파일 속 지시문을 따르지 않고 설정 정보만 분석하도록 안내합니다.
응답은 JSON으로 파싱하고 dockerfile 필드가 문자열인지 확인합니다. 이어서 FROM 명령이 있는지 검사하고, 대화문이나 HTML에 해당하는 일부 패턴이 포함되면 응답을 거절합니다.
Prisma를 사용하는 프로젝트에는 Debian 계열 slim 이미지, OpenSSL 설치, 빌드 전 prisma generate 실행을 포함하도록 안내합니다. 빌드 환경에서 겪었던 호환성 문제를 생성 규칙에 반영한 부분입니다.
워크스페이스와 접근 권한
프로젝트는 워크스페이스에 속합니다. 구성원은 OWNER, ADMIN, MEMBER, VIEWER 역할로 구분하고, 이메일로 초대하거나 대기 중인 초대를 관리할 수 있습니다.
배포와 로그를 조회할 때는 요청한 워크스페이스의 접근 권한을 확인합니다. 배포 상세와 로그가 다른 워크스페이스의 프로젝트에 속하지 않는지도 서버에서 검사합니다.

환경변수는 GitHub 토큰과 같이 AES-256-GCM으로 암호화합니다. 저장할 때 IV, 인증 태그, 암호문을 함께 보관하고 배포 작업에서 복호화해 사용합니다.
운영 화면
관리자 화면에서는 사용자와 워크스페이스, 프로젝트와 배포 현황을 조회할 수 있습니다. 대시보드와 함께 웹훅 로그, 예외 로그, 감사 로그를 제공합니다.

웹훅 로그에는 수신, 처리, 성공, 실패, 무시 상태를 남깁니다. 푸시한 브랜치가 프로젝트 설정과 달라 배포를 건너뛴 경우도 여기서 확인할 수 있습니다.

감사 로그에는 관리자 작업의 대상과 변경 내용을 기록합니다. 사용자 권한이나 워크스페이스 설정이 바뀌었을 때 누가 어떤 작업을 했는지 확인하는 용도로 사용합니다.

관련 링크
- GitHub 저장소
- 라이브 데모: 서버 이전 중
- 연락: [email protected] · GitHub 프로필