개발 slecs

Astro SSR 설정과 운영 서비스 파일 불일치 해결

목차

운영 환경과 로컬(혹은 빌드) 환경의 entry 파일이 어긋나 있던 문제를 잡았다.

왜 SSR 모드 불일치가 문제가 됐나

Astro는 기본적으로 output: 'static' 모드로 동작하는데, 이 경우 빌드 결과물이 정적 HTML 파일로 떨어진다. 반면 output: 'server' (SSR) 모드는 서버 런타임이 요청을 받아 동적으로 렌더링하는 구조라 entry 파일이 달라진다. Astro SSR 빌드는 dist/server/entry.mjs 같은 서버 entry를 만들어내는데, 운영 환경의 서비스 실행 스크립트가 이 entry를 바라보고 있었던 것.

문제는 astro.config.mjsoutput 설정이 SSR이 아닌 상태로 빌드가 돌았다는 거다. 빌드 산출물엔 서버 entry가 없거나 위치가 달랐고, 운영 ssul.service 유닛 파일이 기대하는 경로와 실제 entry가 맞지 않았다. 결과적으로 배포 후 서비스가 제대로 뜨지 않거나, 정적 모드로 빌드된 결과물을 서버처럼 실행하려다 오류가 났을 상황이다.

이런 케이스는 생각보다 자주 발생한다. 초기엔 로컬 테스트 편의상 static 모드로 개발하다가, 운영에서 SSR이 필요해져 서비스 파일만 먼저 바꾸는 경우. 또는 반대로 config를 먼저 바꿨는데 서비스 파일이 예전 경로를 그대로 가리키는 경우. 어느 쪽이든 "빌드 설정 ↔ 운영 실행 스크립트" 두 군데가 서로를 의식하지 않고 각자 수정되면 이런 불일치가 생긴다.

변경 범위

파일 역할 이번 변경 의미
astro.config.mjs Astro 빌드 핵심 설정 output: 'server' (SSR 모드) 명시
package.json 의존성 및 스크립트 정의 SSR 어댑터 추가에 따른 의존성 변경
package-lock.json 의존성 lock package.json 변경분 lock 반영

astro.config.mjs가 핵심이고, package.json / package-lock.json은 Astro SSR 어댑터(Node.js 어댑터 등)를 실제로 설치한 흔적이다. Astro에서 SSR을 쓰려면 @astrojs/node 같은 어댑터를 별도로 붙여야 하기 때문에, config 한 줄만 바꾼 게 아니라 의존성도 함께 정리한 것.

// astro.config.mjs — 변경 후 핵심 포인트
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
  output: 'server',          // static → server (SSR)
  adapter: node({
    mode: 'standalone',      // entry.mjs 생성
  }),
});

mode: 'standalone'이 중요한데, 이걸 지정해야 dist/server/entry.mjs가 독립 실행 가능한 형태로 나온다. 운영 서비스 파일(ssul.service)이 entry.mjs를 직접 ExecStart로 물고 있다면, 이 모드가 반드시 맞아야 한다.

팀 관점 회고

솔직히 이 작업에서 배운 건 "운영 서비스 파일도 코드 리뷰 대상"이라는 거다. astro.config.mjs는 Git에 있으니 리뷰가 되는데, systemd .service 파일은 서버에만 존재하거나 별도 관리되는 경우가 많다. 그러다 보니 빌드 설정이 바뀌어도 서비스 파일은 예전 경로를 그대로 들고 있는 상황이 생긴다.

개선 방향으로 두 가지를 보통 권한다:

  • 서비스 파일도 레포에 포함: .service 템플릿을 deploy/ 같은 디렉토리에 두고, 배포 스크립트가 이를 복사/심링크 처리하게 한다. 그러면 config 변경과 서비스 파일 변경이 같은 PR에서 리뷰된다.
  • 빌드 후 entry 경로 검증 스텝 추가: CI에서 빌드 완료 후 dist/server/entry.mjs 존재 여부를 assert하는 간단한 체크를 넣으면, 불일치를 배포 전에 잡을 수 있다.

이번엔 운영에서 먼저 발견됐지만, 다음 번엔 그 전에 잡아야 한다.

끝.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.