- yunkoo.dev에 접속한다는 것은 브라우저가 DNS를 통해 실제 요청 위치를 찾고, HTTPS 연결을 만든 뒤, 배포된 Next.js 결과물을 받아오는 과정이다.
- 브라우저 렌더링은 HTML, CSS, JavaScript를 DOM, CSSOM, Render Tree, Layout, Paint, Composite 과정을 거쳐 사용자가 볼 수 있는 화면으로 바꾸는 일이다.
- SEO/AEO/GEO는 사람이 보는 화면뿐 아니라 검색엔진과 AI가 글의 구조와 의미를 더 잘 이해하도록 단서를 제공하는 작업이다.
배포된 블로그에 사용자가 접근한 뒤 어떤 일이 일어나는지에 대해 작성했다
yunkoo.dev를 입력했을 때, 브라우저와 검색엔진, AI는 내 블로그를 어떻게 만나고 이해할까? 이 질문은 단순히 배포가 잘 됐는지 확인하는 수준을 넘어선다. 프론트엔드 개발자는 사용자가 보는 화면을 만드는 사람이다. 그렇다면 화면이 어떻게 사용자에게 도착하고, 브라우저 안에서 어떤 과정을 거쳐 그려지는지도 이해해야 한다.
또 블로그는 사람만 읽는 문서가 아니다. 검색엔진도 읽고, RSS 리더도 읽고, 요즘은 AI 검색이나 생성형 AI도 웹 문서를 참고한다. 그래서 이번 글에서는 yunkoo.dev에 접근하는 과정, 브라우저 렌더링 과정, 그리고 SEO/AEO/GEO를 적용한 이유를 정리해보려고 한다.
배포된 사이트에 접근한다는 것
로컬에서 npm run dev로 실행한 블로그는 내 컴퓨터 안에서만 동작한다. 브라우저에서 localhost:3000에 접속하면 내 컴퓨터에서 실행 중인 개발 서버에 요청을 보내는 것이다.
배포된 사이트는 다르다. https://yunkoo.dev는 내 컴퓨터가 아니라, 외부 사용자가 접근할 수 있는 공개 주소다. 사용자는 이 주소만 입력하지만, 실제로는 브라우저가 여러 단계를 거쳐 블로그가 있는 위치를 찾아간다.
이 블로그는 Vercel에 배포했고, Gabia에서 구매한 yunkoo.dev 도메인을 Vercel 프로젝트에 연결했다. 이제 그 연결이 실제 요청 흐름에서 어떤 의미를 가지는지 알아보자.
DNS는 왜 필요한가
사람은 yunkoo.dev 같은 이름을 기억하기 쉽다. 하지만 브라우저가 실제로 요청을 보내려면 이 이름이 어느 서버나 배포 플랫폼을 가리키는지 알아야 한다.
이때 필요한 것이 DNS다.
쉽게 말하면 DNS는 인터넷의 주소록에 가깝다. 사용자가 yunkoo.dev를 입력하면 브라우저는 DNS를 통해 이 도메인이 어디로 연결되어야 하는지 확인한다.
이 블로그에서는 yunkoo.dev 도메인을 Gabia에서 구매했고, DNS 설정을 통해 그 도메인이 Vercel 프로젝트를 가리키도록 연결했다. Gabia는 도메인을 구매하고 관리하는 출발점이고, Vercel은 최종적으로 블로그 결과물을 응답하는 배포 환경이다.
이 흐름에서 중요한 점은 도메인, DNS 설정, 배포 플랫폼이 각각 다른 역할을 한다는 점이다.
접속부터 브라우저 렌더링까지
사용자가 yunkoo.dev에 접속하면 브라우저는 먼저 도메인이 어디를 가리키는지 확인하고, Vercel/CDN에 HTTPS 요청을 보낸다. 그 다음 서버에서 HTML, CSS, JavaScript 같은 리소스를 받아온다. 하지만 파일을 받았다고 바로 화면이 완성되는 것은 아니다. 브라우저는 이 리소스들을 해석해서 실제 픽셀로 바꾸는 과정을 거친다.
이 글에서는 접속부터 렌더링까지의 큰 흐름을 하나로 보면 더 이해하기 쉽다.
이 흐름에서 중요한 점은 브라우저와 크롤러가 같은 응답을 각자의 방식으로 해석한다는 것이다.
사용자가 /posts/... 경로에 접속하면 Next.js는 글 본문 HTML과 metadata를 제공한다. 브라우저는 이 HTML을 바탕으로 DOM을 만들고 CSS를 적용해 화면을 그린다. 반면 검색엔진과 AI 크롤러는 같은 응답 안에 있는 제목, 설명, canonical URL, 본문 내용을 읽으면서 이 페이지가 어떤 문서인지 이해한다.
1. HTML 파싱과 DOM 생성
HTML은 문서의 구조를 나타낸다. 브라우저는 서버에서 받은 HTML을 위에서 아래로 읽으면서 요소를 노드 형태로 바꾼다. 이 결과가 DOM이다.
DOM은 Document Object Model의 줄임말이다. 브라우저가 HTML 문서를 다루기 위해 만든 트리 구조라고 볼 수 있다.
예를 들어 이런 HTML이 있다고 해보자.
<article>
<h1>yunkoo.dev는 어떻게 사용자에게 도착할까</h1>
<p>브라우저는 HTML을 읽고 DOM을 만든다.</p>
</article>브라우저는 이것을 article 안에 h1과 p가 들어 있는 구조로 이해한다. 이 구조가 있어야 CSS를 적용하고, JavaScript로 특정 요소를 찾고, 화면에 어떤 순서로 보여줄지 결정할 수 있다.
2. CSS 파싱과 CSSOM 생성
HTML이 문서의 구조라면 CSS는 그 구조를 어떻게 보여줄지 정하는 규칙이다. 브라우저는 CSS를 읽어서 CSSOM을 만든다.
CSSOM은 CSS Object Model의 줄임말이다. DOM이 HTML 구조를 표현한다면, CSSOM은 각 요소에 어떤 스타일이 적용되어야 하는지 표현한다.
article {
max-width: 720px;
}
h1 {
font-size: 2rem;
}브라우저는 이런 CSS를 읽고 article은 최대 너비를 가지고, h1은 큰 글자로 보여야 한다는 정보를 계산한다.
여기서 중요한 점은 브라우저가 화면을 그리려면 DOM만으로는 부족하다는 것이다. 어떤 요소가 있는지뿐 아니라, 그 요소가 어떤 크기와 색상과 간격을 가져야 하는지도 알아야 한다.
3. Render Tree 생성
DOM과 CSSOM이 준비되면 브라우저는 Render Tree를 만든다.
Render Tree는 실제 화면에 그려질 요소만 모아둔 트리다. DOM에는 존재하지만 display: none이 적용된 요소처럼 화면에 보이지 않는 것은 Render Tree에 포함되지 않는다.
이 단계부터는 브라우저가 단순히 문서를 읽는 것이 아니라, 실제 화면을 만들 준비를 한다고 볼 수 있다.
렌더링 과정을 이해하면 성능 최적화도 더 구체적으로 볼 수 있다. 화면이 느리거나 버벅이는 이유는 단순히 "코드가 많아서"가 아닐 수 있다. 어떤 변경은 Layout을 다시 만들고, 어떤 변경은 Paint를 다시 일으키고, 어떤 변경은 Composite 단계만 다시 처리되기도 한다.
4. Layout
Layout 단계에서는 각 요소가 화면의 어디에, 어떤 크기로 배치될지 계산한다. 그래서 이 단계를 Reflow라고 부르기도 한다.
예를 들어 본문 컨테이너의 너비가 얼마인지, 제목의 높이가 얼마인지, 이미지가 어느 위치에 놓일지 계산하는 과정이다. 화면 크기가 바뀌거나, 폰트 크기가 바뀌거나, 이미지 크기가 뒤늦게 정해지면 Layout이 다시 일어날 수 있다.
프론트엔드 성능에서 Layout이 중요한 이유도 여기에 있다. 위치와 크기를 자주 다시 계산하게 만들면 브라우저가 해야 할 일이 많아지고, 사용자는 화면이 흔들리거나 느리다고 느낄 수 있다.
5. Paint
Paint 단계에서는 Layout에서 계산된 박스에 실제 색상, 글자, 테두리, 그림자, 이미지 등을 칠한다. 즉, 요소가 어디에 놓일지는 Layout에서 결정하고, 그 요소를 어떻게 픽셀로 칠할지는 Paint에서 처리한다.
Layout과 Paint를 구분해서 이해하는 것은 면접에서도 자주 중요하게 다뤄진다.
6. Composite
마지막으로 브라우저는 여러 레이어를 합성해서 최종 화면을 보여준다. 이 단계가 Composite다.
모든 요소를 하나의 큰 그림처럼 한 번에 처리하는 것이 아니라, 브라우저는 필요에 따라 레이어를 나눠 관리한다. 예를 들어 transform이나 opacity 같은 속성은 Layout을 다시 계산하지 않고 합성 단계에서 처리될 수 있는 경우가 있다.
그래서 애니메이션을 만들 때 top, left보다 transform을 선호하라는 말을 자주 듣는다. top, left는 위치 계산에 영향을 줄 수 있지만, transform은 합성 단계에서 처리되기 쉬워 상대적으로 부드러운 애니메이션을 만들기 좋다.
7. Hydration
Next.js나 React 기반 서비스에서 자주 나오는 개념이 hydration이다. 서버나 빌드 과정에서 만들어진 HTML은 브라우저가 먼저 화면에 보여줄 수 있다. 하지만 이 HTML만으로는 React 컴포넌트의 이벤트 처리나 상태 관리가 완전히 살아 있는 상태는 아니다.
Hydration은 브라우저에서 JavaScript가 로드된 뒤, 이미 화면에 있는 HTML에 React의 이벤트와 상태를 연결하는 과정이다.
예를 들어 사용자는 글 본문 HTML을 먼저 볼 수 있다. 그 뒤 JavaScript가 로드되고 hydration이 끝나면 테마 전환 버튼, 클라이언트에서 렌더링되는 Mermaid 다이어그램, 사용자 상호작용이 필요한 컴포넌트가 정상적으로 동작한다.
렌더링 최적화에서 신경 쓸 부분
- 이미지나 광고처럼 크기가 늦게 정해지는 요소는 width와 height를 미리 잡아 Layout Shift를 줄인다
- 반복적으로 DOM 크기를 읽고 바로 스타일을 바꾸는 코드는 Layout을 자주 다시 일으킬 수 있다
- 색상이나 그림자처럼 Paint 비용이 큰 스타일 변경은 남발하지 않는다
- 애니메이션은 가능하면 transform과 opacity처럼 Composite 단계에서 처리되기 쉬운 속성을 사용한다
- 초기 화면에 필요하지 않은 JavaScript는 줄이거나 늦게 불러와 첫 렌더링을 방해하지 않게 한다
브라우저 렌더링 핵심 정리
- 접속은 DNS 조회와 HTTPS 요청에서 시작된다.
- HTML은 DOM이 되고, CSS는 CSSOM이 된다.
- DOM과 CSSOM이 합쳐져 Render Tree가 된다.
- Layout은 위치와 크기를 계산하는 단계다.
- Paint는 계산된 영역을 픽셀로 칠하는 단계다.
- Composite는 여러 레이어를 합쳐 최종 화면을 만드는 단계다.
- Hydration 이후 React 컴포넌트의 상호작용이 연결된다.
여기까지가 사람이 브라우저에서 화면을 보기까지의 과정이라면, 다음은 검색엔진과 AI가 이 문서를 어떻게 이해하는지에 대한 이야기다.
SEO를 한 이유
SEO(Search Engine Optimization)는 검색엔진이 내 페이지를 더 잘 이해하고 검색 결과에 적절히 보여줄 수 있도록 돕는 작업이다.
개인 블로그는 글을 쓰는 것에서 끝나지 않는다. 내가 정리한 내용이 검색을 통해 필요한 사람에게 닿으려면, 검색엔진이 페이지를 읽을 수 있어야 한다. 그래서 제목, 설명, URL, sitemap, robots, RSS, 구조화 데이터 같은 단서가 필요했다.
이 블로그에서는 Next.js의 metadata 기능을 사용해 페이지별 title, description, canonical URL, Open Graph 정보를 관리한다. 그리고 /sitemap.xml은 공개된 글 목록을 검색엔진에게 알려주고, /robots.txt는 크롤러가 사이트를 어떻게 접근해도 되는지 안내한다. /rss.xml은 RSS 리더가 새 글을 가져갈 수 있는 통로다.
또 글 상세 페이지에는 JSON-LD를 추가했다. JSON-LD는 화면에 보이는 UI는 아니지만, 검색엔진이 이 페이지가 블로그 글이고, 제목과 작성일과 태그가 무엇인지 구조적으로 이해하도록 돕는다.
이 블로그에서 SEO를 위해 제공한 단서
- title과 description으로 페이지의 핵심 내용을 알려준다
- canonical URL로 대표 주소를 명확히 한다
- sitemap으로 공개 글 목록을 알려준다
- robots로 크롤러 접근 정책을 안내한다
- RSS로 글 구독 경로를 제공한다
- JSON-LD로 글의 구조를 기계가 읽기 쉽게 제공한다
AEO와 GEO까지 고려한 이유
예전에는 검색 결과에서 링크를 잘 보여주는 것이 중요했다. 하지만 요즘은 검색 방식이 조금씩 달라지고 있다. 사용자는 검색창에 단어만 입력하는 것이 아니라 질문을 던지고, 검색엔진이나 AI는 여러 문서를 참고해 바로 답변을 만들기도 한다.
이 흐름에서 AEO와 GEO를 함께 고려하게 됐다.
AEO(Answer Engine Optimization)는 답변형 검색에 대응하는 관점이다. 사용자가 “Next.js 블로그에서 글 공개를 어떻게 제어할까?”처럼 질문했을 때, 글의 핵심 답변이 분명하게 정리되어 있으면 답변 엔진이 내용을 이해하기 쉽다.
GEO(Generative Engine Optimization)는 생성형 AI가 웹 문서를 참고할 때 글의 맥락과 구조를 더 잘 이해하도록 돕는 관점이다. AI가 내 글을 읽는다면 단순히 긴 본문만 보는 것보다, 요약과 질문, 구조화 데이터가 함께 있는 편이 더 정확한 맥락을 잡기 쉽다.
실제로 적용한 것
이 블로그에서는 SEO/AEO/GEO를 위해 몇 가지 기능을 추가했다. 핵심은 기존 글을 모두 억지로 바꾸는 것이 아니라, 필요한 정보를 선택적으로 더 제공할 수 있게 만드는 것이었다.
- 1
페이지별 metadata와 canonical URL을 관리한다
- 2
sitemap과 robots로 크롤러가 사이트 구조를 이해하게 한다
- 3
RSS로 글 구독 경로를 제공한다
- 4
글 상세 페이지에 BlogPosting JSON-LD를 제공한다
- 5
llms.txt로 AI가 참고할 수 있는 사이트 요약과 공개 글 목록을 제공한다
- 6
summary와 FAQ JSON-LD, wordCount로 글의 핵심과 구조를 더 명확히 제공한다
llms.txt
llms.txt는 AI가 사이트를 이해할 때 참고할 수 있는 텍스트 안내문에 가깝다. 이 블로그에서는 /llms.txt 경로에서 사이트 이름, 설명, 언어, RSS, sitemap, 주요 섹션, 공개 글 목록을 Markdown 형식으로 제공한다.
사람이 보는 화면은 아니지만, AI나 자동화된 도구가 사이트 구조를 빠르게 파악하는 데 도움이 될 수 있다.
AI crawler 정책
robots.ts에서는 일반 크롤러 접근을 허용하면서, OAI-SearchBot, ChatGPT-User, GPTBot 같은 AI 관련 크롤러도 명시적으로 허용했다. 사실 userAgent: "*"에 allow: "/"를 설정했기 때문에 정상적인 크롤러는 기본적으로 접근할 수 있다. AI 관련 크롤러를 따로 적은 것은 기능적으로 완전히 새로운 문을 여는 것이라기보다, 공개 글을 AI 기반 탐색에서도 읽을 수 있게 하겠다는 의도를 코드에 명확히 남긴 것에 가깝다.
이 설정은 “내 블로그 글을 AI가 참고할 수 있다”는 방향을 분명히 하기 위한 선택이다. 개인 블로그의 목적이 글을 공개하고 공유하는 것이라면, 검색엔진뿐 아니라 AI 기반 탐색에서도 문서가 접근 가능하도록 두는 것이 자연스럽다고 생각했다.
다만 여기서 조심해야 할 점이 있다. robots.txt나 Next.js의 robots.ts는 보안 장치가 아니다. 정상적인 크롤러에게 "이 사이트는 이렇게 접근해도 된다"라고 알려주는 약속에 가깝다. Googlebot이나 GPTBot처럼 규칙을 지키는 크롤러는 이 정책을 참고하지만, 악의적인 봇이나 공격자는 이 파일을 무시할 수 있다.
그래서 실제 방어는 다른 계층에서 생각해야 한다. 예를 들어 Vercel이나 CDN 레벨의 DDoS 방어, 과도한 요청에 대한 rate limit, 비용이 큰 API의 인증과 캐싱, 비공개 경로에 대한 실제 접근 제어가 필요하다. 공개 블로그 글처럼 정적인 콘텐츠는 위험이 상대적으로 낮지만, robots.txt만 믿고 보안을 맡기는 것은 맞지 않다.
크롤러 허용과 보안은 분리해서 봐야 한다
- robots.txt는 정상 크롤러에게 보내는 정책 안내다
- 악의적인 봇은 robots.txt를 무시할 수 있다
- 비공개 데이터는 robots.txt가 아니라 인증과 접근 제어로 막아야 한다
- 과도한 요청은 CDN, 배포 플랫폼, rate limit 같은 계층에서 제어해야 한다
- AI crawler 허용은 공개 글을 읽도록 허용한다는 의미이지 모든 봇을 무제한 허용한다는 의미가 아니다
JSON-LD 확장
글 상세 페이지에는 BlogPosting JSON-LD를 제공한다. 여기에는 제목, 설명, 작성일, 태그, 글 URL 같은 정보가 들어간다. 추가로 wordCount, articleSection, isPartOf, FAQ 정보도 넣을 수 있게 확장했다.
이 데이터는 화면에 직접 보이지 않아도 검색엔진과 AI가 글을 구조적으로 이해하는 데 도움을 준다.
summary와 FAQ
글마다 summary와 faq를 선택적으로 작성할 수 있게 했다. 모든 글에 강제로 넣는 값은 아니다. 하지만 중요한 글에서는 핵심 요약과 예상 질문을 frontmatter에 적어둘 수 있다.
이렇게 하면 글 상세 페이지에서는 요약 박스를 보여줄 수 있고, JSON-LD에서는 FAQ 구조를 제공할 수 있다. 검색엔진과 AI 입장에서는 긴 본문을 읽기 전에 글의 핵심 질문과 답변을 더 쉽게 파악할 수 있다.
선택한 이유
- 사람에게는 본문을 읽기 전에 핵심 요약을 제공할 수 있다
- 검색엔진에는 글의 주제와 구조를 더 명확히 알려줄 수 있다
- FAQ JSON-LD를 통해 질문과 답변 구조를 기계가 읽기 쉽게 제공할 수 있다
- 기존 글을 모두 수정하지 않아도 필요한 글부터 점진적으로 확장할 수 있다
정리
이번 글에서 정리하고 싶었던 핵심은 하나다.
배포된 블로그는 단순히 서버 어딘가에 올라간 파일이 아니다. 사용자는 yunkoo.dev라는 도메인으로 접근하고, DNS는 그 도메인을 실제 배포 환경과 연결한다. 브라우저는 서버에서 받은 HTML, CSS, JavaScript를 해석해 화면으로 렌더링한다. 그리고 검색엔진과 AI는 metadata, sitemap, robots, RSS, JSON-LD, llms.txt 같은 단서를 통해 문서를 이해한다.
이제 내 블로그는 단순히 배포된 화면이 아니라, 사람이 접근하고 브라우저가 렌더링하며 검색엔진과 AI가 이해할 수 있는 문서가 되었다. 그래서 배포 방법 자체보다, 배포된 결과물이 웹에서 어떻게 동작하고 이해되는지를 설명하는 글로 정리했다.