프로젝트
✅ 실무형 배포 시 인증서 발급~CSRF & 동기화 무한지옥까지 완벽 정리
Chansman
2025. 6. 15. 08:06
✅ 실무형 배포 시 인증서 발급~CSRF & 동기화 무한지옥까지 완벽 정리
🔖 1️⃣ SSL 인증서 발급 (Let's Encrypt + DuckDNS) 실전 프로세스
- DuckDNS로 서브도메인 생성
- 예시: teamnotfound.duckdns.org
- 토큰(인증값) 발급
- 서버에 certbot, certbot-dns-duckdns 설치
- (pip로 설치하려면 --break-system-packages 등 추가 필요)
- sudo pip3 install certbot-dns-duckdns --break-system-packages
- DuckDNS 토큰 설정파일(duckdns.ini) 준비
dns_duckdns_token = bf05a989-ac28-4ecd-87dd-6daa2e8974fd
- 권한변경: chmod 600 ~/duckdns/duckdns.ini
- certbot 명령어로 인증서 발급
sudo certbot certonly \
--dns-duckdns-credentials ~/duckdns/duckdns.ini \
-d teamnotfound.duckdns.org
- 인증서: /etc/letsencrypt/live/teamnotfound.duckdns.org/fullchain.pem
- 개인키: /etc/letsencrypt/live/teamnotfound.duckdns.org/privkey.pem
- (자동 갱신은 certbot이 cron에 등록)
🛠 2️⃣ Nginx & Docker로 HTTPS 리버스 프록시 구성
- docker-compose.yaml에 nginx, my-django, my-redis 등 모두 포함
nginx.conf 예시:
server {
listen 443 ssl;
server_name teamnotfound.duckdns.org;
ssl_certificate /etc/letsencrypt/live/teamnotfound.duckdns.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/teamnotfound.duckdns.org/privkey.pem;
location /static/ { alias /app/staticfiles/; }
location / { proxy_pass http://my-django:8000; ... }
}
server {
listen 80;
server_name teamnotfound.duckdns.org;
return 301 https://$host$request_uri;
}
- 볼륨 마운트, staticfiles/ 경로, 도메인 모두 꼼꼼하게 맞출 것!
🛠 3️⃣ CSRF 오류 발생, 코드/설정으로 해결
💥 증상
- Django admin 로그인 시도 시
- "CSRF cookie not set", "403 Forbidden", "로그인은 되는데 새로고침하면 풀림" 등
🛠 실전 해결 과정
a. CSRF/쿠키 관련 설정파일(base.py, prod.py 등) 점검
ALLOWED_HOSTS = ["teamnotfound.duckdns.org", "localhost", "127.0.0.1"]
CSRF_TRUSTED_ORIGINS = [
"https://teamnotfound.duckdns.org"
]
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# SESSION_COOKIE_DOMAIN = ".teamnotfound.duckdns.org" # 웬만하면 빼는 게 안전 (특히 단일 도메인 운영이면!)
# CSRF_COOKIE_DOMAIN = ".teamnotfound.duckdns.org"
→ DOMAIN 지정은 세부적으로 맞출 자신 없으면 오히려 안 두는 게 안전!
b. production 환경에서 DEBUG=False / SECURE, CORS 등 올바르게 세팅
- settings.prod.py/ settings.base.py 구분!
c. Docker, Nginx 모두 최신 설정/빌드 반영
(nginx.conf, docker-compose.yml, staticfiles volume, ENV 등)
🚨 4️⃣ 최종 함정: GitHub Actions & PR 머지/CI/CD 연동 문제
💥 실제 겪은 문제 순서
- isort/black 같은 코드 포맷 에러로 Actions 실패
- CI 실패 → PR 머지 차단됨
- (깜빡하고) 서버에서 git pull 하면
머지 안 된 상태라 최신 코드(예: prod.py에서 CSRF 수정 등)가 안 내려옴 - docker-compose down/up, 재빌드해도
옛날 코드로 계속 컨테이너가 돌아감 - (개발자는 코드를 다 고쳤는데 계속 CSRF, 쿠키 오류)
- 5시간 동안 환경/설정/도메인/CORS/쿠키/로그인 등 "딴 데서만 문제 찾음"
🟢 진짜 원인 & 해결
- Actions 에러 고쳐서 PR 머지 반드시 성공시키기
- 서버에서 git pull로 최신 코드 동기화
- docker-compose down && docker-compose up -d --build
(컨테이너 다시 올려서 최신 코드 반영) - 모든 설정이 최신 상태로 정상 동작
⚠️ 실무 팁/주의 사항 총정리
- SSL 인증서/도메인, 리버스 프록시, 정적파일, 도커 볼륨까지 경로 꼼꼼히 확인
- CSRF/쿠키 문제는 "설정, 환경, 도메인"까지 다 맞아야 함
- 코드 머지 안 되면 서버에는 절대 적용 안 됨!
- CI/CD 포맷 에러(black, isort)는 무조건 통과시킬 것
- 문제 생기면, git pull부터 "최신 코드"인지 반드시 확인
✅ 실무 체크리스트 (최소 3번은 다시 읽자)
- 인증서, Nginx, staticfiles 볼륨까지 Docker에 잘 마운트했는가?
- 도메인(duckdns), CSRF_TRUSTED_ORIGINS, ALLOWED_HOSTS, SECURE 쿠키 모두 정확한가?
- settings 파일이 환경별로 분리되어있고, prod.py 등 최종 세팅이 제대로 반영됐는가?
- GitHub Actions(black/isort 등) 통과 & PR 머지 됐는가?
- 서버에서 git pull → docker compose up -d --build로 항상 최신 코드로 배포했는가?
💬 이제 이런 함정은 평생 안 당할 수 있다!
- 실제 현업 DevOps도 실수할 수 있는 부분
- 동기화, 환경, 배포 자동화의 핵심 실무 교훈!