IT 시행착오··약 4분

로컬·운영 구분이 없는 '개발용 Cloudflare URL' 찾기 실패 — 환경 분리의 교훈

운영 워커만 있고 개발용 URL이 따로 없다는 Notion 메모를 바탕으로, 개발·운영 환경을 뒤섞으면 유령 같은 디버깅 문제가 생기는 과정을 공개 가능하게 정리합니다.

서버 하드웨어 보드 — 개발·운영 환경 분리 실험 (cc by 3.0, wikimedia-commons)

“개발용 Cloudflare URL은 어디 있지?“라는 질문으로 시작된 하루였다. Notion에 정리된 운영 구성 설명 메모는 명확하게 답한다. Cloudflare에는 운영만 있고(re-view-all.com 같은 실서비스 + 워커 직접 URL), 개발용 Cloudflare URL은 없다. 개발은 로컬 localhost:3000 / 8787을 쓰면 된다. 그런데 그렇게 단순한 답도, 환경을 구분하는 습관이 없으면 결국 유령 같은 오류를 만든다.

사실: ’운영 배포 URL’과 ’개발 실행 주소’는 서로 다른 세계였다

메모를 풀어 보면 구조가 나온다. 웹 프론트는 Next.js로, API는 Wrangler dev로 따로 띄운다. 프론트가 프로덕션에서 쓰는 API 워커 주소와, 로컬에서 쓰는 localhost:8787은 완전히 다르다. 나는 이 차이를 무시하고, 운영 URL에서 동작하던 엔드포인트를 그대로 로컬로 가져왔다. 그 결과 로그인 콜백·CORS 허용 목록·환경변수 때문에 같은 코드가 다른 곳에서 다르게 행동했다.

더 답답했던 건, 운영에만 있고 개발에는 없는 설정 값이었다. 콜백 URL, 시크릿, CORS 출처가 환경별로 갈라져 있는데, 나는 한 곳의 설정만 바꾸고 두 환경을 “같은 것”처럼 취급했다. 문제가 생겼을 때 확인한 첫번째는 “어느 환경에서 도는 코드인가”가 아니라 배포 기록이어서, 원인 찾기에 담을 짚었다.

이유: 환경 분리는 ’선택’이 아니라 ’디버깅 도구’다

의외로 흔한 실수인데, 코드는 바꿨는데 환경별 설정을 안 바꾸는 경우가 많다. 운영에만 있는 CORS 출처, 개발 전용 로컬 주소, 시크릿 불일치. 이들이 섞이면 “이 코드가 방금 수정했는데 왜 안 되지?“의 원인은 대부분 코드가 아니라 환경 구성이 된다. 로컬과 운영의 URL·시크릿·CORS를 한 번에 목록으로 만들어 두면, 오류가 났을 때 “코드 vs 구성”을 빠르게 분리할 수 있다.

메모의 한 줄 요약(“개발은 localhost, 운영은 Cloudflare”)이 곧 방법론이다. 개발·운영 환경을 명시적으로 갈라 놓고, 어느 쪽을 만지는지 그때그때 확인하는 습관이, 유령 같은 크로스 환경 버그의 대부분을 막는다.

평가: 환경 분리 규칙 세 가지

첫째, URL을 하드코딩하지 말고 환경별로 나눈다. 프론트가 가리키는 API 주소가 환경마다 달라야 한다면, 그 값이 어느 환경인지 소스에서 바로 보이게 한다. 둘째, 시크릿·콜백·CORS 출처는 환경별 목록으로 관리한다. 콜백 URL 하나를 바꾸면 그게 어느 환경에 적용돼야 하는지가 디버깅의 첫 질문이어야 한다. 셋째, 개발·운영을 “같은 서비스”로 보되 “다른 세상”으로 취급한다. 운영 배포 기록으로 로컬 문제를 찾으려는 시도는 원인을 늦춘다.

한계: 이 글은 운영/로컬 두 환경이 나뉜 사례만 다룬다. 스테이징·카나리처럼 환경이 더 많아지면 ‘환경별 구성 저장소’ 관리가 별도 과제가 된다. 또 공개 구성 문서만으로는 특정 버그의 실제 원인을 단정할 수 없으므로, 로그와 실행 주소 확인이 항상 우선이다.

부연: 다음에 손댄다면

개발 서버를 띄울 때 시작 지점에 “지금 어느 환경이며, API는 어디를 바라보는가”를 출력하게 하면 헷갈림이 줄어든다. 그리고 콜백 URL·CORS·시크릿을 바꿀 때마다 해당 환경 목록을 함께 갱신한다. 가장 쉽게 잊는 것이 가장 먼저 터진다. URL 한 줄의 차이가 같은 코드의 결과를 뒤집는다는 걸, 이번 실패는 정확히 보여 줬다.