Redis 설치

최근 모니터링을 위해 스프링 액추에이터를 건드려보다가 EC2에 Redis가 설치되지 않아서 문제가 생겼었다.

이전에 메일 인증을 구현했던 EC2 인스턴스와 다른 인스턴스에서 테스트를 해서 Redis를 설치하지 않았다.

설치는 어렵지 않지만 다시 설치하려 하니 기존에 어떻게 설치했는지 기억이 안나서 글로 정리해두려고 한다.


EC2 Ubuntu 환경에서 Redis 설치 과정

본인의 EC2 OS는 Ubuntu이므로 우분투를 기준으로 정리한다.

1. 시스템 업데이트

apt를 업데이트 해준다.

sudo apt update

2. Redis 설치

sudo apt install redis-server

3. Redis 설치 확인

아래처럼 redis-cli 로 들어가서 ping 명령어로 레디스가 잘 설치 됐는지 확인한다.


Redis 종료하기

가끔 어떤 이유로든 Redis 서버를 종료해야할 수도 있을 것이다.

이때를 위해 종료 및 재시작 방법도 적어둔다.

1. Redis 서버 종료

sudo systemctl stop redis-server

2. Redis 서버 시작

sudo systemctl start redis-server

 

CodeDeploy 설치 및 GitHub Actions 워크플로우 작성

이제 EC2 인스턴스에 CodeDeploy를 설치하고 GitHub Actions 워크플로우를 작성할것이다.

GitHub Actions 워크플로우를 요약하면 아래와 같다.

  1. GitHub Actions로 jar 파일을 빌드하고 jar파일, appspec.yml, 배포 스크립트들을 zip로 압축한다.
  2. GitHub의 Secret에 저장한 AWS IAM 사용자 정보를 이용하여 S3, CodeDeploy 접근 권한을 얻는다.
  3. 1에서 압축한 zip 파일을 S3에 저장하고, CodeDeploy 배포 프로세스를 실행한다.
  4. EC2의 CodeDeploy Agent는 S3에 저장된 zip 파일을 압축 해제하여 appspec.yml을 참고하여 배포 프로세스를 진행한다.

AWS IAM 사용자 설정은 이쪽 글을 참고하도록 하자.

Secret은 아래와 같은 변수명으로 설정해주었다.

Secret에 변수를 저장하는 방법은 이 글을 참고하자.

 


1. EC2에 CodeDeploy 설치

아래 명령어로 EC2 인스턴스에 CodeDeploy를 설치해준다.

sudo apt update
sudo apt install ruby-full
sudo apt install wget
cd /home/ubuntu
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto > /tmp/logfile
sudo service codedeploy-agent status

 

위 명령어를 순서대로 입력하고, 가장 아래 명령어를 입력했을 때 아래처럼 뜨면 CodeDeploy가 제대로 설치된 것이다.


2. GitHub Actions 워크플로우 작성

아래 워크 플로우는 테스트하기 편하게 main 브랜치에 PR을 올릴 때 동작하게끔 했다.

실제로는 PR이 제대로 머지된 후에 동작하게끔 바꾸도록 하자.

name: CI/CD with S3 and CodeDeploy

on:
  pull_request:
    branches: [ "main" ]

env:
  AWS_REGION: ap-northeast-2
  S3_BUCKET_NAME: midcondria-cicd
  CODE_DEPLOY_APPLICATION_NAME: midcon-codedeploy-app
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: midcon-codedeploy-deploy-group

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'  

    ## application.yml 파일 생성
    - name: make application.yml
      run: |
        echo ">> mkdir & touch"
        mkdir -p ./src/main/resources
        cd ./src/main/resources
        touch ./application.yml
        echo ">> copy application.yml"
        echo "${{ secrets.PROPERTIES }}" >> ./application.yml
        
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
      shell: bash

    - name: Build with Gradle Wrapper
      run: ./gradlew build -x test  // 여기서는 편의성을 위해 테스트를 안하기로 했음
      shell: bash

    - name: Make zip file
      run: zip -r ./myapplication.zip appspec.yml scripts/* ./build/libs/team-0.0.1-SNAPSHOT.jar
      shell: bash

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}
        aws-region: ${{ env.AWS_REGION }}

    - name: Upload to AWS S3
      run: |
        aws s3 cp \
          --region $AWS_REGION ./myapplication.zip s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip

    - name: Deploy to AWS EC2 from S3
      run: |
        aws deploy create-deployment \
          --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
          --deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
          --deployment-config-name CodeDeployDefault.AllAtOnce \
          --s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip \
          --region $AWS_REGION

3. 결과 확인

3-1. PR 시 GitHub Actions 동작 확인

3-2. CodeDeploy 동작 확인

아래처럼 배포 세부 정보를 확인할 수 있다.

 

배포 이벤트 별로 확인할 수 있으니 실패 시 어디서 실패했는지 참고할 수 있다.

 

아래 명령어로 CodeDeploy Agent의 로그를 확인할 수 있다.

본인은 대부분 appspec.yml을 대문자로 써서 못찾는 이슈 때문에 보긴 했지만 여러 로그가 남으니 참고하자.

vim /var/log/aws/codedeploy-agent/codedeploy-agent.log

 

3-3. EC2 인스턴스 확인

EC2 인스턴스의 /home/ubuntu/app 경로를 확인하면 아래와 같다.

S3 버킷에 저장된 zip 파일에 담긴 appspec.yml, jar파일, 배포 스크립트 파일들이 이 경로에 있고, 이들을 사용함을 알 수 있다.

 

아래처럼 접속도 잘 된다.

배포 스크립트 작성 및 Nginx 설정

이번 글에서는 무중단 배포를 3가지 스탭으로 나눠서 배포용 쉘 스크립트를 작성하고,

CodeDeploy에서 배포를 위해 참고할 AppSpec 파일을 작성할 것이다.

배포 스크립트는 아래와 같이 세가지 스탭으로 나눈다.

  1. 서비스 중인 WAS와 다른 포트에 새로운 버전의 WAS를 띄운다.
  2. 1번의 과정이 정상 동작 했는지 해당 포트로 HTTP 요청을 보내 확인한다.
  3. 1, 2가 정상 동작한다면 Nginx가 새로운 버전의 WAS를 바라보도록 변경하고 기존의 WAS를 종료한다.

1. 배포 스크립트 작성

이제 배포 시 실행할 쉘 스크립트를 작성할 것이다.

기존에 리버스 프록시로 이용하고 있던 Nginx를 여기서도 써먹어서 무중단 배포를 구현한다.

배포 스크립트의 각 스탭에 주석을 달아두었으니 리눅스 커맨드를 어느정도 알고 있다면 쉽게 이해할 수 있을 것이다.

1-1. run_new_was

업데이트 된 버전의 새로운 WAS를 띄운다.

# run_new_was.sh

#!/bin/bash

# 환경 변수 설정
PROJECT_ROOT="/home/ubuntu/app" # 프로젝트 루트
JAR_FILE="$PROJECT_ROOT/build/libs/team-0.0.1-SNAPSHOT.jar" # 빌드해서 생성된 jar 파일명

# service_url.inc 에서 현재 서비스 중인 WAS의 포트 번호 확인
CURRENT_PORT=$(cat /home/ubuntu/service_url.inc | grep -Po '[0-9]+' | tail -1)
TARGET_PORT=0

echo "> Current port of running WAS is ${CURRENT_PORT}."

# 서비스 중인 포트가 8081이면 8082 포트로 배포
# 서비스 중인 포트가 8082이면 8081 포트로 배포
if [ ${CURRENT_PORT} -eq 8081 ]; then
  TARGET_PORT=8082
elif [ ${CURRENT_PORT} -eq 8082 ]; then
  TARGET_PORT=8081
else
  echo "> Any WAS is connected to nginx" # 애플리케이션이 실행되고 있지 않음
fi

# 타겟 포트 번호로 실행 중인 프로세스가 있는지 확인
TARGET_PID=$(lsof -Fp -i TCP:${TARGET_PORT} | grep -Po 'p[0-9]+' | grep -Po '[0-9]+')

# PID를 이용해 타겟 포트로 실행 중인 프로세스 Kill
if [ ! -z ${TARGET_PID} ]; then
  echo "> Kill ${TARGET_PORT}."
  sudo kill ${TARGET_PID}
fi

# 타켓 포트로 업데이트 된 버전의 새로운 서버 실행
nohup java -jar -Dserver.port=${TARGET_PORT} ${JAR_FILE} > /home/ubuntu/nohup.out 2>&1 &
echo "> Now new WAS runs at ${TARGET_PORT}."
exit 0

1-2. health_check

새로 띄운 WAS가 정상 동작하는지 헬스 체크한다.

# health_check.sh

#!/bin/bash

# 환경 변수 설정
# service_url.inc에서 현재 서비스 중인 WAS의 포트 번호 확인
# 해당 포트 번호로 health_check 실행
CURRENT_PORT=$(cat /home/ubuntu/service_url.inc | grep -Po '[0-9]+' | tail -1)
TARGET_PORT=0

if [ ${CURRENT_PORT} -eq 8081 ]; then
    TARGET_PORT=8082
elif [ ${CURRENT_PORT} -eq 8082 ]; then
    TARGET_PORT=8081
else
    echo "> Any WAS is connected to nginx"  # 헬스체크 시 Nginx에 어떤 WAS도 연결돼있지 않으면 에러 코드
    exit 1
fi

echo "> Start health check of WAS at 'http://127.0.0.1:${TARGET_PORT}' ..."

# "/" 경로로 헬스 체크하여 응답 코드를 보고 서버가 정상적으로 작동하는지 확인
# 최대 10번까지 테스트 해서 그 안에 성공하면 통과(WAS가 늦게 뜨는 경우를 대비한 안전 장치)
for RETRY_COUNT in 1 2 3 4 5 6 7 8 9 10
do
    echo "> #${RETRY_COUNT} trying..."
    # 테스트할 API 주소를 통해 http 상태 코드 확인
    RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:${TARGET_PORT})

	  # RESPONSE_CODE의 http 상태가 200번인 경우 성공
    if [ ${RESPONSE_CODE} -eq 200 ]; then
        echo "> New WAS successfully running"
        exit 0
    elif [ ${RETRY_COUNT} -eq 10 ]; then
        echo "> Health check failed."
        exit 1
    fi
    sleep 5  # 각 시도 마다 5초간 대기
done

 

이 때, 본인은 "/"  경로로 헬스 체크를 수행하였다.

따라서 "/" 경로로 GET 요청 시 상태코드 200을 반환하는 컨트롤러를 하나 만들어줘야 한다.

포트번호까지 확인하고 싶어서 아래처럼 해주었다.

@Slf4j
@RestController
public class HealthChecktController implements ApplicationListener<WebServerInitializedEvent> {

    private int serverPort;

    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        this.serverPort = event.getWebServer().getPort();
    }

    @GetMapping
    public String health() {
        log.info("[헬스체크] 포트번호: {} 호출", serverPort);
        return "hi" + serverPort;
    }
}

1-3. switch

위 두 단계가 정상적으로 진행됐다면 Nginx가 바라보는 애플리케이션을 스위칭한다.

그리고 이전 버전의 WAS는 종료한다.

# switch.sh

#!/bin/bash

# service_url.inc에서 현재 서비스 중인 WAS의 포트 번호 확인
CURRENT_PORT=$(cat /home/ubuntu/service_url.inc  | grep -Po '[0-9]+' | tail -1)
TARGET_PORT=0

echo "> Nginx currently proxies to ${CURRENT_PORT}."

if [ ${CURRENT_PORT} -eq 8081 ]; then
    TARGET_PORT=8082
elif [ ${CURRENT_PORT} -eq 8082 ]; then
    TARGET_PORT=8081
else
    echo "> No WAS is connected to nginx"
    exit 1
fi

# service_url.inc 파일에 적힌 서비스 주소를 새로 띄운 서버의 주소로 변경
echo "set \$service_url http://127.0.0.1:${TARGET_PORT};" | tee /home/ubuntu/service_url.inc

echo "> Now Nginx proxies to ${TARGET_PORT}."

# service_url이 변경됐으므로 nginx를 reload 해줌
sudo service nginx reload

echo "> Nginx reloaded."

# -9 SIGKILL 은 서버를 바로 종료하므로
# -15 SIGTERM  안전 종료인 SIGTERM을 사용하여 이전 포트 프로세스를 제거한다.
CURRENT_PID=$(lsof -Fp -i TCP:${CURRENT_PORT} | grep -Po 'p[0-9]+' | grep -Po '[0-9]+')

if [ -z "$CURRENT_PID" ]; then
    echo "> No process found on port ${CURRENT_PORT}."
else
    echo "> Killing process ${CURRENT_PID} on port ${CURRENT_PORT}."
    sudo kill -15 ${CURRENT_PID}

    # kill 명령이 실패했는지 확인
    if [ $? -eq 0 ]; then
        echo "> Process ${CURRENT_PID} successfully terminated."
    else
        echo "> Failed to terminate process ${CURRENT_PID}."
        exit 1
    fi
fi

2. 무중단 배포를 위한 Nginx 설정

8081, 8082 두개의 포트를 이용하여 애플리케이션을 띄우는 방식으로 무중단 배포를 구현한다.

기존 서비스가 8081이면 8082 포트로 새로운 버전의 애플리케이션을 띄우고, 정상 동작 시 기존 8081 포트를 내린다.

Nginx로 도메인으로의 요청을 포트포워딩 해주고 있으므로 Nginx 설정을 배포 시에 자동으로 수정하도록 변경해줘야 한다.

 

1에서 배포 스크립트를 작성하면서 service_url.inc 를 보았을 것이다.

service_url.inc의 내용은 아래와 같다.

# service_url.inc
set $service_url http://127.0.0.1:8081;

 

배포 시 매번 $service_url이 변경되면서 Nginx가 바라볼 포트 번호를 지정해준다.

/etc/nginx/sites-available/default 파일이 service_url.inc의 $service_url를 이용할 수 있도록 아래처럼 수정해주자.

include /home/ubuntu/service_url.inc; 구문으로 /home/ubuntu/service_url.inc 를 참조할 수 있게 해준다.

다른 포트로 접근 시 막히거나 리다이렉트 되기 때문에 443 포트로 접근할 때만 설정해주면 된다.


3. AppSpec 파일 작성

CodeDeploy Agent는 배포 시 appspec.yml 파일을 참고하여 배포 프로세스를 진행한다.

(참고로 파일 이름은 꼭 appspec.yml 이어야 한다!)

 

본인은 EC2의 /home/ubuntu/app 폴더에서 배포를 진행할 것이다.

아래처럼 설정하면 CodeDeploy Agent가 동작할 때 S3 버킷의 zip 파일을 /home/ubuntu/app 로 압축해제한다.

AppSpec 파일은 기본적으로 배포를 실행할 폴더의 루트 디렉터리 에 위치해야 하기 때문에

압축 시 루트 디렉터리에 위치시켜주면 된다.

appspec.yml

files의 overwrite: yes 로 설정하면 /home/ubunut/app 경로가 없을 시 자동으로 생성한다.

해당 옵션이 없을 때 /home/ubunut/app 경로가 없으면 배포에 실패하므로 참고하자.

version: 0.0
os: linux

files:
  - source: /
    destination: /home/ubuntu/app
    overwrite: yes  # /home/ubuntu/app 경로가 없을 시 생성함

permissions:
  - object: /
    pattern: "**"
    owner: ubuntu
    group: ubuntu

hooks:
  ApplicationStart:
    - location: scripts/run_new_was.sh
      timeout: 60
      runas: ubuntu
    - location: scripts/health_check.sh
      timeout: 60
      runas: ubuntu
    - location: scripts/switch.sh
      timeout: 60
      runas: ubuntu

AWS S3

자동화 된 배포를 위해서는 배포 파일을 저장할 수 있는 저장소가 필요한데, 이 저장소를 S3로 선택했다.

이전 글에서 이미지 저장소를 만들 때도 썼던 그 S3인데, CI/CD 용 버킷을 새로 만들어서 사용한다.

S3를 선택한 이유는 자동 배포를 위해 AWS CodeDeploy를 사용할 예정이라 같은 AWS 서비스라서 연동하기 편하기 때문이다.


1. EC2에 적용할 IAM 역할 설정

CI/CD 과정에서 EC2 인스턴스에서 실행 중인 CodeDeploy를 통해 S3 버킷의 배포용 파일들에 접근한다.

따라서 EC2의 IAM 역할을 설정해줘야 문제 없이 동작한다.

1-1. IAM 역할 생성 페이지로 이동

1-2. 신뢰할 수 있는 엔티티 선택

1-3. 권한 추가

1-4. 역할 이름 지정

역할 이름 지정 후 생성을 완료한다.

1-5. EC2 인스턴스에 IAM 역할 연결

EC2 인스턴스로 이동해서 IAM을 연결한다.


2. S3 버킷 생성

CI/CD 용으로 버킷을 새로 만들것이다.

깃헙 액션에서 IAM 사용자 정보로 이 S3 버킷에 저장한다.

따라서 퍼블릭 엑세스가 필요 없으므로 최대한 private 하게 생성한다.

2-1. S3 버킷 생성 페이지로 이동

2-2. 버킷 만들기

아래처럼 리전과 이름만 설정하면 나머지는 기본값으로 생성하면 된다.

2-3. 버킷 생성 확인

 

CodeDeploy

CodeDeploy는 EC2, ECS 등의 서비스로의 애플리케이션 배포를 자동화하 해주는 배포 서비스이다.

S3에 저장된 배포 파일들을 이 CodeDeploy가 자동으로 배포하도록 설정할 수 있다.


1. CodeDeploy에 적용할 IAM 역할 설정

CodeDeploy 애플리케이션을 생성하고 이를 이용해 EC2에 배포할 것이다.

이 때, CodeDeploy가 EC2에 접근하여 배포 과정을 실행하기 위해 IAM 역할을 설정해줘야 한다.

1-1. IAM 역할 생성 페이지로 이동

1-2. 신뢰할 수 있는 엔티티 선택

CodeDeploy로 선택해주면 권한은 자동으로 추가되므로 이후는 기본값으로 설정한다.

1-3. 역할 이름 지정

역할 이름 지정 후 생성을 완료한다.


2. CodeDeploy 애플리케이션 생성

2-1. 애플리케이션 생성 페이지로 이동

2-2. 애플리케이션 생성

아래 사진처럼 앱 이름과 컴퓨팅 플랫폼을 설정해준다.

컴퓨팅 플랫폼은 EC2/온프레미스로 선택하고 애플리케이션을 생성한다.


3. CodeDeploy 배포 그룹 설정

3-1. 배포 그룹 생성 페이지로 이동

3-2. 배포 그룹 설정

배포 그룹 설정을 해준다.

역할은 위 1 에서 생성한 역할을 선택해준다.

3-3. 환경 구성

3-2에서 아래로 내려오면 환경 구성이 나온다.

EC2 인스턴스를 선택하고, 태그 그룹을 선택해준다.

이 글에서 생성한대로 EC2를 생성했다면 아래처럼 선택할 수 있다.

EC2 설정에서 태그를 따로 생성할 수도 있다.

태그를 선택하면 맨 아래 박스처럼 일치하는 인스턴스를 확인할 수 있다.

3-3. 설정 완료

AWS Systems Manager 설정은 적당히 넘기고

배포 설정을 확인하면 아래처럼 돼 있으면 넘어간다.

로드 밸런서는 사용하지 않으니 설정을 완료하고 배포 그룹을 생성한다.

CI/CD

지금까지 EC2 인스턴스를 만들고 서버를 띄워서 배포도 했고, RDS 인스턴스를 만들어서 DB도 연동했다.

버전 업데이트 시 일일이 테스트 및 빌드 하던 것도 Github Actions로 자동화했으니 CI 까지는 진행하였다.

이제 배포의 틀은 어느정도 갖춰지긴 했지만, 아직까지 수작업으로 매번 scp 커맨드를 써서 최신 버전으로 배포하고 있다.

결국 이런 단순 반복 작업은 사람이 하다보면 언젠가 꼭 실수가 나오기 마련이고, 이는 곧 장애로 이어질 수 있다.

따라서 이번엔 GitHub에 PR을 올리고 머지 시 배포되는것 까지 자동화(CD) 해보려 한다.

 

보통 이 두가지를 합쳐서 CI/CD라고 한다.

자동 빌드 및 테스트(CI, Continuous Integration)

업데이트 한 버전을 자동으로 빌드 및 테스트 하는 것

배포 자동화(CD, Continuous Deploy)

빌드 및 테스트를 마치고 성공적으로 업데이트 한 버전의 애플리케이션을 자동으로 배포 하는 것


CI/CD & 무중단 배포

애플리케이션의 버전을 업데이트하면 자동으로 빌드 및 테스트하고, 자동으로 배포까지 해보려 한다.

하지만 현재 배포 중인 서비스를 종료하고, 새로운 버전의 서비스를 띄우면 서버가 죽어있는 시간이 존재하지 않을까?

만약 별 다른 공지 없이 이렇게 서버가 내려가 있으면 사용자에게 나쁜 경험을 줄 수 있다.

따라서 새로운 버전을 배포해도 서버가 죽어있는 시간이 거의 없는 자동화 과정을 만들어보려 한다.

그림으로 나타내자면 아래와 같다.

 

 

참고자료

 

Github Actions CD: AWS EC2 에 Spring Boot 배포하기

Overview 애플리케이션을 개발하면 외부에서도 접근 가능하도록 클라우드 환경에 배포합니다. 이전에 포스팅 했던 AWS 1편에서는 마지막에 scp 명령어로 로컬에 존재하는 빌드 파일을 EC2 인스턴스

bcp0109.tistory.com

 

 

HTTPS 사용하기

로컬에서는 HTTP 요청으로도 테스트 할만하지만 배포 환경에서 HTTP 만으로는 제한되는 부분이 조금 있다.

특히 쿠키를 사용할 때 크롬 정책으로 인해 쿠키 확인이 너무나도 힘들다.

프론트와 백엔드가 같은 도메인인 경우에는 Strict 쿠키 정책으로 어떻게 HTTP로도 가능하겠지만,

다른 도메인이라면 방법이 없다.

그래서 인증서를 발급받고 SSL을 적용해서 HTTPS 요청을 사용하여 Secure 쿠키 정책을 사용해야 한다.

HTTPS는 인증서, 암호화 이런 단어가 들어있어서 어려울것 같지만 생각보다 간단하고 빠르게 할 수 있다.


사용 기술

  • EC2
  • Nginx
  • certbot

1. SSL 적용

SSL을 적용하기 위해서는 인증서가 필요하다.

전에는 Route53에서 매월 0.5달러인가 주고 했지만 이번에는 certbot으로 무료로 해보려고 한다.

certbot의 공식 문서 를 참고하면 아래와 같은 과정을 거친다.

사실상 그대로 가져왔으니 공식 문서만 봐도 충분히 따라할 수 있다.

# 1. certbot을 snap 명령어로 설치 및 실행하므로 snap을 먼저 설치한다
sudo snap install core
sudo snap refresh core

# 2. 기존에 설치된 certbot을 제거한다
# 공식 가이드에선 certbot명령어를 사용할 때 snap이 사용되게 하기 위함이라고 되어있다.
sudo apt-get remove certbot

# 3. certbot을 설치한다
sudo snap install --classic certbot

# 4. certbot 명령어가 실행될 수 있게 세팅한다
sudo ln -s /snap/bin/certbot /usr/bin/certbot

# 5. 아래 명령어를 입력하면 certbot이 nginx 구성을 자동으로 수정한다.
# nginx가 아닌 apache를 웹서버로 사용할 경우, sudo certbot --apache 가 된다
sudo certbot --nginx -d midcon.store -d www.midcon.store

# certbot은 CLI몇 줄로 SSL을 적용해줄 뿐 아니라 자동 리뉴얼까지 해준다
# 처음 설치할 때부터 이러한 cron job 처리를 위한 내용을 site-available/default 에 자동으로 설정해준다
# 아래 명령어로 자동 리뉴얼이 적용되고 있는지 확인할 수 있다
sudo certbot renew --dry-run

 

5번 커맨드를 입력하면 아래처럼 이메일, 약관 동의 여부 등등을 입력하는 부분이 있다.

당황하지말고 적당히 읽어보고 입력하면 된다.

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): hyukkind@naver.com   # 이메일 입력

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.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: y   # 이메일을 통해 Let's Encrypt 프로젝트 정보를 받아볼지
Account registered.
Requesting a certificate for midcon.store and www.midcon.store

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/midcon.store/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/midcon.store/privkey.pem
This certificate expires on 2024-08-15.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for midcon.store to /etc/nginx/sites-enabled/default
Successfully deployed certificate for www.midcon.store to /etc/nginx/sites-enabled/default
Congratulations! You have successfully enabled HTTPS on https://midcon.store and https://www.midcon.store

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

2. 결과 확인

2-1. /etc/nginx/sites-available/default 확인

아래 사진은 /etc/nginx/sites-available/default 로 들어가본 결과이다.

localtion /ws 부분은 본인이 웹소켓 설정하느라 추가한 부분이고 아래 부분부터 보면 되는데

아래처럼 certbot이 nginx 설정까지 자동으로 변경한 알 수 있다.

 

HTTP로 요청하면 HTTPS로 리다이렉트 시키는 설정도 certbot이 자동으로 해두었다.

2-2. HTTP/HTTPS 요청 시

이제 HTTP 로 요청하면 자동으로 HTTPS 로 리다이렉트 되고, HTTPS 요청도 잘 되는걸 확인할 수 있다.


3. 추가

만약 인증서를 삭제하고 싶다면 아래 명령어를 입력하면 된다.

sudo certbot delete

 

그럼 아래와 같은 창을 확인할 수 있고, 여기서 삭제하고 싶은 인증서의 번호를 입력하면 된다.

아쉽지만 nginx 설정까지는 자동으로 삭제해주지는 않는것 같다.

인증서 삭제 후 nginx 변경 부분은 수동으로 삭제하자.

 

 

참고자료

 

10분만에 끝내는 EC2 생성, NGINX 구성, SSL적용

이 포스팅에선 이론적인 내용에 보다는 구성 방법과 흐름에 대해서만 조망합니다. EC2 생성, NGINX 설치, 프록시 설정, 도메인 및 SSL 적용을 해본 적이 없거나 과정에 대해 모호한 부분이 있으시다

creampuffy.tistory.com

 

 

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

 

도메인 적용

EC2에 애플리케이션 서비스를 배포까지는 했다.

하지만 아직 도메인을 적용하지 않아서 불편하게 퍼블릭 IP를 입력해서 접속해야한다.

이번 글에서는 이름을 가진 도메인을 붙여볼것이다.

Nginx를 리버스 프록시로 사용하여 도메인으로 들어온 요청을 EC2 8080 포트로 포워딩 해보자.


사용 기술

  • EC2
  • Nginx

1. 도메인 확보

우선 도메인을 붙이려면 도메인을 어떻게든 마련해야 한다.

인터넷에 검색해보면 무료로 구할 수 있는 사이트도 있고, 가비아 같은 호스팅 사이트도 많다.

본인은 가비아에서 1년에 500원짜리 도메인을 샀다.

마이 페이지에서 아래의 도메인 란을 누르면 내 도메인을 확인할 수 있다.


2. DNS 레코드 수정

이제 도메인의 DNS 레코드를 설정해서 구매한 도메인으로 접속 시 EC2 서버로 포워딩 해줄것이다.

2-1. 내 도메인의 관리 창으로 이동

2-2. DNS 정보 란의 도메인 연결 설정 창으로 이동

내 도메인 관리 창에서 아래로 내려보면 DNS 정보 란이 보일것이다.

여기서 설정을 누르면 DNS 관리페이지로 넘어간다.

2-3. DNS 관리 페이지에서 DNS 설정

DNS 설정 버튼을 눌러서 DNS 레코드 설정을 해준다.

아래처럼 추가해준다.

호스트는 www, @ 를 넣어준다.

www로 넣으면 www.midcon.store 를 등록하는것이고 @로 넣으면 midcon.store 를 등록함을 의미한다.

값/위치에 해당하는것은 본인의 EC2 인스턴스의 퍼블릭 IP이다.


3. EC2 인스턴스의 인바운드 규칙 설정

우리는 HTTP 혹은 HTTPS 요청으로도메인명/경로 와 같은 형태로 요청을 받을 것이다.

따라서 HTTP  HTTPS에 해당하는 포트 번호를 인바운드 규칙 설정 해줘야한다.

보안그룹으로 이동해서 아래처럼 HTTP, HTTPS에 해당하는 80, 443 포트를 열어준다.


4. Nginx 설정

4-1. Nginx 설치

우선은 EC2에서 Nginx를 설치한다.

Ubuntu 환경의 경우 아래의 명령어를 입력하여 설치한다.

sudo apt-get install nginx -y   // Nginx 설치

 

Nginx가 제대로 설치 되었다면 EC2의 퍼블릭 IP 주소로 접속하면 아래와 같은 화면이 뜰것이다.

4-2. Nginx 설정

HTTP 요청의 기본 포트값은 80이므로 도메인 명:8080 이 아닌 도메인 명 만 입력했을 때 80번 포트로 요청이 들어온다.

따라서 이러한 80번 포트의 요청을 원래 EC2 인스턴스의 8080 포트로 연결시켜야 한다.

이것을 Nginx를 이용해서 해볼 것이다.

 

Nginx의 기본 설정 값은 /etc/nginx/sites-available/default 파일에 설정돼 있다.

이 파일을 수정하여 원하는 설정으로 바꿀것이다.

리눅스 커맨드를 좀 알면 알아서 하겠지만 모른다면 아래 명령어를 입력하면 된다.

sudo vim /etc/nginx/sites-available/default    // 관리자 권한으로 vim으로 뒤 경로 파일 실행

 

위 파일에 들어가면 대략 아래와 같은 창이 뜬다.

 

그럼 i를 눌러서 수정모드로 위 기본 서버 설정 아래에 아래처럼 입력해준다.

아래 설정이 위에서 설명한 80번 포트를 8080번 포트로 연결시켜주는 설정이다.

저장은 Ctrl + c 이후 :wq 입력 후 엔터를 누르면 된다.

# server_name 에 적힌 도메인으로 "/" 이하 경로로 접근 시(사실상 모든 경로) 8080포트로 위임 
server {
    listen 80;
    server_name midcon.store www.midcon.store;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

 

설정을 변경할 때마다 아래 명령어로 Nginx를 재시작 해줘야 한다.

sudo service nginx restart

5. 결과 확인

아래처럼 도메인으로 접속해도 8080포트로 접속하는것처럼 잘 접속 된다.

 

 

참고자료

 

10분만에 끝내는 EC2 생성, NGINX 구성, SSL적용

이 포스팅에선 이론적인 내용에 보다는 구성 방법과 흐름에 대해서만 조망합니다. EC2 생성, NGINX 설치, 프록시 설정, 도메인 및 SSL 적용을 해본 적이 없거나 과정에 대해 모호한 부분이 있으시다

creampuffy.tistory.com

+ Recent posts