IPv4와 IPv6 클라이언트에 같은 안내서 제공하기

LinuxBeginner
지금 연습하기

소개

Riverlight Gathering에는 이미 IPv4로 작동하는 행사 안내서가 있습니다. 방문객에게는 도착 안내와 다운로드할 수 있는 프로그램을 포함한 동일한 전체 안내서를 IPv6로도 제공해야 합니다. 네트워크 주소는 준비되어 있지만 웹 서비스는 아직 IPv6 연결을 수신하지 않으며, 안내서의 AAAA 레코드는 잘못된 주소를 가리킵니다.

두 문제를 구분하여 해결합니다. 먼저 애플리케이션에 직접 IPv6로 접근하게 하고, 그다음 이름을 수정합니다. IPv4, 안내 데스크, 다른 DNS 레코드와 모든 원본 페이지 및 다운로드 바이트를 보존합니다. 기본적인 터미널, 경로, 탭 사용과 주소·이름·포트 구별을 전제로 합니다. Nginx나 IPv6 관리 경험은 필요하지 않습니다. 70분은 작성자의 예상 시간입니다.

Guide Server와 Guide Client는 이 교육 인스턴스의 커널을 공유하는 격리된 네트워크 노드이며, 별도의 VM이 아닙니다. guide.conf의 수신 지시문과 guide.zone의 대상 AAAA/SOA 일련번호만 변경합니다. 다운로드는 클라이언트 작업 공간에 저장합니다. 경로, 주소, IPv6 스위치, 다른 사이트, 원본 페이지 또는 플랫폼 설정은 바꾸지 않습니다. 준비된 로컬 네트워크를 사용하며, 공용 IPv6, RA, DHCPv6, 터널, NAT64는 다루지 않습니다.

주소 계열 비교하기

이 단계에서는 작동 중인 IPv4 안내서를 읽고, 도달 가능한 IPv6 주소와 연결을 수신하는 애플리케이션을 구별합니다. Guide Client에서 시작하세요. 이 터미널은 /home/labex/project/ipv6-guide/client에서 시작하며, 셸과 디렉터리 상태는 Guide Server와 독립적으로 유지됩니다. pwd는 현재 디렉터리를 출력합니다.

pwd

IPv4 주소는 10.77.0.10처럼 네 개의 십진수 부분으로 구성됩니다. IPv6는 여덟 개의 16진수 그룹을 사용합니다. 그룹 앞의 0은 생략할 수 있으며, 하나의 ::로 연속된 0 그룹을 대체할 수 있습니다. 여기서 fd77:7::10은 fd77:0007:0000:0000:0000:0000:0000:0010을 뜻합니다. 마지막 10은 IPv4 끝부분의 십진수와 달리 16진수입니다. 이 사설 교육용 주소가 공용 인터넷 접근성을 의미하지는 않습니다.

curl은 HTTP 리소스를 가져옵니다. -4는 IPv4를 강제하고, -f는 HTTP 오류 응답을 실패로 처리하며, -s는 진행 표시를 숨기고, -S는 오류를 계속 표시합니다. --noproxy '*'는 모든 호스트에 대해 프록시를 우회합니다. 따옴표는 *를 파일 이름으로 확장하지 않고 문자 그대로 유지합니다. 포트 8080은 안내서 애플리케이션을 선택합니다. -o는 받은 바이트를 파일에 저장하며, v4는 준비된 출력 디렉터리입니다.

curl --noproxy '*' -4 -fsS http://guide.riverlight.test:8080/index.html -o v4/index.html

저장에 성공하면 보통 아무것도 출력되지 않습니다. head -c 180은 파일을 변경하지 않고 처음 180바이트를 읽습니다.

head -c 180 v4/index.html

Riverlight Gathering이 포함된 HTML이 보여야 합니다. 이것이 보존할 정상 기준입니다. 브라우저에서 페이지의 완전한 모습을 보려면 나중에 저장할 스타일시트도 필요합니다.

이제 준비된 IPv6 주소를 테스트합니다. ping -6는 IPv6 에코 요청을 보내며, -c 1은 한 번 후 종료합니다. HTTP가 아닌 네트워크 도달성을 검사합니다.

ping -6 -c 1 fd77:7::10

응답이 와야 합니다. URL에서 IPv6 주소를 직접 쓰는 경우 대괄호로 감싸 주소의 콜론과 포트 구분자를 구별합니다. URL 전체를 따옴표로 감쌉니다. -6는 IPv6를 강제하며, --max-time 3은 요청을 3초로 제한합니다.

curl --noproxy '*' -6 -fsS --max-time 3 'http://[fd77:7::10]:8080/'

이 요청은 curl: (7)과 연결 거부로 실패하는 것이 예상 결과입니다. IPv6 주소는 존재하고 에코에 응답하지만, 애플리케이션은 해당 IPv6 끝점을 열지 않았습니다. 반면 시간 초과는 제한 시간 내에 유용한 응답이 없다는 뜻이며 즉시 거부와 다릅니다. 어느 경우도 IPv6를 비활성화해 해결하지 마세요. 일반적인 이중 스택 브라우저는 IPv4로 재시도할 수 있으므로, 거기서 페이지가 보인다고 IPv6 성공이 증명되지는 않습니다.

이름을 잘못 입력하면 curl 오류 6이 나타날 수 있으며, 이름 확인 실패를 뜻합니다. 철자를 비교한 뒤 첫 명령을 다시 실행하세요. 저장 경로 오타는 로컬 쓰기 오류를 일으킵니다. pwd와 제시된 v4/index.html 경로를 확인하세요. 이러한 오류는 도달 가능한 서버가 요청 리소스의 부재를 알리는 HTTP 404와도 다릅니다.

웹 서비스가 IPv6 연결을 수신하도록 설정하기

이 단계에서는 작동 중인 IPv4 리스너를 보존하고 별도의 IPv6 리스너를 추가합니다. Guide Server로 전환하세요. 시작 위치는 /home/labex/project/ipv6-guide/config입니다. cat으로 준비된 끝점 표와 짧은 대상 설정을 읽습니다.

cat endpoints.tsv
cat guide.conf

안내서는 10.77.0.10과 fd77:7::10의 포트 8080에서 제공해야 합니다. 안내 데스크는 포트 8081을 사용하므로 보존합니다. server_name은 사이트 이름을, root는 원본 페이지 위치를, index는 홈페이지를 선택합니다. 중괄호는 서버 블록을 묶고 각 지시문은 세미콜론으로 끝납니다.

ss는 커널의 소켓을 읽습니다. -l은 수신 대기 소켓, -t는 TCP, -n은 숫자 주소와 포트, -p는 소유 프로세스를 표시합니다.

ss -ltnp

IPv4 10.77.0.10:8080의 Nginx를 찾으세요. 안내서 IPv6 리스너는 아직 없습니다. 데스크의 IPv6 :8081 소켓은 안내서 포트를 제공하지 않습니다.

완전한 템플릿으로 짧은 파일 전체를 대체합니다. cat > guide.conf는 이전 내용을 대체하여 이 파일에 씁니다. <<'NGINX'는 here-document를 시작합니다. 셸은 NGINX만 있는 줄까지 이후 모든 줄을 그대로 입력받습니다. 마지막 표시 줄까지 전체 블록을 붙여 넣으세요. 먼저 cp로 로컬 백업을 만듭니다. 두 번째 파일 이름이 복사본입니다.

cp guide.conf guide.conf.before
cat > guide.conf <<'NGINX'
server {
    listen 10.77.0.10:8080;
    listen [fd77:7::10]:8080 ipv6only=on;
    server_name guide.riverlight.test;
    root /opt/labex/ipv6-guide/www;
    index index.html;
    error_page 404 /404.html;
}
NGINX

listen은 애플리케이션 끝점을 엽니다. 새 대괄호 주소는 IPv6이며, ipv6only=on은 해당 리스너를 IPv6 전용으로 유지합니다. 남겨 둔 IPv4 줄이 별도로 IPv4를 제공합니다. 주소 설정만으로는 이 수신 소켓을 만들 수 없습니다.

준비된 guide-control 명령은 이 강좌의 독립된 서비스만 검사하거나 불러옵니다. web-check는 변경을 적용하지 않고 Nginx 설정 검사를 실행합니다.

guide-control web-check

syntax is ok와 test is successful이 보여야 합니다. 세미콜론, 괄호 또는 주소를 잘못 입력하면 오류에 파일과 줄 번호가 나옵니다. 아직 아무것도 적용되지 않았습니다. 위의 완전한 템플릿을 다시 입력하고 검사하세요. 원래 작동하던 IPv4 설정으로 돌아가려면 cp guide.conf.before guide.conf로 백업을 복원할 수 있습니다. 불러오기 전에 파일을 검사하세요. 플랫폼 Nginx나 네트워크를 다시 시작하지 마세요.

web-load는 다시 검사한 뒤 설정 재적용을 요청합니다. 저장된 설정을 적용하면서 강좌의 마스터 프로세스를 유지합니다. 파일을 저장하는 것만으로 서비스가 바뀌지는 않습니다.

guide-control web-load
ss -ltnp

Nginx가 소유한 10.77.0.10:8080과 [fd77:7::10]:8080이 모두 보여야 합니다. 로그에 끝점이 사용 중이라고 나오면 파일을 전체 템플릿과 비교하고 ss를 확인하세요. 무관한 서비스를 중지하지 마세요.

Guide Client로 전환합니다. -w는 본문 뒤에 연결 사실을 출력합니다. 따옴표로 감싼 형식의 \n은 줄바꿈이며, curl은 %{remote_ip}를 실제 상대 주소로, %{http_code}를 응답 상태로 바꿉니다.

curl --noproxy '*' -6 -fsS --max-time 3 -w '\npeer=%{remote_ip} status=%{http_code}\n' 'http://[fd77:7::10]:8080/'

Riverlight HTML 다음에 peer=fd77:7::10 status=200이 나와야 합니다. 상태뿐 아니라 내용도 읽으세요. 무관한 기본 페이지의 200은 올바른 결과가 아닙니다. 이 직접 요청의 성공은 애플리케이션 계층을 분리해 확인합니다. 아직 안내서 이름을 수정하지는 않았습니다.

이름을 작동 중인 IPv6 서비스로 연결하기

이 단계에서는 대상 AAAA만 수정하고 실제 캐시가 자연스럽게 갱신되게 합니다. Guide Client에서 시작합니다. DNS는 Domain Name System, 즉 이름을 데이터에 대응시키는 시스템입니다. A 레코드는 IPv4를, AAAA는 IPv6를 제공합니다. DNS 질의 자체는 IPv4로 전송되면서 IPv6 주소를 반환할 수도 있습니다.

dig는 DNS를 질의합니다. @10.77.0.2는 이 영역을 담당하는 준비된 권한 서버를 선택합니다. +noall +answer는 다른 구역을 숨기고 응답 행을 표시합니다.

dig @10.77.0.2 guide.riverlight.test A +noall +answer
dig @10.77.0.2 guide.riverlight.test AAAA +noall +answer

A 레코드는 10.77.0.10으로 올바릅니다. 현재 AAAA의 fd77:7::99는 작동 중인 서비스와 일치하지 않습니다. 이제 루프백 127.0.0.1의 클라이언트 독립 캐시 리졸버를 질의합니다.

dig @127.0.0.1 guide.riverlight.test AAAA +noall +answer

행에는 이름, TTL, IN, 레코드 유형, 값이 있습니다. TTL은 Time To Live로, 캐시된 응답을 재사용할 수 있는 남은 초입니다. 준비된 영역은 30초를 사용합니다. 이 질의가 이전 주소를 캐시에 넣을 수도 있으며 정상입니다.

Guide Server로 전환하여 전체 영역을 읽습니다.

cat guide.zone

$TTL 30은 기본 유효 시간을 정합니다. @는 이 영역의 루트입니다. SOA(Start of Authority) 레코드에서 괄호 안 첫 숫자는 영역 버전인 일련번호입니다. NS는 영역의 권한 서버를 나타냅니다. 점으로 끝나는 이름은 완전한 이름이며, guide 같은 짧은 이름은 riverlight.test에 상대적입니다. 안내서 AAAA 외 모든 레코드를 보존하고 이번 수정에서 일련번호를 1에서 2로 올립니다. 일련번호는 영역 버전을 기록하며 기존 클라이언트 캐시를 지우지는 않습니다.

백업을 만든 다음 이미 배운 here-document로 짧은 영역 전체를 대체합니다. ZONE의 작은따옴표는 $TTL의 셸 변수 확장도 막습니다.

cp guide.zone guide.zone.before
cat > guide.zone <<'ZONE'
$TTL 30
@ IN SOA ns.riverlight.test. admin.riverlight.test. (2 60 30 3600 30)
@ IN NS ns.riverlight.test.
ns IN A 10.77.0.2
guide IN A 10.77.0.10
guide IN AAAA fd77:7::10
desk IN A 10.77.0.10
desk IN AAAA fd77:7::10
contact IN TXT "Welcome desk opens at 10:00"
ZONE

dns-check는 기본 BIND 영역 검증기를 실행하며, 실행 중인 DNS는 변경하지 않습니다.

guide-control dns-check

loaded serial 2와 OK를 확인합니다. 여기의 loaded는 검증기가 파일을 읽었다는 뜻이며 실행 중인 권한 서버가 바뀌었다는 뜻이 아닙니다. 파싱에 실패하면 줄 번호를 읽고 완전한 템플릿을 다시 입력한 뒤 검사하세요. 필요하면 cp guide.zone.before guide.zone로 원본을 복원할 수 있습니다. 잘못된 이전 AAAA도 복원되므로 이는 복구의 출발점이며 최종 답은 아닙니다.

dns-load는 검사한 뒤 비공개 제어 채널로 강좌의 영역만 다시 불러옵니다.

guide-control dns-load

Guide Client로 전환합니다. 권한 서버와 캐시를 각각 질의하세요.

dig @10.77.0.2 guide.riverlight.test AAAA +noall +answer
dig @127.0.0.1 guide.riverlight.test AAAA +noall +answer

권한 서버는 이제 fd77:7::10을 반환해야 합니다. 캐시는 남은 TTL이 만료될 때까지 이전 주소를 보여도 됩니다. sleep 31은 캐시를 변경하지 않고 31초 기다립니다.

sleep 31
dig @127.0.0.1 guide.riverlight.test AAAA +noall +answer

이제 올바른 IPv6 주소가 나와야 합니다. 전역 캐시 삭제나 리졸버 수정은 필요하지 않습니다. 권한 서버가 아직 틀리면 저장된 영역과 dns-load를 확인합니다. 권한 서버는 맞는데 캐시만 다르면 TTL을 읽고 제한된 기다림을 반복합니다. AAAA 삭제는 IPv6 이름 접근을 고치는 대신 제거합니다.

마지막으로 이름을 사용한 IPv6 요청을 강제합니다.

curl --noproxy '*' -6 -fsS --max-time 3 -w '\npeer=%{remote_ip} status=%{http_code}\n' http://guide.riverlight.test:8080/

Riverlight HTML과 peer=fd77:7::10 status=200이 나와야 합니다. 직접 IPv6가 성공한 뒤 이름만 실패한다면 리스너를 다시 만들기보다 DNS를 확인하세요.

두 방법으로 전체 안내서를 읽고 다운로드하기

이 단계에서는 두 주소 계열로 전체 안내서를 사용하고 보호 대상 데스크와 레코드를 보존합니다. Guide Client에서 시작합니다. 홈페이지가 올바르다는 것만으로 상세 링크, 스타일 또는 전체 다운로드가 작동한다고 증명할 수는 없습니다.

실제 안내서 이름을 사용하여 IPv4로 네 원본 리소스를 모두 저장합니다. 준비된 v4 폴더에는 실제 다운로드한 바이트만 들어갑니다. 각 -o 경로는 해당 리소스의 저장 파일을 지정합니다.

curl --noproxy '*' -4 -fsS http://guide.riverlight.test:8080/index.html -o v4/index.html
curl --noproxy '*' -4 -fsS http://guide.riverlight.test:8080/visit.html -o v4/visit.html
curl --noproxy '*' -4 -fsS http://guide.riverlight.test:8080/style.css -o v4/style.css
curl --noproxy '*' -4 -fsS http://guide.riverlight.test:8080/programme.txt -o v4/programme.txt

IPv6로도 반복하며, 성공 결과가 IPv4 증거를 덮어쓰지 않도록 별도로 저장합니다.

curl --noproxy '*' -6 -fsS http://guide.riverlight.test:8080/index.html -o v6/index.html
curl --noproxy '*' -6 -fsS http://guide.riverlight.test:8080/visit.html -o v6/visit.html
curl --noproxy '*' -6 -fsS http://guide.riverlight.test:8080/style.css -o v6/style.css
curl --noproxy '*' -6 -fsS http://guide.riverlight.test:8080/programme.txt -o v6/programme.txt

cmp는 두 파일을 바이트 단위로 비교합니다. 출력 없이 프롬프트로 돌아오면 같다는 뜻이며, 차이가 출력되면 리소스가 다릅니다. 각 리소스를 비교한 뒤 전체 프로그램을 읽습니다.

cmp v4/index.html v6/index.html
cmp v4/visit.html v6/visit.html
cmp v4/style.css v6/style.css
cmp v4/programme.txt v6/programme.txt
cat v6/programme.txt

WET WEATHER와 마지막 가상 행사 안내까지 읽으세요. 파일의 존재나 크기만으로 전체 일정과 접근성 정보가 올바르게 도착했다고 증명할 수는 없습니다. 잘못된 두 파일이 같을 수도 있으므로 cmp만으로 원본 내용임을 확인할 수도 없습니다. 검사는 준비된 원본 및 실제 서비스와 비교합니다.

Saved Guide로 전환하세요. Open IPv4 saved guide를 선택하고 프로그램 카드를 읽은 뒤 Make a day of it을 선택하여 도착 및 접근성 정보를 읽습니다. 그 페이지에서 Save the programme을 선택해 프로그램을 다운로드합니다. 브라우저 Back 버튼으로 상세 페이지에서 홈페이지로 돌아간 뒤, 다시 Back으로 뷰어 선택 페이지로 돌아갑니다. Open IPv6 saved guide를 선택하고 같은 링크와 다운로드를 반복합니다. 두 경우 모두 동일한 전체 Riverlight 안내서여야 합니다.

상세 정보와 프로그램 링크가 작동하는 저장된 Riverlight 홈페이지 전체

세 프로그램 카드를 읽고 방문 및 다운로드 링크를 사용하세요. 이 페이지는 실제로 저장한 안내서입니다.

뷰어는 Guide Client의 v4와 v6 파일만 읽으며 없는 파일을 가져오지 않습니다. 스타일이나 페이지가 없으면 Guide Client로 돌아가 정확한 계열과 리소스 저장을 반복한 뒤 브라우저를 새로고침하세요. 브라우저와 뷰어의 연결은 표시 경로입니다. IPv6를 증명하는 것은 터미널의 계열 강제 요청과 실제 상대 주소이지 뷰어 URL이 아닙니다.

Guide Client로 전환합니다. 독립된 안내 데스크를 두 계열 모두에서 계속 사용할 수 있게 유지합니다.

curl --noproxy '*' -4 -fsS http://desk.riverlight.test:8081/
curl --noproxy '*' -6 -fsS http://desk.riverlight.test:8081/

둘 다 Welcome desk: open 10:00–20:00. Keep this site available.을 반환합니다. 보존된 A와 TXT를 확인합니다.

dig @10.77.0.2 guide.riverlight.test A +short
dig @10.77.0.2 contact.riverlight.test TXT +short

10.77.0.10과 "Welcome desk opens at 10:00"이 나와야 합니다. 보호 값이 다르면 수정한 안내서 AAAA는 유지하면서 전체 원본 템플릿에서 복원하고 검사하여 다시 불러옵니다. 검사를 통과시키려고 원본 페이지를 복사하거나, 프록시를 추가하거나, 서비스 프로세스를 대체하거나, 주소를 바꾸지 마세요. 검사는 현재 서비스와 저장 결과를 관찰합니다. 일반적인 GET과 DNS 질의는 기본 로그를 추가할 수 있지만 작업을 불러오거나 복구하지 않습니다.

요약

작동 중인 IPv4 안내서에 실제 IPv6 리스너를 추가하고 AAAA를 수정했으며 별도 DNS 캐시가 자연스럽게 갱신되게 했습니다. 계열을 강제한 요청으로 동일한 원본 홈페이지, 도착 페이지, 스타일시트와 전체 프로그램을 받았습니다. IPv4, 안내 데스크, 다른 레코드와 준비된 네트워크를 보존했습니다. 도달성, 이름 확인, 수신 대기와 올바른 애플리케이션 내용은 별개의 사실입니다.