AWS EC2 프리티어 환경에서 Next.js 프로젝트를 배포하면서 겪었던 문제들과 해결 과정을 정리해 봅니다. 특히 메모리 부족 문제와 Standalone 모드, 그리고 Nginx/DNS 연결 이슈를 중점적으로 다룹니다.
환경: AWS EC2 (Ubuntu 24.04, t3.micro 프리티어)
스택: Next.js 16 (App Router), PM2, Nginx, Let's Encrypt, Route53, 가비아 도메인
목표: Github Actions로 자동 배포 파이프라인 구축 및 도메인(https) 연결
pnpm run build → PM2 → Nginx 리버스프록시 → 도메인 연결
프리티어(t3.micro)의 RAM은 고작 1GB인데
pnpm build만 돌리면 서버가 멈춰버리는 현상이 발생했습니다. (SSH 타임아웃)
RAM이 부족할 때 HDD를 RAM처럼 쓰는 스왑 메모리를 설정해서 해결했습니다.
# 2GB 스왑 파일 생성
sudo dd if=/dev/zero of=/swapfile bs=128M count=16
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 재부팅해도 유지되도록 /etc/fstab에 추가
echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab
기본 빌드는 node_modules 전체가 필요해서 무거워서 실행에 필요한 파일만 추려내는 Standalone 모드를 적용하기로 했습니다.
const nextConfig: NextConfig = {
output: "standalone", // 이 한 줄이 핵심!
reactCompiler: true,
};
module.exports = {
apps: [{
name: "aws-practice",
script: "node", // next start 아님!
args: ".next/standalone/server.js",
env: {
NODE_ENV: "production",
PORT: 3000,
HOSTNAME: "0.0.0.0"
}
}]
}
⚠️ 주의할 점
Standalone 모드는 정적 파일(public, static)을 자동으로 복사하지 않기 때문에 배포 스크립트에서 수동으로 복사해줘야 이미지와 스타일이 안 깨진다.
Nginx 설정을 잘 했는데도 무한로딩이 되며 접속이 안 되고 에러 로그에 connect() failed (111: Connection refused)가 떴습니다.
sudo tail /var/log/nginx/error.log
# 2026/02/03 14:24:36 [error] connect() failed (111: Connection refused)
# while connecting to upstream, upstream: "http://127.0.0.1:3000/"
디버깅을 해보고자 아래 명령어로 로컬에 접근했지만 Next.js의 문제가 아니었습니다.
curl http://127.0.0.1:3000
알고 보니 EC2를 재부팅하면서 IP 주소가 바뀌었는데, 도메인(DNS)은 옛날 IP를 가리키고 있어 발생하는 문제였습니다.
AWS EC2 콘솔에서 '탄력적 IP'를 할당받아 인스턴스에 연결하고
Route 53에서 A 레코드 값을 새 IP로 수정했습니다.
Github Actions 배포 스크립트(deploy.yml)의 host 주소도 새 IP로 변경했습니다.
# .github/workflows/deploy.yml
- name: Deploy to EC2
run: |
ssh -i key.pem ubuntu@43.xxx.xxx.xxx << 'EOF'
cd ~/aws-practice
git pull origin main
pnpm install
pnpm build
# Standalone 필수: 정적 파일 복사
cp -r public .next/standalone/
cp -r .next/static .next/standalone/.next/
# PM2 재시작
pm2 restart aws-practice
EOF
프리티어는 용량이 적기에 스왑 메모리가 필수다! (안 그러면 빌드 못함)
Standalone 모드는 가볍고 좋지만, 정적 파일 복사(cp)를 잊으면 안 된다.
EC2 IP는 재부팅 시 변하므로 도메인을 연결할 거면 처음부터 탄력적 IP를 할당하고 시작하자!