🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

CloudFront CDN 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 20. · 6 Views

CloudFront CDN 완벽 가이드

AWS CloudFront를 활용한 콘텐츠 배포 최적화 방법을 실무 관점에서 다룹니다. 배포 생성부터 캐시 설정, HTTPS 적용까지 단계별로 알아봅니다.


목차

  1. CDN이란_무엇인가
  2. CloudFront_배포_생성
  3. 오리진_설정
  4. 캐시_동작_설정
  5. HTTPS_설정
  6. 무효화_처리

1. CDN이란 무엇인가

어느 날 신입 개발자 김개발 씨는 회사 웹사이트가 해외에서 너무 느리다는 고객 불만을 접했습니다. "왜 미국에서 접속하면 이렇게 느린 거죠?" 팀장님이 다가와 말했습니다.

"CDN을 도입할 때가 된 것 같네요."

**CDN(Content Delivery Network)**은 전 세계에 분산된 서버를 통해 사용자에게 콘텐츠를 빠르게 전달하는 시스템입니다. 마치 전국에 물류센터를 두고 가까운 곳에서 배송하는 것처럼, 사용자와 가장 가까운 서버에서 콘텐츠를 제공합니다.

AWS CloudFront는 이러한 CDN 서비스를 제공하는 AWS의 핵심 서비스입니다.

다음 코드를 살펴봅시다.

// CloudFront 배포를 위한 S3 버킷 설정
const s3Config = {
  bucket: 'my-website-bucket',
  region: 'ap-northeast-2'
};

// 사용자 요청 흐름
// 1. 사용자가 example.cloudfront.net 요청
// 2. 가장 가까운 엣지 로케이션으로 라우팅
// 3. 캐시 확인 -> 있으면 즉시 반환
// 4. 없으면 오리진(S3)에서 가져와 캐시 후 반환

console.log('CDN을 통한 응답 시간: 50ms');
console.log('직접 S3 접근 시: 500ms');

김개발 씨는 입사 2개월 차 프론트엔드 개발자입니다. 회사에서 운영하는 쇼핑몰 웹사이트는 한국에서는 빠르게 작동하는데, 해외 고객들로부터 느리다는 불만이 계속 들어왔습니다.

팀장 박시니어 씨가 모니터링 화면을 보여주며 말했습니다. "보세요.

서울에서는 응답 시간이 100ms인데, 뉴욕에서는 1.5초나 걸립니다. 물리적 거리 때문이죠." 그렇다면 CDN이란 정확히 무엇일까요?

쉽게 비유하자면, CDN은 마치 전국에 편의점 체인을 운영하는 것과 같습니다. 서울에 본사 창고가 하나만 있으면 부산 고객은 멀리서 물건을 받아야 하지만, 부산에도 매장이 있다면 바로 근처에서 받을 수 있습니다.

이처럼 CDN도 전 세계 주요 도시에 엣지 로케이션이라는 서버를 두고 콘텐츠를 미리 복사해둡니다. CDN이 없던 시절에는 어땠을까요?

모든 사용자가 하나의 서버에 직접 접속해야 했습니다. 서울에 있는 서버를 미국 사용자가 접속하려면 태평양을 건너는 긴 네트워크 경로를 거쳐야 했죠.

사용자가 많아지면 서버에 부하가 집중되고, 물리적 거리 때문에 응답 속도도 느려졌습니다. 더 큰 문제는 이미지나 비디오 같은 큰 파일을 전송할 때였습니다.

바로 이런 문제를 해결하기 위해 CDN이 등장했습니다. CDN을 사용하면 전 세계 200개 이상의 엣지 로케이션에서 콘텐츠를 제공할 수 있습니다.

사용자는 자동으로 가장 가까운 서버로 연결되어 빠른 속도를 경험합니다. 또한 원본 서버의 부하가 줄어들어 안정성도 높아집니다.

무엇보다 대역폭 비용을 절감할 수 있다는 큰 이점이 있습니다. AWS CloudFront는 Amazon의 글로벌 인프라를 활용한 CDN 서비스입니다.

단순히 정적 파일만 캐싱하는 것이 아니라, 동적 콘텐츠 가속, 실시간 스트리밍, API 응답 캐싱까지 가능합니다. Netflix나 Airbnb 같은 글로벌 서비스들이 CloudFront를 사용하고 있습니다.

위의 코드를 살펴보면 CDN의 작동 원리를 이해할 수 있습니다. 사용자가 웹사이트에 접속하면 CloudFront는 자동으로 가장 가까운 엣지 로케이션으로 요청을 라우팅합니다.

해당 서버에 이미 캐시된 콘텐츠가 있다면 즉시 반환하고, 없다면 오리진 서버(예: S3 버킷)에서 가져와 캐시한 후 사용자에게 전달합니다. 다음 번에 같은 콘텐츠를 요청하면 캐시에서 바로 제공하므로 응답 시간이 획기적으로 빨라집니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 이커머스 웹사이트를 운영한다고 가정해봅시다.

제품 이미지, CSS, JavaScript 파일은 자주 바뀌지 않으므로 CloudFront에 캐싱하면 로딩 속도가 10배 이상 빨라집니다. 실제로 많은 스타트업들이 CloudFront 도입 후 페이지 로딩 시간을 70% 단축했다고 보고합니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 모든 콘텐츠를 무조건 캐싱하려는 것입니다.

사용자별로 다른 내용을 보여줘야 하는 동적 페이지까지 캐싱하면 잘못된 콘텐츠가 표시될 수 있습니다. 따라서 정적 콘텐츠와 동적 콘텐츠를 구분해서 적절한 캐시 정책을 설정해야 합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다.

"아, 그래서 큰 서비스들은 다 CDN을 쓰는 거군요!" CDN의 개념을 제대로 이해하면 글로벌 서비스 구축의 기초를 다질 수 있습니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - 정적 콘텐츠(이미지, CSS, JS)는 반드시 CDN을 통해 제공하세요

  • 사용자 지리적 분포를 분석해 CDN 도입 효과를 측정하세요
  • 캐시 히트율을 모니터링하여 캐시 정책을 최적화하세요

2. CloudFront 배포 생성

CDN의 개념을 이해한 김개발 씨는 이제 실제로 CloudFront를 설정해보기로 했습니다. "처음 설정하는 건데, 어디서부터 시작해야 하나요?" 박시니어 씨가 AWS 콘솔을 열며 답했습니다.

"먼저 배포를 생성해야 합니다."

**CloudFront 배포(Distribution)**는 CDN 서비스의 기본 단위입니다. 배포를 생성하면 고유한 CloudFront 도메인이 발급되고, 이를 통해 전 세계 엣지 로케이션에서 콘텐츠를 제공할 수 있습니다.

웹 배포와 RTMP 배포 두 가지 타입이 있으며, 일반적으로 웹 배포를 사용합니다.

다음 코드를 살펴봅시다.

// AWS SDK를 사용한 CloudFront 배포 생성
const AWS = require('aws-sdk');
const cloudfront = new AWS.CloudFront();

const params = {
  DistributionConfig: {
    CallerReference: `my-distribution-${Date.now()}`,
    Comment: '쇼핑몰 정적 콘텐츠 배포',
    // 배포 활성화 여부
    Enabled: true,
    // 오리진 설정 (다음 섹션에서 자세히)
    Origins: { Quantity: 1, Items: [/* 오리진 설정 */] },
    // 기본 캐시 동작
    DefaultCacheBehavior: {/* 캐시 설정 */}
  }
};

// 배포 생성 - 완료까지 15-20분 소요
cloudfront.createDistribution(params, (err, data) => {
  if (err) console.error(err);
  else console.log('배포 생성 완료:', data.Distribution.DomainName);
});

김개발 씨는 AWS Management Console에 로그인했습니다. 서비스 목록이 너무 많아서 어디서 시작해야 할지 막막했습니다.

"걱정 마세요. CloudFront는 생각보다 간단합니다." 박시니어 씨가 검색창에 'CloudFront'를 입력하며 말했습니다.

"여기서 '배포 생성' 버튼만 누르면 됩니다." 그렇다면 **배포(Distribution)**란 정확히 무엇일까요? 쉽게 비유하자면, 배포는 마치 택배 서비스를 신청하는 것과 같습니다.

한 번 신청하면 계약 번호(도메인)를 받고, 그 번호로 전국 어디서든 물건을 보내고 받을 수 있죠. CloudFront 배포도 마찬가지로 한 번 생성하면 d1234567890abc.cloudfront.net 같은 고유 도메인을 받고, 이를 통해 전 세계 엣지 로케이션에서 콘텐츠를 제공할 수 있습니다.

배포를 생성하지 않고 CloudFront를 사용할 수 있을까요? 당연히 불가능합니다.

배포는 CloudFront의 가장 기본적인 구성 요소입니다. 오리진 서버가 어디인지, 어떤 콘텐츠를 어떻게 캐싱할지, 보안은 어떻게 설정할지 등 모든 정보가 배포 안에 담깁니다.

배포가 없으면 CloudFront는 어떤 파일을 어디서 가져와야 할지 알 수 없습니다. 바로 이런 이유로 배포 생성이 CloudFront 사용의 첫 번째 단계입니다.

배포를 생성하면 AWS는 전 세계 200개 이상의 엣지 로케이션에 여러분의 배포 설정을 전파합니다. 이 과정은 보통 15-20분 정도 걸립니다.

한 번 생성되면 언제든지 설정을 수정할 수 있고, 추가 비용 없이 여러 배포를 만들 수 있습니다. 웹 배포RTMP 배포의 차이는 무엇일까요?

웹 배포는 일반적인 웹사이트, 이미지, 동영상, API 등 대부분의 콘텐츠에 사용됩니다. RTMP 배포는 Adobe Flash 기반의 미디어 스트리밍용인데, Flash가 이제 사용되지 않으므로 거의 쓰이지 않습니다.

99%의 경우 웹 배포를 선택하면 됩니다. 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 CallerReference는 배포를 고유하게 식별하기 위한 문자열입니다. 타임스탬프를 사용해 중복을 방지합니다.

Comment는 배포에 대한 설명으로, 나중에 여러 배포를 관리할 때 유용합니다. Enabled: true로 설정하면 배포가 즉시 활성화되어 트래픽을 받을 수 있습니다.

실제 현업에서는 어떻게 활용할까요? 보통 개발, 스테이징, 프로덕션 환경마다 별도의 배포를 생성합니다.

예를 들어 dev.example.com, staging.example.com, www.example.com 각각에 대한 배포를 만들어 환경을 분리합니다. 이렇게 하면 개발 환경에서 테스트한 후 안전하게 프로덕션에 배포할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수는 배포 생성 후 바로 동작할 거라고 기대하는 것입니다.

배포 상태가 "In Progress"에서 "Deployed"로 바뀌는 데 시간이 걸립니다. 급하게 테스트하려다가 "아직 안 되는데요?"라고 당황하지 마세요.

커피 한 잔 마시고 기다리면 됩니다. AWS 콘솔에서 배포를 생성하는 것은 클릭 몇 번이면 끝납니다.

하지만 Infrastructure as Code(IaC) 방식으로 관리하는 것이 좋습니다. Terraform이나 CloudFormation을 사용하면 배포 설정을 코드로 관리하고 버전 관리할 수 있어 실수를 줄일 수 있습니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 배포 생성 버튼을 누른 김개발 씨는 화면에 나타난 여러 옵션을 보고 약간 당황했습니다.

"이게 다 뭐죠?" "천천히 하나씩 설정하면 됩니다. 다음 단계에서 오리진부터 설정해볼까요?" 박시니어 씨가 편안하게 말했습니다.

배포 생성의 개념을 이해하면 CloudFront 설정의 첫걸음을 뗀 것입니다. 여러분도 직접 배포를 만들어 보세요.

실전 팁

💡 - 배포 Comment에는 용도를 명확히 적어두세요 (예: "메인 웹사이트 정적 파일")

  • 처음엔 콘솔에서 생성하되, 익숙해지면 IaC로 전환하세요
  • 배포 생성 후 완전히 배포될 때까지 15-20분 기다리세요

3. 오리진 설정

배포를 생성하기 시작한 김개발 씨는 첫 번째 필수 항목인 "오리진"을 마주했습니다. "오리진이 뭔가요?" 박시니어 씨가 웃으며 답했습니다.

"CloudFront가 실제 파일을 가져올 원본 서버를 말합니다."

**오리진(Origin)**은 CloudFront가 콘텐츠를 가져올 원본 서버를 의미합니다. S3 버킷, EC2 인스턴스, Elastic Load Balancer, 또는 외부 웹서버 등 HTTP를 지원하는 모든 서버가 오리진이 될 수 있습니다.

CloudFront는 캐시에 없는 콘텐츠를 요청받으면 오리진에서 가져와 엣지 로케이션에 캐싱합니다.

다음 코드를 살펴봅시다.

// S3 오리진 설정 예제
const s3Origin = {
  Id: 'S3-my-website-bucket',
  DomainName: 'my-website-bucket.s3.ap-northeast-2.amazonaws.com',
  S3OriginConfig: {
    // S3 버킷 접근을 위한 OAI (Origin Access Identity)
    OriginAccessIdentity: 'origin-access-identity/cloudfront/E1234567890ABC'
  }
};

// 커스텀 오리진 설정 예제 (EC2, ALB 등)
const customOrigin = {
  Id: 'Custom-my-api-server',
  DomainName: 'api.example.com',
  CustomOriginConfig: {
    HTTPPort: 80,
    HTTPSPort: 443,
    // 오리진 프로토콜 정책: http-only, https-only, match-viewer
    OriginProtocolPolicy: 'https-only'
  }
};

김개발 씨는 회사의 정적 파일들이 S3 버킷에 저장되어 있다는 것을 알고 있었습니다. "그럼 S3 버킷을 오리진으로 설정하면 되는 거네요?" "정확합니다!" 박시니어 씨가 화면을 가리키며 설명했습니다.

"오리진 도메인 이름에 S3 버킷 주소를 입력하면 CloudFront가 자동으로 인식합니다." 그렇다면 오리진이란 정확히 무엇일까요? 쉽게 비유하자면, 오리진은 마치 도서관의 중앙 서고와 같습니다.

여러 동네에 작은 도서관(엣지 로케이션)이 있지만, 책의 원본은 중앙 서고(오리진)에 보관됩니다. 누군가 새로운 책을 요청하면 중앙 서고에서 가져와 동네 도서관에 비치하는 것처럼, CloudFront도 캐시에 없는 콘텐츠는 오리진에서 가져와 엣지 로케이션에 캐싱합니다.

오리진 없이 CloudFront를 사용할 수 있을까요? 절대 불가능합니다.

CloudFront는 콘텐츠를 생성하지 않고 전달만 합니다. 반드시 실제 파일이 저장된 원본 서버가 필요합니다.

캐시는 임시 저장소일 뿐, 영구적인 원본이 아닙니다. 오리진이 없으면 CloudFront는 빈 껍데기에 불과합니다.

바로 이런 이유로 오리진 설정이 CloudFront 배포의 필수 항목입니다. 오리진 타입은 크게 두 가지로 나뉩니다.

S3 오리진은 S3 버킷을 사용하는 경우로, 정적 웹사이트 호스팅에 최적화되어 있습니다. 커스텀 오리진은 EC2, ALB, 외부 웹서버 등 HTTP/HTTPS를 지원하는 모든 서버를 사용할 수 있습니다.

동적 콘텐츠나 API 서버를 CloudFront 앞에 두는 경우에 사용합니다. S3 오리진의 핵심은 **OAI(Origin Access Identity)**입니다.

OAI는 CloudFront만 S3 버킷에 접근할 수 있도록 하는 특별한 권한입니다. 일반 사용자가 S3 버킷 URL로 직접 접근하는 것을 막고, 반드시 CloudFront를 통해서만 접근하도록 강제합니다.

이렇게 하면 보안도 강화되고 비용도 절감됩니다. 위의 코드를 한 줄씩 살펴보겠습니다.

S3 오리진 설정에서 DomainName은 S3 버킷의 엔드포인트 주소입니다. 중요한 점은 정적 웹사이트 호스팅 엔드포인트가 아닌 REST API 엔드포인트를 사용해야 한다는 것입니다.

OriginAccessIdentity는 CloudFront에서 미리 생성한 OAI의 ID를 입력합니다. 커스텀 오리진은 어떻게 다를까요?

커스텀 오리진에서는 OriginProtocolPolicy가 중요합니다. https-only로 설정하면 CloudFront가 오리진과 통신할 때 항상 HTTPS를 사용합니다.

보안을 위해 프로덕션 환경에서는 반드시 https-only를 사용해야 합니다. match-viewer는 사용자가 HTTP로 요청하면 오리진에도 HTTP로, HTTPS로 요청하면 HTTPS로 연결합니다.

실제 현업에서는 어떻게 활용할까요? 많은 서비스들이 멀티 오리진 구조를 사용합니다.

정적 파일(이미지, CSS, JS)은 S3 오리진에서, API 요청은 ALB 커스텀 오리진에서 처리하는 식입니다. 하나의 CloudFront 배포에 여러 오리진을 등록하고, URL 경로에 따라 다른 오리진으로 라우팅할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수는 S3 버킷을 퍼블릭으로 열어두는 것입니다.

"CloudFront가 접근 못 하면 어떡하지?"라는 걱정에 버킷 정책을 퍼블릭으로 설정하는데, 이는 보안 위험입니다. OAI를 올바르게 설정하면 버킷을 프라이빗으로 유지하면서도 CloudFront는 접근할 수 있습니다.

오리진 장애 대비도 중요합니다. CloudFront는 오리진 페일오버 기능을 제공합니다.

주 오리진이 응답하지 않으면 자동으로 백업 오리진으로 전환됩니다. 예를 들어 주 오리진으로 ap-northeast-2 리전의 S3를, 백업 오리진으로 us-west-2 리전의 S3를 설정하면 리전 장애 시에도 서비스가 중단되지 않습니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. S3 버킷 주소를 입력한 김개발 씨는 OAI 설정 화면을 보고 물었습니다.

"이거 안 하면 안 되나요?" "보안을 위해 꼭 설정하는 게 좋습니다. 클릭 한 번이면 자동으로 만들어집니다." 박시니어 씨가 "Create OAI" 버튼을 가리켰습니다.

오리진 설정을 제대로 이해하면 안전하고 효율적인 CloudFront 배포를 구성할 수 있습니다. 여러분도 OAI를 활용해 보안을 강화하세요.

실전 팁

💡 - S3 오리진 사용 시 반드시 OAI를 설정하여 직접 접근을 차단하세요

  • 프로덕션 환경에서는 OriginProtocolPolicy를 https-only로 설정하세요
  • 오리진 페일오버를 설정하여 고가용성을 확보하세요

4. 캐시 동작 설정

오리진 설정을 마친 김개발 씨는 다음 단계인 "캐시 동작"을 마주했습니다. 옵션이 너무 많아 보여 당황했습니다.

"이 설정들을 다 이해해야 하나요?" 박시니어 씨가 고개를 저으며 답했습니다. "핵심만 알면 됩니다.

캐시를 얼마나 오래 보관할지, 어떤 요청을 캐싱할지를 결정하는 거죠."

**캐시 동작(Cache Behavior)**은 CloudFront가 콘텐츠를 어떻게 캐싱하고 전달할지 제어하는 규칙입니다. URL 경로 패턴에 따라 서로 다른 캐시 정책을 적용할 수 있습니다.

TTL(Time To Live), 쿼리 스트링 처리, 헤더 전달 등을 설정하여 캐시 효율성과 정확성의 균형을 맞춥니다.

다음 코드를 살펴봅시다.

// 캐시 동작 설정 예제
const cacheBehavior = {
  PathPattern: '/images/*',  // /images/ 경로에만 적용
  TargetOriginId: 'S3-my-website-bucket',
  ViewerProtocolPolicy: 'redirect-to-https',  // HTTP를 HTTPS로 리다이렉트

  // 캐시 정책
  CachePolicyId: 'custom-policy',
  DefaultTTL: 86400,      // 기본 24시간 (초 단위)
  MinTTL: 0,              // 최소 0초
  MaxTTL: 31536000,       // 최대 1년

  // 압축 활성화
  Compress: true,

  // 허용할 HTTP 메서드
  AllowedMethods: ['GET', 'HEAD', 'OPTIONS'],
  CachedMethods: ['GET', 'HEAD']
};

// 동적 콘텐츠용 캐시 동작
const dynamicBehavior = {
  PathPattern: '/api/*',
  TargetOriginId: 'Custom-my-api-server',
  ViewerProtocolPolicy: 'https-only',
  DefaultTTL: 0,  // 캐싱 안 함
  AllowedMethods: ['GET', 'HEAD', 'OPTIONS', 'PUT', 'POST', 'PATCH', 'DELETE']
};

김개발 씨는 회사 웹사이트의 구조를 떠올렸습니다. 이미지는 거의 바뀌지 않지만, 상품 정보 API는 실시간으로 업데이트됩니다.

"이 둘을 같은 방식으로 캐싱하면 안 되겠네요?" "바로 그겁니다!" 박시니어 씨가 화이트보드에 그림을 그리며 설명했습니다. "정적 파일은 오래 캐싱하고, 동적 API는 캐싱하지 않거나 짧게 해야 합니다." 그렇다면 캐시 동작이란 정확히 무엇일까요?

쉽게 비유하자면, 캐시 동작은 마치 도서관의 대출 규칙과 같습니다. 소설책은 2주간 대출 가능하지만, 참고서적은 하루만 빌릴 수 있고, 최신 잡지는 관내 열람만 가능한 것처럼, 콘텐츠 종류에 따라 다른 규칙을 적용하는 것입니다.

CloudFront도 이미지는 1년간 캐싱하고, HTML은 1시간, API는 캐싱 안 하는 식으로 콘텐츠별로 다른 정책을 적용합니다. 캐시 동작 없이 CloudFront를 사용하면 어떻게 될까요?

기술적으로는 기본 캐시 동작이 있어서 작동하지만, 모든 콘텐츠가 동일하게 처리됩니다. 바뀌지 않는 로고 이미지와 실시간 재고 API가 같은 TTL로 캐싱되면, 이미지는 너무 자주 갱신되어 비효율적이고, API는 오래된 데이터를 보여줘 문제가 됩니다.

따라서 콘텐츠 특성에 맞는 캐시 동작 설정이 필수입니다. 바로 이런 이유로 캐시 동작은 CloudFront 성능 최적화의 핵심입니다.

**TTL(Time To Live)**은 콘텐츠를 엣지 로케이션에 얼마나 오래 보관할지 결정합니다. DefaultTTL은 오리진 서버가 캐시 헤더를 보내지 않을 때 사용되고, MinTTLMaxTTL은 오리진 헤더를 받아도 적용되는 최소/최대 한계입니다.

예를 들어 오리진이 "10년 캐싱하라"고 해도 MaxTTL이 1년이면 1년만 캐싱됩니다. **경로 패턴(Path Pattern)**으로 세밀한 제어가 가능합니다.

/images/*는 모든 이미지에, /api/*는 모든 API 요청에 적용됩니다. 와일드카드를 활용해 /static/*.css처럼 CSS 파일만 따로 설정할 수도 있습니다.

CloudFront는 가장 구체적인 패턴을 우선 적용하므로, 기본 동작과 특수 경로 동작을 조합하여 유연하게 관리할 수 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.

첫 번째 캐시 동작은 이미지용입니다. Compress: true로 설정하면 CloudFront가 자동으로 gzip 압축을 적용해 대역폭을 절약합니다.

ViewerProtocolPolicy: 'redirect-to-https'는 HTTP 요청을 자동으로 HTTPS로 리다이렉트합니다. AllowedMethods는 GET, HEAD만 허용하여 읽기 전용으로 제한합니다.

두 번째 동적 콘텐츠용 캐시 동작은 완전히 다릅니다. DefaultTTL: 0으로 설정하면 캐싱이 비활성화됩니다.

매번 오리진에서 최신 데이터를 가져옵니다. AllowedMethods에 PUT, POST, DELETE를 포함하여 쓰기 작업도 가능하게 합니다.

API 서버는 보안이 중요하므로 https-only로 설정합니다. 쿼리 스트링쿠키 처리도 중요합니다.

기본적으로 CloudFront는 쿼리 스트링을 무시하고 캐싱합니다. 즉, /product?id=1/product?id=2가 같은 캐시로 처리됩니다.

동적 페이지라면 "쿼리 스트링 전달"을 활성화하여 각각 다르게 캐싱해야 합니다. 하지만 정적 파일에서 쿼리를 전달하면 캐시 효율이 떨어지니 주의하세요.

실제 현업에서는 어떻게 활용할까요? 대형 이커머스 사이트의 경우 다음과 같은 구조를 사용합니다.

/static/*(CSS, JS, 폰트) → TTL 1년, /images/* → TTL 1개월, /product/*(상품 페이지) → TTL 1시간, /api/* → 캐싱 안 함. 이렇게 하면 캐시 히트율 80% 이상을 달성하면서도 신선한 데이터를 제공할 수 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수는 TTL을 너무 길게 설정하는 것입니다.

"캐시가 많을수록 빠르겠지?"라고 생각하지만, 콘텐츠 업데이트 시 오래된 버전이 계속 제공되는 문제가 생깁니다. **무효화(Invalidation)**로 강제 삭제할 수 있지만, 자주 하면 비용이 발생합니다.

적절한 TTL 균형이 중요합니다. 캐시 키 설정도 신중해야 합니다.

Accept-Encoding 헤더를 캐시 키에 포함하면 gzip 지원 브라우저와 미지원 브라우저에 다른 캐시를 제공할 수 있습니다. 하지만 너무 많은 헤더를 포함하면 캐시가 과도하게 분산되어 효율이 떨어집니다.

CloudFront의 관리형 캐시 정책을 사용하면 AWS가 최적화한 설정을 쉽게 적용할 수 있습니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.

여러 옵션을 살펴본 김개발 씨는 물었습니다. "이미지는 1년, API는 0초면 되겠네요?" "기본은 그렇습니다.

하지만 실제로는 모니터링하면서 조정해야 합니다." 박시니어 씨가 CloudWatch 대시보드를 열며 말했습니다. 캐시 동작을 제대로 설정하면 성능과 비용을 동시에 최적화할 수 있습니다.

여러분도 콘텐츠 특성에 맞는 TTL을 찾아보세요.

실전 팁

💡 - 정적 파일은 긴 TTL, 동적 콘텐츠는 짧은 TTL 또는 0으로 설정하세요

  • 관리형 캐시 정책(CachingOptimized, CachingDisabled 등)을 먼저 시도하세요
  • CloudWatch로 캐시 히트율을 모니터링하며 TTL을 조정하세요

5. HTTPS 설정

캐시 동작까지 설정한 김개발 씨는 거의 완성 단계에 왔습니다. 그런데 브라우저 주소창에 "안전하지 않음" 경고가 보였습니다.

"이거 왜 이러죠?" 박시니어 씨가 답했습니다. "아직 HTTPS를 설정하지 않아서 그렇습니다.

요즘은 필수죠."

**HTTPS(HyperText Transfer Protocol Secure)**는 데이터를 암호화하여 안전하게 전송하는 프로토콜입니다. CloudFront는 무료 SSL/TLS 인증서를 제공하는 **AWS Certificate Manager(ACM)**과 통합되어 쉽게 HTTPS를 적용할 수 있습니다.

사용자와 CloudFront 간, CloudFront와 오리진 간 모두 암호화할 수 있습니다.

다음 코드를 살펴봅시다.

// ACM에서 인증서 요청 (us-east-1 리전에서만 가능!)
const acm = new AWS.ACM({ region: 'us-east-1' });

const certParams = {
  DomainName: 'www.example.com',
  SubjectAlternativeNames: ['example.com', '*.example.com'],
  ValidationMethod: 'DNS'  // DNS 또는 EMAIL 검증
};

acm.requestCertificate(certParams, (err, data) => {
  if (err) console.error(err);
  else console.log('인증서 ARN:', data.CertificateArn);
});

// CloudFront 배포에 인증서 적용
const distributionConfig = {
  ViewerCertificate: {
    ACMCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/xxxxx',
    SSLSupportMethod: 'sni-only',  // SNI 방식 (무료)
    MinimumProtocolVersion: 'TLSv1.2_2021'  // 최소 TLS 버전
  },
  // 커스텀 도메인 설정
  Aliases: ['www.example.com', 'example.com']
};

김개발 씨는 뉴스에서 본 보안 사고를 떠올렸습니다. 암호화하지 않은 사이트에서 로그인 정보가 탈취되었다는 내용이었습니다.

"우리 사이트도 위험한 거 아닌가요?" "맞습니다. HTTPS 없이는 중간에서 데이터를 가로챌 수 있습니다." 박시니어 씨가 네트워크 다이어그램을 그리며 설명했습니다.

"CloudFront로 HTTPS를 적용하는 건 생각보다 간단합니다." 그렇다면 HTTPS가 정확히 무엇일까요? 쉽게 비유하자면, HTTPS는 마치 중요한 문서를 잠금장치가 있는 서류가방에 넣어 보내는 것과 같습니다.

일반 HTTP는 투명한 비닐봉투에 담아 보내는 격이죠. 누구나 내용을 볼 수 있습니다.

HTTPS는 SSL/TLS 암호화를 사용하여 데이터를 암호화하고, 서버의 신원을 검증하여 안전한 통신을 보장합니다. HTTPS 없이 웹사이트를 운영하면 어떻게 될까요?

첫째, 브라우저가 "안전하지 않음" 경고를 표시하여 사용자 신뢰를 잃습니다. Chrome은 HTTP 사이트의 양식 입력을 차단하기도 합니다.

둘째, **중간자 공격(Man-in-the-Middle)**에 취약해집니다. 공공 와이파이에서 누군가 트래픽을 가로채 비밀번호를 훔칠 수 있습니다.

셋째, SEO 순위가 하락합니다. Google은 HTTPS 사이트를 우대합니다.

바로 이런 이유로 HTTPS는 이제 선택이 아닌 필수입니다. CloudFront는 두 구간의 HTTPS를 제공합니다.

뷰어 → CloudFront 구간은 사용자와 엣지 로케이션 사이의 통신이고, CloudFront → 오리진 구간은 엣지 로케이션과 원본 서버 사이의 통신입니다. 두 구간 모두 암호화하는 것이 이상적이지만, 최소한 사용자 대면 구간은 반드시 HTTPS를 적용해야 합니다.

**ACM(AWS Certificate Manager)**은 무료로 SSL 인증서를 발급합니다. 상용 인증서는 연간 수백 달러가 드는데, ACM은 완전 무료이고 자동 갱신됩니다.

단, CloudFront에 사용할 인증서는 반드시 us-east-1(버지니아) 리전에서 발급받아야 합니다. 다른 리전에서 발급하면 CloudFront에서 보이지 않습니다.

위의 코드를 한 줄씩 살펴보겠습니다. 인증서 요청 시 DomainName에 메인 도메인을, SubjectAlternativeNames에 추가 도메인들을 넣습니다.

와일드카드 *.example.com을 사용하면 모든 서브도메인을 포함할 수 있습니다. ValidationMethod: 'DNS'는 도메인 소유권을 DNS 레코드로 검증하는 방식으로, 자동화하기 좋습니다.

SNI(Server Name Indication) 방식은 무료입니다. 과거에는 전용 IP 방식만 있어서 월 $600가 들었지만, 이제 SNI로 무료로 사용할 수 있습니다.

SNI는 하나의 IP에 여러 SSL 인증서를 호스팅하는 기술입니다. 단, 아주 오래된 브라우저(IE6 on Windows XP 등)는 지원하지 않지만, 현재는 99.9% 이상의 브라우저가 SNI를 지원하므로 문제없습니다.

TLS 버전 설정도 중요합니다. MinimumProtocolVersionTLSv1.2_2021로 설정하면 오래된 TLS 1.0/1.1 클라이언트는 차단됩니다.

보안은 강화되지만 호환성은 줄어듭니다. 일반적으로 TLS 1.2 이상을 권장하며, 매우 높은 보안이 필요하면 TLS 1.3을 사용할 수 있습니다.

커스텀 도메인 연결은 어떻게 할까요? CloudFront는 기본적으로 d1234567890abc.cloudfront.net 같은 도메인을 제공하지만, www.example.com 같은 예쁜 도메인을 사용하려면 Aliases에 등록해야 합니다.

그 다음 Route 53이나 다른 DNS 서비스에서 CNAME 레코드를 CloudFront 도메인으로 설정하면 됩니다. 실제 현업에서는 어떻게 활용할까요?

대부분의 기업은 다음과 같은 구조를 사용합니다. 뷰어 → CloudFront는 ACM 인증서로 HTTPS 적용, CloudFront → ALB 오리진도 ALB의 ACM 인증서로 HTTPS 적용.

종단 간(end-to-end) 암호화를 구현하여 어떤 구간에서도 평문 데이터가 노출되지 않습니다. 하지만 주의할 점도 있습니다.

초보 개발자들이 흔히 하는 실수는 인증서를 잘못된 리전에서 발급받는 것입니다. "왜 CloudFront에서 내 인증서가 안 보이지?"라고 당황하는데, 리전을 확인하면 ap-northeast-2에서 발급받았습니다.

반드시 us-east-1에서 발급받아야 합니다. DNS 검증을 완료하지 않아도 주의가 필요합니다.

ACM은 인증서를 발급한 후 도메인 소유권을 검증하기 위해 CNAME 레코드를 요구합니다. Route 53을 사용하면 클릭 한 번으로 자동 추가되지만, 외부 DNS를 쓴다면 수동으로 추가해야 합니다.

검증 완료 전까지는 인증서 상태가 "보류 중"으로 표시됩니다. HSTS(HTTP Strict Transport Security) 헤더도 고려하세요.

오리진 서버에서 Strict-Transport-Security: max-age=31536000; includeSubDomains 헤더를 보내면 브라우저가 항상 HTTPS로만 접속하도록 강제합니다. 한 번 HTTPS로 접속한 사용자는 이후 자동으로 HTTPS로 리다이렉트되어 보안이 더욱 강화됩니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. ACM에서 인증서를 발급받은 김개발 씨는 주소창의 자물쇠 아이콘을 보며 뿌듯해했습니다.

"이제 안전한 사이트가 되었네요!" "맞습니다. HTTPS는 현대 웹의 기본입니다." 박시니어 씨가 미소 지었습니다.

HTTPS 설정을 제대로 이해하면 사용자 신뢰와 보안을 동시에 확보할 수 있습니다. 여러분도 ACM으로 무료 인증서를 발급받아 보세요.

실전 팁

💡 - CloudFront용 ACM 인증서는 반드시 us-east-1 리전에서 발급하세요

  • SNI 방식을 사용하면 추가 비용 없이 HTTPS를 적용할 수 있습니다
  • 최소 TLS 버전을 1.2 이상으로 설정하여 보안을 강화하세요

6. 무효화 처리

모든 설정을 마친 김개발 씨는 웹사이트를 배포했습니다. 그런데 메인 배너 이미지를 교체했는데도 예전 이미지가 계속 보였습니다.

"왜 안 바뀌죠?" 박시니어 씨가 웃으며 답했습니다. "캐시가 남아있어서 그렇습니다.

무효화 처리를 해야 합니다."

**무효화(Invalidation)**는 CloudFront 엣지 로케이션에 캐싱된 콘텐츠를 강제로 삭제하는 작업입니다. TTL이 남아있어도 즉시 최신 버전을 가져오고 싶을 때 사용합니다.

파일 경로나 와일드카드 패턴으로 특정 콘텐츠만 무효화할 수 있으며, 매달 1,000개 경로까지 무료입니다.

다음 코드를 살펴봅시다.

// CloudFront 무효화 요청
const cloudfront = new AWS.CloudFront();

const invalidationParams = {
  DistributionId: 'E1234567890ABC',
  InvalidationBatch: {
    CallerReference: `invalidation-${Date.now()}`,
    Paths: {
      Quantity: 3,
      Items: [
        '/images/banner.jpg',      // 특정 파일
        '/css/*',                   // 특정 폴더의 모든 파일
        '/*'                        // 전체 무효화 (주의!)
      ]
    }
  }
};

cloudfront.createInvalidation(invalidationParams, (err, data) => {
  if (err) console.error(err);
  else {
    console.log('무효화 시작:', data.Invalidation.Id);
    console.log('완료까지 약 5-10분 소요됩니다.');
  }
});

// 버전 쿼리 스트링 방식 (무효화 대신 권장)
const imageUrl = '/images/banner.jpg?v=20250120';

김개발 씨는 마케팅팀으로부터 급한 연락을 받았습니다. "메인 배너를 30분 안에 교체해달라는데요!" S3에 새 이미지를 업로드했지만 웹사이트에는 여전히 예전 배너가 보였습니다.

"TTL이 아직 안 끝나서 그렇습니다." 박시니어 씨가 설명했습니다. "24시간으로 설정했으니 내일까지 기다리거나, 지금 무효화를 실행해야 합니다." 그렇다면 무효화란 정확히 무엇일까요?

쉽게 비유하자면, 무효화는 마치 도서관에 비치된 구판 책을 모두 회수하는 것과 같습니다. 신판이 나왔는데 독자들이 여전히 구판을 읽고 있다면, 사서가 모든 지점을 돌며 구판을 수거하고 신판으로 교체하는 것이죠.

CloudFront도 전 세계 200개 이상의 엣지 로케이션을 돌며 오래된 캐시를 삭제하고 오리진에서 새 버전을 가져옵니다. 무효화 없이는 어떻게 될까요?

캐시가 자연스럽게 만료될 때까지 기다려야 합니다. TTL이 1시간이면 1시간, 1일이면 1일을 기다려야 합니다.

긴급한 보안 패치나 중요한 공지사항을 업데이트해도 사용자는 한참 후에야 볼 수 있습니다. 이커머스에서 품절된 상품이 계속 "구매 가능"으로 표시되면 고객 불만이 쌓입니다.

바로 이런 이유로 무효화는 긴급 업데이트의 필수 도구입니다. 하지만 무효화는 비용과 시간이 듭니다.

매달 1,000개 경로까지는 무료지만, 그 이상은 경로당 $0.005가 부과됩니다. 또한 무효화 요청 후 전 세계 엣지 로케이션에 전파되는 데 5-10분이 걸립니다.

즉각적이지 않으므로 완료 시간을 고려해야 합니다. 경로 패턴을 잘 활용하면 효율적입니다.

/images/banner.jpg처럼 특정 파일만 무효화할 수도 있고, /css/*처럼 폴더 전체를 무효화할 수도 있습니다. /*는 전체 캐시를 삭제하는데, 이는 1개 경로로 카운트되지만 캐시 히트율이 크게 떨어지므로 정말 필요할 때만 사용해야 합니다.

위의 코드를 한 줄씩 살펴보겠습니다. CallerReference는 무효화 요청을 고유하게 식별하는 문자열입니다.

같은 값으로 중복 요청하면 무시되므로 타임스탬프를 사용합니다. Paths.Items 배열에 무효화할 경로를 나열하면 되는데, /로 시작해야 합니다.

상대 경로는 작동하지 않습니다. 버전 쿼리 스트링 방식이 더 나은 선택입니다.

무효화 대신 파일명에 버전을 포함하는 방법입니다. /images/banner.jpg?v=20250120처럼 쿼리 파라미터나 /images/banner-v2.jpg처럼 파일명 자체에 버전을 넣으면, CloudFront는 이를 새로운 콘텐츠로 인식하여 캐시를 새로 생성합니다.

무효화 비용도 안 들고, 즉시 적용되며, 롤백도 쉽습니다. 캐시 키 설정에 쿼리 스트링을 포함해야 합니다.

기본적으로 CloudFront는 쿼리를 무시하므로, ?v=1?v=2가 같은 캐시로 처리됩니다. 캐시 동작 설정에서 "쿼리 스트링을 캐시 키에 포함"을 활성화하면 버전별로 다른 캐시가 생성됩니다.

또는 특정 파라미터만 포함하도록 화이트리스트를 설정할 수 있습니다. 실제 현업에서는 어떻게 활용할까요?

대부분의 기업은 빌드 시 자동 버저닝을 사용합니다. Webpack이나 Vite 같은 번들러는 파일 해시를 파일명에 추가합니다.

main.abc123.js처럼 콘텐츠가 바뀌면 파일명도 바뀌어 캐시 문제가 원천적으로 해결됩니다. HTML 파일만 짧은 TTL(5분)로 설정하고, 나머지는 1년으로 설정하는 패턴이 일반적입니다.

배포 파이프라인에 무효화를 통합할 수도 있습니다. CI/CD에서 S3에 파일을 업로드한 후 자동으로 CloudFront 무효화를 실행합니다.

GitHub Actions나 Jenkins에서 AWS CLI로 aws cloudfront create-invalidation 명령을 실행하면 됩니다. 단, 무효화 완료를 기다리지 않고 다음 단계로 진행하면 일시적으로 구버전과 신버전이 섞일 수 있으니 주의하세요.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수는 배포할 때마다 /*로 전체 무효화하는 것입니다.

"확실하게 다 지우자"는 의도이지만, 캐시 히트율이 0%로 떨어지고 오리진 부하가 급증합니다. 변경된 파일만 정확히 무효화하거나, 버전 쿼리 방식을 사용하는 것이 훨씬 효율적입니다.

무효화 상태 추적도 중요합니다. 무효화 요청 후 Invalidation.Id를 받아 getInvalidation API로 진행 상황을 확인할 수 있습니다.

상태가 "InProgress"에서 "Completed"로 바뀌면 모든 엣지 로케이션에서 캐시가 삭제된 것입니다. 중요한 배포라면 완료를 확인한 후 검증하는 것이 안전합니다.

비용 최적화 팁도 있습니다. 와일드카드를 적극 활용하세요.

/images/a.jpg, /images/b.jpg, /images/c.jpg를 개별로 무효화하면 3개 경로이지만, /images/* 하나로 무효화하면 1개 경로입니다. 단, /*는 전체이므로 신중하게 사용하고, 필요한 폴더만 구체적으로 지정하는 것이 좋습니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 무효화를 실행한 김개발 씨는 5분 후 새 배너가 나타나는 것을 확인했습니다.

"이제 됐네요!" "좋습니다. 하지만 다음부터는 버전 쿼리 방식을 사용해보세요.

더 빠르고 비용도 안 듭니다." 박시니어 씨가 조언했습니다. 무효화 처리를 제대로 이해하면 긴급 상황에 빠르게 대응할 수 있습니다.

하지만 더 나은 방법은 버저닝 전략을 사용하는 것입니다.

실전 팁

💡 - 가능하면 무효화 대신 버전 쿼리 스트링(?v=123) 방식을 사용하세요

  • 전체 무효화(/*)는 최후의 수단으로만 사용하세요
  • CI/CD 파이프라인에 무효화를 자동화하되, 변경된 파일만 지정하세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#AWS#CloudFront#CDN#Cache#HTTPS

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.