logo

DowanKim

7. 나스에 배포를 해보자 (두근두근).. 어 왜 다 깨지는거지

2025년 10월 9일

졸업논문 대체 웹사이트

저희 졸전 웹사이트는, 나스서버를 활용해서 배포를 진행하고, 역대 웹사이트의 파일들도 전부다 나스에 올라가져 있었습니다.

브랜딩팀에서 url과 qr코드가 슬슬 필요해져 나스에 저희 사이트도 올려야될 시기가 되었습니다.

그런데,

Vercel에서 배포할 때는 멀쩡하던 웹사이트가, NAS에 빌드된 결과물을 올리자마자 한 번에 망가졌습니다. 새로고침하면 404, 이미지도 안 뜨고, 자바스크립트도 안 불러와지고..

대략적인 해결 과정은 다음과 같습니다.

  • Vite base: "./"로 자산을 상대 경로로 다시 빌드하고
  • React Router를 HashRouter로 바꿔서 새로고침 404를 막았습니다.

아래 글은 문제 인식과 그 해결 과정을 정리한 글입니다.


1. Vercel에서는 왜 문제가 없었을까?

  • Vercel은 React 같은 SPA(Single Page Application)를 잘 인식합니다.
  • /about, /designer 같은 경로로 들어오거나 새로고침해도 서버가 자동으로 index.html을 돌려줍니다.
  • 정적 자산들(/assets/...)도 도메인 루트에서 바로 제공해줍니다.

즉, 서버가 똑똑하게 우리의 SPA를 이해하고, 모든 요청을 알아서 내가 만든 앱으로 연결시켜주는 환경입니다. 그래서 기본 설정과 깃허브를 연결하기만 해도 잘 배포가 되었습니다.


2. NAS에 올렸을 때 왜 깨졌을까?

NAS는 그냥 “정적 파일”만 올려놓고 서비스하는 환경입니다. 똑똑한 리라이트나 SPA 대응 기능이 없습니다. 여기서 두 가지 문제가 발생했습니다.

문제 1. 정적 자산 파일 경로가 전부 깨짐 (Vite base 문제)

Vite 기본 설정은 base: "/"입니다. 이 상태로 빌드하면 HTML 파일 안에 있는 CSS·JS·이미지 경로가 전부 /assets/...처럼 절대 경로로 들어갑니다.

그런데 NAS에는 정적 파일을 서브 폴더 아래에 넣어뒀습니다.

https://dt.pusan.ac.kr/pages/DT_page/DT_016_page/index.html
https://dt.pusan.ac.kr/pages/DT_page/DT_016_page/assets/...

이렇게 하면 브라우저가 /assets/...를 요청할 때 https://dt.pusan.ac.kr/assets/...(루트)에서 찾게 됩니다. 당연히 없고, 그래서 assets 폴더가 통째로 안 불렸던 겁니다.

해결: Vite base를 상대 경로로 강제

// vite.config.ts export default defineConfig({ plugins: [react()], base: "./", // ✔ 빌드 결과물이 상대 경로를 쓰도록 강제 });

이제 HTML이 ./assets/...처럼 상대 경로를 쓰게 되어, 어떤 하위 폴더에 두더라도 자산을 잘 불러옵니다.


문제 2. 새로고침 시 404 (BrowserRouter 문제)

초기에는 BrowserRouter(React Router의 기본)를 썼습니다. 이 방식은 /designer?name=박세은 같은 URL을 실제 경로처럼 다룹니다.

브라우저가 이 URL에서 새로고침을 누르면, 서버에 /designer 파일을 요청합니다. 그런데 정적 파일만 있는 NAS에는 /designer라는 파일이 없습니다. 그래서 바로 404가 뜹니다.

Vercel에서는 서버가 알아서 index.html을 돌려주지만, NAS는 그런 기능이 없기 때문입니다.

해결: HashRouter로 변경

// src/App.tsx function App() { return ( <HashRouter basename="/"> <ScrollToTop /> <AppRoutes /> </HashRouter> ); }

HashRouter는 URL을 /designer 대신 /#/designer 형태로 만들어줍니다. # 뒤에 있는 값은 서버가 신경쓰지 않습니다. 항상 index.html만 요청합니다. 브라우저가 문서를 받은 후에, React Router가 # 뒤를 읽고 해당 페이지를 렌더링합니다.

즉, 서버가 SPA를 몰라도, HashRouter를 쓰면 새로고침 404 없이 정확하게 동작합니다.


3. 정리

환경기본 설정문제점해결
VercelBrowserRouter + base: "/"문제 없음그대로 사용
NASBrowserRouter + base: "/"절대 경로(자산) 404, 새로고침 404base: "./" + HashRouter

NAS 같은 “그냥 정적 파일만 있는” 환경에서는:

  1. 자산 경로를 상대 경로로 빌드 (Vite base: "./" 설정)
  2. 라우터를 HashRouter로 바꿔서 새로고침 404 방지

이 두 가지를 반드시 해줘야 합니다.


4. 사용된 개념

SPA(Single Page Application)

  • SPA는 한 개의 index.html로 시작해서, 나머지는 JavaScript로 화면을 바꾸는 방식입니다.
  • 실제 서버에는 /designer.html 같은 파일이 없습니다.
  • 브라우저가 /designer를 요청하면 서버가 index.html을 주고, 브라우저가 그 안에서 라우팅을 처리하는 구조입니다.

BrowserRouter vs HashRouter

구분BrowserRouterHashRouter
URL 형태/designer?name=박세은/#/designer?name=박세은
서버에게 전달되는 경로/designer/ (서버는 # 뒤를 모름)
서버 조건“/어떤 경로든 index.html 줘”가 필요그냥 정적 파일만 있어도 됨
새로고침서버에 /designer 요청 → 404 가능항상 /index.html만 요청

Vercel처럼 서버가 SPA를 이해하면 BrowserRouter가 예쁘고 좋습니다. 하지만 NAS처럼 단순 정적 호스팅에선 HashRouter가 안전합니다.

Vite base 설정

  • 기본값 "/": 빌드 결과물이 /assets/... 같은 절대 경로로 만들어짐 → 루트가 아니면 깨짐
  • "./": 빌드 결과물이 ./assets/... 같은 상대 경로 → 어디 배포해도 경로 안 깨짐

정리하면, NAS에 빌드 파일만 올릴 때 문제가 생긴 이유는 정적 서버가 SPA를 이해하지 못하고, 절대 경로를 그대로 쓰도록 빌드되어 있었기 때문입니다. 그래서

  • Vite base: "./"로 자산을 상대 경로로 다시 빌드하고
  • React Router를 HashRouter로 바꿔서 새로고침 404를 막았습니다.

이 두 가지 설정 덕분에 Vercel이 아닌 NAS에서도 같은 웹사이트를 정상적으로 서비스할 수 있었습니다. 정적 파일만 배포하는 환경이라면 앞으로도 꼭 떠올려야 할 것입니다.