node.js, next.js, AWS EC2, nginx 배포 시 403에러

AFDB·2024년 8월 9일

AWS EC2에서 인스턴스를 생성하고 인바운드 규칙 설정, 키페어를 사용해 utuntu 로그인, 웹 콘솔과 putty에서도 잘 접속이 된다.

리눅스 터미널에서 아래 과정으로 프론트와 백을 빌드했다.

  1. Github에 저장된 프로젝트를 클론해온다.
# 프론트엔드 프로젝트 클론
cd ~/frontend
git clone <프론트엔드-레포지토리-URL> front

# 백엔드 프로젝트 클론
cd ~/backend
git clone <백엔드-레포지토리-URL> back

# 그리고
#.evn 파일이나 app.js 파일 등, 개발 환경에 맞춰진 코드들
# (localhost:3000으로 설정한 주소, mysql 정보 등)
# 배포 환경에 맞게 수정해준다.
  1. 프론트 빌드
# 프론트엔드 디렉토리로 이동
cd ~/frontend/front

# 빌드 명령어 실행
npm install
npm run build

# 빌드된 파일을 Nginx 루트 디렉토리로 복사
sudo cp -r .next/* /var/www/html/

# Nginx 서버 재시작
sudo systemctl restart nginx
  1. 백엔드 빌드
# 백엔드 디렉토리로 이동
cd ~/backend/back

# 의존성 설치
npm install

# PM2로 백엔드 애플리케이션 실행
pm2 start app.js --name backend

❓ 여기까지 진행하고 IP주소로 접속했는데, 403 Forbidden가 에러가 뜬다.

nginx 에러 로그에는 directory index of /var/www/html/ is forbidden 에러가 뜬다.

🔎 이 에러는 nginx가 /var/www/html 디렉토리 내에 기본 index 파일(예: index.html)을 찾지 못해서 발생한다고 한다.
1. 그래서 빌드된 프론트를 복사한 .next 폴더 안에 index.html 파일 생성하고 다시 접속해보니
2. index.html 파일을 잘 읽어서 Welcome to nginx 는 표시된다. 근데 어쨌든 index.html 말고 내가 clone했던 프론트 파일을 읽어야 한다.
3. index.html 파일 삭제
🔎 생각해보니 백엔드 코드는 pm2 start app.js --name backend명령어로 애플리케이션을 실행시켰는데, 프론트는 실행시킨 게 없는 것 같다.

  1. pm2 start npm --name "next-app" -- start 명령어로 프론트 실행
  • backend와 next-app 둘 다 online으로 잘 실행이 된다.
  1. 프론트도 실행시켰으니, nginx에서 잘 읽을 수 있게 설정 파일을 수정해준다.
    nginx 설정 파일로 들어가는 명령어
    sudo nano /etc/nginx/sites-available/default
server {
    listen 80;
    server_name [AWS 탄력적 IP주소]; # 대괄호 빼고

    # IP로 접속 시 403 Forbidden 응답
    return 403;
}

server {
    listen 80;

    server_name [구매한 도메인 주소];  # 대괄호 빼고

    root /var/www/html;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location /api {
        proxy_pass http://localhost:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

  • server_name에 퍼블릭 IP 넣는 것 중요하고, root 에서 프론트 파일 클론 했던 경로인 /var/www/html; 넣는 것 중요하다.
  • index index.html; 이 부분은 디렉토리 요청에 대해 기본적으로 제공할 파일을 지정한다. 예를 들어, / 요청이 들어오면 /var/www/html/index.html 파일을 반환합니다.
    단, 밑에서 설정할 location / 블록에서 모든 요청을 Next.js 서버(포트 3000)로 프록시한다. 따라서 /index.html 파일이 없어도 Next.js 서버가 요청을 처리하여 적절한 HTML을 반환할 수 있다.
  • location / { ... }: 이 블록에서 루트 경로(/)로 오는 모든 요청을 처리한다.
    proxy_pass http://localhost:3000;: 모든 요청을 http://localhost:3000 으로 프록시하므로, Nginx는 클라이언트의 요청을 받아서 로컬에서 실행 중인 Next.js 애플리케이션(포트 3000)으로 전달.(백엔드 3001포트도 마찬가지!)

❓ nginx 설정 파일이 읽히지 않는 것 같을 때

sudo nano /etc/nginx/sites-available/default
명령어로 접속한 뒤, server_name 을 제거해도 도메인 주소가 여전히 읽히고 있어서, Nginx의 설정 파일을 제대로 읽지 못하는 것 같았다.
✅ 설정 파일이 사이트 활성화 디렉토리로 심볼릭 링크가 제대로 되어 있는지 확인

  • ls -l /etc/nginx/sites-enabled/
    /etc/nginx/sites-enabled/에 해당 설정 파일이 없다면, 이를 심볼릭 링크로 추가
  • sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/

✅ Nginx가 읽고 있는 설정 파일이 여러 개일 수 있다. 예를 들어, /etc/nginx/nginx.conf 파일에 기본 설정이 존재하거나, 다른 설정 파일이 겹칠 수 있으므로,
Nginx의 메인 설정 파일인 /etc/nginx/nginx.conf 파일에서 include 지시자를 사용하여 다른 설정 파일을 포함하고 있는지 확인한다.
include /etc/nginx/sites-enabled/*;
이 줄을 추가하면 /etc/nginx/sites-enabled/에 있는 모든 설정 파일을 Nginx가 읽을 수 있다.

✅ 요약하면 루트 경로(/)로 오는 모든 요청을 Next.js 애플리케이션(포트 3000)으로 프록시하고. API 경로(/api): 모든 요청도 Express.js API 서버(포트 3001)로 프록시한다.

✅ 덕분에 클라이언트의 요청을 Nginx가 프록시하여 백엔드 서버로 전달하고 Next.js 애플리케이션과 API 서버를 동시에 구동할 수 있었다.

0개의 댓글