Hosting
Vercel, Firebase, Fly.io, Convex, SSH 배포 템플릿
collabops/vercel-deploy@v1
On-Premise: ❌ — Vercel SaaS 연결 필요
Vercel 프로젝트를 빌드하고 배포합니다. Preview 및 Production 환경을 지원합니다.
사전 준비
1. Vercel API Token 발급
Vercel Dashboard > Settings > Tokens에서 토큰을 생성합니다.
2. Vercel 프로젝트 생성
Git provider 연결 없이 Vercel API로 프로젝트를 생성해야 합니다.
curl -X POST https://api.vercel.com/v10/projects \
-H "Authorization: Bearer {VERCEL_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"name": "my-project", "framework": "nextjs"}'name: 프로젝트 이름
framework: 프로젝트에 맞게 지정 (nextjs, vite, nuxtjs, svelte 등)
응답의 id → VERCEL_PROJECT_ID로 사용
3. Organization ID 확인
Vercel Dashboard > Settings > General에서 Vercel ID (= Organization ID)를 확인합니다.
4. Secrets 등록
CollabOps 프로젝트 설정에서 다음 시크릿을 등록합니다.
| Secret | 설명 |
|---|---|
VERCEL_TOKEN | Vercel API 토큰 |
VERCEL_ORG_ID | Organization / Team ID |
VERCEL_PROJECT_ID | 프로젝트 ID |
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
vercel-token | YES | - | Vercel API 토큰. $\{\{ secrets.VERCEL_TOKEN \}\} 권장 |
vercel-org-id | YES | - | Vercel Organization ID |
vercel-project-id | YES | - | Vercel Project ID |
production | NO | "false" | Production 배포 여부 (false = Preview) |
working-directory | NO | "/workspace/source" | 프로젝트 루트 경로 |
사용 예시
steps:
- name: Checkout
uses: collabops/checkout@v2
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
ref: ${{ collabops.ref_name }}
sha: ${{ collabops.sha }}
- name: Deploy to Vercel
uses: collabops/vercel-deploy@v1
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
production: "false"Production vs Preview 분기
# push 와 change_request 모두 트리거. 이벤트 별로 Job 을 분리해서 production 여부를 결정.
triggers:
push:
branches: [main]
change_request:
branches: [main]
jobs:
deploy-production:
# main push 일 때만 production. Job 레벨 if 사용.
if: "collabops.event_name == 'push'"
steps:
- name: checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
- name: vercel-prod
uses: "collabops/vercel-deploy@v1"
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
production: "true"
deploy-preview:
# CR 이벤트는 preview.
if: "collabops.event_name == 'change_request'"
steps:
- name: checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
- name: vercel-preview
uses: "collabops/vercel-deploy@v1"
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
production: "false"
포인트 — production 분기는 triggers + Job 별 if: "collabops.event_name == ..." 로 한다. 여러 프로젝트가 한 리포에 있다면 working-directory 로 분리.
collabops/firebase-deploy@v1
On-Premise: ❌ — Firebase SaaS 연결 필요
Firebase 리소스를 배포합니다. Functions, Hosting, Firestore Rules 등 선택적 배포를 지원합니다.
| Input | Required | Default | Description |
|---|---|---|---|
service-account-key | YES | - | GCP 서비스 계정 키 JSON. $\{\{ secrets.FIREBASE_SA_KEY \}\} 권장 |
project-id | YES | - | Firebase 프로젝트 ID |
deploy-targets | NO | "" | 배포 대상 (쉼표 구분: functions, hosting, firestore:rules, storage:rules). 미지정 시 전체 배포 |
working-directory | NO | "/workspace/source" | firebase.json이 있는 디렉토리 |
예시
기본 — 전체 firebase.json 배포
jobs:
deploy:
steps:
- name: checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
- name: install-and-build
run: |
npm ci
npm run build
image: node:22-alpine
# deploy-targets 미지정 → firebase.json 전체 대상이 배포됨.
- name: firebase-deploy
uses: "collabops/firebase-deploy@v1"
with:
service-account-key: ${{ secrets.FIREBASE_SA_KEY }}
project-id: my-firebase-project
부분 배포 — 특정 리소스만
jobs:
deploy-hosting:
steps:
- name: checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
- name: install-and-build
run: |
npm ci
npm run build
image: node:22-alpine
- name: firebase-deploy-targeted
uses: "collabops/firebase-deploy@v1"
with:
service-account-key: ${{ secrets.FIREBASE_SA_KEY }}
project-id: my-firebase-project
# 쉼표 구분 — hosting, functions, firestore, storage, ...
deploy-targets: "hosting,functions"
포인트 — service-account-key 는 GCP 콘솔에서 받은 JSON 키 전체. deploy-targets 으로 hot path 만 빠르게 배포 가능 (전체 배포는 느림). 모노레포라면 working-directory 로 firebase.json 위치 지정.
collabops/fly-deploy@v1
On-Premise: ❌ — Fly.io SaaS 연결 필요
Fly.io 앱을 flyctl을 사용하여 원격 빌드 및 배포합니다.
| Input | Required | Default | Description |
|---|---|---|---|
api-token | YES | - | Fly.io API 토큰. $\{\{ secrets.FLY_API_TOKEN \}\} 권장 |
app-name | NO | "" | Fly.io 앱 이름 (미지정 시 fly.toml에서 읽음) |
remote-only | NO | "true" | 원격 빌더 사용 여부 |
working-directory | NO | "/workspace/source" | fly.toml이 있는 디렉토리 |
예시
기본 — fly.toml 의 앱 이름 사용
jobs:
deploy:
steps:
- name: checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
# app-name 생략 → 워크스페이스의 fly.toml 에서 app 이름을 읽음.
- name: fly-deploy
uses: "collabops/fly-deploy@v1"
with:
api-token: ${{ secrets.FLY_API_TOKEN }}
모노레포 — 환경별 앱 + 로컬 빌드
jobs:
deploy-staging:
steps:
- name: checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
- name: fly-deploy-staging
uses: "collabops/fly-deploy@v1"
with:
api-token: ${{ secrets.FLY_API_TOKEN }}
# fly.toml 의 [app] 와 다른 이름으로 배포할 때 명시.
app-name: web-staging
# 원격 빌더 대신 Job 컨테이너에서 직접 빌드 — Job 에 BuildKit 가용 시.
remote-only: "false"
working-directory: /workspace/source/apps/web
포인트 — app-name 은 fly.toml 의 [app] 와 다른 이름으로 띄울 때만 명시. remote-only 는 기본 true (Fly 원격 빌더 사용) — 자체 buildx 가 있다면 "false". Job 컨테이너 이미지는 fly 공식 flyio/flyctl 권장.
collabops/convex-deploy@v1
On-Premise: ❌ — Convex SaaS 연결 필요
Convex Functions를 배포합니다. 선택적으로 빌드 커맨드를 실행할 수 있습니다.
| Input | Required | Default | Description |
|---|---|---|---|
deploy-key | YES | - | Convex Deploy Key. $\{\{ secrets.CONVEX_DEPLOY_KEY \}\} 권장 |
cmd | NO | "" | 배포 후 실행할 빌드 커맨드 |
working-directory | NO | "/workspace/source" | 프로젝트 루트 경로 |
예시
기본 — Convex Functions 배포
jobs:
deploy:
steps:
- name: checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
- name: npm-install
run: npm ci
image: node:22-alpine
# deploy-key 는 Convex 대시보드의 Production / Preview deploy key.
- name: convex-deploy
uses: "collabops/convex-deploy@v1"
with:
deploy-key: ${{ secrets.CONVEX_DEPLOY_KEY }}
배포 후 빌드 명령어 실행
jobs:
deploy:
steps:
- name: checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
- name: npm-install
run: npm ci
image: node:22-alpine
- name: convex-deploy-with-cmd
uses: "collabops/convex-deploy@v1"
with:
deploy-key: ${{ secrets.CONVEX_DEPLOY_KEY }}
# 배포 직후 Next.js 사전렌더링 등 후속 빌드 트리거.
cmd: "npm run build:next"
포인트 — deploy-key 는 환경(production/preview) 마다 별도 secret. cmd 는 Convex schema/codegen 이 끝난 뒤 실행되므로 codegen 산출물에 의존하는 빌드(Next.js prerender 등) 에 유용.
collabops/ssh-exec@v1
On-Premise: ✅ — 폐쇄망에서도 동작
원격 호스트에 SSH로 접속해 셸 스크립트를 실행해요. 배포 스크립트 호출, 서비스 재기동, 마이그레이션 등 임의의 명령을 원격에서 돌릴 때 사용해요.
런타임 이미지는 alpine/git:2.43.0 으로 고정되어 있고, 실행 시점에 apk/apt 같은 추가 패키지 설치가 없어요. 그래서 air-gap(폐쇄망) 환경에서도 그대로 동작합니다.
사전 준비
대상 호스트에 접속할 SSH private key 와, ssh-keyscan -p <port> <host> 으로 미리 얻어 둔 known_hosts 값이 필요해요. 두 값 모두 CollabOps 시크릿으로 등록해서 주입하는 것을 권장합니다.
known-hosts 는 MITM (중간자 공격) 을 막기 위한 호스트 키 검증 값이라서 필수입니다. 비워 두면 호스트 키가 바뀌어도 그대로 접속해 버려요.
| Secret | 설명 |
|---|---|
DEPLOY_SSH_PRIVATE_KEY | 원격 접속용 OpenSSH private key |
DEPLOY_KNOWN_HOSTS | ssh-keyscan -p <port> <host> 결과 |
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
host | YES | - | 원격 호스트 (IP 또는 도메인) |
username | YES | - | SSH 사용자명 |
port | NO | "22" | SSH 포트 |
ssh-key | YES | - | SSH private key 내용 (OpenSSH 형식). $\{\{ secrets.DEPLOY_SSH_PRIVATE_KEY \}\} 권장 |
known-hosts | YES | - | known_hosts 내용. ssh-keyscan -p <port> <host> 결과. MITM (중간자 공격) 방지를 위해 필수 |
script | YES | - | 원격에서 실행할 셸 스크립트 (멀티라인 가능). silent fail 방지를 위해 set -eu 가 자동 prepend 되어 bash -s 로 실행됨 |
사용 예시
steps:
- name: Restart service over SSH
uses: collabops/ssh-exec@v1
with:
host: ${{ vars.DEPLOY_HOST }}
username: ${{ vars.DEPLOY_USER }}
ssh-key: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
known-hosts: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
script: |
cd /opt/myapp
docker compose pull
docker compose up -d --remove-orphans여러 호스트에 같은 스크립트 배포
# strategy.matrix 는 현재 미지원. 호스트별로 별도 Job 을 선언해서 병렬 실행 (Job 은 기본 병렬).
jobs:
restart-web1:
steps:
- name: ssh-restart
uses: "collabops/ssh-exec@v1"
with:
host: web1.prod
username: deploy
ssh-key: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
known-hosts: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
script: |
sudo systemctl restart api
sudo systemctl status api --no-pager
restart-web2:
steps:
- name: ssh-restart
uses: "collabops/ssh-exec@v1"
with:
host: web2.prod
username: deploy
ssh-key: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
known-hosts: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
script: |
sudo systemctl restart api
sudo systemctl status api --no-pager
restart-web3:
steps:
- name: ssh-restart
uses: "collabops/ssh-exec@v1"
with:
host: web3.prod
username: deploy
ssh-key: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
known-hosts: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
script: |
sudo systemctl restart api
sudo systemctl status api --no-pager
포인트 — strategy.matrix 가 미지원이므로 호스트마다 Job 을 명시. Job 은 needs 가 없으면 기본적으로 병렬 실행됨. 모든 호스트의 known-hosts 가 같은 secret 에 포함되어 있어야 함 (ssh-keyscan 묶음).
collabops/scp-upload@v1
On-Premise: ✅ — 폐쇄망에서도 동작
원격 호스트로 SCP 를 통해 파일이나 디렉토리를 업로드해요. compose 파일·정적 자산·빌드 산출물을 배포 서버로 옮길 때 사용해요.
런타임 이미지는 alpine/git:2.43.0 으로 고정되어 있고 실행 시점 추가 패키지 설치가 없어요. air-gap (폐쇄망) 환경에서도 그대로 사용할 수 있습니다.
known-hosts 는 MITM (중간자 공격) 방지를 위한 호스트 키 검증 값으로 ssh-exec 과 동일하게 필수입니다. 두 값 모두 CollabOps 시크릿으로 등록해서 주입하는 것을 권장합니다.
| Secret | 설명 |
|---|---|
DEPLOY_SSH_PRIVATE_KEY | 원격 접속용 OpenSSH private key |
DEPLOY_KNOWN_HOSTS | ssh-keyscan -p <port> <host> 결과 |
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
host | YES | - | 원격 호스트 (IP 또는 도메인) |
username | YES | - | SSH 사용자명 |
port | NO | "22" | SSH 포트 |
ssh-key | YES | - | SSH private key 내용 (OpenSSH 형식). $\{\{ secrets.DEPLOY_SSH_PRIVATE_KEY \}\} 권장 |
known-hosts | YES | - | known_hosts 내용. ssh-keyscan -p <port> <host> 결과. MITM (중간자 공격) 방지를 위해 필수 |
source | YES | - | 업로드할 로컬 경로 (파일 또는 디렉토리). /workspace/source 기준 절대 경로 권장 |
target | YES | - | 원격 대상 경로. 디렉토리인 경우 trailing slash 권장. scp user@host:path 문법 한계로 공백 포함 경로는 미지원 |
recursive | NO | "false" | 디렉토리 재귀 업로드 (true/false). 디렉토리 source 시 true 필요 |
사용 예시
steps:
- name: Upload compose file
uses: collabops/scp-upload@v1
with:
host: ${{ vars.DEPLOY_HOST }}
username: ${{ vars.DEPLOY_USER }}
ssh-key: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
known-hosts: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
source: "/workspace/source/docker-compose.yml"
target: "/opt/myapp/docker-compose.yml"디렉토리 업로드 후 ssh-exec 으로 재시작
jobs:
release:
steps:
- name: checkout
uses: "collabops/checkout@v2"
with:
repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
- name: build-dist
run: |
npm ci && npm run build # → dist/ 생성
image: node:22-alpine
# 1) 빌드 산출물을 원격으로 푸시
- name: upload-dist
uses: "collabops/scp-upload@v1"
with:
host: web1.prod
username: deploy
ssh-key: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
known-hosts: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
source: dist
target: /var/www/app/current
# 2) 원격 nginx reload
- name: reload-nginx
uses: "collabops/ssh-exec@v1"
with:
host: web1.prod
username: deploy
ssh-key: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
known-hosts: ${{ secrets.DEPLOY_KNOWN_HOSTS }}
script: |
sudo nginx -t
sudo systemctl reload nginx
포인트 — scp 직후 같은 호스트에 ssh-exec 으로 reload/restart 를 묶는 패턴이 흔함. 두 Step 이 같은 secret 을 공유 — Job 단위에서 한번만 인증 정보 준비.