본문 바로가기
  • 구름빵의 개발 블로그
프로그래밍/웹 프로그래밍

클라우드 인스턴스에 웹 서비스 배포하기 ( feat. React, Spring Boot

by 은빛구름빵 2025. 7. 3.

배경

웹 서버와 API 서버를 구동하기 위한 모든 준비를 마쳤다면 이제 내 프로젝트를 서버에 배포하는 일이 필요합니다.

FE 개발을 위해 React를 사용했고 BE 개발을 위해 Spring Boot를 사용했으며, 이 프로젝트를 클라우드 인스턴스에 배포하고 인터넷을 통해 접속하는 과정까지 진행해보도록 하겠습니다.

다만, 일반적으로 이 과정에서 CI/CD 파이프라인을 구축해서 자동화를 하지만 저는 간단한 배포이기 때문에 수동으로 배포하는 작업을 진행해보도록 하겠습니다.

 

React 프로젝트 배포

React 프로젝트를 배포하기 전에 React 프로젝트를 빌드해주어야 합니다.

React 프로젝트를 빌드하면 프로젝트 경로 안에 dist라는 폴더가 만들어집니다.

이 폴더가 React 프로젝트의 빌드 결과물을 모두 담고 있는 폴더입니다.

이제 이 폴더를 인스턴스에 업로드 해줍니다.

업로드 방식에는 여러 가지가 있지만 저는 모든 작업을 수동으로 간단하게 할 예정이니 FileZilla라는 프로그램을 사용해보도록 하겠습니다.

FileZilla를 들어오면 좌측에 로컬 디렉토리가, 우측에 원격 디렉토리가 나오게 됩니다.

저는 /var/www 경로에 특정 폴더를 만들어서 이 폴더에 모든 파일을 넣어서 사용하도록 하겠습니다.

따라서, 아까 React 프로젝트를 빌드하고 나온 결과물인 dist 폴더를 이 경로에 복사해줍니다.

 

이제 파일을 위치해주었다면 인터넷에서 IP 주소, 혹은 도메인으로 접속했을 때 해당 React 프로젝트로 접근하도록 만들어야 합니다.

즉, Nginx가 해당 폴더 경로를 인지하고 dist 폴더 안에 있는 빌드 파일을 실행해주어야 한다는 의미입니다.

 

이를 위해서는 Nginx 설정 파일을 수정해주어야 합니다.

우선 Nginx 설정 파일에 접속해주어야 합니다.

Nginx는 기본적으로 default라는 파일에 기본 설정이 작성되어 있습니다.

하지만 저는 새로 저만의 설정 파일을 만들어서 적용하는 방법으로 진행해보도록 하겠습니다.

 

인스턴스에 PuTTY와 같은 Shell을 통해 접속한 다음 아래 명령어를 입력해 설정 파일을 텍스트 편집기를 통해 엽니다.

명령어 특성상 만약 해당 파일이 없다면 해당 경로에 생성하게 됩니다.

// vi 편집기를 사용할 경우
sudo vi /etc/nginx/sites-available/{설정 파일 이름}

// nano 편집기를 사용할 경우
sudo nano /etc/nginx/sites-available/{설정 파일 이름}

편집기는 무엇을 사용하던 상관 없습니다. 본인에게 더 잘 맞는 편집기를 사용해주시면 됩니다.

아마 새로 파일을 열면 아무 내용이 존재하지 않을 겁니다.

( 혹은 제 지난 포스트를 따라왔다면 기본 틀이 작성되어 있을 겁니다. )

해당 파일에 아래 내용을 자신의 프로젝트에 맞게 작성해줍니다.

server {
    listen 80;
    server_name localhost;
    location / {
        root {dist 폴더 경로};    // ex) /var/www/html/dist
        index index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
    location /api/ {
        proxy_pass http://localhost:8080/;
        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;
    }
}

이 파일에 대해 간단하게 설명하자면 아래와 같습니다.

listen 80;

80번 포트를 통해 Nginx를 사용한다는 의미입니다.

기본적인 http 포트를 허용합니다.

server_name localhost;

localhost 경로에서 아래 내용을 탐색한다는 의미입니다. 

localhost 대신에 자신의 퍼블릭 IP나 도메인 주소를 입력해도 됩니다.

단, 이 퍼블릭 IP와 도메인 주소는 실제로 접근할 수 있는 경로여야 합니다.

location / { }

/ 경로에 { } 안의 내용을 적용합니다.

이를 응용하면 아래 location /api/ 라는 구문은 /api/라는 경로에 대한 정의라는 것을 알 수 있습니다.

이를 통해 같은 도메인 주소라도 뒤에 오는 URL 주소에 따라 다른 정적 파일로 이동시킬 수 있습니다.

root {dist 폴더 경로}

기본 경로를 root 경로로 지정합니다.

이 구문에서는 / 경로를 dist 폴더로 지정한다는 의미입니다.

index index.html index.htm

index 파일로 인식할 파일을 지정합니다.

index.html 파일이나 index.htm이라는 파일을 index 파일( 메인 파일 )로 인식합니다.

proxy_pass http://localhost:8080/;

location 경로로 들어오는 접근을 리다이렉팅합니다.

즉, ~~~/api/ 로 들어오는 접근은 모두 http://localhost:8080/으로 보낸다는 의미입니다.

제 API 서버는 동일한 서버 내에서 8080 포트로 서비스가 작동할 예정이기 때문에 이렇게 지정해주었습니다.

 

파일을 모두 작성하고 저장까지 했다면 작성한 설정 파일을 Nginx에서 적용하도록 등록해주어야 합니다.

이 작업을 심볼릭 링크를 생성해준다고 말합니다.

아래 명령어를 통해 심볼릭 링크를 생성하고 활성화해줍니다.

sudo ln -s /etc/nginx/sites-available/{설정 파일 이름} /etc/nginx/sites-enabled/

이 명령어를 입력하면 등록이 완료된 것입니다.

확인을 하기 위해서는 아래 명령어를 입력하고 자신의 설정 파일이 잘 등록되어 있는지 확인해줍니다.

ls -la /etc/nginx/sites-enabled/

목록에 자신이 만든 설정 파일이 존재한다면 성공입니다.

근데 보면 default도 같이 등록이 되어 있는 것을 확인할 수 있습니다.

반드시 필요한 작업은 아니지만 저는 혹시 모를 상황을 대비해 이 파일을 비활성화 해주겠습니다.

아래 명령어를 통해 비활성화 할 수 있습니다.

// default 파일 비활성화
sudo rm /etc/nginx/sites-enabled/default

// 자신이 만든 설정 파일 비활성화
sudo rm /etc/nginx/sites-enabled/{설정 파일 이름}

활성화 및 등록까지 완료되었다면 이제 Nginx 설정이 잘 작동되는지 테스트를 해봐야 합니다.

아래 명령어를 입력하면 테스트를 진행하고 문법에 오류가 없는지 확인할 수 있습니다.

sudo nginx -t

명령어를 입력하면 테스트 결과를 확인할 수 있습니다.

만약 문법에 오류가 있다면 위와 같이 test failed라는 문구가 나옵니다

( 위 오류는 $scheme이라고 입력해야 할 것을 $schema라고 오타를 내서 나온 오류입니다 )

반대로 성공하게 되면 test is successful이라는 문구가 나옵니다.

위 문구가 나올 때까지 설정 파일을 수정해가며 문법 오류를 찾아주시면 됩니다!

 

테스트까지 완료되었다면 Nginx 서비스를 재시작해줍니다.

sudo systemctl restart nginx

 재시작 이후 퍼블릭 IP를 인터넷 창에 입력하면 React 프로젝트가 정상적으로 나오는 것을 확인할 수 있습니다.

 

Spring Boot 프로젝트 배포

이번엔 API 서버인 Spring Boot 프로젝트를 배포해보도록 하겠습니다.

마찬가지로 Spring Boot 프로젝트를 로컬에서 빌드해줍니다.

./gradlew build

빌드해주면 기본적으로 결과물은 프로젝트 폴더의 build/lib 폴더 내부에 위치합니다.

따로 경로를 지정했다면 따로 지정한 경로를 확인해주시면 됩니다.

그럼 결과로 ~~~~.SNAPSHOT.jar라는 파일이 생깁니다.

간혹가다 -plain이 붙은 파일이 같이 생기기도 하는데 실제 빌드 파일을 붙지 않은 파일이니 주의하시기 바랍니다.

 

해당 파일을 이제 FileZilla를 통해 인스턴스에 업로드 해줍니다.

파일 업로드는 어느 위치에 해주어도 좋지만 저는 한 번에 관리하기 위해 앞서 만든 /var/www 경로에 있는 폴더에 위치하도록 하겠습니다.

 

파일이 업로드 되었으면 이제 이 API 서버를 백그라운드 서비스로 등록합니다.

이 작업이 있어야 서버를 재부팅하더라도 자동으로 재실행합니다.

우선 서비스 등록을 위한 파일을 만들어줍니다.

// 서비스 파일을 만들 때 확장자를 .service로 만들어줍니다
sudo nano /etc/systemd/system/{API서비스 이름.service}

파일을 만들면 마찬가지로 빈 파일이 만들어집니다.

이 안에 내용은 아래와 같이 채워줍니다.

내용은 자신의 서비스에 맞게 일부 수정해주시면 됩니다.

[Unit]
Description={서비스 설명}
After=network.target

[Service]
Type=simple
User={사용자 계정 이름}
WorkingDirectory={빌드 파일 경로} // ex. /var/www/myfood
ExecStart=/usr/bin/java -jar {빌드 파일 경로} // ex. /var/www/myfood/myfood-SNAPSHOT.jar
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

 

위와 같이 작성해주셨다면 저장해줍니다.

이후 이 서비스를 등록하고 자동으로 실행되도록 설정해봅시다.

// 서비스 파일을 새로고침합니다
sudo systemctl daemon-reload

// 새로운 서비스를 시작하고 자동 시작되도록 등록합니다.
sudo systemctl start {서비스 파일명}
sudo systemctl enable {서비스 파일명}

// 실시간 서비스 로그를 확인합니다. Java IDE의 콘솔창처럼 사용할 수 있습니다.
sudo systemctl status {서비스 파일명}

 

위 작업까지 완료되면 드디어 웹 서버와 API 서버가 모두 정상적으로 배포되었습니다.

이제 브라우저에 접속해 API가 정상 작동하는지 확인하면 됩니다.

 

결론

이후 CI/CD 파이프라인을 만들어야 하지만 이전에 빠르게 배포 테스트를 진행할 때 이처럼 직접 배포해서 작업합니다.

수동 작업이지만 나름 빠르게 진행할 수 있고 쉽게 진행할 수 있다는 특징이 있습니다.

물론 프로젝트에 수정이 필요하면 로컬에서 다시 빌드에 업로드를 진행해야 한다는 단점이 있습니다.

이러한 문제를 위해 유지 보수 측면에서는 CI/CD 파이프라인이 필수적으로 필요하다고 느껴집니다.