[Nginx] SSL Connection refused.

Infinity-blue·2023년 11월 6일
0

Nginx란?

리버스 프록시의 역할과 정적파일을 처리하는 웹 서버.

리버스 프록시란?
외부 클라이언트에서 서버로 접근 시, 내부 서버로 접근할 수 있게 해주는 중개자 역할.

Problem

VM에 백엔드 서버가 돌아가고 있다. 백엔드 서버를 SSL화 하기 위하여 Nginx와 Letsencrypt를 사용하였다. nginx와 Letsencrypt를 VM에 설치하고 실행하였지만 포트 충돌이 발생하였다. 결국 nginx를 VM에 직접 설치하는 게 아닌 Nginx가 도커화 된 이미지를 VM에 직접 실행시키기로 하였다. Nginx 이미지가 Letsencrypt의 SSL 인증서를 인식하여 SSL 설정을 하기까지 제목과 같은 오류가 떴고 삽질과정과 해결방법은 다음과 같다:


Troubleshooting process & Solution

우선, VM의 네트워크 방화벽 설정에는 문제가 없다는 걸 확인 후 'nginx -t'로 syntax오류를 점검하였지만 정상이었다. 'error.log'를 출력하고자 하였지만 아무것도 뜨지 않았다. SSL 점검해주는 온라인 사이트에 주소를 입력한 결과, SSL 인증서를 nginx가 전혀 인식하지 못하는 걸 발견하였다. nginx 설정 코드와 SSL인증서 인식의 문제로 보인다.
SSL Test tool

1. Letsencrypt SSL은 '/etc/letsencrypt/live/your_domain_name/'에 저장되어 있다. ls -la으로 symbolic link를 확인. 결국 파일 하나하나를 복붙하였다.

sudo cp /etc/letsencrypt/archive/your_domain_name/cert1.pem /etc/docker_certs/
sudo cp /etc/letsencrypt/archive/your_domain_name/privkey1.pem /etc/docker_certs/
sudo cp /etc/letsencrypt/archive/your_domain_name/chain1.pem /etc/docker_certs/
sudo cp /etc/letsencrypt/archive/your_domain_name/fullchain1.pem /etc/docker_certs/

2. 'docker-compose.yml'의 'Volumes:"에 위의 경로를 마운트한다. 도커 이미지 실행 시 도커가 컨테이너 내부에 디렉토리를 ':'의 오른쪽 경로와 같이 만들고 ':' 왼쪽의 경로에 존재하는 데이터를 도커가 만든 그 경로에 복붙하겠다는 뜻이다. 오른쪽의 경로는 Dockerfile에 설정해 놓은 경로이다. Docker 이미지가 실행될 때 만들어질 오른쪽의 경로에 '/etc/docker_certs'의 내용을 복사한다.

/etc/docker_certs:/etc/nginx/ssl

3. SSL파일이 위의 경로에 존재하는지 확인한다.

docker exec -it <nginx-container-name> ls -l /etc/docker_certs

4. nginx 설정과 관련된 코드를 의심한 만큼 nginx 컨테이너의 default.conf파일을 확인한다. nginx를 설치할 때 기본으로 설정되어 있는 코드 외에 SSL 코드는 없었다.

docker exec -it <nginx-container-name> cat /etc/nginx/conf.d/default.conf

5. default.conf 외의 ssl코드가 있을만한 .conf파일을 찾던 과정에 'nginx.conf'파일을 발견하였다. 'include...'에 있는 '../conf.d/' 디렉토리에 SSL코드가 들어있는지 확인한다.

include /etc/nginx/conf.d/*.conf;

6. SSL코드가 들어있는 파일이 없다. docker-compose.yml에 nginx 설정관련 코드의 볼륨 마운트가 없었기에 nginx container 내부에 SSL설정 코드가 존재하지 않다는 걸 깨달았다. Server블락이 들어있도록 미리 커스텀 해놓았던 VM 홈 디렉토리에 있는 'nginx.conf'를 'docker-compose.yml'에 추가하였다.

...
services:
  nginx:
    volumes:
     ./nginx.conf:/etc/nginx/nginx.conf

7. 컨테이너를 실행시켜 보니 './nginx.conf'파일에 'server' 블락이 존재해서는 안 된다고 나온다. 이를 해결하기 위하여 'server' 블락을 옮겨놓을 'tryon.conf' 파일을 VM 홈 디렉토리에 새로 만든다.'nginx.conf'파일의 'Server' 블락을 tryon.conf에 복사한다.

tryon.conf

server {
    # Redirect all HTTP traffic to HTTPS
    listen 80;
    server_name <your_domain_name_or_IP>;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name <your_domain_name_or_IP>;

    ssl_certificate /etc/nginx/ssl/fullchain1.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey1.pem;

    # Strong SSL Settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
    ssl_prefer_server_ciphers off;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets off;

    # Add headers to serve security related headers
    add_header Strict-Transport-Security "max-age=63072000" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-XSS-Protection "1; mode=block" always;
    # Forward all requests to Django application running in a Docker container named 'django' on port 8000.
    location / {
		# add_header 'Access-Control-Allow-Origin'.
        proxy_pass http://<"service name in docker-compose.yml">:8000; //One of services in docker-compose.yml
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    # The path inside the Nginx container to the static files.
    location /static/ {
        alias /usr/share/nginx/html/static/;
    }
    # The path inside the Nginx container to the media files. 
    location /media/ {
        alias /usr/share/nginx/html/media/;
    }
}

8. docker-compose.yml에 ssl관련 코드가 들어있는 tryon.conf를 볼륨 마운트한다. 아래 코드의 "마운트"를 쉽게 설명하자면 현재경로에 있는 tryon.conf 란 서브 디렉토리의 내용물을 컨테이너를 생성할 때 컨테이너의 내부경로인 '/etc/nginx/conf.d/tryon.conf'에 복사붙여넣기 하겠다는 말이다.

...
  nginx:
    volumes:
      - ./tryon.conf:/etc/nginx/conf.d/tryon.conf

이로서, Nginx를 설치할 때 기본으로 깔려있는 'nginx.conf'에 'include /etc/nginx/conf.d/*.conf'가 존재하기에 nginx 컨테이너를 실행할 시 '/etc/nginx/conf.d/tryon.conf'가 적용된다.
이로서 SSL인증 문제가 해결되었다..


Conclusion

도커 컨테이너 실행 시 볼륨 마운트는 컨테이너 내부구조 구축과 그에 따른 SSL인증을 위해서도 아주 중요하다.

0개의 댓글