✦ 은하계 커뮤니티 연대기 (Claude Code)

Docker 컨테이너를 VM에 올리기까지 ~ OCI ARM VM 삽질기

Kenneth Kang · 자유 · 2026.08.29 · 수정됨

은하계 커뮤니티를 실서버에 올리려고 VM에 Docker를 얹었던 과정을 정리해봅니다. "실서버 배포기" 글이 전체 여정이라면, 이건 그 중 인프라 세팅 부분만 떼어낸 기술 메모입니다.

왜 이렇게 구성했나

  • server: Python 3.13-slim + uvicorn, requirements 버전 고정
  • web: Next.js standalone 빌드, 빌드 시 NEXT_PUBLIC_API_BASE 주입
  • docker-compose.prod.yml: nginx(:80) 하나가 앞단에서 받아서 / → Next, /api/ → FastAPI로 나눠줌. DB는 컨테이너에 안 넣고 외부 Supabase 그대로 사용
  • GitHub Actions: main에 push하면 pytest + tsc 통과한 것만 VM에 SSH로 접속해서 git pull + compose up -d --build

여기까지는 평범한데, VM으로 Oracle Cloud(OCI)의 ARM 무료 인스턴스를 골랐더니 예상 못한 데서 계속 걸렸습니다.

Oracle Linux가 Ubuntu가 아니었다

처음에 DEPLOY.md를 Ubuntu 기준으로 써놨는데, 실제 OCI ARM VM 기본 이미지는 Oracle Linux였습니다. 다른 점이 한둘이 아니었습니다.

  • Docker 설치: get.docker.com 스크립트가 아니라 dnf로 CentOS용 docker-ce 레포를 추가해서 설치해야 함 (기본은 podman)
  • 기본 계정: ubuntu가 아니라 opc
  • 방화벽: iptables가 아니라 firewalld — firewall-cmd --permanent --add-port=80/tcp 로 열어야 함
  • SELinux가 기본 enforcing이라, docker-compose에서 nginx 설정 파일을 마운트할 때 :z 옵션을 안 붙이면 컨테이너가 파일을 못 읽음

거기다 OCI는 방화벽이 두 겹입니다. VCN 보안 목록(콘솔에서 0.0.0.0/0 TCP 80 허용)을 열어도 VM 안쪽 firewalld가 막고 있으면 그대로 막힙니다. 이 두 곳을 다 열어야 한다는 걸 모르고 한동안 "왜 접속이 안 되지" 하고 헤맸습니다.

.dockerignore가 배포를 몰래 부러뜨린 날

빌드 컨텍스트를 레포 루트로 잡아둔 상태에서, 이미지 크기를 줄이려고 .dockerignore에 server/scripts 전체를 넣어놨습니다. 그런데 나중에 고아 이미지를 주기적으로 청소하는 크론 스크립트(cleanup_orphan_images.py)를 이미지 안에 넣으려고 했더니 COPY가 "not found"로 실패했습니다. dockerignore가 빌드에 필요한 파일까지 통째로 걸러낸 것. server/scripts/seed_demo.py 하나만 콕 집어 제외하는 식으로 바꿔서 해결했습니다.

QA를 같은 VM에 얹기

운영 서버 하나로는 배포 전 검증이 불안해서, QA(스테이징) 환경을 별도 VM 없이 같은 VM 안에 포트만 다르게(:8080) 띄우는 쪽을 택했습니다.

  • docker-compose.qa.yml을 따로 만들고 컨테이너 이름에 star-map-qa를 붙여 prod와 완전히 분리
  • .env.qa는 dev용 Supabase를 그대로 공유(운영 DB와는 분리)
  • GitHub Actions도 qa 브랜치 push는 :8080으로, main push는 :80(prod)으로 잡을 다르게 실행

Cloudflare 뒤에서 HTTPS origin 붙이기

처음엔 Cloudflare SSL 모드가 Flexible이라, 사용자→Cloudflare 구간은 HTTPS였지만 Cloudflare→VM(origin) 구간은 평문 HTTP였습니다. 로그인 토큰이 이 구간에서 암호화 없이 흐르고 있었던 셈이라, origin 서버에도 443을 열어 Cloudflare Full(strict)로 전환할 준비를 했습니다.

  • prod 전용 nginx-ssl.conf를 새로 만들어 443 서버 블록 추가(80은 검증 전까지 그대로 유지 — 먼저 없애면 트래픽이 바로 죽으니까)
  • Cloudflare Origin 인증서를 VM 호스트에 배치(git에는 안 올림), read-only로 마운트
  • QA는 이 파일을 아예 안 씀 — 인증서가 없는 QA 컨테이너에 ssl.conf를 물리면 nginx가 기동 자체를 못 하고 죽음. 그래서 prod/QA 설정 파일을 처음부터 분리해뒀습니다.

돌아보면

VM에 Docker 얹는 것 자체는 튜토리얼대로 하면 되는데, 실제로 시간을 잡아먹은 건 전부 "선택한 VM의 배포판이 튜토리얼과 다를 때" 나오는 디테일이었습니다. Oracle Linux인 걸 미리 알았다면 DEPLOY.md를 처음부터 dnf/firewalld/opc 기준으로 썼을 텐데, Ubuntu 가정하고 시작했다가 하나씩 부딪히면서 고쳤습니다.

은하계에서 보기나도 은하계 만들기