Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.

pushState를 사용하는 SPA를 S3와 CloudFront로 서비스하기

AWS의 스토리지 서비스인 S3에는 웹 호스팅 기능을 제공하고 있어서 정적 웹사이트일 때 HTML, CSS, JavaScript 파일을 올려놓고 웹사이트를 운영할 수 있다. 간단한 정적 웹사이트는 서버 운영 걱정 없이 사이트를 제공할 수 있고 S3가 죽는 경우는 흔치 않으므로 웹사이트를 안정적으로 제공할 수 있다. 정적 파일은 CDN을 제공하는 게 좋으므로 보통 S3 앞에 CloudFront를 연결해서 제공하는 것이 일반적이다.

S3 웹사이트 호스팅

먼저 Terraform으로 S3 웹사이트 호스팅을 설정해보자.

resource "aws_s3_bucket" "website" {
  bucket = "demo.example.com"
  acl    = "private"
  policy = "${data.aws_iam_policy_document.website.json}"

  website {
    index_document = "index.html"
  }
}

data "aws_iam_policy_document" "website" {
  statement {
    actions   = ["s3:GetObject"]
    resources = ["arn:aws:s3:::demo.example.com/*"]

    principals {
      type        = "AWS"
      identifiers = ["${aws_cloudfront_origin_access_identity.website.iam_arn}"]
    }
  }
}

정적 파일을 저장할 S3 버킷을 생성하고 CloudFront에서 이 S3 버킷 파일에 접근 할 수 있도록 권한을 부여했다.

resource "aws_cloudfront_origin_access_identity" "website" {
  comment = "website demo Cloudfront"
}

resource "aws_cloudfront_distribution" "website" {
  origin {
    domain_name = "${aws_s3_bucket.website.bucket_domain_name}"
    origin_path = ""
    origin_id   = "${aws_s3_bucket.website.id}"

    s3_origin_config {
      origin_access_identity = "${aws_cloudfront_origin_access_identity.website.cloudfront_access_identity_path}"
    }
  }

  aliases             = ["demo.example.com"]
  comment             = "demo.example.com"
  enabled             = true
  is_ipv6_enabled     = false
  default_root_object = "index.html"
  http_version        = "http2"

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD", "OPTIONS"]
    cached_methods   = ["GET", "HEAD", "OPTIONS"]
    target_origin_id = "${aws_s3_bucket.website.id}"

    forwarded_values {
      query_string = false

      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    max_ttl                = 360
    default_ttl            = 60
  }

  price_class = "PriceClass_All"

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

이번엔 CloudFront 설정이다. 정적 파일을 CDN으로 제공하기 위해 CloudFront를 생성하고 그 대상을 앞에서 만든 S3 버킷으로 지정했다. 물론 실제로 서비스를 한다면 여기서 Route53과 ACM을 이용해서 도메인을 연결하고 인증서를 붙이겠지만 여기서는 크게 중요하지 않으므로 생략한다.

이렇게 설정하고 나면 CloudFront의 도메인이나 Route53으로 설정한 도메인을 통해서 웹사이트에 접속할 수 있다.

Push State를 사용하는 SPA

SPA는 Single Page Application의 약자로 React 등이 프론트엔드의 기술로 자리잡으면서 요즘은 많이 사용하고 있다. 웹사이트를 SPA로 만드는 경우 백엔드 API를 사용하지만, 페이지 자체는 정적 웹사이트이기 때문에 S3의 웹 호스팅 기능을 이용해서 서비스하기 좋다. SPA롤 웹사이트를 만들면 URL에 따라 라우팅을 해야 하는데 anchor(#)를 이용해서 라우팅하거나 Push State를 이용해서 URL을 조작할 수 있다. SPA에서 URL을 변경할 때 중간에 #이 있으면 전자이고 일단 웹사이트와 같게 /board/1 같은 식의 URL이라면 Push State를 사용한 것이다.

S3를 이용한 웹사이트 호스팅에서 index_document = "index.html"로 설정되어 있으므로 demo.example.com에 접속하면 자동으로 index.html을 보여주지만, 그 외의 파일을 경로에 맞게 보여준다. 즉 demo.example.com/app.js를 요청하면 S3 버킷에 app.js가 있어야 한다.

SPA는 최초 요청에서 index.html을 받아서 앱을 초기화한 뒤 라우팅을 하므로 페이지를 이동하면 각 페이지의 URL이 /newest/1이나 /show/5 같은 식이 될 수 있다. 처음 로딩하고 웹을 사용할 때는 잘 동작하지만, URL을 복사해서 demo.example.com/show/5로 접속한다면 S3 버킷에 show/5라는 파일이 없으므로 403 오류를 받게 된다. 원래대로라면 404여야 하지만 S3를 쓰고 있어서 403이 반환된다.

이 문제를 해결하려면 / 밑으로 어떤 URL로 요청이 오던 간에 /index.html을 반환하도록 처리해야 한다. nginx 등의 웹서버가 있다면 라우팅 설정을 하면 되지만 S3 웹사이트 호스팅에서 이 문제를 해결하려면 CloudFront의 커스텀 오류 페이지 기능을 이용해야 한다.

aws_cloudfront_distribution 설정에 아래 custom_error_response 설정을 추가한다.

custom_error_response {
  error_code         = 404
  response_code      = 200
  response_page_path = "/index.html"
}

이는 404 오류일 때 /index.html 파일을 내려주고 응답 코드는 200을 반환하라는 의미이다. 이렇게 하면 jscss 같은 파일을 계속 제공하지만, Push State 라우팅으로 인한 페이지가 없는 경우에는 /index.html가 반환되게 되고 SPA는 이 URL을 분석해서 URL에 맞는 페이지를 보여주게 될 것이다.

2018/08/11 20:22 2018/08/11 20:22

기술 뉴스 #107 : 18-08-01

웹개발 관련

  • I created the exact same app in React and Vue. Here are the differences. : ToDo 앱을 React와 Vue로 똑같이 만들면서 폴더구조, 상태 관리, ToDo 아이템 관리 등에서 React와 Vue가 어떻게 다르게 접근하고 어떤 부분이 유사한지를 비교한 글이다. 비교적 간단한 앱이지만 똑같은 기능을 구현하면서 비교해 주어서 각 프레임워크의 차이점을 이해하기에 좋은 글이다.(영어)
  • 트리 쉐이킹으로 자바스크립트 페이로드 줄이기 : Reduce JavaScript Payloads with Tree Shaking의 번역 문서로 Webpack으로 빌드하는 간단한 웹사이트에서 트리 쉐이킹으로 어떻게 용량을 줄일 수 있는지를 잘 설명하고 있다. 트리 쉐이킹이 동작하는 방식부터 babel을 사용할 때나 의존하는 모듈이 트리 쉐이킹을 잘 지원하지 않을 때의 주의점까지 나와 있다.(한국어)
  • Introduction to Feature Policy : HTTP 응답에 Feature-Policy 헤더를 지정해서 웹사이트에서 사용할 수 있는 기능을 제한하는 방법을 소개한 글이다. 보안에 사용하는 CSP(Content Security Policy)와 비슷하지만, 기능을 담당하고 있다.(영어)
  • 크롬에서 보안이 향상된 웹을 만나보세요 : 7월 25일 출시된 크롬 68부터 모든 HTTP 사이트를 "주의 요함"으로 표시된다. 이후 9월에 출시될 크롬 69에서는 HTTPS 사이트를 녹색의 "보안 연결"로 표시하는 대신 아무것도 표시하지 않고 크롬 70부터는 HTTP 사이트에서 입력값에 값을 입력하면 붉은색의 "주의 요함"으로 표시된다.(한국어)

그 밖의 프로그래밍 관련

  • Mocking은 코드 냄새(Code Smell)입니다 : 6월에 소개했던 Mocking is a Code Smell의 번역 글이다. 테스트 코드를 사용할 때 Mocking이 필요하다면 코드에 개선할 부분이 있다는 신호로 봐야 한다는 논조의 글인데 원문 읽느라고 고생했는데 번역 글이 있어서 다시 소개한다.(한국어)
  • Serverless와 기술도입, Backend Application의 미래 : AWS Lambda로 대부분의 백엔드를 구성한 빙글에서 Severless의 가치와 미래에 관한 생각을 정리한 글이다. 나도 예전에 Serverless에 빠져있었는데(생각이 바뀌었다기보다는 그쪽으로 할 일이 줄어든...) Serverless를 도입함으로써 로직 개발 외에 운영 업무가 줄어들어 "쉽지만 귀찮다"로 생각되는 많은 부분을 구현할 수 있게 되었고 이런 부분에서 Severless의 장래는 밝다고 이야기하고 이야기하고 있다. 이야기를 풀어가는 방식에서 많은 고민이 담겨있는 것 같아서 재미있었다.(한국어)
  • "TDD 실천법과 도구" 책 전체를 PDF 공개합니다. : 2010년에 출간된 "테스트 주도 개발 (고품질 쾌속개발을 위한 TDD 실천법과 도구)"의 전체 내용을 약간의 보충 설명과 함께 온라인에 공개한다고 합니다.(한국어)
  • The Site Reliability Workbook : Google에서 새로운 SRE 책을 공개했다. 이 책은 무료로 8월 23일까지 무료로 다운로드 받을 수 있다.(영어)
  • 아마존 웹 서비스 계정 생성 후 해야 하는 IAM 보안 조치 : AWS를 처음 시작할 때 root 계정 사용에서 조심해야 할 부분과 IAM으로 계정을 다루는 법에 관해서 설명하는 글이다.(한국어)
  • AWS VPC 피어링 : 기본적으로 VPC는 내부에서만 통신할 수 있는데 2개 이상의 VPC가 서로 통신하기 위해서 피어링을 설정하는 방법을 설명하고 있다. VPC를 만들어서 내부에서 서로 접속하는 방법을 설명한 뒤 2개의 VPC를 만들고 피어링을 연결하는 과정을 보여준다.(한국어)

볼만한 링크

  • Good to great UI animation tips : 좋은 UI 애니메이션을 훌륭한 UI 애니메이션으로 팁을 정리한 글이다. 탭의 전환 애니메이션이나 버튼 전환, 콘텐츠 등장 효과에서 미세한 변화이지만 더 훌륭하게 만드는 방법을 비교해주면서 보여주고 있어서 이해하기 좋다. 번역글도 있다.(영어)
  • 우아한형제들 개발자 채용을 위한 페이스북 한 달 운영기 : 최근에 많이 보던 우아한형제들의 개발자 채용 관련 카드 뉴스를 한 달 운영한 경험을 정리한 글이다. 개발자는 타부서에서 마케팅하기 어려운 직종이라고 생각하는 편이라서(선입견일지라도...) 마케팅 쪽에서 개발자 채용 카드뉴스가 나온 과정과 그 결과에 관한 내용이 재미있었다.(한국어)
  • 비트코인 논문 한국어 번역판 (ver0.94) : 2018년 초에 발행된 번역본에서 거래, 타임스탬프 서버, 작업증명 부분이 개선된 버전이다.(한국어)

IT 업계 뉴스

프로젝트

  • ndb : Node.js 디버깅 도구.
  • Evergreen : Segment에서 만든 React UI 프레임워크
  • Data Transfer Project : 온라인 서비스 간에 데이터를 이동시킬 수 있게 하려는 프로젝트로 현재 Google, Facebook, Microsoft, Twitter
  • Hasura GraphQL Engine : Postgres에 바로 연결할 수 있는 GraphQL 서버.
  • terminalizer : 터미널을 gif 이미지로 녹화할 수 있는 도구.

버전 업데이트

2018/08/01 23:31 2018/08/01 23:31