- 인공지능기초다지기
- 데이터 분석 기반 에너지 운영 관리자 양성 및 취업과정
- 코딩테스트 python
- PY4E
- [멀티잇]데이터 시각화&분석 취업캠프(Python)
- 빅데이터분석기사
- 데이터베이스
- 이기적
- AI 플랫폼을 활용한 데이터 분석
- Oracle
- 프로그래머스
- Ai
- 오라클
- 부스트코스
- unsub
- r
- 네이버부스트캠프
- 이것이 취업을 위한 코딩테스트다 with 파이썬
- boostcoures
- 기초다지기
- 정보처리기사
- 코딩테스트
- boostcourse
- 빅데이터 분석 기반 에너지 운영 관리자 양성 및 취업과정
- 파이썬
- DB
- python
- 빅분기
- SQL
- Django
- Today
- Total
매일공부
[Django] 화면에서 로고 이미지가 깨지는데 PDF에는 정상 — DEBUG=False의 함정 본문
증상
같은 이미지(회사 로고, 직인)인데 PDF에는 정상적으로 나오고, 웹 화면에서는 깨져서 보였다.
원인 — 미디어 파일 서빙이 DEBUG=True일 때만 등록되어 있었다
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
미디어 파일(/media/...) 서빙이 DEBUG=True일 때만 URL에 등록되고 있었다. 운영서버는 DEBUG=False라서 Django가 /media/... 요청을 아예 처리하지 않고 404를 반환한다. 화면의 <img src="{{ company.logo.url }}">가 이 경로를 가리키니 깨질 수밖에 없었다.
반면 PDF는 WeasyPrint가 브라우저처럼 HTTP로 요청하는 게 아니라, 파일시스템 경로(MEDIA_ROOT)를 직접 읽어서 렌더링하기 때문에 이 문제와 무관했다 — 그래서 PDF는 멀쩡했던 것.
정적파일과 미디어파일은 서빙 주체가 다르다
정적파일(css/js)은 WhiteNoiseMiddleware가 운영에서도 서빙해주고 있었다. 하지만 WhiteNoise는 STATIC_ROOT만 서빙 대상으로 삼고, 업로드된 파일(MEDIA_ROOT)은 다루지 않는다.
서빙 주체 운영(DEBUG=False)에서
| 정적파일 (css/js) | WhiteNoise | 정상 서빙 ✅ |
| 미디어파일 (업로드 이미지) | (아무도 없음) | 404 ❌ |
DEBUG=True일 때는 Django가 둘 다 대신 서빙해주기 때문에 개발 중엔 이 차이가 전혀 드러나지 않았다. 딱 운영 배포 시점에야 터지는 전형적인 케이스.
nginx란 무엇이고 왜 필요한가
Django(gunicorn)를 운영 배포할 때 흔한 구조는 이렇다.
사용자 브라우저 → nginx → gunicorn → Django
nginx가 앞단에서 요청을 받아서, 정적파일/이미지처럼 단순한 파일 요청은 nginx가 디스크에서 직접 읽어 바로 응답하고, 그 외 동적인 요청(로그인, DB 조회 등)만 gunicorn에 넘긴다. gunicorn(파이썬 프로세스)이 파일 서빙까지 직접 하면 비효율적이라, 파일 서빙에 최적화된 nginx가 그 역할을 떼어가는 구조다.
선택지 두 가지
당장의 간단한 해결책(코드 한 줄): 미디어 서빙을 DEBUG 조건 밖으로 빼서 Django가 직접 서빙하게 하는 방법도 있었다. 지금 같은 내부용 소규모 서비스라면 실용적으로 문제없는 선택이다.
정석적인 해결책: nginx를 앞단에 추가하는 것. PDF/첨부파일이 앞으로 늘어날 걸 감안해서, 이번엔 nginx를 도입하는 쪽으로 결정했다 — 실제로 어떻게 붙였는지는 다음 글에서 이어서 다룬다.
정리
- DEBUG=True/False에 따라 동작이 달라지는 코드는, 로컬 개발 환경에서는 절대 문제가 드러나지 않는다는 걸 명심해야 한다
- "정적파일"과 "미디어파일"은 이름은 비슷해 보여도 Django/WhiteNoise 입장에서는 완전히 다른 취급을 받는다 — 하나가 되면 다른 하나도 될 거라고 넘겨짚으면 안 된다
'IT > 작업기록' 카테고리의 다른 글
| [Docker] 네트워크 통합하다가 DB가 통째로 끊긴 사고 (0) | 2026.08.28 |
|---|---|
| [Docker] docker-compose 없이 Container Manager로 nginx 붙이기 (0) | 2026.08.28 |
| [배포] PDF는 한글이 정상인데 운영서버 배포 후에만 깨진 이유 (0) | 2026.08.27 |
| [Django] select_related 하나로 쿼리가 490개→29개 준 이유 (0) | 2026.08.20 |
| 시놀로지 NAS + 라우터로 내부 서비스에 서브도메인 연결하기 (IP:포트 대신 도메인으로 접속하기) (0) | 2026.08.20 |