certificate, x509, handshake, unknown authority 등의 로그가 표시되는 v2rayN, v2rayNG, v2flyNG 사용자를 위한 글입니다. 원본 로그를 보존한 뒤 시스템 시간과 시간대를 확인하고 SNI를 점검한 다음 인증서 유효 기간과 체인을 검증하세요. allowInsecure는 문제를 잠시 좁혀 보는 용도로만 사용해야 하며 장기적인 해결책이 아닙니다.
TLS 오류는 어느 단계에서 발생할까
VMess 또는 VLESS 노드에서 TLS를 활성화해도 클라이언트가 서버에 연결하는 즉시 프록시 데이터를 전송하는 것은 아닙니다. 먼저 TCP 연결을 만든 다음 SNI, 지원하는 TLS 버전, ALPN 등을 포함할 수 있는 TLS ClientHello를 보내고, 서버는 인증서 체인을 반환하며 세션 키를 협상합니다. 핸드셰이크가 성공해야 이후의 프로토콜 인증과 데이터 전송이 암호화된 채널로 진행됩니다.
따라서 ‘노드에 연결되지 않음’이 곧 노드 계정이 만료되었다는 뜻은 아닙니다. 로그에 인증서 만료, 호스트 이름 불일치, 알 수 없는 인증 기관이 이미 표시되었다면 문제는 대개 VMess 사용자 ID, VLESS UUID, 전송 경로, 라우팅 규칙보다 앞선 단계에 있습니다. 이때 구독 그룹, 시스템 프록시 포트, 분기 규칙을 바꿔도 인증서 오류는 보통 해결되지 않습니다.
문제를 점검할 때는 브라우저 화면만 보지 말고 먼저 클라이언트 코어 로그를 확인해야 합니다. v2rayN은 메인 창 하단 로그 영역에서 최근 연결 기록을 볼 수 있으며, ‘설정’ → ‘매개변수 설정’에서 로그 수준이 지나치게 낮게 설정되지 않았는지도 확인할 수 있습니다. v2rayNG와 v2flyNG는 해당 설정의 실행 로그 화면으로 들어가 처음 나타난 TLS 또는 x509 원문을 기록하세요.
오류: x509: certificate has expired or is not yet valid
원인과 해결: 기기의 시간이 인증서 유효 기간을 벗어났거나 서버 인증서가 실제로 만료된 경우입니다. 먼저 시스템 시간을 동기화한 다음 로그의 현재 시간과 인증서 시작·만료 날짜를 확인하세요.
오류: x509: certificate is valid for another.example, not node.example
원인과 해결: 서버가 반환한 인증서 이름과 클라이언트가 검증하는 이름이 일치하지 않습니다. 노드의 SNI를 확인하고 구독 메모, WebSocket 경로 또는 IP 주소를 이 항목에 입력하지 마세요.
오류: x509: certificate signed by unknown authority
원인과 해결: 인증서 체인에 중간 인증서가 없거나 시스템이 해당 인증서를 신뢰하지 않는 경우입니다. 시스템 인증서 환경을 업데이트하세요. 여러 기기에서 동시에 재현된다면 서버에서 인증서 체인을 완성해야 합니다.
오류: remote error: tls: handshake failure
원인과 해결: 서버가 핸드셰이크를 능동적으로 거부한 것입니다. SNI, TLS 버전, ALPN 불일치가 흔한 원인이므로 먼저 구독 원본 파라미터를 확인한 뒤 서버의 리스닝 설정을 점검하세요.
첫 단계: 시스템 시간과 시간대 확인
TLS 인증서에는 Not Before와 Not After라는 두 시간 경계가 있습니다. 클라이언트는 기기의 현재 시간으로 인증서가 유효해졌는지와 만료되었는지를 판단합니다. 시스템 시간이 몇 달 빠르면 정상 인증서를 만료된 것으로 판단하고, 몇 달 늦으면 아직 유효하지 않은 인증서로 표시할 수 있습니다. 시간대 자체가 절대 시간을 바꾸지는 않지만 잘못된 시간대와 수동 시계 설정이 함께 사용되면 실제 시간에 큰 오차가 생기기 쉽습니다.
Windows에서는 시스템 날짜 및 시간 설정에서 자동 시간 설정과 자동 시간대 설정을 켠 다음 즉시 동기화를 한 번 실행하세요. Linux 데스크톱에서는 먼저 시스템 시간 상태를 확인하고 NTP 서비스가 동기화 중인지 점검합니다. Android 기기에서는 네트워크 제공 날짜, 시간, 시간대를 사용하도록 설정하세요. 수정한 뒤에는 클라이언트 코어를 완전히 종료하고 다시 시작해 이전 연결의 실패 상태가 재사용되지 않도록 해야 합니다.
-
원본 로그 저장
현재 노드의 연결을 끊고 로그를 지운 뒤 다시 한 번 연결하세요. 첫 번째 x509 또는 TLS 오류와 타임스탬프를 저장하고 이후에 나타나는 타임아웃 정보만 남기지 마세요.
-
현재 시간 확인
기기의 날짜, 분 단위 시간, 시간대를 신뢰할 수 있는 시스템 시간 소스와 대조하세요. 오차는 가능한 한 60초 이내로 유지하고 수동 시간으로 잘못 설정되어 있지 않은지도 확인합니다.
-
시간 동기화 실행
시스템 자동 동기화를 켜세요. Linux에서는
timedatectl status를 실행해 출력에서 시스템 시계가 동기화되었는지와 시간대 설정이 올바른지 확인할 수 있습니다. -
클라이언트 코어 재시작
v2rayN에서는 먼저 서비스를 중지한 다음 다시 시작하세요. Android 클라이언트에서는 현재 설정의 연결을 끊고 연결을 종료한 뒤 다시 연결해 이전 세션이 이어지지 않도록 합니다.
-
재테스트 결과 비교
오류에서 not yet valid가 사라졌다면 원인은 기기의 시간이었던 것입니다. 같은 인증서 만료 날짜가 계속 표시된다면 인증서가 실제로 만료되었는지 추가로 확인하세요.
두 번째 단계: SNI와 노드 주소 확인
SNI는 TLS ClientHello에 전송되는 서버 이름입니다. 하나의 IP 주소에서 여러 사이트를 호스팅할 수 있으며 서버는 SNI에 따라 인증서와 해당 가상 호스트를 선택합니다. 노드의 연결 주소는 도메인일 수도 있고 IP일 수도 있지만, 인증서 검증 이름은 일반적으로 인증서에 기재된 도메인이어야 합니다. 노드 메모만 보고 임의로 추측해서는 안 됩니다.
예를 들어 클라이언트의 연결 주소가 진입 IP이고 인증서는 특정 도메인으로 발급된 경우, 노드 설정의 serverName 또는 SNI 필드에 해당 도메인을 입력해야 합니다. 반대로 노드 주소 자체가 올바른 도메인이고 구독에서 SNI를 명시했다면 구독 값을 그대로 유지하세요. WebSocket의 Host, HTTP 경로, 구독 이름, 노드 메모를 SNI에 복사하면 이름 불일치가 발생합니다.
| 설정 항목 | 실제 역할 | 흔한 오류 |
|---|---|---|
| 주소 | DNS 확인 후 TCP 연결을 설정하는 데 사용 | 프로토콜 접두사나 경로가 포함된 전체 URL을 잘못 입력 |
| 포트 | 서버의 TLS 리스닝 포트 지정 | 로컬 포트 10808을 원격 포트로 잘못 입력 |
| SNI / serverName | 서버 인증서를 선택하고 검증 이름을 결정 | IP, 노드 메모 또는 전송 경로를 입력 |
| Host | HTTP 또는 WebSocket 요청 헤더에 사용 | Host가 반드시 SNI와 같다고 판단 |
| Path | WebSocket 또는 HTTP 전송 경로 지정 | 인증서 이름 불일치를 경로 오류로 오해 |
v2rayN에서는 대상 노드를 두 번 클릭하거나 마우스 오른쪽 버튼으로 ‘서버 편집’을 선택한 뒤 TLS 관련 영역에서 serverName, SNI 또는 ‘위장 도메인’ 항목을 확인하세요. 표시 이름은 코어와 설정 유형에 따라 달라질 수 있습니다. 수정하기 전에 구독 원본 값을 저장하고, 수정 후에는 이 항목만 테스트하세요. 포트, 전송 방식, UUID를 동시에 바꾸지 마세요.
v2rayNG 또는 v2flyNG에서는 먼저 연결을 끊은 다음 설정 오른쪽의 편집 메뉴를 눌러 TLS 보안 설정 아래에서 서버 이름 또는 위장 도메인을 찾으세요. 구독으로 생성된 설정은 다음 구독 업데이트 때 수동 수정 내용이 덮어써질 수 있습니다. 올바른 값을 확인했다면 구독 제공자에게 원본 설정 수정을 요청해야 합니다.
오류: certificate is valid for example.net, not 203.0.113.10
원인과 해결: 클라이언트가 IP 주소로 인증서를 검증하고 있습니다. 구독에 명시된 인증서 도메인을 SNI에 입력하되 원래 연결 주소는 유지하고, 검증을 끄는 방식으로 문제를 가리지 마세요.
오류: tls: unrecognized name
원인과 해결: 서버가 현재 SNI를 허용하지 않습니다. 구독의 원래 serverName으로 되돌리세요. 여러 클라이언트에서 실패한다면 서버의 가상 호스트와 TLS 리스닝 설정을 점검해야 합니다.
세 번째 단계: 인증서 만료와 불완전한 인증서 체인 확인
시스템 시간과 SNI가 모두 올바르다면 서버가 실제로 어떤 인증서를 반환하는지 확인해야 합니다. 인증서 만료는 Not After가 현재 시간보다 이전이라는 뜻이고, 인증서 체인 불완전은 서버가 사이트 인증서만 보내고 필요한 중간 인증서를 보내지 않을 때 흔히 발생합니다. 둘 다 서버 설정 문제이므로 클라이언트에서 구독을 다시 가져와도 보통 해결되지 않습니다.
OpenSSL이 설치된 Linux 환경에서는 다음 명령으로 443 포트에서 반환하는 인증서 체인을 확인할 수 있습니다. -connect 뒤에는 실제 연결 도메인과 포트를 입력하고, -servername 뒤에는 노드가 요구하는 SNI를 입력하세요. 두 매개변수를 모두 지정해야 하며, 그렇지 않으면 다른 기본 인증서가 반환될 수 있습니다.
openssl s_client -connect server.example:443 \
-servername node.example \
-showcerts
openssl s_client -connect server.example:443 \
-servername node.example \
-verify_return_error < /dev/null
출력에서 subject는 현재 인증서의 주체, issuer는 발급자, notBefore와 notAfter는 유효 기간을 뜻합니다. 마지막 줄에 Verify return code: 0 (ok)가 표시되면 현재 시스템의 신뢰 환경에서 완전한 검증 경로를 만들 수 있다는 의미입니다. 코드 10은 보통 인증서 만료를, 코드 20 또는 21은 로컬 발급자를 가져오지 못했거나 첫 번째 인증서를 검증하지 못했음을 나타냅니다.
- 한 대의 기기에서만 오류가 발생: 먼저 시스템 시간, 시스템 인증서 환경, 클라이언트 코어를 업데이트한 뒤 로컬 네트워크가 TLS에 간섭하는지 확인하세요.
- Windows와 Android에서 동시에 오류가 발생: 인증서 만료, SNI 설정 오류, 서버 인증서 체인 누락일 가능성이 더 높습니다.
- 같은 서버에서 하나의 도메인만 오류가 발생: 해당 도메인에 연결된 인증서와 가상 호스트를 확인하고 모든 노드를 한꺼번에 수정하지 마세요.
- 네트워크를 바꾸면 정상으로 복구: 두 네트워크에서 확인되는 IP를 비교하고 DNS 조회 이상이나 투명 프록시 개입이 있는지 점검하세요.
- 인증서를 갱신했는데도 이전 날짜가 표시: 모든 진입 서버에 새 인증서가 적용되었는지 확인하고 해당 TLS 서비스를 재시작하거나 다시 로드하세요.
allowInsecure의 기능과 위험성
allowInsecure는 정상적인 검증을 통과하지 못한 서버 인증서도 클라이언트가 받아들이도록 합니다. 만료된 인증서, 자체 서명 인증서, 이름이 일치하지 않는 인증서, 신뢰할 수 없는 인증서를 일시적으로 통과시킬 수 있지만 서버 인증서를 수정하거나 SNI, 주소, 포트, 전송 설정을 자동으로 바로잡지는 않습니다.
활성화해도 TLS 데이터 자체는 암호화되지만, 클라이언트는 서버 신원을 신뢰할 수 있게 확인하는 핵심 절차를 잃습니다. 공격자가 네트워크 연결에 개입할 수 있다면 다른 인증서로 목표 서버를 사칭할 수 있습니다. 따라서 이 옵션은 단기 진단에 적합합니다. 활성화한 뒤 연결이 즉시 복구되면 문제 범위가 인증서 검증 단계라는 뜻이므로, 확인 후에는 끄고 시간, SNI 또는 서버 인증서 체인을 수정해야 합니다.
v2rayN에서는 해당 서버를 편집하고 TLS 영역에서 allowInsecure 또는 ‘인증서 검증 건너뛰기’를 찾으세요. v2rayNG와 v2flyNG에서는 보통 설정 편집 화면의 TLS 설정에 ‘안전하지 않은 연결 허용’ 또는 비슷한 이름으로 표시됩니다. 현재 테스트 노드에만 적용하고 전체 구독 설정을 일괄 변경하지 마세요.
로그 결과로 문제 책임 위치 판단
효율적인 점검에서는 한 번에 하나의 변수만 바꾸고 변경 전후의 첫 번째 오류를 기록해야 합니다. 구독을 다시 가져오고, 코어를 바꾸고, SNI를 수정하고, allowInsecure를 켜고, 네트워크까지 동시에 바꾸면 연결이 복구되어도 실제 원인을 판단할 수 없습니다. 이후 구독 업데이트로 문제가 다시 나타날 수도 있습니다.
최소 테스트 세트를 구성하세요. 같은 노드, 같은 네트워크, 같은 클라이언트 코어를 고정한 뒤 먼저 시간을 동기화하고, SNI를 확인한 다음 인증서 체인을 검증하며, 마지막에만 allowInsecure를 잠시 테스트합니다. 테스트 중에는 빈번한 노드 자동 전환 기능을 잠시 끄고 다른 서버의 오류가 로그에 섞이지 않도록 하세요.
시간을 동기화했는데도 인증서 만료가 표시되나요?
로그 또는 OpenSSL 출력에서 notAfter를 확인하세요. 만료일이 실제로 현재 시간보다 이르면 서버 인증서 문제입니다. 클라이언트에 표시된 날짜가 서버에서 공개한 결과와 다르다면 이전 진입 IP에 연결된 것은 아닌지 계속 확인하세요.
SNI에는 노드 주소를 입력해야 하나요, Host를 입력해야 하나요?
구독에 명시된 서버 이름을 입력하세요. 별도로 제공되지 않는다면 일반적으로 인증서가 포함하는 도메인을 사용하며, 노드 메모만으로 판단해서는 안 됩니다. Host와 SNI는 용도가 다르므로 억지로 같은 값으로 바꾸지 마세요.
allowInsecure를 켜니 연결됩니다. 다음에는 어떻게 해야 하나요?
활성화 전후의 로그를 즉시 저장한 다음 해당 옵션을 끄세요. 구체적인 오류를 바탕으로 인증서 유효 기간, 이름 일치 여부, 인증서 체인을 확인하고 임시 진단 설정을 구독에 장기간 남겨 두지 마세요.
구독을 업데이트해도 인증서 오류가 해결되지 않는 이유는 무엇인가요?
구독 업데이트는 클라이언트가 받는 노드 매개변수만 갱신합니다. 서버가 여전히 만료된 인증서를 보내거나 중간 인증서를 누락한 상태라면 반복해서 업데이트해도 핸드셰이크 결과는 달라지지 않습니다. 서버에서 인증서를 갱신하고 다시 로드해야 합니다.
모바일 네트워크에서만 핸드셰이크 실패가 발생하면 어떻게 하나요?
먼저 모바일 네트워크와 다른 네트워크의 DNS 조회 결과를 비교한 다음 시스템 시간이 네트워크를 통해 자동 보정되는지 확인하세요. 인증서 이름이 달라지거나 다른 진입점이 반환된다면 두 네트워크의 로그를 각각 저장해 대조하세요.
최종 판단은 세 가지로 정리할 수 있습니다. 시간 오류는 로컬 기기에서 수정하고, SNI 오류는 구독 값과 인증서 도메인에 맞게 수정하며, 여러 기기에서 만료된 인증서나 불완전한 인증서 체인이 확인되면 서버에서 처리해야 합니다. 이 세 가지를 먼저 분리해야 TLS 핸드셰이크 실패를 포트, UUID, 구독 또는 라우팅 문제로 잘못 판단하지 않을 수 있습니다.