Django dev prod setup 한 번에 정리: .env로 개발·운영 나누는 방법 3편

로컬에선 잘 되는데 서버만 가면 터지는 이유
로컬에서는 python manage.py runserver 하면 잘 돌아가요.
근데 케미클라우드에 올려서 https://studymate.secondlife.lol 로 접속하면… 500 에러, CSRF, ALLOWED_HOSTS, SECRET_KEY 경고까지 😅
이게 다 뭐 때문이냐면, 결국 Django dev prod setup 구분이 제대로 안 돼서입니다.
- 로컬에서는
DEBUG=True, sqlite, 아무 호스트나 허용 - 운영에서는
DEBUG=False, 보안 옵션 빡세게, 진짜 도메인만 허용
이 두 세계를 한 파일에 다 때려 넣으면,
언젠가 반드시 꼬이게 돼 있어요. 그래서 이번 편에서는
“.env + base/dev/prod 구조로 장고 dev prod 설정 깔끔하게 나누는 법”
을 정리해봅니다.
실제 Studymate 배포 과정에서 겪었던 에러까지 녹여서,
나중에 비슷한 장고 dev prod 설정 구조를 그대로 쓸 수 있게 하는 게 목표입니다.
왜 굳이 Django dev prod setup을 이렇게까지 나눌까?
1. 사내벤처·데모 서버가 여러 개일 때
사내벤처 하다 보면
- 로컬 개발 환경
- 내부 테스트 서버 (사내망)
- 실제 운영 서버 (인터넷 공개)
이렇게 2~3개 환경이 생깁니다.
이때 장고 dev prod 설정을 분리해 두면
- dev 서버는
DEBUG=True, 테스트용 메일, 테스트 DB - prod 서버는
DEBUG=False, 실제 도메인, 실제 DB, 보안 옵션 On
으로 깔끔하게 구분 가능.
특히 AI 기능 붙일 때, 개발 중인 프롬프트나 테스트 키를
실제 운영 환경으로 잘못 섞어 넣을 위험을 줄일 수 있어요.
2. AI·데이터 관련 설정을 안전하게 숨기고 싶을 때
LLM API 키, DB 비밀번호, S3 버킷 키…
이런 것들을 코드에 직접 하드코딩하면 바로 보안 지옥입니다.
.env + 장고 dev prod 설정 구조를 쓰면
.env에는 민감 정보만 넣고dev.py,prod.py에서는os.getenv()로만 읽어서 사용
하는 방식이라, 깃허브에 올리더라도.env만 .gitignore에 넣으면 꽤 안전해집니다.
3. 케미클라우드·PythonAnywhere 등 공유 호스팅 환경에서
공유 호스팅은 서버 OS를 마음대로 못 만지니까,
환경에 따라 달라지는 부분을 전부 코드/설정에서 처리해야 합니다.
ALLOWED_HOSTSCSRF_TRUSTED_ORIGINSSECURE_SSL_REDIRECT- DB URL
이런 것들은 Django dev prod setup을 통해 확실히 나누고,
실제 값은 .env로 빼두면 서버를 옮겨도 설정만 바꿔 끼우면 됩니다.
Organizing: .env + base/dev/prod로 장고 dev prod 설정 설계하기
1단계. settings를 base / dev / prod로 쪼개기

먼저 config/settings 구조를 이렇게 가져갑니다.
config/
settings/
__init__.py
base.py
dev.py
prod.py핵심 아이디어는
base.py→ 모든 환경 공통 설정dev.py→ 개발용(로컬/테스트 서버) 오버라이드prod.py→ 운영용(케미클라우드) 오버라이드
dev.py는 예를 들어 이렇게 시작합니다.
from .base import *
DEBUG = True
ALLOWED_HOSTS = ["*"]prod.py는
from .base import *
DEBUG = False
ALLOWED_HOSTS = os.getenv(
"ALLOWED_HOSTS",
"secondlife.lol,www.secondlife.lol",
).split(",")이렇게 하면, Django dev prod setup이 깔끔하게 갈리는 구조가 됩니다.
2단계. base.py에서 BASE_DIR와 .env 로딩 통합
base.py 상단은 이렇게 통일해 두면 편해요.
import os
from pathlib import Path
from dotenv import load_dotenv
BASE_DIR = Path(__file__).resolve().parent.parent.parent
env_path = BASE_DIR / ".env"
load_dotenv(env_path)이렇게 하면
- 로컬에서
manage.py실행하든 - 케미클라우드에서
passenger_wsgi.py로 실행하든
항상 BASE_DIR/.env를 읽게 됩니다.
장고 dev prod 설정 파일 어디에서든os.getenv()만 쓰면 되는 구조가 완성되는 거죠.
3단계. .env 설계 – dev와 prod를 동시에 지원하는 패턴

.env는 운영 서버용 기준으로 만들고,
로컬에는 .env.dev 같은 파일을 별도로 두는 것도 좋습니다.
기본 예시는 이런 식으로 구성했습니다:
# 공통
SECRET_KEY=랜덤_영문_숫자_기호키
DATABASE_URL=sqlite:////home2/calcanyc/naxdax_project/db.sqlite3
# 운영용 (prod)
DEBUG=False
ALLOWED_HOSTS=naxdax.store,www.naxdax.store
SECURE_SSL_REDIRECT=True
SECURE_HSTS_SECONDS=31536000
# dev용은 별도 파일 또는 로컬 .env에서만:
# DEBUG=True
# ALLOWED_HOSTS=*
# SECURE_SSL_REDIRECT=False핵심은
- 값에는 한글 넣지 않기 (케미클라우드 환경에서 Unicode 문제 방지)
- dev / prod 차이는
- DEBUG
- ALLOWED_HOSTS
- SSL 관련 옵션
정도만 바꾸면 충분히 구분 가능하다는 것
이 패턴을 쓰면,
“Django dev prod setup이 꼬여서 로컬은 되는데 서버는 안 된다” 같은 상황을 많이 줄일 수 있습니다.
4단계. 어떤 settings를 쓸지 고르는 기준 – manage.py vs passenger_wsgi.py
장고 dev prod 설정을 실제로 선택하는 지점은 두 곳입니다.
4-1. 로컬 개발 – manage.py / runserver
manage.py 안에는 보통 이렇게 들어있죠.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.dev")이렇게 두면 로컬에서 python manage.py runserver 할 때
자동으로 dev 설정을 사용합니다.
4-2. 서버 운영 – passenger_wsgi.py
케미클라우드에서는 우리가 아까 정리한 것처럼
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.prod")로 운영 설정을 직접 지정했습니다.
이렇게 하면
- 로컬: Django dev prod setup 중 dev.py 사용
- 서버: Django dev prod setup 중 prod.py 사용
각자 알아서 다른 환경을 타게 되죠.
5단계. prod에서만 필요한 추가 보안 설정들

운영용 prod.py에서는 dev와 달리 이런 옵션을 켜줍니다.
CSRF_TRUSTED_ORIGINS = [
"https://secondlife.lol",
"https://www.secondlife.lol",
]
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = "DENY"이건 dev에서는 오히려 귀찮을 수 있으니,
장고 dev prod 설정에서 prod에만 넣고 dev에서는 빼두는 것이 좋습니다.
6단계. .env 인코딩 삽질에서 얻은 교훈
진짜 피땀눈물 포인트였던 게 이거죠.
.env값에 한글을 넣었다가- 케미클라우드 파이썬 3.12 환경에서
UnicodeEncodeError로 전부 터짐 - CLI에서는 잘 돌아가는데, 웹에서만 500이 나는 아주 골치 아픈 상황
결국 해결책은 딱 하나였습니다:
“값은 ASCII로, 설명은 주석(#)에 한글로 적자”
예를 들어
# 서비스 이름: 스터디메이트 (Studymate)
SERVICE_NAME=Studymate이렇게 하면 장고 dev prod 설정 어디서든os.getenv("SERVICE_NAME")로 안전하게 읽을 수 있고,
사람 눈에도 “이게 무슨 값인지” 바로 이해됩니다.
정리: 장고 dev prod 설정, 한 방에 다시 쓰는 템플릿
지금까지 경험을 요약하면,
Django dev prod setup을 잘 나눠 두는 게 배포 삽질을 줄이는 첫 번째 방어선입니다.
템플릿만 기억해 두면 돼요.
- 폴더 구조
config/settings/base.py config/settings/dev.py config/settings/prod.py - base.py 상단
BASE_DIR = Path(__file__).resolve().parent.parent.parent load_dotenv(BASE_DIR / ".env") - dev.py & prod.py에서 장고 dev prod 설정 분리
- dev:
DEBUG=True,ALLOWED_HOSTS=["*"] - prod:
DEBUG=False,ALLOWED_HOSTS는.env에서, 보안 옵션 추가
- dev:
- manage.py / passenger_wsgi.py에서 어떤 settings 쓸지 선택
- manage.py →
config.settings.dev - passenger_wsgi.py →
config.settings.prod
- manage.py →
- .env 값은 ASCII만, 설명은 주석에
이 템플릿 하나만 잘 만들어 둬도,
앞으로 다른 AI 서비스, 다른 장고 프로젝트에서도
Django dev prod setup은 그냥 복붙해서 재사용 가능해집니다.






