우리는 컴퓨터가 없으면 안되는 시대에 살고있습니다, 그리고 그에 걸맞게 컴퓨터를 거의 매일 사용히죠.
문자를 주고받거나, 웹서핑을 하거나, 문서를 이용해 업무를 보거나, 또 그 문서를 주고받거나..
컴퓨터는 매우 유용하게 우리의 곁에서 한 자리를 차지하고 있습니다.
그리고 이 컴퓨터는 나날이 발전하여 우리의 생활을 더욱더 편리하게 해주고 있습니다.
인터넷의 발전은 내 방에서 전세계와 소통할 수 있는 창구를 열어주었고, 지구 반대편에 있는 나라에서
무슨 일이 일어나는지 컴퓨터만 키면 확인이 가능하게 됬으니까요.
만약 우리가 그저 일반인이라면 이정도에서 만족하고 그대로 발전된 기술을 즐기면 그만이겠지만.
다행히도(?) 우리는 개발자 입니다, 이러한 현상에 대해서 궁금할 수 있게 되었습니다.
어떻게? 왜? 엔터의 클릭 한번만으로 전세계의 정보를 가져올 수 있는가? 어떻게 지구 반대편 나라에 있는
친구와 이렇게 간단하게 소통할 수 있는가? 도대체 이 네트워크 안에서 어떤일이 벌어지고 있는것인가?
우리는 궁금해할 수 있습니다, 아니어도 그렇다고 칩시다.
이제 이 물음에 대한 해답을 찾아볼 시간입니다, 물론 이 해답이 완벽하진 않을 수 있습니다.
우리가 사용하고 있는 HTTP를 단순히 Document 전송프로토콜 로 생각할 수도 있겠지만,
본질적으로는 인터넷의 근간이 된다고 생각합니다.
HTTP 요청은 주소창에 URL 을 입력하거나, 앱, 웹사이트 또는 다른 프로그램을 이용하는것으로
그 요청이 시작되고, 요청에 대한 응답을 수신하면 그 소통은 끝이나게 되는데, 이 사이에
마법같은 일이 일어납니다, 이것이 조금은 과하지만 우리가 HTTP 요청을 이해하는 전형적인 방식입니다.
예를 하나 들어봅시다, 우리의 시스템 내에서 app.mydomain.com/me
을 열었다고 가정해 보겠습니다.
URL 앞에는 http://
가 있을것이구요, 그럼 http://app.mydomain.com/me
가 되겠군요.
이 URL 을 분해해서 살펴보겠습니다.
http://
: 통신에 사용된 프로토콜mydomain.com
: 서버의 도메인app
: 서버의 서브도메인/me
: 요청 Path한글을 사용할때, 또는 영어를 사용할때, 그 언어만의 표준 문법으로 모든 사람이 소통이 가능하듯이
HTTP 프로토콜도 전세계적으로 약속되어있는 표준규칙이 있어서 이러한 유의미한 통신이 가능한것입니다.
인터넷은 쉽게 말하자면 글로벌 케이블 네트워크 입니다. 이 인터넷으로 인해 전세계에 뿌려져있는
각각에 디바이스들이 연결되어 서로 통신이 가능하게 해줍니다. 그것을 가능하게 해주는것이 지구전역의
모든 데이터들을 전달하는 심해케이블 덕분이랄까요.
심해케이블이란 녀석이 생소할 수 있지만, 걱정은 안하셔도 됩니다, 저도 그랬으니까요.
당연히 우주에 떠다니는 인공위성에서 라우팅 해주는줄 알았더니, 바닷속에 있었다네요.
예를 들어보자면, 우리가 한국에 있는데 미국에 있는 서버를 연결하려고 한다치자면, 이 케이블 중 하나는
우리의 요청을 한국에서 미국으로 보낼것입니다, 근데 함정이 있다고 합니다.
패킷/데이터 라우팅은 IP 주소를 이용하는것이지 도메인네미을 이용하지는 않는다고 합니다.
(우편이 거리이름과 집 주소를 보지, 우리 이름을 보고 배달되는것이 아닌것과 같은 의미입니다.)
이제 우리는 인터넷의 주소록인 Domain Name Server (DNS) 에 붙어서 app.domain.com
의
IP 주소를 물어봅니다, 그러면 DNS 서버는 그 IP 주소를 알려줍니다.
그럼 여기서 또 하나의 의문이 생기죠, "그럼 DNS 서버의 주소는 어떻게 알지?"
통신을하기 위해서 한 기기는 다른기기의 IP 주소를 꼭 알고 있어야 하기에, 클라이언트는 DNS 서버의
IP 주소를 미리 알고 있어야 합니다. 우리가 네트워크에 연결되면 그 클라이언트는 IP 주소를 할당받는데,
이때 DNS의 서버주소도 같이 알려주게 됩니다, 또한 우리가 수동으로 특정 DNS 서버를 등록하여
사용할 수 도 있습니다.
그러면 실제로 DNS 서버가 어떻게 도메인을 IP 주소로 풀까요?
일단 클라이언트는 DNS recursor server
로 요청을 보냅니다.
우리가 도메인을 구입할때마다 우리의 모든 DNS record 를 관리하기에 믿을만한 네임서버에 설정을 합니다.
이제 우리의 도메인 (mydomain.com) 을 cloudfare 네임서버에 설정했다고 보겠습니다.
그러면 우리 도메인에 대한 모든 쿼리는 cloudfare 가 응답할 권한을 가집니다. 그래서 이 네임서버가
Authoritative Name Server
로 불립니다.
그러면 DNS recursor 는 어떻게 우리의 Authoritative Name Server 로 도달할 수 있을까요?
.com
에 해당 ).com
)의 모든 도메인에 대한 Authoritative Name Server우리는 처음에 app.domain.com
을 요청했기때문에 표를 보면 app 에 해당하는 레코드를 찾을 수 있고
그에 해당하는 IP 주소를 리턴합니다, 이제 app.mydomain.com
에 해당하는 IP 주소를 알기때문에
클라이언트가 서버에 붙을 수 있게 되었습니다.
우리는 인입되는 HTTP 요청을 다룰 수 있는 웹 서버를 운영합니다, 대개 자주 사용되는 웹서버는
Apache 나 Nginx 가 있습니다, 이 웹서버는 계속해서 인입되는 요청을 기다리고,요청에 대한 응답을 합니다.
근데, 서버에서 돌고 있는 프로세스가 많을텐데, 어떻게 Apache 로 잘 도착을 하는걸까요?
다른 장비처럼 여러 프로세스가 있겠죠? 이때 네트워크 포트가 유용한 지점입니다.
Apache 와 같은 프로세스는 네트워크 포트를 물고잇고, 이 포트를 통해서 listen 합니다.
단, 하나의 포트는 다수의 프로세스가 함께 사용할 수 는 없지만 하나의 프로세스는 여러 포트를
사용할 수 있습니다.
그래서 우리는 통신을 위한 포트를 정해야 합니다, 그런데 우리는 포트를 정한적이 없습니다, 그렇죠?
앞에서 말했듯이 HTTP 프로토콜은 전세계적으로 미리 정의된 규칙을 가지고 있습니다. 그중 하나가
기본포트가 80(http)
,443(http)
인것입니다 (같은맥락으로 DNS 는 53입니다)
그래서 우리의 Apache 는 우리 서버에서 80,433 포트를 listen 하는것입니다.
단지 우리가 기본포트를 변경하지 않았을뿐이지, 우리는 3000번 포트로 Apache를 띄울 수 있습니다.
그러나 그렇게 되면 HTTP 의 표준포트를 이용하는것이 아니기 때문에, 명시적으로 포트를 써워야 합니다.
-> http://app.mydomain.com:3000/me
웹 서버 애플리케이션의 대표적인 두가지 Use case 가 있습니다.
스태틱 파일 서빙
<VirtualHost *:80>
ServerName app.mydomain.com
DocumentRoot "/var/www/my-static-website"
ServerAdmin admin@mydomain.com
</VirtualHost>
우리가 app.mydomain.com/me
로 요청하면, /var/www/my-static-website
에서
폴더나 파일을 찾습니다. 그리고 파일이 있으면 그 파일을 리턴합니다. 또는 폴더가 존재한다면,
해당 폴더에서 index.html(변경가능)
찾아 리턴합니다.
다른 프로세스로 요청을 전달
우리가 Node, Java, Python 또는 다른 프로세스를 4000번 포트로 띄우고,
그 프로세스가 요청을 처리하기를 원한다고 해봅시다.
이 경우, 아파치는 그 서버에 대해 프록시 역할을 할 수 있습니다.
<VirtualHost *:80>
ServerName app.mydomain.com
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:4000/
ProxyPassReverse / http://127.0.0.1:4000/
</VirtualHost>
app.mydomain.com
으로 들어온 모든 요청은 http://127.0.0.1:4000
으로 포워딩 될 것이고,
응답을 받으면, 그 응답을 클라이언트로 다시 전달해 줄 것입니다.
꼭 localhost로 포워딩 할 필요는 없고 다른 서버에 대한 프록시 역할도 가능합니다.
보통 한 서버에 하나 이상의 웹사이트를 띄우는데 그렇게되면, 두개 이상의 프로세스가 하나의 포트를 점유할
수 없습니다, 다행히 Apache는 ServerName 기반으로 요청을 받기 때문에 여러 웹 사이트 운용이 가능하죠.
그러나 만약 Node와 같이 우리가 하나의 서버만 호스팅한다면, Apache를 제거하고 얘네들을 직접 80으로
띄워서 운영할 수 있습니다. 직접 응답을 클라이언트로 보내게 됩니다.
HTTPS는 HTTP의 업그레이드 버전입니다. HTTP는 모든 것을 평문으로 전송한죠. 우리는 이 데이타가
여러 회사가 갖고 있는 광케이블 네트워크를 통해 전달되고, 여러 정치관할구역을 지나는 것도 압니다.
이때 누군가가 슬쩍 이 네트워크를 건드려서 클라이언트와 서버사이의 메시지를 볼 수도 있습니다.
우리 Gmail 계정으로 예를 들면, 모두가 우리 이메일과 비밀번호를 읽을 수 있습니다.
끔찍하죠?, 이것이 HTTPS 가 없는 인터넷입니다. HTTPS는 클라이언트와 서버사이에 end-to-end 암호화
를 제공하고, 아무도 이 메시지를 읽을 수 없습니다.
HTTPS의 보안이 없다면 광범위한 현대의 인터넷은 불가능 했을 것입니다.