배포하기에 앞서
1. AWS 라면 EC2 가 제일 유명하지만...
EC2는 가상 서버(인스턴스)를 빌리는 상품으로, 숙련자라면 커스터마이징이 가능하고 빠르기 때문에
EC2를 사용하는 것이 맞지만 편하고 쉽게 배포하려면 AWS의 Elastic Beanstalk 을 사용하는 것을 추천
2. AWS 의 Elastic Beanstalk 이란
코드만 올리면 알아서 EC2 인스턴스 빌리고 npm install 한 뒤 npm run start 까지 실행해주며,
무료로 도메인 연결과 24시간 서버 구동이 가능한 상품이다.
유저가 훗날 많아지면 확장도 쉬워지고 버전관리도 가능하다고 한다. 그러므로 사용자는 코드에 집중하면 되는 것
구글 클라우드에 App Engine 이라는 상품도 비슷한 역할을 해준다고 한다.
3. Vercel
Next.js 는 Vercel이 만들고 관리했기 때문에 Vercel 에서 배포가 매우 쉽다고 한다.
Github repo 에 코드를 올릴 때마다 자동으로 Elastic Beanstalk 과 유사하게 배포해준다고 한다.
그리고 월 100gb 트래픽까지 무료계정으로 가능하므로 포트폴리오용으로 편리하고 좋다고 한다. (다만 서버에 하드디스크가 없음)
배포 전 체크사항
배포해줄 가상 서버에도 mongodb에 접속을 해야 데이터를 꺼낼 수 있다.
즉, 몽고DB의 Network access 메뉴에서 접속 가능 IP를 0.0.0.0 으로 바꿔준다.
혹 보안을 높이고 싶다면 AWS VPC 로 mongodb atlas 연결하면 된다고 한다.
배포 순서
- 빌드 - npm run build
- zip 압축 - 프로젝트 폴더 안에 있는 파일들(node_modules 폴더 제외) 특히 .next 폴더를 포함한 내용을 압축
- AWS 접속 후 서울 리전으로
- IAM 역할(aws-elasticbeanstalk-ec2-role) 만들기 - elastic beanstalk ec2 를 마음대로 사용할 수 있는 계정
- 설정 (버그 때문에 자동으로 안되는 경우)
- 신뢰할 수 있는 엔터티 AWS 서비스, 사용례는 EC2
- 권한 추가 메뉴에선 AWSElasticBeanstalkWebTier, AWSElasticBeanstalkWorkerTier, AWSElasticBeanstalkMulticontainerDocker 선택
- Elastic Beanstalk 시작하기
- 플랫폼 : nodejs 18버전
- 프리셋 : 단일 인스턴스
- 버전레이블 : version 1.0
- 로컬파일에 위에서 만든 zip 압축 파일 넣어줌
- 기존 서비스 역할 사용 > aws-elasticbeanstalk-service-role
- EC2 인스턴스 프로파일 > aws-elasticbeanstalk-ec2-role
- t2.micro
- 도메인 접속 - 배포 완료
배포는 됐지만 로그인/회원가입이 안된다면
Nextauth 와 소셜로그인 세팅을 변경해줘야 한다.
원래 OAuth 용 앱 만들었던건 개발용 url, 즉 localhost:3000 에 가능한 것이므로 위에서 할당 받은 도메인 주소로 바꿔줘야 한다.
처음부터 새로운 OAuth 앱을 만들어서 개발용과 배포용 두개씩 만들어 놓으면 편하다.
다음은 NEXTAUTH_URL 환경 변수도 설정해줘야 한다.
NEXTAUTH_URL = 배포한 사이트 주소 를 .env 에 추가해줘야 하는데, 재배포 시 다시 위의 소스코드zip 을 올려야하므로
AWS CloudShell(AWS 사이트 왼쪽 하단)에 접속하여
eb use 환경이름 // Elastic Beanstalk 에 접속하여 환경 탭으로 접속하면 확인 가능
eb setenv NEXTAUTH_URL=배포한사이트주소
처럼 써주면 됨. 다만 버그가 많아서 안될 가능성이 크므로 소스파일 zip 을 지향
사이트 업데이트 시
업로드 및 배포 버튼 눌러서 또 zip 파일로 묶어서 업로드하면 되지만 요금이 나올 수 있음
이미지 업로드
AWS S3
AWS 를 가입하면 S3가 1년간 무료로 5gb 만큼 이용 가능
AWS S3보다 쉽게 사용하려면 firebase 를 이용한다.(평생 5gb 무료)
- S3 접속
- 버킷 만들기 - 버킷은 저장공간과 동일한 의미
- 버킷의 퍼블릭 액세스 차단 설정은 개발 시에는 아래처럼
4. 버킷의 보안을 높이고자 하면, 버킷 > 권한 > 버킷 정책 편집으로 관리자와 일반유저의 권한을 정의해준다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::버킷명/*"
},
{
"Sid": "2",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AWS계정ID:root"
},
"Action": [
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::버킷명/*"
}
]
}
- 자료 읽기 - s3:GetObject
- 쓰기 - s3:PutObject
- 삭제 - s3:DeleteObject
5. CORS 설정
버킷 안의 파일들을 읽기,쓰기,삭제할 수 있는지 CORS 설정하는 부분
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"PUT",
"POST"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"ETag"
]
}
]
6. Access 키 발급
액세스 키와 비밀 키 2개 세트를 코딩할 때 사용
7. 업로드할 이미지를 고르면 미리볼 수 있게끔 처리
Presigned URL
브라우저에서 서버를 거치지 않고 직접 S3에 업로드가 가능(서버 부하⬇️)
- input 태그에 이미지를 고르는 순간 서버에 GET 요청
- 서버는 유효한 요청인지 확인하고 Presigned url 을 만들어서 유저 브라우저로 응답
- 브라우저에선 presigned url 을 이용하여 S3로 POST 요청해서 이미지를 보냄
- 업로드 성공 시 해당 url 을 img 태그에 넣어 업로드된걸로 보여줌
프론트측에서 file 을 입력 받으면 e.target.files[0] 에 업로드시킨 파일이 들어간다.
파일의 이름으로 encodeURIComponent() 함수를 사용하여 파일명을 분리시키고 /api/post/image url에 파일명을 쿼리스트링으로 보내준다.
<input type="file" accept="image/*" onChange={
async (e)=>{
let file = e.target.files[0]
let filename = encodeURIComponent(file.name)
let res = await fetch('/api/post/image?file=' + filename)
res = await res.json()
}
} />
<img />
서버에서 presigned url 발급해서 보내주기
먼저 npm install aws-sdk 를 설치하여 AWS를 다룰 수 있는 라이브러리를 설치한다.
aws.config.update 안에 정보를 채워줘야 한다.
import aws from 'aws-sdk'
export default async function handler(request, response){
aws.config.update({
accessKeyId: process.env.REACT_APP_ACCESS_KEY,
secretAccessKey: process.env.REACT_APP_SECRET_KEY,
region: 'ap-northeast-2',
signatureVersion: 'v4',
})
const s3 = new aws.S3();
const url = await s3.createPresignedPost({
Bucket: process.env.REACT_APP_BUCKET_NAME,
Fields: { key : request.query.file },
Expires: 60, // seconds
Conditions: [
['content-length-range', 0, 1048576], //파일용량 1MB 까지 제한
],
})
response.status(200).json(url)
}
- aws-sdk 로 S3() 를 new 해준다음, createPresignedPost() 메서드를 사용해주면 PresignedURL 을 발급받을 수 있다.
- Fields 에 들어가는 key는 유저가 보낸 쿼리스트링의 파일명을 넣어주면 된다.
- 그밖에 업로드 가능한 용량(content-length-range)과 제한시간(Expries) 설정도 가능
.env에는 위에 사용한 값을 넣어주고
REACT_APP_ACCESS_KEY=액세스키
REACT_APP_SECRET_KEY=액세스키비번
REACT_APP_BUCKET_NAME=버킷명
'use client'
import { useState } from "react";
export default function Write(){
let [src, setSrc] = useState('')
return (
<div className="p-20">
<h4>글작성</h4>
<form action="/api/post/new" method="POST">
<input name="title" placeholder="글제목"/>
<input name="content" placeholder="글내용"/>
<button type="submit">전송</button>
</form>
<input type="file" accept="image/*" onChange={
async (e) => {
let file = e.target.files[0]
let filename = encodeURIComponent(file.name)
let res = await fetch('/api/post/image?file=' + filename)
res = await res.json()
//S3 업로드
const formData = new FormData()
Object.entries({ ...res.fields, file }).forEach(([key, value]) => {
formData.append(key, value)
})
let result = await fetch(res.url, {
method: 'POST',
body: formData,
})
console.log(result)
if (result.ok) {
setSrc(result.url + '/' + filename)
} else {
console.log('실패')
}
}
} />
<img src={src} />
</div>
)
}
위처럼 받아준 res 값을 활용하여 S3에 업로드 해준다.
이때 form 태그 대신, new FormData() 를 사용해주고 데이터를 넣어줄 수도 있다.
result url 뒤에 파일이름을 붙여주면 업로드된 이미지의 경로가 되므로 해당 경로를 img src에 넣어주면 된다. (useState 로 관리)
AWS 사용을 간단하게 해보았다..😂
'Web Study > Next.js' 카테고리의 다른 글
코딩애플 - 마지막 Next.js ... Middleware (0) | 2023.07.09 |
---|---|
코딩 애플 - Dark mode 만들기 (0) | 2023.07.07 |
코딩애플 - 예외적인 페이지들 (0) | 2023.07.04 |
코딩 애플 - 댓글 (0) | 2023.07.03 |
코딩애플 - 로그인 / 회원기능 (0) | 2023.07.02 |