Nginx 활용하여 플러터 웹 배포하기

김동욱·2024년 4월 15일

NGINX

목록 보기
2/2
post-thumbnail

현재 ec2 인스턴스에 Docker Compose로 실행한 Django, Nginx 컨테이너가 API 서버로 동작 중이다. 동일한 서버에 플러터 웹을 배포하고 SSL 인증서 적용도 진행해보았다.

아래의 파일 생성 및 명령어 입력은 모두 플러터 루트 디렉토리 위치에서 진행한다.

nginx 설정 파일 생성

[플러터 프로젝트/nginx.conf]

server {
    listen 80;
    server_name www.roccia-901.com;
    
	# SSL 인증서를 발급 받기 위한 블록
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        root /app/build;
        index index.html;
        try_files $uri $uri/ /index.html;
    }
}

location /.well-known/acme-challenge/ 블록은 ssl 인증서를 발급 받기 위한 블록이다. 만약 http로만 통신하려면 생략해도 된다.

Dockerfile 작성하기

[플러터 프로젝트/Dockerfile]

FROM nginx

RUN mkdir /app
WORKDIR /app

RUN mkdir ./build
ADD ./build/web ./build

RUN rm /etc/nginx/conf.d/default.conf
COPY ./nginx.conf /etc/nginx/conf.d

RUN mkdir /var/www
RUN mkdir /var/www/certbot

EXPOSE 80 443

CMD ["nginx", "-g", "daemon off;"]

위 도커 파일은 /app/build 위치에 빌드한 플러터 파일을 추가한다. 그리고 기존의 Nginx 설정 파일을 지우고 위에서 작성한 설정 파일을 복사한다. 인증서를 발급받기 위해 /var/www/certbot 디렉토리를 생성한다.

Docker hub에 이미지 올리기

# 누락된 부분이 없게 최신 내용을 모두 가져옴
git pull
# 환경변수 파일 옮기기

# Flutter 프로젝트에서 자동 코드 생성 및 기타 빌드 관련 작업을 실행
dart run build_runner build

# 웹 지원 활성화
flutter config --enable-web

# /build/web 경로에 빌드된 내용 위치
flutter build web

# docker 이미지 빌드. macOS 일 경우 --platform linux/amd64 옵션 필수로 설정
sudo docker buildx build --platform linux/amd64 -t {도커 계정명}/{프로젝트 이미지명}:{태그} .

# docker 이미지를 docker hub에 올리기(사전에 도커 계정에 연결되어 있어야 함)
# docker login
sudo docker push {도커 계정명}/{프로젝트 이미지명}:{태그}

위 명령을 순차적으로 입력하면 Docker hub의 repositories에서 확인할 수 있다.

Docker 컨테이너 실행하기

# Docker hub에서 이미지 가져오기
sudo docker pull {도커 계정명}/{프로젝트 이미지명}

# Docker 컨테이너를 실행하고 외부의 80, 443 포트를 컨테에너 내부와 연결
sudo docker run -p 80:80 -p 443:443 \
  -v /var/www/certbot:/var/www/certbot \
  -v /etc/letsencrypt:/etc/letsencrypt \
  -v /var/lib/letsencrypt:/var/lib/letsencrypt \
  --name {컨테이너 이름}:{태그} \
  -dt {도커 계정명}/{프로젝트 이미지명}:{태그}

SSL 인증서 발급 후 적용하기

sudo docker run -it --rm \
  -v /etc/letsencrypt:/etc/letsencrypt \
  -v /var/lib/letsencrypt:/var/lib/letsencrypt \
  -v /var/www/certbot:/var/www/certbot \
  certbot/certbot certonly --dry-run --webroot \
  --webroot-path=/var/www/certbot \
  --email {본인 이메일} \
  --agree-tos \
  --no-eff-email \
  --keep-until-expiring \
  -d {도메인1} -d {도메인2}

--dry-run 옵션을 통해 제대로 동작하는지 테스트 후 해당 옵션을 제거하고 실행시킨다. 정상적으로 인증서를 발급 받으면 아래와 같음 문구가 나온다.

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Account registered.
Requesting a certificate for www.roccia-901.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/www.roccia-901.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/www.roccia-901.com/privkey.pem
This certificate expires on 2024-04-13.
These files will be updated when the certificate renews.

NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

위 문구를 살펴보면 알겠지만 인증서는 만료 날짜가 존재한다. 발급으로부터 3달간 유효하다. 따라서 1달마다 인증서를 갱신할 수 있는 크론탭을 생성하자.

crontab -e # 크론탭 편집
crontab -l # 작성된 크론탭 조회


[crontab]
0 0 13 * * /home/ubuntu/renew-certbot.sh # 매달 13일마다 실행


[/home/ubuntu/renew-certbot.sh]
# 인증서를 갱신하고 Nginx reload 하는 스크립트
# 로그가 작성될 파일 및 디렉토리가 존재해야 하고 권한을 설정해야 함

# 로그 디렉토리가 존재하는지 확인
mkdir -p /var/log/certbot

# certbot 갱신을 실행하고 출력을 로그에 기록
sudo docker run --rm \
  -v /etc/letsencrypt:/etc/letsencrypt \
  -v /var/lib/letsencrypt:/var/lib/letsencrypt \
  -v /var/www/certbot:/var/www/certbot \
  certbot/certbot renew --webroot -w /var/www/certbot --quiet --no-self-upgrade >> /var/log/certbot/certbot-renew.log 2>&1

if [ $? -eq 0 ]; then
  echo "$(date) - Certbot renew succeeded" >> /var/log/certbot/certbot-renew.log
  # Nginx 설정을 리로드하고 출력을 로그에 기록
  sudo docker exec flutter-nginx nginx -s reload >> /var/log/certbot/nginx-reload.log 2>&1
  if [ $? -eq 0 ]; then
    echo "$(date) - Nginx reload succeeded" >> /var/log/certbot/nginx-reload.log
  else
    echo "$(date) - Nginx reload failed" >> /var/log/certbot/nginx-reload.log
  fi
else
  echo "$(date) - Certbot renew failed" >> /var/log/certbot/certbot-renew.log
fi

nginx에 인증서 적용하기

위에서 작성한 nginx.conf 파일을 아래와 같이 수정한다.

[플러터 프로젝트/nginx.conf]

server {
    listen 80;
    server_name www.roccia-901.com;

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

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

server {
    listen 443 ssl;
    server_name www.roccia-901.com;

    ssl_certificate /etc/letsencrypt/live/www.roccia-901.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.roccia-901.com/privkey.pem;

    location / {
        root /app/build;
        index index.html;
        try_files $uri $uri/ /index.html;
    }
}

수정된 내용을 살펴보면 http 요청을 https 요청으로 리다이렉션한다. 그리고 발급받은 SSL 인증서를 사용하여 요청을 암호화한다. 이를 통해 클라이언트와 서버 간의 데이터 전송이 암호화되어 안전하게 이루어진다.

여기까지 진행했으면 도커 파일을 새롭게 빌드하여 Docker hub에 올린 후 이미지를 활용하여 컨테이너를 생성하면 된다.





참고 자료

https://blog.yjyoon.dev/flutter/2021/12/31/flutter-09/

profile
안녕하세요! 질문과 피드백은 언제든지 환영입니다:)

0개의 댓글