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

Django dev prod setup image

로컬에선 잘 되는데 서버만 가면 터지는 이유

로컬에서는 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_HOSTS
  • CSRF_TRUSTED_ORIGINS
  • SECURE_SSL_REDIRECT
  • DB URL

이런 것들은 Django dev prod setup을 통해 확실히 나누고,
실제 값은 .env로 빼두면 서버를 옮겨도 설정만 바꿔 끼우면 됩니다.

Organizing: .env + base/dev/prod로 장고 dev prod 설정 설계하기

1단계. settings를 base / dev / prod로 쪼개기

장고 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를 동시에 지원하는 패턴

Django dev prod setup image

.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에서만 필요한 추가 보안 설정들

server setup image

운영용 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을 잘 나눠 두는 게 배포 삽질을 줄이는 첫 번째 방어선입니다.

템플릿만 기억해 두면 돼요.

  1. 폴더 구조config/settings/base.py config/settings/dev.py config/settings/prod.py
  2. base.py 상단BASE_DIR = Path(__file__).resolve().parent.parent.parent load_dotenv(BASE_DIR / ".env")
  3. dev.py & prod.py에서 장고 dev prod 설정 분리
    • dev: DEBUG=True, ALLOWED_HOSTS=["*"]
    • prod: DEBUG=False, ALLOWED_HOSTS.env에서, 보안 옵션 추가
  4. manage.py / passenger_wsgi.py에서 어떤 settings 쓸지 선택
    • manage.py → config.settings.dev
    • passenger_wsgi.py → config.settings.prod
  5. .env 값은 ASCII만, 설명은 주석에

이 템플릿 하나만 잘 만들어 둬도,
앞으로 다른 AI 서비스, 다른 장고 프로젝트에서도
Django dev prod setup은 그냥 복붙해서 재사용 가능해집니다.

유사한 게시물