ssongk
ssongk
ssongk
전체 방문자
오늘
어제

공지사항

  • resources
  • 분류 전체보기 (626)
    • CTF (24)
    • background (79)
      • fuzzing (5)
      • linux (29)
      • linux kernel (15)
      • windows (2)
      • web assembly (1)
      • embedded (0)
      • web (13)
      • crypto (9)
      • mobile (1)
      • AI (1)
      • etc.. (3)
    • write-up(pwn) (171)
      • dreamhack (102)
      • pwn.college (4)
      • pwnable.xyz (51)
      • pwnable.tw (3)
      • pwnable.kr (5)
      • G04T (6)
    • write-up(rev) (32)
      • dreamhack (24)
      • reversing.kr (8)
    • write-up(web) (195)
      • dreamhack (63)
      • LOS (40)
      • webhacking.kr (69)
      • websec.fr (3)
      • wargame.kr (6)
      • webgoat (1)
      • G04T (7)
      • suninatas (6)
    • write-up(crypto) (19)
      • dreamhack (16)
      • G04T (1)
      • suninatas (2)
    • write-up(forensic) (53)
      • dreamhack (5)
      • ctf-d (47)
      • suninatas (1)
    • write-up(misc) (13)
      • dreamhack (12)
      • suninatas (1)
    • development (31)
      • Linux (14)
      • Java (13)
      • Python (1)
      • C (2)
      • TroubleShooting (1)
    • 자격증 (8)
    • 이산수학 (1)
    • 정보보안 (0)
hELLO · Designed By 정상우.
ssongk

ssongk

development/TroubleShooting

[AWS lightsail] Docker(Nginx + Nodejs) 환경에 SSL 적용

2023. 5. 1. 21:08

[ 배경 ]

학교 팀 프로젝트로 웹 애플리케이션을 만들기 위해 Godaddy를 활용해 AWS와 도메인을 연결했다.
AWS에서 nodejs로 만든 애플리케이션을 도커를 활용해 배포하는 환경까지 만들었다.
google map api 사용을 위해서 https를 지원해줘야 하는데
도메인을 발급 받을 때 ssl 적용이 안되는 상품을 구매했나보다..
 
우리의 지갑은 언제나 넉넉한 것은 아니므로 무료로 해결할 수 있는 방법을 찾게 되었다.
찾아보니 let's encrypt라는 곳에서 발급 받을 수 있다고 한다.
 


[ SSL 인증서 발급 ]

<1번째 레퍼런스 글 참조>
Certbot을 활용해 인증서를 생성할 수 있다.
AWS의 인스턴스에 연결해준 뒤 아래와 같이 certbot을 설치해준다.

sudo snap install certbot --classic

 
이후 standalone 방식으로 인증서를 생성한다.
다른 방법도 있지만 필자는 standalone 방식을 사용했으며 다른 방법은 아래 레퍼런스 링크에 나와있다.

sudo certbot certonly --standalone
dev@vultr:~$ sudo certbot certonly --standalone                                   
[sudo] password for dev:   <root password>
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): vompressor@gmail.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y <- ACME 약관에 동의하는지 N선택시 진행불가

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N <- 이메일을 통해 Let's Encrypt 프로젝트 정보를 받아볼지
Please enter in your domain name(s) (comma and/or space separated)
(Enter 'c' to cancel): vompressor.com www.vompressor.com  <- {1} 인증서를 발급할 도메인 입력
Requesting a certificate for vompressor.com and www.vompressor.com

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/vompressor.com/fullchain.pem <- {2} 발급된 인증서 경로
   Your key file has been saved at:
   /etc/letsencrypt/live/vompressor.com/privkey.pem <- {2} 발급된 인증서 경로
   Your certificate will expire on 2021-05-16. To obtain a new or
   tweaked version of this certificate in the future, simply run
   certbot again. To non-interactively renew *all* of your
   certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:
 
   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

 
다른 방법으로 인증서를 받으려고 삽질한 것을 제외하면 이 과정에서 특별한 문제는 없었다.
 
인증서 경로로 가서 "ls -l"로 확인해보면 해당 파일들이 심볼릭 링크 파일임을 알 수 있다.
이 심볼릭 링크 파일은 도커 내부로 공유할 수 없기 때문에 원본 파일을 복사해야할 필요가 있다.
 
fullchain1.pem과 privkey1.pem 파일을 /var/www/custom_name 밑으로 옮겨준다.
(pem 파일의 이름은 약간 다를 수 있음)
 


[ dockerfile docker-compose.yml ]

먼저 nodejs에 대한 도커파일이다.

FROM node:16

# 앱 의존성 설치
# 가능한 경우(npm@5+) package.json과 package-lock.json을 모두 복사하기 위해
# 와일드카드를 사용
COPY package.json .

RUN npm install
# 프로덕션을 위한 코드를 빌드하는 경우
# RUN npm ci --only=production

# 앱 소스 추가
COPY . .

EXPOSE 3000

CMD [ "node", "app.js" ]

특별한 내용은 없고 포트 번호를 3000번으로 지정했다.
 
다음으로 docker-compose.yml 파일이다.

version: '3'
services:
  nodejs:
    container_name: "nodejs"
    build:
      context: "."
      dockerfile: "dockerfile"
    image: nodejs
    restart: unless-stopped

  nginx:
    image: "nginx:latest"
    container_name: "webserver"
    restart: unless-stopped
    ports:
    - 80:80
    - 443:443
    depends_on:
    - nodejs
    volumes:
    - ./data/nginx/conf.d:/etc/nginx/conf.d
    - ./data/certbot/conf:/etc/letsencrypt
    - ./data/certbot/www:/var/www/certbot

nginx에 대해선 아래에서 따로 컨테이너를 생성하니 없어도 될 것 같기도 하다.
(확실하진 않음)
 


[ nginx: container 생성 및 conf 파일 설정 ]

 <2, 4번째 레퍼런스 글 참조>
다음과 같은 명령어로 빌드 및 실행이 가능하다.

docker-compose up -d --build

 
다음과 같은 명령어로 현재 실행되고 있는 컨테이너를 확인할 수 있다.

docker ps

 
아무튼 이 nginx라는 친구를 활용해서 https 서비스를 활성화 시켜줘야 한다.
다음과 같은 명령어로 컨테이너를 만들어준다.

docker run --name webserver -it -d -p 80:80 -p 443:443 -p 3000:3000 -v /var/www/custom_name:/var/www/custom_name nginx:mainline-alpine

webserver라는 이름으로 80, 443, 3000번 포트를 개방했다.
 
다음으로 exec 명령을 사용해 해당 컨테이너의 쉘로 접근한다.

docker exec -it [container name] sh

/var/www/custom_name 폴더에 가보면 아까 복사한 pem 파일들이 있을 것이다.
 
이제 nginx의 설정 파일을 바꿔주면 끝이다.
/etc/nginx/conf.d/default.conf 파일을 다음과 같이 바꿔줬다.

server {
        listen 80;
        listen [::]:80;
        server_name Domain_name www.Domain_name;

        location ~ /.well-known/acme-challenge {
          allow all;
          root /var/www/tripmate;
        }

        location / {
                rewrite ^ https://$host$request_uri? permanent;
        }
}

server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name Domain_name www.Domain_name;

        server_tokens off;

        ssl_certificate /var/www/tripmate/fullchain1.pem;
        ssl_certificate_key /var/www/tripmate/privkey1.pem;


        location / {
                proxy_pass http://nodejs:3000;
                add_header X-Frame-Options "SAMEORIGIN" always;
                add_header X-XSS-Protection "1; mode=block" always;
                add_header X-Content-Type-Options "nosniff" always;
                add_header Referrer-Policy "no-referrer-when-downgrade" always;
                add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
                #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
                # enable strict transport security only if you understand the implications
        }
}

servername 옆에 있는 Domain_name을 본인의 도메인으로 바꿔주면 된다.
맨 아래 location의 proxy_pass의 nodejs는 본인의 노드 컨테이너 명으로 바꿔주면 된다.
 
수정을 끝낸 뒤 아래와 같이 테스트 및 적용할 수 있다.

nginx -T // conf 파일 테스트
nginx -s reload // conf 파일 적용

(만약 오류가 생긴다면 아래 네트워크 설정을 한 뒤 다시 시도하면 될 수도 있다..)

네트워크는 상관 없는 것 같습니다.

(참고만 해주세요)

 

 
conf 파일을 적용한 뒤 도메인으로 접속하니 그토록 찾아 헤맸던 자물쇠를 발견할 수 있었다..!
 


[ docker network ]

<3번째 레퍼런스 글 참조>
이 2개의 도커 컨테이너에 네트워크 연결을 해줘야 한다.
(같은 호스트의 도커끼리도 통신이 안되나 보다)
 
다음과 같은 명령어로 현재 생성되어 있는 도커의 네트워크 목록을 확인할 수 있다.

docker network ls

 
bridge, host, none은 Docker 데몬이 실행되면서 디폴트로 생성되는 네트워크하고 한다.
이런 디폴트 네트워크를 이용하는 것 보다는 사용자가 직접 네트워크를 생성해서 사용하는 것이 권장된다고 하니!
적혀있는 방법을 따라서 직접 만들어주자.
 
bridge 네트워크는 하나의 호스트 컴퓨터 내에서 여러 컨테이너들이 서로 소통할 수 있도록 해준다고 한다.
현재 하나의 aws 인스턴스에 2개의 도커 컨테이너가 있는 상황이므로 bridge를 사용할 것이다.
 
다음과 같은 명령어로 네트워크를 하나 만들어준다.

docker network create our-net

docker network ls로 확인해보면 bridge 네트워크가 생긴 것을 확인할 수 있다.
 
다음과 같은 명령어로 생성한 네트워크 our-net에 대한 상세 정보를 확인할 수 있다. 

docker network inspect our-net

현재는 도커 컨테이너가 연결되지 않은 상태일 것이다.
 
다음과 같은 명령어로 컨테이너를 네트워크에 연결할 수 있다.

docker network connect our-net container_name

이 container_name은 docker ps의 결과의 name에서 확인할 수 있다.
nodejs 컨테이너와 nginx 컨테이너의 이름을 사용해서 연결해준 뒤
docker network inspect our-net으로 확인해주면
컨테이너들이 연결된 것을 확인할 수 있을 것이다.
 
도커에서 지원하는 ping 명령어로 테스트해볼 수 있다.

docker exec container_name ping container_name

ping이 정상적으로 이루어 진다면 실제 도커 환경에서도 통신이 정상적으로 이루어질 것이다.


[ dockerfile, docker-compose.yml 수정 ]

도커 파일을 통해서 nodejs와 nginx를 빌드 및 실행 할 수도 있다.
처음에는 잘 안 됐었는데 좀 더 시도해보니 성공했다.

 

먼저 nodejs 프로젝트 디렉터리에 nodejs에 대한 dockerfile과 설정을 위한 docker-compose.yml 파일을 만든다.

다음은 아까도 봤던 nodejs에 대한 dockerfile이다. 

FROM node:16

# 앱 의존성 설치
# 가능한 경우(npm@5+) package.json과 package-lock.json을 모두 복사하기 위해
# 와일드카드를 사용
COPY package.json .

RUN npm install
# 프로덕션을 위한 코드를 빌드하는 경우
# RUN npm ci --only=production

# 앱 소스 추가
COPY . .

EXPOSE 3000

CMD [ "node", "app.js" ]

 

다음은 수정된 docker-compose.yml 파일이다.

version: '3'
services:
  nodejs:
    container_name: "nodejs"
    build:
      context: "."
      dockerfile: "dockerfile"
    image: nodejs
    restart: unless-stopped

  nginx:
    container_name: "webserver"
    image: "nginx:mainline-alpine"
    restart: unless-stopped
    ports:
    - "80:80"
    - "443:443"
    - "3000:3000"
    depends_on:
    - nodejs
    volumes:
    - ./nginx:/etc/nginx/conf.d
    - /var/www/tripmate:/var/www/tripmate

 

nginx 서비스에 대해 ports 옵션으로 80,443,3000번 포트를 열고

volumes 옵션으로 nginx의 기본 설정 파일을 변경시켜주고 인증서 키가 존재하는 디렉토리를 복사한다.

필자는 nginx 디렉터리를 만든 뒤 nginx.conf라는 파일을 만들었다.

(nginx의 기본 설정 파일은 /etc/nginx/conf.d 디렉터리에 존재함)

본인의 nginx 설정 파일과 인증서 키 파일의 위치에 따라 디렉터리를 바꿔주면 된다.

 

nginx 설정 파일은 위에서 설정했듯이 해주면 된다.

server {
        listen 80;
        listen [::]:80;
        server_name Domain_name www.Domain_name;

        location ~ /.well-known/acme-challenge {
          allow all;
          root /var/www/tripmate;
        }

        location / {
                rewrite ^ https://$host$request_uri? permanent;
        }
}

server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name Domain_name www.Domain_name;

        server_tokens off;

        ssl_certificate /var/www/tripmate/fullchain1.pem;
        ssl_certificate_key /var/www/tripmate/privkey1.pem;


        location / {
                proxy_pass http://nodejs:3000;
                add_header X-Frame-Options "SAMEORIGIN" always;
                add_header X-XSS-Protection "1; mode=block" always;
                add_header X-Content-Type-Options "nosniff" always;
                add_header Referrer-Policy "no-referrer-when-downgrade" always;
                add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
                #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
                # enable strict transport security only if you understand the implications
        }
}

 

이제 다음과 같은 명령어로 빌드 및 실행을 진행한다.

docker-compose up -d --build
# 권한 부족으로 실패 시 sudo 사용

 

docker ps 명령으로 확인해보면 컨테이너들이 잘 실행되고 있으며 접속 또한 잘 된다!

$ docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED        STATUS        PORTS                                                                                                                 NAMES
f8d7aa79659d   nginx:mainline-alpine   "/docker-entrypoint.…"   45 hours ago   Up 45 hours   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp, 0.0.0.0:3000->3000/tcp, :::3000->3000/tcp   webserver
84b1cfd50f2c   nodejs                  "docker-entrypoint.s…"   45 hours ago   Up 9 hours    3000/tcp                                                                                                              nodejs

 


레퍼런스
https://www.vompressor.com/tls1/

 

Certbot으로 무료 HTTPS 인증서 발급받기

Let’s Encrypt - Free SSL/TLS CertificatesLet’s Encrypt is a free, automated, and open certificate authority brought to you by the nonprofit Internet Security Research Group (ISRG).Free SSL/TLS Certificates Let's Encrypt라는 비영리 기관을 통해

www.vompressor.com

https://anomie7.tistory.com/59

 

[ssl] aws에 docker와 letsencrypt(certbot) 이용해서 ssl 인증 적용하기

1. ssl를 적용할 수 밖에 없던 과정 수개월째 백수로 지내면서 개인프로젝트를 하고 있다. 개인프로젝트에 ssl을 도입할 수 밖에 없는 이유가 두가지 있었다. 첫째, JWT 기반의 로그인을 하고 있다.

anomie7.tistory.com

https://www.daleseo.com/docker-networks/

 

Docker 네트워크 사용법

Engineering Blog by Dale Seo

www.daleseo.com

https://robot-log.tistory.com/4

 

Docker Compose로 Nginx + NodeJS + SSL 환경 만들기

만약 NodeJS를 사용하여 만든 웹 서버를 어딘가에 deploy 하고 싶다면 pm2를 사용하거나 nginx로 port를 연 후 proxy를 통하여 실행 중인 NodeJS 웹 서버와 연결하여 사용하게 됩니다. 그 중 Nginx로 환경 제

robot-log.tistory.com

 

    ssongk
    ssongk
    벌레 사냥꾼이 되고 싶어요

    티스토리툴바