Remix on AWS with SST
SST를 사용하여 AWS에 Remix 앱을 생성하고 배포하기
SST로 AWS에 Remix 배포하기
SST를 사용해 Remix 앱을 AWS에 배포하는 방법은 두 가지입니다.
아래에서 두 가지 방법을 모두 사용해 간단한 앱을 만들어 보겠습니다.
예제
여러분이 참고할 수 있는 다른 Remix 예제도 몇 가지 있습니다.
서버리스
이제 Remix 앱을 만들고, 파일 업로드를 위한 S3 버킷을 추가한 다음, Remix 컴포넌트를 사용해 배포해 보겠습니다.
시작하기 전에 AWS 자격 증명을 설정했는지 확인하세요.
1. 프로젝트 생성
프로젝트를 만들어 보겠습니다.
npx create-remix@latest aws-remixcd aws-remix모든 기본 옵션을 선택합니다.
SST 초기화
이제 앱에서 SST를 초기화해 보겠습니다.
npx sst@latest initnpm install기본값을 선택하고 AWS를 선택합니다. 이렇게 하면 프로젝트 루트에 sst.config.ts 파일이 생성됩니다.
개발 모드 시작
개발 모드를 시작하려면 다음 명령어를 실행하세요. 이 명령어는 SST와 여러분의 Remix 앱을 시작합니다.
npx sst dev실행이 완료되면 사이드바에서 MyWeb을 클릭하고 브라우저에서 Remix 앱을 열어보세요.
2. S3 버킷 추가하기
파일 업로드를 위해 S3 버킷에 공개 access를 허용해 보겠습니다. sst.config.ts 파일을 업데이트하세요.
const bucket = new sst.aws.Bucket("MyBucket", { access: "public"});이 코드를 Remix 컴포넌트 위에 추가하세요.
버킷 연결하기
이제 버킷을 Remix 앱에 연결해 보겠습니다.
new sst.aws.Remix("MyWeb", { link: [bucket],});3. 업로드 폼 만들기
app/routes/_index.tsx에 업로드 폼 클라이언트를 추가합니다. Index 컴포넌트를 다음 코드로 교체하세요:
export default function Index() { const data = useLoaderData<typeof loader>(); return ( <div className="flex h-screen items-center justify-center"> <div className="flex flex-col items-center gap-8"> <h1 className="leading text-2xl font-bold text-gray-800 dark:text-gray-100"> Welcome to Remix </h1> <form className="flex flex-row gap-4" onSubmit={async (e) => { e.preventDefault();
const file = (e.target as HTMLFormElement).file.files?.[0]!;
const image = await fetch(data.url, { body: file, method: "PUT", headers: { "Content-Type": file.type, "Content-Disposition": `attachment; filename="${file.name}"`, }, });
window.location.href = image.url.split("?")[0]; }} > <input name="file" type="file" accept="image/png, image/jpeg" className="block w-full text-sm text-slate-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-violet-50 file:text-violet-700 hover:file:bg-violet-100" /> <button className="bg-violet-500 hover:bg-violet-700 text-white text-sm font-semibold py-2 px-4 rounded-full"> Upload </button> </form> </div> </div> );}4. 사전 서명된 URL 생성하기
앱이 로드될 때 파일 업로드를 위한 사전 서명된 URL을 생성하고 폼에서 사용합니다.
app/routes/_index.tsx 파일의 Index 컴포넌트 위에 다음 코드를 추가합니다.
export async function loader() { const command = new PutObjectCommand({ Key: crypto.randomUUID(), Bucket: Resource.MyBucket.name, }); const url = await getSignedUrl(new S3Client({}), command);
return { url };}필요한 import 문을 추가합니다.
import { Resource } from "sst";import { useLoaderData } from "@remix-run/react";import { getSignedUrl } from "@aws-sdk/s3-request-presigner";import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";그리고 npm 패키지를 설치합니다.
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner브라우저에서 로컬 Remix 앱(http://localhost:5173)으로 이동하여 이미지를 업로드해 보세요. 이미지가 업로드되고 다운로드되는 것을 확인할 수 있습니다.

5. 앱 배포하기
이제 여러분의 앱을 AWS에 배포해 보겠습니다.
npx sst deploy --stage production여기서는 어떤 스테이지 이름을 사용해도 되지만, 프로덕션을 위해 새로운 스테이지를 만드는 것이 좋습니다.
축하합니다! 이제 여러분의 사이트가 라이브 상태가 되었습니다!
컨테이너
이번에는 Remix 앱을 만들고, 파일 업로드를 위한 S3 버킷을 추가한 후, Cluster 컴포넌트를 사용해 컨테이너에 배포해 보겠습니다.
시작하기 전에 AWS 자격 증명을 설정해야 합니다.
1. 프로젝트 생성하기
먼저 앱을 만들어 보겠습니다.
npx create-remix@latest aws-remix-containercd aws-remix-container모든 기본 옵션을 선택합니다.
Init SST_fhQu7Z5f9DSet4jkhu9f9f
이제 앱에서 SST를 초기화해 보겠습니다.
npx sst@latest init기본값을 선택하고 AWS를 선택합니다. 이렇게 하면 프로젝트 루트에 sst.config.ts 파일이 생성됩니다.
2. 서비스 추가하기
컨테이너에 Remix 앱을 배포하기 위해 AWS Fargate와 Amazon ECS를 사용합니다. sst.config.ts 파일의 run 함수를 다음과 같이 수정합니다.
async run() { const vpc = new sst.aws.Vpc("MyVpc"); const cluster = new sst.aws.Cluster("MyCluster", { vpc });
cluster.addService("MyService", { loadBalancer: { ports: [{ listen: "80/http", forward: "3000/http" }], }, dev: { command: "npm run dev", }, });}이 코드는 VPC와 Fargate 서비스가 포함된 ECS 클러스터를 생성합니다.
dev.command는 SST에게 개발 모드에서 Remix 앱을 로컬에서 실행하도록 지시합니다.
개발 모드 시작
개발 모드를 시작하려면 다음 명령어를 실행하세요. 이 명령어는 SST와 여러분의 Remix 앱을 시작합니다.
npx sst dev실행이 완료되면 사이드바에서 MyService를 클릭하고 브라우저에서 Remix 앱을 열어보세요.
3. S3 버킷 추가하기
파일 업로드를 위해 S3 버킷에 공개 access를 허용해 보겠습니다. sst.config.ts 파일을 업데이트하세요.
const bucket = new sst.aws.Bucket("MyBucket", { access: "public"});이 코드를 Vpc 컴포넌트 아래에 추가하세요.
Link the bucket_NNJ4xTrozAqG7pACAw5SYj
이제 버킷을 컨테이너에 연결합니다.
cluster.addService("MyService", { // ... link: [bucket],});이렇게 하면 Remix 앱에서 버킷을 참조할 수 있습니다.
4. 업로드 폼 만들기
app/routes/_index.tsx에 업로드 폼 클라이언트를 추가합니다. Index 컴포넌트를 다음 코드로 교체하세요:
export default function Index() { const data = useLoaderData<typeof loader>(); return ( <div className="flex h-screen items-center justify-center"> <div className="flex flex-col items-center gap-8"> <h1 className="leading text-2xl font-bold text-gray-800 dark:text-gray-100"> Welcome to Remix </h1> <form className="flex flex-row gap-4" onSubmit={async (e) => { e.preventDefault();
const file = (e.target as HTMLFormElement).file.files?.[0]!;
const image = await fetch(data.url, { body: file, method: "PUT", headers: { "Content-Type": file.type, "Content-Disposition": `attachment; filename="${file.name}"`, }, });
window.location.href = image.url.split("?")[0]; }} > <input name="file" type="file" accept="image/png, image/jpeg" className="block w-full text-sm text-slate-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-violet-50 file:text-violet-700 hover:file:bg-violet-100" /> <button className="bg-violet-500 hover:bg-violet-700 text-white text-sm font-semibold py-2 px-4 rounded-full"> Upload </button> </form> </div> </div> );}5. 사전 서명된 URL 생성하기
앱이 로드될 때 파일 업로드를 위한 사전 서명된 URL을 생성하고 폼에서 사용합니다.
app/routes/_index.tsx 파일의 Index 컴포넌트 위에 다음 코드를 추가합니다.
export async function loader() { const command = new PutObjectCommand({ Key: crypto.randomUUID(), Bucket: Resource.MyBucket.name, }); const url = await getSignedUrl(new S3Client({}), command);
return { url };}필요한 import를 추가합니다.
import { Resource } from "sst";import { useLoaderData } from "@remix-run/react";import { getSignedUrl } from "@aws-sdk/s3-request-presigner";import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";그리고 npm 패키지를 설치합니다.
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner브라우저에서 로컬 Remix 앱(http://localhost:5173)으로 이동해 이미지를 업로드해 보세요. 이미지가 업로드되고 다운로드되는 것을 확인할 수 있습니다.

6. 앱 배포하기
앱을 배포하기 위해 Dockerfile을 추가합니다.
FROM node:lts-alpine as baseENV NODE_ENV production
# Stage 1: 모든 node_modules 설치 (개발 의존성 포함)FROM base as depsWORKDIR /myappADD package.json ./RUN npm install --include=dev
# Stage 2: 프로덕션 node_modules 설정FROM base as production-depsWORKDIR /myappCOPY --from=deps /myapp/node_modules /myapp/node_modulesADD package.json ./RUN npm prune --omit=dev
# Stage 3: 앱 빌드FROM base as buildWORKDIR /myappCOPY --from=deps /myapp/node_modules /myapp/node_modulesADD . .RUN npm run build
# Stage 4: 프로덕션 이미지 빌드FROM baseWORKDIR /myappCOPY --from=production-deps /myapp/node_modules /myapp/node_modulesCOPY --from=build /myapp/build /myapp/buildCOPY --from=build /myapp/public /myapp/publicADD . .
CMD ["npm", "start"]이렇게 하면 Remix 앱이 Docker 이미지로 빌드됩니다.
또한 루트 디렉토리에 .dockerignore 파일을 추가합니다.
node_modules.cachebuildpublic/build이제 Docker 이미지를 빌드하고 배포하려면 다음 명령어를 실행합니다:
npx sst deploy --stage production여기서는 어떤 스테이지 이름을 사용해도 되지만, 프로덕션용으로 새로운 스테이지를 만드는 것이 좋습니다.
축하합니다! 이제 앱이 배포되었습니다!
콘솔 연결하기
다음 단계로 SST 콘솔을 설정하여 앱을 _git push로 배포_하고 로그를 확인할 수 있습니다.

무료 계정을 생성하고 AWS 계정에 연결할 수 있습니다.