Free

Claude에게 프로덕션 배포 맡기기

배포 실수는 아무도 안 알려준다. 분리된 credentials, EDITOR 스크립트, 읽기-검증, env 기반 런타임 전환 네 가드레일로 Claude를 쓰되 태우지 않기.


배포와 코드 작성의 가장 큰 차이: 배포는 일회성, 고위험, 롤백이 괴롭다. 코드 한 줄 잘못 써도 테스트 한 번이면 잡힌다. Credentials 한 줄 잘못 쓰면 첫 실결제가 실패할 때야 알게 된다——그때는 사용자가 이미 카드 승인했고, 돈은 네 계좌로 안 들어오고, 로그는 400으로 도배된다.

최근 Claude와 how2claude를 로컬 개발에서 프로덕션으로 올렸다: Stripe 라이브 계정, x402 메인넷 지갑, Google OAuth, Kamal secrets. Claude는 어느 값이 테스트 환경인지 실제인지 모른다. sk_live_sk_test_가 한 글자 차이로 세계가 끝난다는 것도 모른다. 가드레일은 직접 세운다.

가드레일 #1: dev와 prod를 별개 credentials 파일로 분리

Rails 기본값은 config/credentials.yml.enc, 복호화 키 config/master.key. 이 기본값을 쓰는 순간 진다.

sk_live_xxx를 이 파일에 넣고 로컬에서 테스트를 돌리면, 테스트 코드가 프로덕션 Stripe를 때린다. 테스트 한 번에 카드가 한 번 긁힌다.

두 개로 나눈다:
- config/credentials.yml.enc + config/master.key: dev/test용, sk_test_xxx 넣기
- config/credentials/production.yml.enc + config/credentials/production.key: 프로덕션용, sk_live_xxx 넣기

.gitignore에 두 .key 모두 무시, 두 .enc 모두 커밋. production.key는 배포 머신에만 둔다.

그다음 Kamal secrets가 맞는 파일을 가리키게:

 # .kamal/secrets
-RAILS_MASTER_KEY=$(cat config/master.key)
+RAILS_MASTER_KEY=$(cat config/credentials/production.key)

컨테이너 안의 RAILS_MASTER_KEY가 프로덕션 키를 가리키게 되고, 복호화되는 건 프로덕션 credentials. Claude가 이 줄을 쓸 때 특히 지켜봤다——기본 생성된 Kamal 템플릿은 config/master.key(dev용)이고, 조용히 dev Stripe key를 프로덕션에 배포한다.

가드레일 #2: 값 넣기는 EDITOR 스크립트로, 수동 복붙 아님

bin/rails credentials:edit --environment production은 인터랙티브 에디터를 연다. Claude는 인터랙티브 에디터를 못 다룬다. 너도 수십 개 키를 손으로 복붙하기 싫다 (오타 하나에 전부 망함).

이 패턴을 써라:

EDITOR="ruby script/set_prod_webhook_secret.rb" \
  bin/rails credentials:edit --environment production
rm script/set_prod_webhook_secret.rb

script/set_prod_webhook_secret.rb는 이런 모양:

# ARGV[0]은 복호화된 임시 YAML 파일 경로
file = ARGV[0]
require "yaml"
data = YAML.load_file(file) || {}
data["stripe"] ||= {}
data["stripe"]["webhook_secret"] = "whsec_GHWObNAKFh2HPOlJpbGmlYfIiKz1C8EY"
File.write(file, data.to_yaml)

Rails는 복호화된 YAML을 임시 파일에 쓰고, 그 경로를 인자로 "EDITOR"를 호출한 뒤, 종료되면 다시 암호화한다. 우리 "EDITOR"는 사실 Ruby 스크립트로, 키 하나만 정확히 바꿔 저장한다.

장점:
- 정확: stripe.webhook_secret 하나만 건드리고 나머지는 안 건드림.
- 멱등: 두 번 돌려도 결과 같음.
- 감사 가능: 스크립트 자체가 변경의 diff. Claude가 쓴 스크립트를 한 번 훑으면 뭘 바꿀지 정확히 안다.
- 삭제하면 사라짐: rm 후엔 디스크에 평문 credential 없고, shell history에도 whsec_... 복붙 흔적 없음.

credential마다 스크립트 하나: set_stripe_live_key.rb, set_webhook_secret.rb, set_price_ids.rb, set_wallet_address.rb. 끝나면 바로 rm.

가드레일 #3: 쓴 뒤 Rails runner로 읽어서 검증

쓰고 나서 맞게 썼다고 믿지 마라. 읽어 와서:

bin/rails runner -e production "
c = Rails.application.credentials
puts 'sk_live set: ' + c.dig(:stripe, :secret_key).to_s.start_with?('sk_live_').to_s
puts 'webhook_secret set: ' + c.dig(:stripe, :webhook_secret).to_s.start_with?('whsec_').to_s
puts 'wallet prefix: ' + c.dig(:x402, :wallet_address).to_s[0..5]
puts 'wallet len: ' + c.dig(:x402, :wallet_address).to_s.length.to_s
"

중요한 건 접두사길이 검증이지 그냥 출력해서 눈으로 보는 게 아니다.

  • Stripe live secret key는 항상 sk_live_로 시작. 읽은 게 sk_test_로 시작하면 Claude가 test key를 prod 파일에 넣은 것——첫 실결제까지는 발견 못 함.
  • Webhook secret은 항상 whsec_로 시작. 형식 맞는지 한눈에 보임.
  • EVM 지갑 주소는 항상 42자 0x.... 길이 안 맞으면 다른 문자 섞여 들어간 것.

접두사 검증만 붙여도 오타, 필드 누락, 환경 혼용 같은 오류는 대부분 막힌다.

가드레일 #4: 런타임에 env로 자동 전환, 배포 시 수동 전환 금지

"배포 전에 network를 mainnet으로 바꾸자"고 생각하기 쉽다——이런 전환은 인간의 기억에 의존하고, 언젠간 터진다.

규칙은 initializer에 박아넣는다:

# config/initializers/x402.rb
X402.configure do |c|
  c.wallet_address = Rails.application.credentials.dig(:x402, :wallet_address)
  c.chain = Rails.env.production? ? "base" : "base-sepolia"
end

같은 코드로 dev는 테스트넷(sepolia), prod는 메인넷(base). 배포 시 아무것도 안 바꿔도 됨. Claude도 "전환 까먹을" 일 없다, 전환이 Claude 일이 아니니까.

같은 트릭을 basescan_tx_url, Plan 가시성(dev 전용 플랜은 프로덕션에 안 보임), Stripe price ID 선택 등에 적용. dev와 prod에서 다른 모든 설정은 Rails.env로 뒤집는다. 배포 시 기억하는 것에 의존하지 마라.

마지막 단계: 실제 플로우를 직접 한 번 걷기

네 가드레일을 다 세워도 첫 실돈 결제 클릭은 네가 직접 해야 한다.

이전 글 《Claude로 조용한 버그 디버깅하기》에서 썼다: 프로덕션 첫 x402 결제 클릭에서 console에 invalid_string at payTo——지갑 주소 43번째 문자가 중국어 IME에서 딸려 들어온 전각 물음표였다. 접두사 검증이 못 잡고 (0x 유지), 테스트도 못 잡고 (테스트는 실거래 안 보냄), 실제로 클릭해야만 드러났다.

배포 가드레일은 Claude를 위한 게 아니다, 너를 위한 거다——자동화할 수 있는 것(접두사, 길이, env 전환)은 자동화하고, 아낀 주의력을 자동화가 못 덮는 실제 상호작용에 쓴다.


Claude에게 배포를 맡기는 전체 플로우:

  1. dev와 prod의 credentials 파일 + .key 파일 분리.
  2. 설정할 값마다 일회성 Ruby 스크립트 작성, EDITOR=script로 넣고 즉시 rm.
  3. 쓴 직후 Rails runner로 읽어 와서 접두사/길이 검증.
  4. 런타임 차이는 전부 Rails.env로 뒤집기, 배포 시 수동 전환 금지.
  5. 첫 실돈 버튼은 직접 클릭.

배포는 "더 위험한 코딩"이 아니다. 배포는 "틀려도 아무도 바로 안 알려주는 코딩"이다. 가드레일의 역할은 "아무도 안 알려줌"을 "15초 안에 알게 됨"으로 바꾸는 것.