One Server

문서

배포

저장소 연결, 프로덕션 브랜치, 모노레포의 빌드 폴더.

배포

저장소는 콘솔의 배포 화면에 있는 웹훅 주소를 GitHub에 등록하고 첫 push를 하면 연결돼요. 그 뒤로는 push마다 빌드하고 배포해요.

list_apps    연결된 저장소, 프로덕션 브랜치, 빌드할 폴더
update_app   프로덕션 브랜치, 빌드할 폴더, 프레임워크 프리셋, 빌드·출력·설치 명령, 실행 사용자(run_as) 바꾸기
delete_app   앱 하나 지우기: 주소를 내리고 배포를 지워요 (confirm에 앱 이름)
  • 프로덕션 브랜치에 push하면 프로젝트의 기본 주소가 바뀌어요. 다른 브랜치는 브랜치 이름이 붙은 프리뷰 주소로 가요.
  • 모노레포라면 root_directory에 앱 폴더(예: apps/web)를 넣으세요. 저장소 전체는 .이에요.
  • 프레임워크는 빌드할 때 자동으로 감지해요. 감지가 틀리면 framework로 프리셋을 고르고, 필요하면 build_command · output_directory · install_command로 덮어쓰세요(콘솔의 빌드 설정과 같은 값). null은 프리셋 기본값, 빈 명령은 그 단계를 건너뛰어요.
  • 백그라운드 작업자(대기열 작업, 챗봇, 거래소 연결 유지처럼 웹 요청 없이 도는 서버)는 blackwall.json에 "worker": true를 넣고 package.json의 start로 실행할 명령을 정하세요. 포트를 열지 않아도 되고, 계속 켜 두며 멈추면 다시 시작해요. 웹 요청에는 404로 답해요.
  • GPU 작업과 GPU 서버: Pro 이상에서 GPU를 초 단위로 빌려요. create_gpu_job은 공개 이미지에서 명령을 끝까지 돌리고(학습, 일괄 작업) 끝나면 GPU를 돌려줘요. 결과는 프로젝트 저장소 같은 바깥에 직접 올려야 남아요. get_gpu_job으로 상태와 출력 끝부분을, cancel_gpu_job으로 멈춰요. create_gpu_server는 모델을 띄워 두고 https://<ref>.<zone>/gpu/v1/servers/<이름>/으로 secret 키를 붙여 불러요. 꺼져 있으면 첫 요청에 켜지고(켜지는 동안 503), 정한 시간 동안 요청이 없으면 꺼져요. stop_gpu_server·delete_gpu_server로 멈추거나 지워요. create_gpu_volume으로 한 데이터센터에 GPU 저장소를 만들어 작업·서버에 volume으로 주면 /workspace에 붙어서, 모델을 한 번만 받아 두면 돼요(있는 동안 1GB·월 요금, delete_gpu_volume으로 지워요). region(auto·asia·us·eu)으로 빌릴 지역을 고르고, 저장소를 주면 그 데이터센터에서 빌려요. 한국에서 가까운 곳은 AP-JP-1(일본)이에요. 입력한 이미지·명령·환경 변수와 저장소 파일은 RunPod의 데이터센터에서 처리돼요. 요금과 쓰는 수는 list_gpu에 나와요. RTX 4090 1시간 4,500원부터, GPU를 빌린 때부터 돌려줄 때까지(이미지 받는 시간 포함) 초 단위로 청구해요.
  • MySQL 데이터베이스 (WordPress): create_mysql_database로 MariaDB 11.4 데이터베이스와 전용 로그인을 만들어요(보통 1분). app을 주면 그 앱만, 없으면 프로젝트 전체용이에요(전체용이 하나뿐이면 앱 모두가 받아요). bind_mysql_database로 받을 앱을 바꿔요. 받는 앱의 서버는 실행할 때 MYSQL_URL·MYSQL_HOST·MYSQL_PORT·MYSQL_USER·MYSQL_PASSWORD·MYSQL_DATABASE와 공식 WordPress 이미지가 읽는 WORDPRESS_DB_HOST(호스트:포트)·WORDPRESS_DB_USER·WORDPRESS_DB_PASSWORD·WORDPRESS_DB_NAME을 받아요. 빌드에는 들어가지 않고, 같은 이름으로 저장한 변수가 이겨요. 프리뷰도 같은 데이터베이스를 받아요. 주소는 이 서버 안의 앱에서만 닿아요. get_mysql_connection으로 연결 정보를, list_mysql_databases로 목록과 요금제 한도(무료 1개, Pro 10개, Enterprise 50개)를 봐요. 매일 밤 자동으로 백업되고, create_mysql_backup·list_mysql_backups·restore_mysql_backup으로 지금 백업하고 되돌려요(복원 직전 상태를 먼저 백업해요). delete_mysql_database는 데이터베이스와 로그인, 백업을 모두 지워요. 지우기와 복원은 confirm에 데이터베이스 이름을 그대로 넣어야 해요. REST: /mysql, /mysql/<이름>, /mysql/<이름>/connection, /mysql/<이름>/backups, /mysql/<이름>/restore.
  • 전화와 websocket: 서버 배포는 websocket을 받아요. Twilio 번호의 음성 웹훅을 https://<주소>/voice로 두면 통화 음성이 실시간으로 들어와요(시작 예제: 저장소의 examples/phone-voice). 연결이 열려 있는 동안 서버는 멈추거나 밀려나지 않아서 긴 통화도 끊기지 않아요. 대표 번호는 프로덕션 배포로 두세요. 멈춰 있던 서버를 깨우면 첫 전화가 몇 초 늦어요.
  • 서버 메모리는 기본 512MB(CPU 1개)이고, set_server_memory(콘솔의 배포 → 빌드 설정, 지금 값과 한 달 금액은 get_server_memory)로 1024·2048·4096MB 중에서 고를 수 있어요. 1024MB보다 크면 CPU가 2개예요. 쓴 메모리는 시간 단위로 runtime_gb_hour로 계량돼요. 요금제마다 고를 수 있는 최대 크기가 정해져 있어요. 프로덕션과 브랜치 주소의 서버는 요청이 없어도 늘 켜져 있어요(최소 인스턴스 1개, 따로 켤 설정은 없어요). 그래서 get_server_memory의 한 달 금액이 서버 하나의 한 달 요금이에요.
  • 동시 빌드: 이 프로젝트의 빌드가 한꺼번에 몇 개까지 돌지 set_concurrent_builds로 1~20을 정하거나 null로 한도를 없애요(콘솔의 배포 → 빌드 설정, 서버 메모리 바로 아래. 지금 값은 get_concurrent_builds). 넘는 빌드는 대기열에서 기다리고, 기다리는 동안에는 빌드 시간이 청구되지 않아요.
  • Dockerfile: 프로젝트 폴더에 Dockerfile만 있고 package.json이 없으면(Python, Go 등) 그 Dockerfile로 이미지를 빌드해 실행해요. package.json도 있는 저장소는 프리셋을 docker로 고르거나 blackwall.json에 "framework": "docker"를 넣으면 이미지로 빌드해요. 이미지의 CMD로 시작하고, 이미지가 EXPOSE한 포트(가장 낮은 TCP 포트, 없으면 3000)에서 들어요. 다른 포트면 update_app의 port로 정해요. 보안을 위해 이미지의 USER와 상관없이 권한 없는 사용자(uid 10001)로, 읽기 전용 파일 시스템으로 실행해요. 쓸 수 있는 곳은 /tmp(64MB), /run·/var/run/apache2·/var/lock/apache2(각 16MB, 다시 시작하면 비어요), blackwall.json의 "writablePaths"에 적은 경로(최대 8개, 각 16MB), 그리고 볼륨이에요. 남겨야 하는 파일은 볼륨에 두세요(아래). WordPress 공식 이미지처럼 root로 시작해야 하는 이미지는 빌드 설정의 "이미지의 사용자로 실행"(update_app의 run_as: "image")을 켜세요. 그러면 gVisor 격리 환경 안에서 이미지의 USER(root 포함)로 실행돼서 root여도 다른 프로젝트에는 닿지 못해요. 이 서버에 gVisor가 없으면 켤 수 없다고 알려 줘요. 포트 80처럼 1024 아래 포트에서도 들을 수 있어요. 빌드할 때 환경 변수는 --build-arg로 전달되고 이미지 기록에 남으니 비밀값은 실행 변수로 두세요. 빌드는 단계마다 메모리 2GB·CPU 2개, 최대 45분이고 이미지는 4GB까지예요.
  • /data: Dockerfile이 아닌 서버(Node 등)는 /data에 바로 쓸 수 있어요. Railway·Fly용으로 만든 SDK가 캐시와 토큰을 거기에 두기 때문이에요. 서버 메모리의 1/8(16MB~256MB)까지이고 다시 시작하면 비어요. 남겨야 하면 /data에 볼륨을 붙이세요(아래). 볼륨이 그 자리를 대신해요.
  • 볼륨: 서버를 다시 시작하거나 새로 배포해도 남는 디스크예요. create_volume으로 앱의 프로덕션 서버에 붙이고(예: WordPress는 /var/www/html), list_volumes로 보고, resize_volume으로 늘리고(줄일 수는 없어요), delete_volume으로 지워요(파일과 백업이 모두 사라지고 되돌릴 수 없어서 confirm에 경로를 넣어야 해요). create_volume_backup은 파일을 묶어 30일 보관하고, restore_volume_backup은 그 백업으로 되돌려요(되돌리기 전 파일은 7일 동안 백업해 둬요). 크기는 1~500GB이고 상한이라 넘으면 쓰기가 실패해요. 프로젝트의 볼륨 합계는 요금제가 정해요(Free 1GB, Pro 50GB). 프리뷰와 지금 프로덕션이 아닌 예전 배포에는 붙지 않아요. 붙이거나 지우면 1분 안에 서버가 다시 시작해요. 콘솔의 배포 → 빌드 설정에도 있어요.
  • 바꾼 설정은 다음 push부터 적용돼요. 소유자·관리자만 바꿀 수 있어요.

Git 연결: 저장소 가져오기, 비공개 저장소와 GitLab

콘솔의 배포 → Git 연결과 같은 것들이에요.

list_git_access               연결한 저장소(connected), GitHub 계정, 저장한 토큰(끝 네 글자)
list_importable_repositories  GitHub App이 볼 수 있는 저장소 찾기 (query는 전체에서, refresh는 다시 묻기)
import_repository             저장소를 연결하고 첫 배포 시작 (빌드 설정·dotenv를 함께)
disconnect_repository         저장소 하나의 연결 해제: push해도 배포하지 않음, 배포 기록은 그대로
set_checks_on_server          검사를 One Server에서 실행: GitHub 저장소의 Actions 작업을 One Server 머신에서(켜기·끄기)
add_repository                첫 push 전에 저장소 붙이기 (github: owner/name, gitlab: group/name)
set_repo_token                비공개 저장소를 받을 토큰 (자체 GitLab이면 gitlab_base)
remove_repo_token             토큰 지우기
link_github_app               조직의 다른 프로젝트에 연결된 GitHub 계정을 이 프로젝트에 연결
unlink_github_app             GitHub 계정(App 설치) 하나 또는 전부의 연결 해제

GitHub 계정을 연결하는 것은 GitHub에서 사람이 직접 확인해야 해서 콘솔의 배포 → Git 연결에서만 돼요. 연결한 뒤의 가져오기는 MCP로 할 수 있어요. 비공개 저장소의 빌드가 받기 단계에서 실패하면 list_git_access부터 보세요. 모두 소유자·관리자만 바꿀 수 있어요.

다른 서버에서 가져오기

콘솔의 조직 → 다른 서버에서 가져오기와 같아요. 원본 계정(Supabase, Vercel, PostgreSQL)은 콘솔에서 한 번 연결해요(토큰을 대화에 붙여 넣지 않게). Supabase는 [Supabase로 로그인]으로 허락만 누르면 연결돼요(토큰 복사 없음).

import_sources                연결한 원본 계정과 그 프로젝트, 지금까지의 가져오기
start_import                  가져오기 시작 (콘솔에서 나눈 import, 또는 connection+project로 묶음마다 새 프로젝트)
get_import                    옮길 곳마다 단계별 진행, 옮기지 않는 것과 이유
copy_auth_from_import         Supabase 프로젝트의 로그인 설정(소셜 제공자, 돌아갈 주소)을 이 서버의 프로젝트로 복사
set_vault_project_keys       이 프로젝트 자기 주소·비밀 키를 Vault에 넣기(서버 안에서만 옮겨요)
copy_vault_secrets_from_project  다른 프로젝트의 Vault 비밀을 값째 복사(값은 서버 안에서만 옮겨요)
copy_jobs_from_project        다른 프로젝트의 예약 작업을 꺼진 채로 복사
copy_auth_from_project        다른 프로젝트의 로그인 설정을 이 프로젝트로 복사(시크릿은 서버 안에서만 옮겨요)
copy_storage_from_project     다른 프로젝트의 버킷과 파일을 이 프로젝트로 복사 (같은 크기면 건너뛰어요)
copy_storage_from_import      Supabase 프로젝트의 버킷과 파일을 이 서버의 프로젝트로 복사 (같은 크기면 건너뛰어요)

Supabase 원본은 start_import의 address에 세션 풀러 연결 문자열을 넣어요. 이번 실행에만 쓰고 지워요. 예약 작업은 꺼진 채로 옮겨요. REST로는 GET /v1/imports/sources, POST /v1/imports {org, import, connection, project, address}, GET /v1/imports/<id>이에요.

이미 있는 프로젝트로 로그인 설정만 옮길 때는 copy_auth_from_import예요. 시크릿은 연결한 계정으로 Supabase에서 바로 읽어 저장하고 답에는 넣지 않아요. 먼저 dry_run으로 무엇이 옮겨질지 보고, 끝나면 답의 callback_url을 각 제공자 콘솔에 등록하세요. 등록 전에는 로그인이 실패해요. REST로는 POST /v1/projects/<ref>/config/auth/copy-from-import {connection, project, providers, dry_run}이에요.

파일만 옮길 때는 copy_storage_from_import예요. 여기 없는 버킷은 Supabase와 같은 공개 여부·한도로 만들고, 파일은 크기가 같은 것이 이미 있으면 건너뛰어요. 한 번에 파일 200개·45초까지 옮기고, 남으면 답의 next를 넘겨 done이 true가 될 때까지 다시 불러요. Supabase 키는 서버 안에서만 쓰고 답에 넣지 않아요. 버킷의 접근 규칙은 옮기지 않아요. REST로는 POST /v1/projects/<ref>/storage/copy-from-import {connection, project, buckets, rename, dry_run, next, max_files}이에요.

push 없이 배포하기

redeploy             같은 커밋을 다시 빌드 (환경 변수를 나중에 넣었을 때)
deploy_commit        특정 커밋을 배포
promote_deployment   빌드가 끝난 프리뷰를 프로덕션으로
rollback_deployment  프로덕션을 예전 프로덕션 배포로 (다시 빌드하지 않음, 프로덕션 보류)
create_deploy_hook   부르면 브랜치의 최신 커밋을 빌드하는 주소 (CMS 발행 등)
list_deploy_hooks    그 주소들
remove_deploy_hook   주소 지우기

환경 변수를 바꿨다면 redeploy가 필요해요. 빌드 결과에 박힌 값은 다시 빌드해야 바뀌어요. 프리뷰를 프로덕션으로 올리면 프로덕션 환경 변수로 다시 빌드해요. 프리뷰 빌드를 그대로 쓰지 않아요. 프로덕션으로 가는 배포는 소유자·관리자만 할 수 있어요.

저장소 없이 배포하기

deploy_files    파일(경로 → 내용)을 보내 빌드하고 배포 (합쳐 3MB까지, 넘으면 create_source_upload_url → deploy_source)
deploy_source   이미 올린 압축 파일(source)을 배포
create_source_upload_url   큰 압축 파일을 토큰 없이 PUT할 주소 (1시간)
  • push된 커밋과 같은 빌드를 거쳐요. package.json이 있으면 프레임워크를 찾아 빌드하고, index.html만 있으면 그대로 서비스해요.
  • prebuilt: true면 빌드하지 않고 보낸 파일을 그대로 서비스해요(이미 빌드한 dist/).
  • target은 preview(기본) 또는 production이에요. 프리뷰 주소는 branch(기본 preview)로 정해져요. 앱이 없는 프로젝트에는 site 앱이 생겨요.
  • 큰 사이트는 oneend deploy(폴더를 압축해 올림)나 POST /deployments/sources(본문: .zip, .tar, .tar.gz, 50MB까지)를 쓰고, 받은 source로 배포해요.
  • 도구만 쓸 때는 create_source_upload_url로 주소를 받아 압축 파일을 PUT하고(curl -X PUT --data-binary @site.zip '<url>'), 답의 source로 deploy_source를 불러요. 주소는 1시간 동안 그 프로젝트에만 쓰이고, 크기 한도와 검사는 POST /deployments/sources와 같아요. REST로는 POST /v1/projects/<ref>/deployments/sources/upload-urls이에요.
  • node_modules와 .git은 빼고 올려요. 폴더 밖을 가리키는 경로나 링크, 압축을 풀면 너무 커지는 파일은 거절해요.

빌드 설정 더, 시스템 변수, 배포 보안

get_build_settings        앱마다 개발 명령, Node.js 버전, 빌드 건너뛰기, 프로덕션 먼저, 필요한 검사
set_build_dev_settings    개발 명령(oneend dev)과 Node.js 버전 (18 | 20 | 22 | 24)
set_ignored_build_step    빌드할 push (automatic | every | production | preview | folder | command)
set_production_first      대기열에서 프로덕션 빌드 먼저
set_git_checks            필요한 GitHub 검사, Git LFS, 서명된 커밋만
set_expose_system_env     BLACKWALL_ENV, BLACKWALL_URL 같은 시스템 변수 넣기·빼기
set_directory_listing     index.html 없는 폴더의 파일 목록 보이기
get_deployment_security   빌드 로그·출력을 볼 사람, 포크 보호, OIDC
set_deployment_security   위를 바꾸기 (빠진 항목은 그대로)

프레임워크, 빌드·설치·출력 명령, 빌드 머신은 update_app이에요. 모두 소유자·관리자만 바꿀 수 있어요.

배포 보관 기간과 되돌리기

get_deployment_retention   배포 종류별 보관 기간(지금 적용되는 날 수, 프로젝트 값, 요금제 기본값)
set_deployment_retention   보관 기간 바꾸기 (null이면 요금제 기본값, 프로젝트 관리자)
list_deleted_deployments   3일 안에 삭제된 배포와 되돌릴 수 있는 마감
delete_deployment          배포 삭제 (3일 동안 되돌릴 수 있어요)
restore_deployment         삭제한 배포 되돌리기
  • 요금제 기본값: Free는 모두 30일. Pro·Enterprise는 취소 30일, 실패 90일, 프리뷰 180일, 프로덕션 1년(365일). 프로젝트가 정한 값이 있으면 그걸 따라요.
  • 기간과 상관없이 남기는 배포: 가장 최근 배포 10개, 가장 최근 완료된 프로덕션 배포 20개, 가장 최근 완료된 프로덕션 외 배포 20개, 프로덕션·브랜치·도메인이 지금 서비스 중인 배포(브랜치마다 최근 프리뷰 포함).
  • 삭제한 배포와 기간이 지나 삭제된 배포는 3일 동안 restore_deployment로 되돌릴 수 있어요. 그동안 그 배포의 dpl-… 주소는 410으로 답하고, 3일이 지나면 파일과 빌드 로그를 지워 되돌릴 수 없어요.
  • REST로는 GET·PUT /v1/projects/<ref>/deployment-retention, GET /v1/projects/<ref>/deployments/deleted, DELETE /v1/projects/<ref>/deployments/<id>, POST /v1/projects/<ref>/deployments/<id>/restore이에요. CLI는 oneend deployments retention, oneend deployments deleted, oneend deployments rm, oneend deployments restore예요.

배포의 주소, 기다리기, 보안 점검

  • 배포를 만드는 도구(deploy_files, deploy_source, deploy_commit, redeploy, promote_deployment)와 get_deployment, list_deployments, rollback_deployment는 주소를 함께 줘요. url은 그 배포만의 dpl-… 주소, production_url은 프로덕션 주소, preview_url은 그 브랜치의 프리뷰 주소예요. 프리뷰 보호가 켜져 있으면 note가 누가 열 수 있는지 말해요.
  • rollback_deployment 뒤에는 그 앱의 프로덕션이 보류돼요(production_held, 콘솔의 "프로덕션 보류"). 새 프로덕션 빌드는 만들어지지만 프로덕션 주소로 나가지 않아요. promote_deployment로 빌드가 끝난 프로덕션 배포를 올리면 다시 빌드하지 않고 바로 나가고 보류가 풀려요. 지금 배포를 올리면 보류만 풀려요. list_deployments의 production_held가 보류된 앱을 알려 줘요.
  • wait(초, 120까지)를 주면 빌드가 끝날(ready·error) 때까지 기다려 결과를 한 번에 줘요. 실패하면 error와 build_log 끝부분이 오고, 시간 안에 안 끝나면 still_running: true와 retry_after_seconds가 와요. 그 뒤에 get_deployment를 wait와 함께 부르면 이어서 기다려요. create_project의 wait는 데이터베이스가 준비될 때까지 기다리고, list_projects의 status가 ready·provisioning·failed·paused를 알려줘요.
  • 답의 advisors는 get_advisors의 심각한 보안 문제(누구나 쓸 수 있는 규칙, 규칙을 무시하는 뷰 같은 것) 수와 상위 3개예요. 기본은 알리기만 하고 배포해요. block_on_advisors: true를 주면 그런 문제가 있는 동안 프로덕션 배포를 거절해요(프리뷰는 막지 않아요). oneend deploy --block-on-advisors도 같아요. git push로 시작한 배포는 막지 않아요.