프로젝트

✅ 실무형 배포 시 인증서 발급~CSRF & 동기화 무한지옥까지 완벽 정리

Chansman 2025. 6. 15. 08:06

✅ 실무형 배포 시 인증서 발급~CSRF & 동기화 무한지옥까지 완벽 정리


🔖 1️⃣ SSL 인증서 발급 (Let's Encrypt + DuckDNS) 실전 프로세스

  1. DuckDNS로 서브도메인 생성
    • 예시: teamnotfound.duckdns.org
    • 토큰(인증값) 발급
  2. 서버에 certbot, certbot-dns-duckdns 설치
    • (pip로 설치하려면 --break-system-packages 등 추가 필요)
    • sudo pip3 install certbot-dns-duckdns --break-system-packages
  3. DuckDNS 토큰 설정파일(duckdns.ini) 준비
dns_duckdns_token = bf05a989-ac28-4ecd-87dd-6daa2e8974fd
  1. 권한변경: chmod 600 ~/duckdns/duckdns.ini
  2. 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 연동 문제

💥 실제 겪은 문제 순서

  1. isort/black 같은 코드 포맷 에러로 Actions 실패
  2. CI 실패 → PR 머지 차단됨
  3. (깜빡하고) 서버에서 git pull 하면
    머지 안 된 상태라 최신 코드(예: prod.py에서 CSRF 수정 등)가 안 내려옴
  4. docker-compose down/up, 재빌드해도
    옛날 코드로 계속 컨테이너가 돌아감
  5. (개발자는 코드를 다 고쳤는데 계속 CSRF, 쿠키 오류)
  6. 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도 실수할 수 있는 부분
  • 동기화, 환경, 배포 자동화의 핵심 실무 교훈!