๐ Next.js App Router SelfโHosting ์๋ฒฝ ๊ฐ์ด๋
๐ Next.js App Router SelfโHosting ์๋ฒฝ ๊ฐ์ด๋
Next.js๋ Vercel์ ์ต์ ํ๋์ด ์์ง๋ง, ์์ฒด ์๋ฒ(Node.js, Docker, CDN ๋ฑ)์์๋ ๊ฐ๋ ฅํ๊ฒ ์๋ํ ์ ์๋๋ก ์ค๊ณ๋์ด ์์ต๋๋ค. ์ด ๊ธ์์๋ App Router ๊ธฐ๋ฐ ํ๋ก์ ํธ๋ฅผ ์ค์ค๋ก ํธ์คํ ํ ๋ ์์์ผ ํ ๋ชจ๋ ๋ด์ฉ์ ์ ๋ฆฌํฉ๋๋ค.
๐ 1. ์คํ ๋ฐฉ์ ์ ํ
Node.js ์๋ฒ ์คํ
npm run build
npm run start
- next start๋ production ๋ชจ๋ ์คํ
- ๋ชจ๋ ๊ธฐ๋ฅ(SSR, API Route, ์ด๋ฏธ์ง ์ต์ ํ ๋ฑ) ์ฌ์ฉ ๊ฐ๋ฅ
Docker ์ปจํ ์ด๋
- next build → ์ด๋ฏธ์ง ์์ฑ ํ ์ปจํ ์ด๋ํ
- Kubernetes, AWS ECS, GCP ๋ฑ์์ ์ฌ์ฉ ๊ฐ๋ฅ
์ ์ ์ฌ์ดํธ ๋ด๋ณด๋ด๊ธฐ
- next export ๋ช ๋ น์ผ๋ก ์์ฑ
- ๋จ, API Routes, SSR, ISR์ ์๋ํ์ง ์์
๐ผ๏ธ 2. ์ด๋ฏธ์ง ์ต์ ํ (next/image)
- ๊ธฐ๋ณธ ์ด๋ฏธ์ง ์ต์ ํ ๊ธฐ๋ฅ์ ์๋ฒ ๋ด sharp์ ํตํด ์ํ๋จ
- ์๋ฒ์ sharp์ด ์์ผ๋ฉด ์ฑ๋ฅ์ด ์ ํ๋ ์ ์์
- ์ปค์คํ ๋ก๋๋ฅผ ์ง์ ํด ์ธ๋ถ ์ด๋ฏธ์ง ์ต์ ํ ์๋น์ค ์ฐ๊ฒฐ๋ ๊ฐ๋ฅ
๐ 3. ํ๊ฒฝ ๋ณ์ ์ค์
- .env, .env.production ๋ฑ์ผ๋ก ๊ตฌ์ฑ
- ํด๋ผ์ด์ธํธ์ ๋ ธ์ถํ๋ ค๋ฉด NEXT_PUBLIC_ ์ ๋์ฌ ํ์
DATABASE_URL=...
NEXT_PUBLIC_API_URL=https://...
โก 4. ์บ์ ํธ๋ค๋ง (ISR ๋ฑ)
Next.js๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ผ ์์คํ ๊ธฐ๋ฐ ์บ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๋ณต์ ์ธ์คํด์ค๋ฅผ ์ด์ํ๊ฑฐ๋ ํด๋ฌ์คํฐ ํ๊ฒฝ(Kubernetes ๋ฑ)์์ ์บ์ ๊ณต์ ๊ฐ ํ์ํ๋ค๋ฉด ์ปค์คํ ์บ์ ํธ๋ค๋ฌ๋ฅผ ์ค์ ํด์ผ ํฉ๋๋ค.
// next.config.js
module.exports = {
cacheHandler: require.resolve('./my-cache-handler.js'),
cacheMaxMemorySize: 0,
};
- Redis, S3 ๋ฑ ์ธ๋ถ ์คํ ๋ฆฌ์ง๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
โ๏ธ 5. CDN ๊ตฌ์ฑ
- ์ ์ ์์ฐ (/_next/static/)์ CDN์ ํตํด ์๋น
- ISR ์ฌ์ฉ ์ stale-while-revalidate ์บ์ ์ ์ฑ ์ ์ง์ํ๋ CDN ํ์
- ์: AWS CloudFront, Fastly, Cloudflare
๐ฟ 6. ์คํธ๋ฆฌ๋ฐ & ํ๋ก์ ์ค์
App Router๋ ์๋ฒ ์คํธ๋ฆฌ๋ฐ ๊ธฐ๋ฅ์ ์ ๊ทน ํ์ฉํฉ๋๋ค. ์ด๋ฅผ ์ํด ํ๋ก์(Nginx ๋ฑ)์์ buffering ๋นํ์ฑํ๊ฐ ํ์ํ ์ ์์ต๋๋ค.
proxy_buffering off;
๐งฌ 7. ๋น๋ ID ๊ด๋ฆฌ (๋น๋ ๊ฐ ๋ฒ์ ์ ํฉ์ฑ)
์ฌ๋ฌ ์๋ฒ ์ธ์คํด์ค ๊ฐ ์์ฐ ๋ถ์ผ์น ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด generateBuildId๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค:
// next.config.js
module.exports = {
generateBuildId: async () => process.env.GIT_COMMIT_SHA || 'default',
};
๐งน 8. ์ข ๋ฃ ์๊ทธ๋ ์ฒ๋ฆฌ (Graceful Shutdown)
Docker ๋๋ Kubernetes ํ๊ฒฝ์์๋ SIGTERM, SIGINT ์๊ทธ๋์ ์์ ํด ์๋ฒ๋ฅผ ์ ๋ฆฌ ์ข ๋ฃํ๋ ์ฝ๋๊ฐ ํ์ํฉ๋๋ค:
NEXT_MANUAL_SIG_HANDLE=true npm run start
process.on('SIGTERM', () => {
console.log('SIGTERM received, closing...');
server.close();
});
โ ์ ์ฒด ์ฒดํฌ๋ฆฌ์คํธ ์์ฝ
ํญ๋ชฉ ์ค์ ํ์ ์ฌ๋ถ
Node.js ์คํ or Docker ์ง์ | โ |
์ด๋ฏธ์ง ์ต์ ํ (sharp) | โ |
ํ๊ฒฝ ๋ณ์ (NEXT_PUBLIC ํฌํจ) | โ |
์บ์ ๊ณต์ ํธ๋ค๋ฌ | โ |
CDN ์ค์ (ISR ์ง์) | โ |
ํ๋ก์ ๋ฒํผ๋ง ๋นํ์ฑํ | โ |
๋น๋ ID ๋๊ธฐํ (generateBuildId) | โ |
์ข ๋ฃ ์๊ทธ๋ graceful ์ฒ๋ฆฌ | โ |
โจ ๋ง๋ฌด๋ฆฌ
Next.js๋ฅผ ์ง์ ํธ์คํ ํ๋ ๊ฒ์ ๋ ๋ง์ ์ ์ฐ์ฑ์ ์ฃผ์ง๋ง, ์ฑ ์๋ ๋ฐ๋ฆ ๋๋ค. ์บ์ฑ ์ ๋ต, ์ด๋ฏธ์ง ์ฒ๋ฆฌ, CDN ์ต์ ํ, ๋ก๊ทธ/๋ชจ๋ํฐ๋ง๊น์ง ๊ณ ๋ คํด์ผ ํ ๊ฒ์ด ๋ง์ง๋ง, App Router๋ ์ด๋ฅผ ์ ๋ค๋ฃฐ ์ ์๋ ๊ตฌ์กฐ๋ก ์ค๊ณ๋์ด ์์ต๋๋ค.
Next.js, App Router, Self Hosting, Docker, Node.js ์๋ฒ, ์ด๋ฏธ์ง ์ต์ ํ, ํ๊ฒฝ๋ณ์ ์ค์ , ์บ์ ํธ๋ค๋ง, CDN ๊ตฌ์ฑ, graceful shutdown, build ID ๊ด๋ฆฌ