프론트엔드 개발자 입장에서 바라보는 웹 서버 (feat. Nginx)
저는 한때 백엔드로 취업을 준비했으나 당시 수요가 더 높았던 프론트엔드로 일을 시작했습니다. 그러다 보니 다른 주니어 프론트엔드 동료들과 조금은 다른 시각을 가지게 된지도 모르겠습니다. 동료들이 언어, 프레임워크 등을 배울 때 저는 결과물이 어떻게 배포되는지에 대해 고민을 더 많이 했던 것 같습니다. 그러면서 프론트엔드 개발자라면 웹 서버 배포 방식 정도는 이해해야 한다는 생각을 하게 됩니다.
웹 서버는 여러 의미가 있을 수 있지만 이번 글에서 사용하는 웹 서버라는 용어는 Web Application Server (WAS) 와 대조되는 의미로 Nginx
와 Apache HTTP Server
등의 웹 서버 소프트웨어를 기반으로 한 서버를 의미합니다. 편의상 WAS와 비교하기 위해 영어로 Web Server라고 표기하겠습니다.
Web Server에 대하여
Web Server는 보통 웹 서비스의 앞단에 위치되고, 정적 파일 서비스, Reverse Proxy, Load Balancer 등의 기능을 가지고 있습니다. 이 중에서도 정적 파일 서비스는 프론트엔드 배포에 많이 사용됩니다. 또한 Header를 통해 캐시 정책을 설정할 수도 있습니다.
Web Server 소프트웨어의 점유율을 보면 1위에 Apache HTTP Server
가 오랫동안 자리잡고 있지만, 성능적 이점을 가진 Nginx
가 빠르게 따라잡고 있습니다. 저 또한 Nginx
를 더 선호하는 편입니다.
프론트엔드와 백엔드의 분리된 역할에 대하여
현재 웹 개발 분야는 프론트엔드와 백엔드 개발로 나뉘는 추세가 확실하게 자리를 잡았다고 봐도 무방합니다. 그러나 사실 이 둘이 완벽하게 분리될 수는 없습니다. 프론트엔드 개발의 결과물을 어떻게 배포하느냐의 질문에서 결국은 서버에서 지속적인 서비스가 되어야 한다는 결론에 이르기 때문입니다. 이는 모바일 앱과 같이 프로그램을 사용자의 기기에 다운받아 사용하는 클라이언트 소프트웨어와는 사정이 다르죠.
또한 프론트엔드에서 서버사이드 로직이 완전히 빠졌을 때 발생하는 단점 또한 무시할 수 없습니다. 렌더링 속도와 검색엔진 최적화에 있어서 치명적인 단점을 가지게 되죠. 이에 서버사이드 렌더링 (SSR) 및 정적페이지 생성기 (SSG) 가 많은 각광을 받고 있습니다. 서버사이드 렌더링은 오늘의 주제랑은 좀 달라서 나중에 관련 내용을 다뤄보도록 하겠습니다.
프론트엔드 배포 방법
프론트엔드 개발의 결과물은 서버사이드 렌더링을 하는게 아니라면 html
, css
, js
정적인 파일이 됩니다. 요즘 많이 사용하는 React JS
로 예를 들어봅시다. build
명령어를 실행하면 build
폴더가 생성되고, 그 안에 index.html
과 여러 css
, js
파일로 빌드됩니다. 이렇게 빌드된 결과물은 사용자 요청에 따라 내어줄 수 있는 형태로 배포되어야 합니다.
Template Engine
MVC 모델이 익숙하다면 View에 해당되는 Template Engine을 통해 프론트엔드를 서비스하는 방식을 생각할 수 있습니다. 이 경우 프론트엔드는 백엔드의 한 부분으로 들어가게 됩니다.
Web Server
또 다른 방법으로는 Web Server와 WAS의 역할을 분리하는 겁니다. Web Server는 요청이 들어왔을 때 정적 파일을 내어주거나 다른 서버로 Reverse Proxy를 하는 등 안내데스크와 같은 역할만 합니다. 흔히 알고있는 백엔드의 경우 WAS에 해당됩니다. Web Server를 가장 앞단에 두어 프론트엔드는 정적으로 서비스하고 백엔드는 Reverse Proxy로 서비스하는 형태가 되는겁니다.
예시: React JS
React JS
로 프론트엔드 개발을 하고 Nginx
로 배포하는 상황을 가정해보면 아래와 같이 Nginx
설정파일을 작성할 수 있습니다.
location / {
root [정적 파일 루트 경로];
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
React JS
빌드 결과물에 대한 Nginx
설정 예시
try_files
속성에서 정의된 패턴을 통해 정적 파일을 서비스하게 됩니다. 이러한 패턴은 사용하는 프레임워크 또는 개발 방식에 따라 달라질 수 있습니다. React JS
의 경우 SPA 구조답게 html
이 루트 디렉토리의 index.html
하나밖에 없습니다. 따라서 어떤 경로로 들어가든 루트 경로의 index.html
을 내어주도록 되어야 합니다.
예시: Next.js
아래는 좀 다른 예시로 Next.js
를 정적으로 배포하는 경우에 적합한 설정 예시입니다.
location / {
root [정적 파일 루트 경로];
index index.html index.htm;
try_files $uri $uri/index.html =404;
error_page 404 /404/index.html;
}
Next.js
정적 빌드 결과물에 대한 Nginx
설정 예시
Next.js
는 React JS
와 다르게 각 경로마다 html
이 존재한다는 차이가 있습니다. 이와 같이 각 프레임워크별 파일 구성을 고려하여 설정파일을 작성할 수 있습니다.
백엔드로 Reverse Proxy 하는 경우는 아래와 같이 작성할 수 있습니다.
location ^~ /api/ {
proxy_pass [백엔드 서버 URL];
}
/api/
경로에 대해서 백엔드로 Reverse Proxy
Web Server를 이해하면 좋은 이유
프론트엔드의 정적 파일을 구성하는 방법은 다양합니다. 파일을 하나로 묶어서 bundling 하는 것, code splitting 하여 분리하는 것, 파일명에 해시값을 붙이는 것 등을 활용할 수 있으며, React JS
와 같은 SPA 구성, Next.js
와 같은 MPA 구성에도 차이가 있습니다.
Web Server를 이해한다면 달라지는 구성에 따른 장단점을 미리 예상해볼 수 있습니다. 캐싱 정책, 요청 횟수, 파일 사이즈 등을 고려하여 최적화하는 것 또한 가능하며, 문제가 발생했을 때 해결 방안에 대한 스팩트럼을 넓힐 수 있습니다.
어떤 배포 방법을 사용하든 프론트엔드의 파일 구성을 고려해야 합니다. 프론트엔드 개발자가 직접 서버를 개발하지 않더라도 정적 파일 구성에 대한 가이드만 줄 수 있어도 훨씬 원활해질 것입니다. 프론트엔드 개발자 모두가 그럴 필요는 없다 할지라도 이러한 역량까지 가추고 있다면 스스로의 가치를 더욱 높일 수 있지 않을까 싶습니다.
댓글남기기