Django

Django서버에 간단한 HTTPS Let's Encrypt 적용하기

친구들안녕 2022. 7. 30. 21:46

서론

웹 서비스에 기본적으로 들어가는 https는 nginx 설정, ssl 발급, 키파일 적용까지
필자에게는 너무 복잡하고 어려운 일이었다.

그러나 아래 레퍼런스의 튜토리얼을 보고 간단하게 ssl 적용하는 내용을 기억할 겸 다시 적어보는 내용이다.

 

그리고 튜토리얼 답게 정말 간단하게 사용이 가능하다.

글로만 설명 해보면

1. docker-compose로 nginx-proxy, acme-companion(let's encrypt) 연결

2. 환경변수를 통한 도메인 ssl 적용

 

그리고 인증서의 만료는 3개월이나

자동으로 인증서를 체킹 하여, 갱신해준다 (필자가 직접 3개월 동안 뒀더니 자동으로 갱신되었다.)

 

주의사항

  • docker container를 사용하여 무료 ssl인 let's encrypt를 적용하는 내용입니다.
  • 레퍼런스 그대로 따라가면서 최신 docker image를 사용한 내용이라 레퍼런스와 조금 다를 수 있습니다

 

 

본론

해야 할 내용

1. docker-compose로 nginx-proxy와 acme-companion(let's encrypt) 연결

nginx-proxy와 acme-companion(let's encrypt)를 볼륨으로 연결

 

2. 도메인 준비

당연하지만 ssl을 적용하려면 도메인이 필요하다.
도메인은 환경변수에 적용하면 됩니다.

 

3. 환경변수

let's encrypt에 적용될 도메인 host와

nginx에 적용될 port 정보가 필요하므로 env 파일을 만들어 적용한다.

 

이하 파일의 환경변수는 필자의 프로젝트에 썼던 파일들입니다.

 

docker-compose.prod.yml

certs, vhost, html, docker.sock을 volume으로 nginx와 let's encrypt 연결

version: '3.8'
services:
  ###########################
  web:
    container_name: web
    build:
      context: ./company_review
      dockerfile: Dockerfile/Dockerfile.prod
    command: gunicorn config.wsgi:application --bind 0.0.0.0:8000
    ports:
      - 8000
    env_file:
      - ./.env/.env.prod
    volumes:
      - static:/usr/src/company_review/static
      - media:/usr/src/company_review/media
  ###########################
  redis:
    image: redis:6.2.6-alpine
    ports:
      - 6379:6379
    volumes:
      - redis_data:/etc/redis_data/data
    depends_on:
      - web
  ###########################
  nginx-proxy:
    container_name: nginx-proxy
    restart: always
    build:
      context: nginx
    ports:
      - 80:80
      - 443:443
    volumes:
      - certs:/etc/nginx/certs
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - static:/usr/src/company_review/static
      - media:/usr/src/company_review/media
    depends_on:
      - web
  ###########################
  nginx-proxy-acme:
    container_name: nginx-proxy-acme
    image: nginxproxy/acme-companion
    volumes:
      - certs:/etc/nginx/certs
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - acme:/etc/acme.sh
    env_file:
      - ./.env/.env.prod.nginx_acme
    depends_on:
      - nginx-proxy
  ###########################
volumes:
  redis_data:
  certs:
  vhost:
  html:
  acme:
  static:
  media:

 

.env.prod

VIRTUAL_HOST와 VIRTUAL_PORT로 nginx에 적용할 호스트를 적고,

LETSENCRYPT_HOST로 let's encrypt에 적용할 도메인을 정의해준다.

다른 env는 django에 사용되는 env이므로 설정하지 않아도 된다.

DEBUG=False
STAGE=PROD
DJANGO_SETTINGS_MODULE=config.settings.prod
VIRTUAL_HOST=mixedprogramming.net
VIRTUAL_PORT=8000
LETSENCRYPT_HOST=mixedprogramming.net

 

.env.prod.nginx_acme

nginx-proxy와 acme-companion(let's encrypt) 연결을 위한 컨테이너 명 지정

email은 ssl 적용 후 만료 알람 등 이메일 보내는 용도

DEFAULT_EMAIL=skarndrkd1@naver.com
NGINX_PROXY_CONTAINER=nginx-proxy

let's encrypt 인증에는 시간당 횟수 제한이 있으므로 테스트 환경에서는 아래의 staging letsencrypt를 추가하여 사용하도록 하자

ACME_CA_URI=https://acme-staging-v02.api.letsencrypt.org/directory

 

이후 적용된 nginx / default.conf

아래 코드를 보면 단순 env 설정만으로 도메인, 포트 연결이 된 걸 알 수 있다.

당연하겠지만 ssl도 적용이 완료되었다.

 

#default.conf

...
# 생략
# mixedprogramming.net
upstream mixedprogramming.net {
	## Can be connected with "job-search-and-company-review_default" network
	# web
	server 172.18.0.3:8000;
}
server {
	server_name mixedprogramming.net;
	listen 80 ;
	access_log /var/log/nginx/access.log vhost;
	# Do not HTTPS redirect Let'sEncrypt ACME challenge
	location ^~ /.well-known/acme-challenge/ {
		auth_basic off;
		auth_request off;
		allow all;
		root /usr/share/nginx/html;
		try_files $uri =404;
		break;
	}
	location / {
		return 301 https://$host$request_uri;
	}
}
server {
	server_name mixedprogramming.net;
	listen 443 ssl http2 ;
	access_log /var/log/nginx/access.log vhost;
	ssl_session_timeout 5m;
	ssl_session_cache shared:SSL:50m;
	ssl_session_tickets off;
	ssl_certificate /etc/nginx/certs/mixedprogramming.net.crt;
	ssl_certificate_key /etc/nginx/certs/mixedprogramming.net.key;
	ssl_dhparam /etc/nginx/certs/mixedprogramming.net.dhparam.pem;
	ssl_stapling on;
	ssl_stapling_verify on;
	ssl_trusted_certificate /etc/nginx/certs/mixedprogramming.net.chain.pem;
	add_header Strict-Transport-Security "max-age=31536000" always;
	include /etc/nginx/vhost.d/default;
	location / {
		proxy_pass http://mixedprogramming.net;
	}
}

 

Reference

Django on Docker Series:

Dockerizing Django with Postgres, Gunicorn, and Nginx

 

Dockerizing Django with Postgres, Gunicorn, and Nginx

This tutorial details how to configure Django to run on Docker along with Postgres, Nginx, and Gunicorn.

testdriven.io

Securing a Containerized Django Application with Let's Encrypt

 

Securing a Containerized Django Application with Let's Encrypt

In this tutorial, we'll look at how to secure a containerized Django app running behind an HTTPS Nginx proxy with Let's Encrypt SSL certificates.

testdriven.io

Deploying Django to AWS with Docker and Let's Encrypt

 

Deploying Django to AWS with Docker and Let's Encrypt

In this tutorial, we'll deploy a Django app to AWS EC2 with Docker and Let's Encrypt.

testdriven.io