Next(SSR) 어디에 어떻게 배포하는 게 좋을까?
회사에서 대외 홍보용 웹사이트가 필요해서
랜딩페이지가 필요한 상황이었다.
Next13 App Router버전 SSR방식이 적용된 프로젝트
배포과정에서 겪은 이슈를 공유하고자 한다.
우선 기존 배포방식 에서
다른 배포방식을 고려한 2가지 이유가 있었다.
Next.js 프레임워크의 전환으로 인한 호스팅 환경 전환 필요
기존 클라이언트 Web Application은
S3에 정적웹호스팅 되어있고,
AWS Cloudfront로 캐싱을 적용해
서비스를 제공하고 있다.
새로운 next프로젝트를 기존과 같이
S3에 배포하면 빌드된 파일이기 때문에
동적으로 구성되는 SSR이 적용되지 않는다.
Image optimization
넥스트에서 제공하는 이미지컴포넌트는
다양한 성능최적화 기능을 제공하는데
로컬이미지의 경우 파일포맷변환, 이미지 리사이징과 같은 웹사이트 최적화가 가능하고,
리모트이미지도 크기를 지정하고 config에 도메인만 추가하면 최적화 적용가능하다.
이미지 최적화를 직접 구현하려면????
이미지 리사이즈를 파일서버로 운영 중인 s3를 통해 직접 구현하려면 2가지 방법이 있다.
1. 직접 이미지를 저장하고 불러오기 :
업로드 시 자주 사용하는 규격을 정의해 완료된 이미지를 저장하고 클라이언트 요청쿼리값에 따라 처리

2. 이미지 요청시점에 리사이징 해서 캐시로 전송(클라우드프런트)
1) 이미지 요청하면 있을 때 cloudfront functions을 이용해서 요청한 쿼리값(너비, 높이등)을 확인.
2) 현재 캐시 되어있는 이미지가 동일한 규격일경우 그대로 제공.
2-1) 요청한 사진과 캐시 되어있는 사진의 크기가 다르고 s3에 업로드되어있지 않은 크기일경우 람다트리거를 통해 이미지 리사이즈해서 s3에 저장후 캐시제공.
2-2) 요청한 사진과 캐시되어있는 사진의 크기가 다르지만 s3에 업로드되어있는 경우 그대로 제공

1. Amplify 웹 호스팅
Amplify 호스팅은
완전관리형 CI/CD 및 호스팅 서비스로 SSR이 가능하며
Remote branch와 연결하면 CI/CD Pipeline이 가능하다.
이번 설계 구조는 다음과 같다.
배포를 위해 Next 친화적인 vercel을 고려했으나,
aws의존도가 높은 현재 구조상
amplify에서 vercel로 옮길 이유가 크지 않았다.
큰 트래픽을 기대하는 사이트도 아니어서
비용부담 없이 amplify로 결정했다.
구조는 아래와 같다.
amplify app에 새로운 프로젝트를 배포하고
원격저장소와 연결해 commit 할 때마다
자동으로 배포되도록 연동해 두었다.
배포될 때 email을 AWS SNS서비스연동하여
이메일을 트리거로 Lambda를 실행시켜
Slack에 배포 status 메시지를 전송하여
개발팀이 배포상황을 트래킹 할 수 있도록 설계했다.
Amplify App 생성
➜ amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project 프로젝트명
The following configuration will be applied:
Project information
| Name: 프로젝트이름
| Environment: dev //배포환경
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: react
| Source Directory Path: src
| Distribution Directory Path: .next //ssr을 적용하려면 .next를 적용해야함
| Build Command: npm run-script build
| Start Command: npm run-script start
? Initialize the project with the above configuration? Yes
Using default provider awscloudformation
? Select the authentication method you want to use: AWS profile
For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
? Please choose the profile you want to use 액세스키와시크릿키가 저장된 사용하려는 프로필
Adding backend environment dev to AWS Amplify app: dlpiythpvdnvl
⠇ Initializing project in the cloud...
CREATE_IN_PROGRESS amplify-asiaukdev2023-dev-151237 AWS::CloudFormation::Stack Mon May 08 2023 15:12:38 GMT+0900 (GMT+09:00) User Initiated
CREATE_IN_PROGRESS UnauthRole AWS::IAM::Role Mon May 08 2023 15:12:41 GMT+0900 (GMT+09:00)
CREATE_IN_PROGRESS DeploymentBucket AWS::S3::Bucket Mon May 08 2023 15:12:41 GMT+0900 (GMT+09:00)
CREATE_IN_PROGRESS DeploymentBucketBlockHTTP AWS::S3::BucketPolicy Mon May 08 2023 15:12:41 GMT+0900 (GMT+09:00)
CREATE_IN_PROGRESS AuthRole AWS::IAM::Role Mon May 08 2023 15:12:41 GMT+0900 (GMT+09:00)
CREATE_IN_PROGRESS AuthRole AWS::IAM::Role Mon May 08 2023 15:12:42 GMT+0900 (GMT+09:00) Resource creation Initiated
CREATE_IN_PROGRESS UnauthRole AWS::IAM::Role Mon May 08 2023 15:12:43 GMT+0900 (GMT+09:00) Resource creation Initiated
CREATE_IN_PROGRESS DeploymentBucket AWS::S3::Bucket Mon May 08 2023 15:12:43 GMT+0900 (GMT+09:00) Resource creation Initiated
⠋ Initializing project in the cloud...
CREATE_IN_PROGRESS DeploymentBucketBlockHTTP AWS::S3::BucketPolicy Mon May 08 2023 15:12:47 GMT+0900 (GMT+09:00) Resource creation Initiated
CREATE_COMPLETE DeploymentBucketBlockHTTP AWS::S3::BucketPolicy Mon May 08 2023 15:12:48 GMT+0900 (GMT+09:00)
⠇ Initializing project in the cloud...
CREATE_COMPLETE DeploymentBucket AWS::S3::Bucket Mon May 08 2023 15:13:04 GMT+0900 (GMT+09:00)
CREATE_COMPLETE AuthRole AWS::IAM::Role Mon May 08 2023 15:13:06 GMT+0900 (GMT+09:00)
CREATE_COMPLETE UnauthRole AWS::IAM::Role Mon May 08 2023 15:13:06 GMT+0900 (GMT+09:00)
⠧ Initializing project in the cloud...
CREATE_COMPLETE amplify-asiaukdev2023-dev-151237 AWS::CloudFormation::Stack Mon May 08 2023 15:13:08 GMT+0900 (GMT+09:00)
✔ Successfully created initial AWS cloud resources for deployments.
✔ Help improve Amplify CLI by sharing non sensitive configurations on failures (y/N) · no
✔ Initialized provider successfully.
✅ Initialized your environment successfully.
Your project has been successfully initialized and connected to the cloud!
Some next steps:
"amplify status" will show you what you've added already and if it's locally configured or deployed
"amplify add <category>" will allow you to add features like user login or a backend API
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify console" to open the Amplify Console and view your project status
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
Pro tip:
Try "amplify add api" to create a backend API and then "amplify push" to deploy everything
App 생성 완료
위의 생성과정을 거치고 나면 정상적으로 amplify app이 생성된다.
원하는 저장소 선택(bitbucket)
- Amplify는 commit 될 때마다 저장소의 소스코드를 빌드하여 다시 배포하는 구조로 원격저장소를 연결을 통해 ci/cd가 가능하다.
- 우린 Bitbucket을 사용 중이어서 Bitbucket으로 진행했다.
- connect를 진행할 경우 Bitbucket 로그인 리다이렉트가 완료되고, 연결된 계정에 활성화된 저장소가 나열된다.
활성화된 저장소 선택 후 연결
- 로그인한 유저의 권한에 따라 접근권한 활성화 여부가 달라진다.
- 자동배포를 원한다면 배포하려는 Reomote repo의 로그인유저가 관리자권한이 있어야 한다.
- bitbucket기준 관리자 권한부여방법 : Project Console > Repository settings > Repository permissions > Add user or groups에서 권한변경
배포 관련 권한설정
배포가 가능하도록 Role을 생성해서 부여해야 하는데 IAM Role생성 > Amplify Deploy 권한이 필요하다.
배포완료
임시도메인 발급으로 배포된 것을 확인할 수 있다.
이제 원하는 도메인으로 매핑해야 한다.
2. 도메인추가
DNS서비스를 Route53을 사용 중이다.
amplify가 배포한 도메인에 대해 SSL인증서를 생성해서 설정하고
새롭게 추가하려는 도메인을 연결하도록 설정한다.
사용하려는 도메인 추가
AWS Amplify> App Settings > Domain management
추가하고자 할 Domain 입력
AWS계정 내에 Route53에 도메인이 등록이 되어있는 경우 드롭다운으로 활성화됨
SSL 생성 > SSL 구성
DNS records를 참고하여 Route53에 Record생성해야 함
우측상단에 View DNS records > Https 검증과 DNS provider를 각각 Route53에 Record로 생성한다.
amplify로 호스팅 할 경우 자동으로 cloudfront가 적용되어 있다.
Route53 Records 생성
amplify호스팅 된 cloudfront주소를 Route53 record로 등록한다.
About Record type
- A Record (IPv4 Address):
- 도메인 이름을 IPv4 주소에 매핑하는 레코드.
- 웹사이트의 도메인 이름을 웹 서버의 IP 주소와 연결할 때 사용.
- AAAA Record (IPv6 Address):
- 도메인 이름을 IPv6 주소에 매핑하는 레코드.
- IPv6 주소 체계를 사용하는 환경에서 사용.
- CNAME Record (Canonical Name):
- 도메인 이름을 다른 도메인 이름에 매핑하는 레코드
- 주로 서브도메인이나 별칭에 사용되며, 도메인의 다른 이름으로 리소스에 액세스할 수 있게 함.
- MX Record (Mail Exchange):
- 이메일을 처리하는 메일 서버의 정보를 지정하는 레코드.
- 이메일을 수신하는 메일 서버를 지정하여 도메인의 이메일 전달을 관리.
- TXT Record (Text):
- 도메인에 대한 추가 정보를 저장하는 텍스트 정보를 포함하는 레코드
- 주로 SPF (Sender Policy Framework) 등과 같은 이메일 인증을 위해 사용.
- NS Record (Name Server):
- 도메인의 네임서버를 지정하는 레코드.
- 도메인을 관리하는 네임서버의 정보를 포함.
레코드까지 생성하고 나면 도메인이 활성화되기까지 약 30분 이내의 시간이 소요됨
배포완료
3. 슬랙(Slack) 웹훅연동
배포가 잘 진행되는지 배포과정을 확인하고 싶다.
이제 SSR을 위해 기존 s3정적 웹사이트 배포에서
amplify 호스팅으로 이전작업을 진행했다
프로젝트의 원격 저장소와 연결되어
자동으로 클라이언트에 배포되는
파이프라인이 구축되었다.
하지만
직접 AWS Amplify Deploy Log를 확인하는 것 외에는
배포의 과정 및 결과를 확인하기 힘들다.
이 문제점을 해결하고자
사내협업툴로 활용 중인 슬랙에
로그를 확인할 수 있도록 추가로 작업진행했다.
진행순서
Amplify는 기본 알림 시스템만 제공할 뿐 슬랙의 채널로 전송할 수는 없으므로 다음과 같은 단계로 진행했다.
- SNS Topic 생성
- Slack Webhook 생성
- lambda 트리거 연결 및 실행
SNS Topic 생성
Amazon SNS는 A2A 및 A2P 메시징을 위한 완전관리형 게시/구독 서비스로 다른 서비스 간의 연계가 가능하다
amplify에서 알림을 받고자 하는 앱을 선택 후 Notification으로 이동
알림을 받고자 하는 메일 입력
메인 인증 완료되면 알림 설정이 완료된다.
SNS topic이 세팅이 될 경우 메일이 발송될 때마다 catch 할 수 있는 이벤트가 생성
이를 통해 AWS Lambda와 연결하여 원하는 로직으로 설계가 가능함.
슬랙 웹훅 WebHook 세팅
Incoming Webhook이란?
- Slack에 Slack이 정한 포맷에 일치하는 데이터를 보내주면, 지정된 채널에 메시지를 보내주는 기능
- Slack에 원하는 메시지를 보내기 위해 Slack에 웹훅을 연동필요
웹훅설정
Slack Incoming Webhook(인커밍웹훅) 설정에는 2가지 방법 존재
- 직접 앱생성( https://api.slack.com에서 시작 )
- 해당채널 > 앱 추가 > Incoming WebHooks 추가
앱 추가 방식은 해당 웹훅을 만든 사용자에 의존적이므로, 생성자가 퇴사(Disable)할 경우,
웹훅 URL도 비활성화되는 문제가 생길 수 있으므로, 슬랙에서도 앱 생성 방식으로 진행하기를 권고합니다.
Slack App 생성
1. https://api.slack.com 접속 > Your apps > Create your first app
Slack은 생산성 플랫폼입니다
Slack은 팀과 커뮤니케이션할 수 있는 새로운 방법입니다. 이메일보다 빠르고, 더 조직적이며, 훨씬 안전합니다.
slack.com
2. From scratch > 앱이름(소문자와 '-'로 구성)과 슬랙 워크스페이스 선택 > Create App
3. Collaborators > 동료 또는 또는 절대 삭제 안 되는 공용계정 추가 <- 이래야 퇴사자 발생 시 방어됩니다.
4. Incoming Webhooks 선택 > On > Add New Webhook to Workspace > 채널 선택 > 허용
5. Incoming Webhooks 선택 > Webhook URL 값 확인
6. 메시지전송테스트
`curl -X POST --data-urlencode "payload={\"channel\": \"#z-incoming-webhook\", \"username\": \"webhookbot\", \"text\": \"This is posted to #z-incoming-webhook and comes from a bot named webhookbot.\", \"icon_emoji\": \":ghost:\"}" <WebHook URL>`
슬랙의 웹훅과 채널이 연동되었으니 이제 원하는 메시지가 작성되도록 람다를 작성해 보자.
4. 람다(AWS Lambda) 생성
람다 기본생성(Node@16)
람다 코드
기본로직은
deploy가 시작되면 amplify는
Notification에 등록한 이메일을 발송하는데
이전 단계에서 설정한
SNS Topic이 트리거 되면
람다가 동작한다.
event에 필요한 부분을 parsing 해서
슬랙이 원하는 형태로 변환하고
웹훅을 실행하는 단순한 코드이다.
파라미터의 attachment부분은 원하는 입맛대로 수정하면 된다.
https://api.slack.com/reference/messaging/attachments
Reference: Secondary message attachments
Another way to attach content to messages is the old attachments system. We prefer Block Kit now.
api.slack.com
const webhookUrl =
process.env.webhook_url
const https = require('https');
const stage = process.env.stage;
function postRequest(data) {
return new Promise((resolve, reject) => {
const url = new URL(webhookUrl);
const options = {
host: url.hostname,
path: url.pathname,
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
};
//이벤트 웹훅으로 전송
const req = https.request(options, (res) => {
resolve(JSON.stringify(res.statusCode));
});
// handle the possible errors
req.on('error', (e) => {
reject(e.message);
});
//do the request
req.write(JSON.stringify(data));
//finish the request
req.end();
});
}
exports.handler = async (event) => {
console.log(`DEPLOY_STAGE ::, [${stage}]`);
console.log('DEPLOY_SNS_EVENT INFO ::', event.Records[0].Sns, stage);
const snsMessage = event.Records[0].Sns.Message;
const message = snsMessage.slice(1, -1);
const timestamp = new Date(event.Records[0].Sns.Timestamp).getTime() / 1000;
const color = message.includes('FAILED')
? 'danger'
: message.includes('SUCCEED')
? 'good'
: 'info';
const slackMessage = {
attachments: [
{
pretext: `Deploy Stage: [${stage.toUpperCase()}]`,
color,
text: message,
ts: timestamp,
},
],
};
try {
await postRequest(slackMessage);
console.log(`Successfully sent Slack message: ${message}`);
} catch (err) {
console.error(`Failed to send Slack message: ${err}`);
}
};
트리거 연결
람다의 트리거 부분을 앞서 설정했던 sns topic으로 설정한다.
각 Stage별 재배포로 슬랙 확인
amplify에서 다시 배포를 시도하고 slack의 메시지를 확인하면 된다.
참고자료
https://docs.aws.amazon.com/ko_kr/amplify/latest/userguide/server-side-rendering-amplify.html
Amplify 호스팅을 사용하여 서버 측 렌더링 앱 배포 - AWS Amplify호스팅
이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.
docs.aws.amazon.com
https://docs.amplify.aws/guides/hosting/nextjs/q/platform/js/#adding-amplify-hosting
https://docs.amplify.aws/guides/hosting/nextjs/q/platform/js/#adding-amplify-hosting
docs.amplify.aws
How to Send Slack Notifications for AWS Amplify Deployments
Save time and set up Slack notifications for your front-end projects
betterprogramming.pub
https://api.slack.com/messaging/webhooks
Sending messages using Incoming Webhooks
Creating an Incoming Webhook gives you a unique URL to which you send a JSON payload with the message text and some options.
api.slack.com
https://slack.com/apps/A0F7XDUAZ--?tab=more_info
수신 웹후크
> _Please note, this is a legacy custom integration - an outdated way for teams to integrate with Slack. These integrations lack newer features and they will be deprecated and possibly removed in the
slack.com
https://api.slack.com/reference/messaging/attachments
Reference: Secondary message attachments
Another way to attach content to messages is the old attachments system. We prefer Block Kit now.
api.slack.com
'AWS' 카테고리의 다른 글
Next.js 정적 웹사이트 S3 + CloudFront + Route53 (가비아 도메인적용) (0) | 2023.09.08 |
---|---|
SSL/TLS 인증서 자동갱신이 되지 않을때 - AWS ACM, Route53 (0) | 2023.08.17 |
[AWS]DynamoDB Scan vs Query 성능 및 비용테스트 및 DB설계의 중요성 (0) | 2023.02.03 |
[AWS Amplify Studio] - 초스피드 풀스택 서비스 만들기(React) (0) | 2022.06.24 |