[Next.js] Thymeleaf 기반 구조 Next.js로 리팩토링 : Next.js 준비 및 설정 / Docker 컨테이너화 / Nginx 프록시 설정

2025. 10. 20. 18:39·FrontEnd
728x90

 

 

 

 

기존 프로젝트는 Thymeleaf 기반의 간단한 페이지로 구성되어 있었는데
프론트 협업을 대비해서 연습해보고 싶어서 Next.js 기반으로 리팩토링‼

 

 

 

 

1. Next.js 란?

  • React를 위해 만든 오픈 소스 JavaScript 웹 프레임워크
  • React에는 없는 기능 제공
    • 서버 사이드 렌더링(SSR; Server-Side Rendering)
    • 정적 사이트 생성(SSG; Static Site Generation)
    • 증분 정적 재생성(ISR; Incremental Static Regeneration)

 

 

 

1.1. SSR vs CSR

  SSR (Server-Side Rendering) CSR (Client-Server Rendering)
JavaScript 로딩 서버에서 JS 로딩
→ 완성된 HTML 클라이언트로 전달
(초기 로딩 속도 빠름)
브라우저에 JS 정보 가진 빈 HTML 전달
→ 브라우저가 JS 로딩하여 UI 빌드
(초기 로드 완료되면 렌더링 빠름)
SEO
(Search Engine Optimization)
HTML 파일에 모든 정보가 포함되어 있어
봇이 데이터 수집 가능
초기 HTML 파일이 비어있어
봇이 데이터 수집하기 어려움

 

 

 

1.2. React vs Vue vs Next.js

  React Vue Next.js
개발 유형 라이브러리 프레임워크 React 기반 프레임워크
학습 곡선 중간 낮음 중간
렌더링 방식 CSR CSR SSR, SSG
라우팅 별도 라이브러리 필요 Vue Router 필요 파일 기반 라우팅
상태 관리 Redux, Context API Vuex Redux, Context API
사용 사례 대규모 SPA 소규모~중규모 프로젝트 SEO가 필요한 프로젝트
커뮤니티 및 생태계 매우 활발 활발 활발 (React 기반)

 

 

 

 

 

 

 


2. Next.js 프로젝트 준비

 

2.0. 최종 목표 디렉토리

2025-posleep/
├─ backend/
├─ frontend/     # ← Next.js 프로젝트 추가
├─ infra/
│  ├─ docker-compose.yml
│  └─ nginx/
│     └─ nginx.conf
└─ ...
  • SpringBoot + Thymeleaf 구조  →→→  Next.js + 백엔드 API (SpringBoot)
  • 모노레포 (Monorepo)
    • CI/CD 통합을 위한 구성
    • frontend, backend API 프로젝트를 하나의 레포지토리에서 관리
  • Spring root를 2025-posleep → 2025-posleep/backend로 변경

 

 

2.1. 설치 및 프로젝트 생성

  • nvm + Node 20 LTS 설치
  • 프로젝트 생성 : npm create-next-app
    • 프로젝트 이름 : frontend
    • Turbopack : Next.js 팀이 만든 Rust 기반 초고속 번들러 → 협업 대비 연습이기 때문에 안정성 중요하여 설치 ❌
syun@SyunMac 2025-posleep % npx create-next-app@latest frontend \
  --ts --eslint --tailwind --app --src-dir --import-alias "@/*"
Need to install the following packages:
create-next-app@15.5.3
Ok to proceed? (y) y

✔ Would you like to use Turbopack? (recommended) … No / Yes

 

 

 

2.2. 로컬 백엔드 API 연동

  • 개발 중에는 백엔드(로컬 8080)로 붙도록 환경 변수 사용 (.env.local)
    • 환경변수를 process.env로 자동으로 로드 (ex. process.env.NEXT_PUBLIC_BACKEND_URL)
    • 운영 환경 백엔드 URL은 docker-compose.yml 에 설정하여 주입 (3.3 참고)
# frontend/.env.local
NEXT_PUBLIC_API_BASE_URL=http://localhost:8080
  • 개발 중 CORS 없이 호출하도록 next.config.ts에 rewrites 추가
import type { NextConfig } from "next";
import { PHASE_DEVELOPMENT_SERVER } from "next/constants";

const base: NextConfig = {
  reactStrictMode: true,
};

// 개발 모드에서만 /api → 8080 프록시
const config = (phase: string): NextConfig => {
  if (phase === PHASE_DEVELOPMENT_SERVER) {
    return {
      ...base,
      async rewrites() {
        return [
          { source: "/api/:path*", destination: "http://localhost:8080/:path*" },
        ];
      },
    };
  }
  return base;
};

export default config;

 

 

 

2.3. 개발 서버 실행

cd frontend
npm run dev

 

 

 

 

 

 


3. 프론트엔드 Docker 컨테이너화

 

3.1. standalone 빌드 설정

  • next.config.ts 파일에서 standalone 빌드 설정
    • 빌드 시 .next/standalone 디렉토리 생성 : 서버 실행에 필요한 최소한의 파일만 분리
    • EC2나 Docker 같은 서버 환경에서 가볍고 빠르게 실행 가능
import type { NextConfig } from "next";
import { PHASE_DEVELOPMENT_SERVER } from "next/constants";

const base: NextConfig = {
  reactStrictMode: true,
  output: "standalone",
};

const config = (phase: string): NextConfig => {
  if (phase === PHASE_DEVELOPMENT_SERVER) {
    return {
      ...base,
      async rewrites() {
        return [
          { source: "/api/:path*", destination: "http://localhost:8080/:path*" },
        ];
      },
    };
  }
  return base;
};

export default config;

 

 

 

3.2. Dockerfile 작성

  • frontend/Dockerfile
# ========= 1) Build stage =========
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
# 프로덕션 빌드 (standalone 산출물 생성)
RUN npm run build

# ========= 2) Runtime stage =========
FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV PORT=3000
EXPOSE 3000

# 보안상 node 유저 사용
RUN addgroup -S nodejs && adduser -S nextjs -G nodejs

# standalone 서버 코드 & 정적 리소스 복사
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

USER nextjs
CMD ["node", "server.js"]

 

 

 

3.3. docker-compose에 프론트 추가

  • infra/docker-compose.yml
version: "3.9"
services:
  api:
    image: syun32/posleep-api:prod
    container_name: posleep-api
    env_file:
      - /opt/posleep/app.env
    volumes:
      - /opt/posleep/keys:/opt/posleep/keys:ro
    expose:
      - "8080"
    restart: unless-stopped
    environment:
      - JAVA_OPTS=-XX:MaxRAMPercentage=75 -XX:+UseG1GC
      - TZ=Asia/Seoul
    networks:
      - posleep-net

  frontend:
    build:
      context: ../frontend
      dockerfile: Dockerfile
    image: syun32/posleep-frontend:prod
    container_name: posleep-frontend
    expose:
      - "3000"
    restart: unless-stopped
    environment:
      - NEXT_PUBLIC_API_BASE_URL=http://api:8080
      - TZ=Asia/Seoul
    networks:
      - posleep-net
    depends_on:
      - api

  nginx:
    image: nginx:1.27-alpine
    container_name: posleep-nginx
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "80:80"
    restart: unless-stopped
    depends_on:
      - frontend
      - api
    networks:
      - posleep-net

networks:
  posleep-net:
    driver: bridge

 

 

 

 

 


4. Nginx 프록시 설정

  • infra/nginx/nginx.conf
  • 프록시 설정
    • 기본 트래픽 → 프론트  (외부에는 80만 오픈, 3000은 컨테이너 내부 네트워크 통신)
    • /api → 백엔드             (외부에 8080 오픈 유지: 테스트용)
worker_processes auto;

events { worker_connections 1024; }

http {
  upstream frontend {
    server posleep-frontend:3000;
  }

  upstream api {
    server posleep-api:8080;
  }

  server {
    listen 80;
    server_name _;

    # Next.js 프론트
    location / {
      proxy_pass http://frontend;
      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;
    }

    # Spring Boot API
    location /api/ {
      proxy_pass http://api/;
      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;
    }
  }
}

 

 

 

 

 

 


5. GitHub Actions Workflow 변경

  • .github/workflows/cicd.yml 변경
    • 서버 env에 프론트 이미지 이름/태그 추가
    • 프론트 빌드/푸시 Job 추가
    • deploy Job은 두 이미지(BE / FE) 모두 푸시된 후에 실행

 

 

 

 

 

 


99. 접속 테스트 ⭐️ 성공 ⭐️

  • EC2-IP/  →  프론트엔드(Next.js) 접속 성공

 

  • EC2-IP/api → 백엔드(Spring) 접속 성공

 

 

 

 

 

https://github.com/syun32/2025-posleep

 

GitHub - syun32/2025-posleep

Contribute to syun32/2025-posleep development by creating an account on GitHub.

github.com

 

 

 

 

 

 

 

 

📌 References

https://subtlething.tistory.com/115#google_vignette

https://velog.io/@attosisss_/CSR-%EA%B3%BC-SSR%EC%9D%98-%EC%B0%A8%EC%9D%B4-%EA%B7%B8%EB%A6%AC%EA%B3%A0-SEO

https://velog.io/@hyunnzl/React-Vue-Next.js-%EC%84%A4%EB%AA%85%EA%B3%BC-%EC%B0%A8%EC%9D%B4%EC%A0%90

https://velog.io/@milkboy2564/Next.js-env%ED%99%98%EA%B2%BD-%EB%B3%80%EC%88%98-%EC%A0%95%EB%A6%AC

 

 

 

 

 

 

 

 

 

 

728x90
저작자표시 비영리 (새창열림)

'FrontEnd' 카테고리의 다른 글

[React] 리액트의 프로퍼티(props) / useState / 이벤트 핸들러(onChange, onClick)  (0) 2025.09.17
[React] 리액트(React)란? : 정의 / 실행환경 구축 / JSX 기본 문법  (0) 2025.09.17
[CSS] 티스토리 코드블럭 여백, 테두리 없애기 : pre / !important  (0) 2022.09.30
[CSS] CSS3 (4) : 버튼, UI, 다중 칼럼 레이아웃, 플렉서블 박스 레이아웃, 미디어 쿼리  (0) 2021.07.10
[CSS] CSS3 (3) : 2D / 3D Transform, Transition, Animation  (0) 2021.07.07
'FrontEnd' 카테고리의 다른 글
  • [React] 리액트의 프로퍼티(props) / useState / 이벤트 핸들러(onChange, onClick)
  • [React] 리액트(React)란? : 정의 / 실행환경 구축 / JSX 기본 문법
  • [CSS] 티스토리 코드블럭 여백, 테두리 없애기 : pre / !important
  • [CSS] CSS3 (4) : 버튼, UI, 다중 칼럼 레이아웃, 플렉서블 박스 레이아웃, 미디어 쿼리
s_ih_yun
s_ih_yun
  • s_ih_yun
    CODESYUN
    s_ih_yun
  • 전체
    오늘
    어제
    • 분류 전체보기 (352)
      • Web (8)
      • Java (7)
      • Spring (26)
      • Git (16)
      • MyBatis (1)
      • FrontEnd (17)
      • JavaScript (11)
      • DevOps (6)
      • Project (0)
      • Cloud (9)
      • Lanuage (13)
        • C++ (3)
        • Python (10)
      • DB (4)
        • MySQL (1)
        • Oracle (2)
      • Computer Science (26)
        • Concept (3)
        • Algorithm (23)
      • Baekjoon (104)
        • 단계별로 풀어보기 (78)
      • CodeUp (98)
        • Python 기초 100제 (98)
      • Programmers (2)
      • Books (3)
      • etc (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • Syun's Pages
  • 인기 글

  • 태그

    자료구조
    aws
    CodeUp 기초 100제
    codeup
    github
    Cloud
    단계별로 풀어보기
    web
    HTML
    Python
    C
    spring
    myBatis
    db
    Programmers
    알고리즘
    Tistory
    MySQL
    git
    JavaScript
    java
    VS Code
    c++
    웹
    clean code
    SourceTree
    oracle
    BOJ
    CSS
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
s_ih_yun
[Next.js] Thymeleaf 기반 구조 Next.js로 리팩토링 : Next.js 준비 및 설정 / Docker 컨테이너화 / Nginx 프록시 설정
상단으로

티스토리툴바