Skip to content

Nginx SSI(Server-Side Includes)를 이용한 서버 통합

Nginx의 SSI 기능을 활용하여 서버에서 여러 팀의 HTML 프래그먼트를 조합한 뒤 클라이언트에 완성된 페이지를 전달하는 마이크로 프론트엔드 통합 방식의 원리, 설정, 장단점을 학습한다.

학습 목표

  • SSI(Server-Side Includes)의 개념과 동작 원리를 설명할 수 있다
  • Nginx에서 SSI를 활성화하고 <!--#include --> 지시문을 사용하여 프래그먼트를 조합하는 설정을 이해한다
  • SSI 방식의 장점(SEO, 낮은 지연시간)과 단점(동적 콘텐츠 한계, SPA 경험 부재)을 구분한다
  • SSI와 클라이언트사이드 통합을 혼합하는 전략을 설명할 수 있다

1. SSI(Server-Side Includes)란

1.1 개념

SSI는 웹 서버가 HTML 문서 내의 특수 지시문(directive)을 해석하여, 다른 파일이나 URL의 내용을 삽입한 뒤 최종 결과를 클라이언트에 전달하는 기술이다. 1990년대부터 사용된 검증된 기술로, Nginx, Apache 등 주요 웹 서버에서 지원한다.

핵심 지시문:

html
<!--#include virtual="/jobs/fragments/recommendation/index.html" -->

웹 서버가 이 지시문을 만나면, 지정된 경로의 HTML을 가져와 해당 위치에 삽입한다. 클라이언트는 이미 조합이 완료된 HTML을 수신하므로, JavaScript 없이도 완성된 페이지를 볼 수 있다.

1.2 Ajax 통합과의 핵심 차이

비교 항목Ajax 프래그먼트 통합SSI 서버 통합
조합 시점브라우저(클라이언트)웹 서버(서버)
조합 주체JavaScript (fetch)Nginx (SSI 모듈)
HTML 도착 상태비어 있는 슬롯 + JS완성된 HTML
JavaScript 필수아니오
SEO불리유리
깜빡임있음 (비동기 로딩)없음 (서버에서 조합 완료)

2. 동작 원리

2.1 SSI 통합 흐름

동작 순서:

  1. 사용자가 Nginx 프록시 서버에 페이지를 요청한다
  2. Nginx가 팀 홈 서버로 요청을 프록시하여 index.html을 받아온다
  3. Nginx의 SSI 모듈이 HTML을 스캔하여 <!--#include --> 지시문을 발견한다
  4. 지시문이 가리키는 경로(팀 잡스 서버)에서 프래그먼트 HTML을 가져온다
  5. 지시문 위치에 프래그먼트 HTML을 삽입하여 최종 HTML을 완성한다
  6. 완성된 HTML을 사용자에게 전달한다

사용자가 받는 HTML에는 SSI 지시문이 존재하지 않으며, 이미 모든 프래그먼트가 삽입된 완성 상태이다.


3. Nginx SSI 설정

3.1 SSI 활성화

Nginx에서 SSI를 사용하려면 server 블록에 ssi on; 한 줄만 추가하면 된다.

nginx
upstream team_home {
    server host.docker.internal:3001;
}
upstream team_jobs {
    server host.docker.internal:3002;
}

server {
    listen 3000;

    # SSI 기능 활성화 (핵심 설정)
    ssi on;

    location / {
        proxy_pass http://team_home;
    }

    location /jobs {
        proxy_pass http://team_jobs;
    }
}

ssi on;이 설정되면, Nginx는 프록시로 받아온 HTML 응답을 스캔하여 SSI 지시문을 자동으로 처리한다.

3.2 팀 홈의 HTML (SSI 지시문 포함)

html
<!-- 팀 홈의 index.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>서비스 메인</title>
</head>
<body>
  <header>
    <h1>서비스 헤더</h1>
    <nav>
      <a href="/">홈</a>
      <a href="/jobs">채용</a>
    </nav>
  </header>

  <main>
    <h2>메인 콘텐츠</h2>
    <p>팀 홈이 관리하는 영역</p>

    <!-- SSI 지시문: 팀 잡스의 추천 프래그먼트 삽입 -->
    <!--#include virtual="/jobs/fragments/recommendation/index.html" -->
  </main>

  <footer>서비스 푸터</footer>
</body>
</html>

3.3 팀 잡스의 프래그먼트

html
<!-- 팀 잡스의 fragments/recommendation/index.html -->
<section class="jobs-recommendation">
  <h3>추천 채용공고</h3>
  <ul>
    <li>프론트엔드 개발자 - A사</li>
    <li>백엔드 개발자 - B사</li>
    <li>DevOps 엔지니어 - C사</li>
  </ul>
</section>
<style>
  .jobs-recommendation {
    border: 1px solid #dee2e6;
    border-radius: 8px;
    padding: 16px;
    margin: 16px 0;
  }
</style>

Nginx가 SSI 처리를 완료하면, 사용자가 받는 최종 HTML에는 <!--#include ...--> 대신 프래그먼트의 실제 내용이 들어간다.


4. SSI 지시문 상세

4.1 주요 지시문

지시문용도예시
#include virtual지정된 URL의 내용을 삽입<!--#include virtual="/frag.html" -->
#include file로컬 파일 경로로 삽입<!--#include file="header.html" -->
#set변수 설정<!--#set var="title" value="Home" -->
#if / #else / #endif조건부 포함<!--#if expr="$var" -->...<!--#endif -->
#echo변수 값 출력<!--#echo var="DATE_LOCAL" -->

4.2 virtual vs file

마이크로 프론트엔드에서는 virtual을 사용해야 한다. virtual은 Nginx의 location 규칙을 따르므로, 다른 upstream 서버(다른 팀의 서버)에서 프래그먼트를 가져올 수 있다.


5. 장점

5.1 SEO에 유리

서버에서 완성된 HTML을 내려주므로, 검색 엔진 크롤러가 JavaScript를 실행하지 않아도 모든 콘텐츠를 인식할 수 있다. 콘텐츠 소비 위주의 사이트에서 특히 강력한 장점이다.

5.2 낮은 지연시간

Nginx와 내부 서버 간 통신은 내부 네트워크에서 이루어지므로 레이턴시가 매우 낮다. 클라이언트에서 외부 서버로 Ajax 요청을 보내는 것보다 훨씬 빠르다.

프래그먼트가 정적 HTML이면 사실상 추가 지연이 거의 없다. Nginx 레벨 캐싱을 결합하면 더욱 빠르다.

5.3 클라이언트 깜빡임 없음

Ajax 통합과 달리, 사용자가 받는 HTML은 이미 완성 상태이므로 프래그먼트 영역이 비어 있다가 채워지는 깜빡임(FOUC)이 발생하지 않는다.

5.4 안정성과 검증

SSI는 1990년대부터 사용된 오래된 기술로, 안정성이 검증되어 있다. Nginx의 SSI 모듈은 프로덕션 환경에서 오랫동안 사용되어 왔으며 성숙한 기술이다.

5.5 JavaScript 불필요

프래그먼트 삽입에 JavaScript가 필요 없으므로, JavaScript가 비활성화된 환경이나 느린 네트워크에서도 완성된 페이지를 제공할 수 있다.


6. 단점

6.1 동적 콘텐츠 처리 어려움

프래그먼트가 DB 조회 등 동적으로 생성되는 경우, 서버에서 생성이 완료될 때까지 전체 페이지 응답이 지연된다. 여러 프래그먼트 중 하나라도 느리면 전체 페이지의 TTFB(Time To First Byte)가 늘어난다.

6.2 가장 느린 프래그먼트에 의존

SSI는 모든 프래그먼트를 조합한 뒤에야 응답을 보낸다. 프래그먼트를 병렬로 가져오지만, 가장 느린 프래그먼트의 응답 시간이 전체 페이지 응답 시간을 결정한다.

페이지 응답 시간 = max(프래그먼트A 시간, 프래그먼트B 시간, ...) + 조합 시간

6.3 사용자 인터랙션 한계

SSI로 조합된 페이지는 기본적으로 정적 HTML이다. 버튼 클릭, 폼 제출, 실시간 업데이트 같은 동적 인터랙션을 위해서는 결국 JavaScript가 필요하다. SSI만으로는 SPA 수준의 사용자 경험을 제공할 수 없다.

6.4 SPA 느낌이 아님

페이지 전환 시마다 서버에 새로 요청해야 하므로 전체 새로고침이 발생한다. 부드러운 전환 애니메이션이나 화면 일부만 갱신하는 것이 불가능하다.

6.5 중첩 SSI의 성능 문제

프래그먼트 안에 또 다른 SSI 지시문이 있으면(중첩 SSI), 조합이 순차적으로 이루어져 응답 시간이 급격히 증가한다.

# 중첩 SSI 예시 (성능에 불리)
index.html
  └─ <!--#include virtual="/header.html" -->
       └─ <!--#include virtual="/user-menu.html" -->  ← 순차적 처리
  └─ <!--#include virtual="/content.html" -->

6.6 에러 처리 계획 필수

프래그먼트 서버가 다운되면 SSI 지시문이 에러를 발생시킬 수 있다. Nginx의 ssi_silent_errors 설정이나 타임아웃 설정으로 폴백 전략을 반드시 수립해야 한다.

nginx
server {
    ssi on;
    ssi_silent_errors on;          # SSI 에러 시 빈 문자열로 대체
    proxy_connect_timeout 3s;      # 프래그먼트 서버 연결 타임아웃
    proxy_read_timeout 5s;         # 프래그먼트 응답 대기 타임아웃
}

7. 혼합 전략: SSI + 클라이언트사이드

SSI의 장점(SEO, 빠른 초기 로딩)과 클라이언트사이드 통합의 장점(동적 인터랙션)을 결합하면 양쪽의 이점을 모두 취할 수 있다.

혼합 전략 가이드라인:

영역추천 통합 방식이유
공통 헤더/푸터SSI모든 페이지에 공통, SEO 중요
본문 핵심 콘텐츠SSISEO 핵심, 빠른 FCP
사용자 맞춤 추천Ajax로그인 상태에 따라 동적 변경
실시간 알림WebSocket/JS서버에서 조합 불가
인터랙티브 필터/검색JavaScript사용자 입력에 즉각 반응 필요

8. SSI 외의 서버사이드 조합 기술

SSI가 유일한 서버사이드 조합 기술은 아니다. 다른 기술들도 같은 원리로 동작한다.

기술동작 위치특징
ESI (Edge-Side Includes)CDN/캐시 서버Akamai, Varnish 등에서 사용, CDN 레벨 캐싱과 결합
Tailor (Zalando)Node.js 서버스트리밍 방식으로 프래그먼트 조합, SSI보다 유연
Podium (FINN.no)Node.js 서버프래그먼트 레지스트리 기반, CSS/JS 자동 관리
SSR 프레임워크애플리케이션 서버Next.js, Nuxt.js 등에서 서버사이드 조합 가능

핵심 정리

  1. SSI는 웹 서버가 HTML 내의 <!--#include --> 지시문을 해석하여 서버에서 프래그먼트를 조합한 뒤 완성된 HTML을 클라이언트에 전달하는 기술이다.
  2. 장점: SEO에 유리하고, 내부 네트워크 레이턴시가 낮으며, 클라이언트 깜빡임이 없고, JavaScript 없이도 완성된 페이지를 제공한다.
  3. 단점: 동적 콘텐츠 생성 시 전체 응답이 지연되고, 사용자 인터랙션이 제한적이며, SPA 수준의 경험을 제공할 수 없다.
  4. 프로덕션에서는 SSI(정적 콘텐츠, SEO)와 클라이언트사이드 통합(동적 인터랙션)을 혼합하여 사용하는 전략이 효과적이다.
  5. 에러 처리(ssi_silent_errors), 타임아웃 설정, 폴백 전략 등 서버 조합 실패에 대한 계획이 반드시 필요하다.

다음 단계

  • Web Components 통합: 웹 표준 기술인 Custom Elements와 Shadow DOM을 이용하여 프레임워크에 독립적인 마이크로 프론트엔드 컴포넌트를 구현하는 방법을 학습한다.