리팩토링과 삽질 — ModSecurity와의 전쟁, 그리고 아키텍처 재설계
2026년 2월 4일 — 하루 종일 400 Bad Request와 싸웠다. 원인은 예상치 못한 곳에 있었다.
그날의 시작
2월 4일, 아침부터 코드를 리팩토링하기로 했다. BTC와 ALT 두 개의 시스템이 각각 다른 DB 테이블, 다른 API 구조, 다른 워크플로우로 돌아가고 있었고, 이대로는 새 전략을 추가할 때마다 모든 걸 처음부터 만들어야 했다.
목표는 명확했다:
- 통합 DB 스키마 설계
- API 경로 정리
- 워크플로우 URL 업데이트
간단할 줄 알았다. 전혀 아니었다.
400 Bad Request의 늪
BTC API를 /model/api/ 경로에서 다른 곳으로 옮기는 과정에서 문제가 시작됐다. n8n에서 API를 호출하면 ERROR: Request failed with status code 400 메시지만 반복됐다.
PHP 코드는 아예 실행되지 않았다. echo "hello"; 한 줄짜리 파일도 400을 뱉었다. PHP 문법 오류도 아니었다. 로컬에서는 잘 되는데 서버에서만 안 됐다.
원인 찾기 — 삽질의 기록
- 시도 1: JSON 포맷 문제? (실패) - n8n의 jsonBody 포맷 변경 및 Content-Type 헤더 수정. 효과 없음.
- 시도 2: 파일명 문제? (실패) -
position.php를poslog.php로 변경. 효과 없음. - 시도 3: base64_decode 제거? (실패) - SQL 쿼리 인코딩을 평문으로 변경. 효과 없음.
- 시도 4: 경로 변경 (부분 성공) -
/model/api/를/btc/api/로 바꾸니 단순 파일은 작동함. - 시도 5: http_response_code 제거 (해결!) - 모든 응답에서 에러 코드를 제거하고 HTTP 200으로 반환하니 완전히 해결됐다.
범인: ModSecurity (닷홈 웹 방화벽)
닷홈 공유 호스팅의 ModSecurity(웹 방화벽)가 특정 패턴을 차단하고 있었다.
| 차단 패턴 | 예시 | 차단 이유 |
|---|---|---|
| 특정 경로명 | /model/api/*.php |
의심스러운 시스템 경로명 |
| 비200 응답 | http_response_code(400) |
악성 에러 페이지 생성 의심 |
| 경로 탐색 | ../../config.php |
디렉토리 트래버설 공격 방어 |
| 난독화 패턴 | base64_decode() |
악성 스크립트 실행 의심 |
http_response_code(400)을 설정하는 PHP 파일을 ModSecurity가 "이 파일은 400 에러를 의도적으로 만드는 악성 코드"로 판단해서 파일 자체를 차단한 것이다. PHP가 실행되기도 전에 Apache 레벨에서 요청이 거부됐으니, 아무리 코드를 고쳐도 소용이 없었던 것이다.
해결 원칙: 닷홈 생존 가이드
이 삽질에서 얻은 교훈을 바탕으로 비비드인덱스의 배포 원칙을 정리했다.
- 경로명 주의:
/model/,/admin/같은 민감한 이름은 절대 피할 것. - 항상 HTTP 200: 에러 응답도 HTTP 200으로 보내고, JSON body에서
success: false로 구분할 것. - 절대 경로 사용:
../../대신$_SERVER['DOCUMENT_ROOT']를 활용할 것. - 난독화 금지:
base64_encode/decode사용을 자제할 것. - POST 테스트 필수: GET은 통과해도 POST만 차단되는 경우가 많으니 반드시 확인.
같은 날: 멀티 전략 아키텍처 설계
삽질을 끝내고 나서야 원래 하려던 멀티 전략 아키텍처 설계에 착수했다.
현재 구조의 문제점
BTC와 ALT가 각각 전용 테이블과 로직을 가져서 새 전략을 추가할 때마다 코드 중복이 심하고 성과 비교가 불가능했다.
설계한 새 구조 (통합 DB)
- positions: 모든 전략의 포지션 통합 (
strategy컬럼으로 구분) - trades: 모든 거래 기록 통합
- strategy_stats: 전략별 실시간 통계 정보
핵심은 WHERE strategy = ?만으로 모든 데이터를 필터링할 수 있게 만드는 것이다. 이제 SQL 한 줄로 모든 전략의 승률을 비교할 수 있다.
바이낸스 타임스탬프 동기화 에러
리팩토링 마무리 단계에서 바이낸스 API가 타임스탬프 에러를 뱉었다. n8n 서버와 바이낸스 서버의 시간이 미세하게 어긋난 것이 원인이었다.
해결: API 요청 직전에 바이낸스 서버 시간을 먼저 조회하고, 그 시간을 기준으로 타임스탬프를 설정하도록 수정했다.
하루의 교훈
- 공유 호스팅의 보안 설정은 직접 겪어봐야 안다. 에러 메시지도 모호하니 삽질은 필수다.
- 리팩토링 전에는 반드시 백업 커밋을 하자.
Pre-refactoring backup커밋이 내 멘탈을 지켜줬다. - 한 번에 하나씩 바꾸자. 경로, 코드, DB를 동시에 바꾸면 범인을 찾을 수 없다.
EP.06 | 2026년 2월 4일
Vivid Index 개발기