일반 TLS를 사용하는 v2rayN, v2rayNG, v2flyNG 노드에 적용됩니다. 먼저 커널 로그의 구체적인 오류를 확인한 다음 시스템 시간, 서버 주소와 SNI, 인증서 체인, 전송 설정을 차례로 점검하세요. 이 과정을 통해 로컬 설정 문제와 서버 인증서 문제를 구분하고, 서버 관리자에게 전달할 확인 정보를 정리할 수 있습니다. 인증서 검증을 끄는 방법은 해결책으로 권장하지 않습니다.
1. 전체 로그를 확인해 실패한 단계 파악하기
‘TLS 핸드셰이크 실패’는 문제의 범위를 나타낼 뿐, 원인을 하나로 특정하지는 않습니다. 일반적인 연결은 서버 주소를 조회하고 TCP 연결을 맺은 뒤 TLS 협상과 인증서 검증을 거칩니다. 그다음 프록시 프로토콜과 상위 전송이 진행됩니다. VMess와 VLESS는 프록시 프로토콜 이름이며, 프로토콜 이름만으로 인증서가 올바른지 판단할 수는 없습니다.
v2rayN 메인 창의 로그 영역을 확인하세요. 필요한 경우 ‘설정’ → ‘매개변수 설정’에서 커널 로그 수준을 찾아 임시로 info로 설정합니다. 버전에 따라 메뉴 위치와 이름이 다를 수 있습니다. v2rayNG와 v2flyNG에서는 앱 메뉴의 로그 화면에서 커널 출력을 확인할 수 있습니다. 기존 로그를 지운 뒤 노드 하나만 다시 연결하고, 해당 시도의 오류를 기록하세요. 다른 앱의 연결 오류가 섞이지 않도록 주의해야 합니다.
오류: x509: certificate has expired or is not yet valid
원인 및 해결 방법: 기기의 시간이 인증서 유효 기간과 맞지 않거나 인증서가 이미 만료됐거나 아직 유효해지지 않은 상태입니다. 먼저 시스템 날짜와 시간을 확인한 뒤, 서버 관리자가 실제 배포된 인증서의 유효 기간을 확인하도록 요청하세요.
오류: x509: certificate signed by unknown authority
원인 및 해결 방법: 인증서 체인을 클라이언트가 신뢰하는 루트 인증서까지 연결할 수 없는 상태입니다. 중간 인증서가 누락됐거나, 사설 인증서를 사용하거나, 신뢰 저장소가 오래된 경우 발생할 수 있습니다. 먼저 서버가 보내는 인증서 체인을 확인하고, 검증 건너뛰기를 바로 켜지 마세요.
오류: tls: first record does not look like a TLS handshake
원인 및 해결 방법: 연결 대상에서 TLS가 아닌 데이터가 반환된 상태로, 포트나 서비스 유형을 잘못 입력했을 때 흔히 발생합니다. 구독 제공자가 안내한 주소, 포트, TLS 사용 여부를 대조하세요. 포트를 443으로 바꾸는 것만으로 문제가 해결됐다고 단정해서는 안 됩니다.
로그에 표시된 i/o timeout, connection refused, EOF만으로는 인증서 문제라고 판단할 수 없습니다. 앞의 두 오류는 먼저 네트워크 연결 여부와 서비스의 포트 대기 상태를 확인해야 합니다. EOF는 연결이 조기에 종료됐다는 뜻이므로 서버 로그도 함께 살펴봐야 합니다. 로그를 다른 사람에게 전달할 때는 구독 링크, 사용자 식별 정보, 액세스 토큰을 가리세요.
2. 시스템 시간 오차: 동기화한 뒤 인증서 만료 여부 확인하기
인증서에는 유효 시작 시간과 만료 시간이 포함됩니다. 시스템 날짜가 1년 틀리면 유효 기간을 벗어나 인증서 검증이 실패할 수 있습니다. 몇 분 정도의 오차도 인증서가 막 발급됐거나 만료를 앞둔 시점에는 문제를 일으킬 수 있습니다. 시간대 표시가 다르다고 해서 시계가 틀린 것은 아닙니다. 시간대 이름만 보지 말고 기기에 기록된 실제 시간이 정확한지 확인하세요.
- Windows: ‘설정’ → ‘시간 및 언어’ → ‘날짜 및 시간’을 열고 시간 자동 설정을 켠 다음 ‘지금 동기화’를 선택하세요. 날짜, 연도, 시간대를 확인한 뒤 클라이언트 커널을 다시 시작합니다.
- macOS: ‘시스템 설정’ → ‘일반’ → ‘날짜 및 시간’을 열고 날짜 및 시간 자동 설정을 켜세요. 기기가 장시간 잠자기 상태였다가 깨어난 경우에도 현재 시간이 정확한지 다시 확인하세요.
- Android: 시스템 설정에서 ‘날짜 및 시간’을 검색한 뒤 시간 자동 설정과 시간대 자동 설정을 켜세요. 네트워크 연결을 확인하고 v2rayNG 또는 v2flyNG로 돌아가 같은 노드를 다시 시도합니다.
- Linux:
timedatectl status로 시계 동기화 상태를 확인하세요. systemd를 사용하는 시스템에서는sudo timedatectl set-ntp true를 실행해 네트워크 시간 동기화를 켤 수 있습니다.
Windows에서는 터미널에서 먼저 동기화 상태를 확인할 수 있습니다. 두 번째 명령은 관리자 권한으로 실행해야 합니다. 동기화에 실패하면 노드 설정을 계속 바꾸기보다 시스템 안내에 따라 시간 서비스와 네트워크를 점검하세요.
w32tm /query /status
w32tm /resync
위 포트는 각 프로토콜에서 흔히 사용하는 포트이며, 노드가 반드시 이 중 하나를 사용해야 한다는 뜻은 아닙니다. 네트워크에서 UDP 123을 차단하면 기존 NTP 동기화에 영향을 줄 수 있지만, 이를 근거로 프록시 포트도 차단됐다고 단정할 수는 없습니다. 시스템 시간이 정확한데도 로그에 인증서 만료가 명확히 표시된다면 서버에서 인증서를 갱신하고 다시 불러와야 합니다. 로컬 날짜를 바꾸는 것은 해결 방법이 아닙니다.
3. SNI, 서버 주소, Host: 세 항목을 각각 확인하기
SNI는 TLS 핸드셰이크 중 전송되는 서버 이름으로, 같은 주소의 여러 서비스 중 사용할 인증서를 선택하는 데 쓰입니다. v2rayN 노드 편집 창의 ‘SNI’ 또는 ‘서버 이름’은 일반적으로 커널 TLS 설정의 serverName에 해당합니다. 클라이언트는 설정된 서버 이름을 기준으로 인증서의 신원을 확인하므로, 접속되는 것처럼 보이는 웹사이트 도메인을 임의로 입력해서는 안 됩니다.
| 항목 | 역할 | 확인 방법 |
|---|---|---|
| 서버 주소 | 연결할 도메인 또는 IP 주소를 지정합니다. | 현재 유효한 구독 정보와 일치해야 하며, 프로토콜 접두사와 경로는 포함하지 않습니다. |
| 포트 | 연결 대상에서 접속할 서비스를 지정합니다. | 서버 설정에 맞춰 입력하세요. 기본값이 443이라고 가정하지 마세요. |
| SNI / serverName | TLS 서비스 선택과 인증서 이름 검증에 사용됩니다. | 서비스 제공자가 지정하고 인증서에 포함된 도메인을 사용하세요. |
| WebSocket Host | TLS 연결이 성립된 뒤 전송되는 HTTP 요청 헤더입니다. | 리버스 프록시 설정에 맞춰 입력하세요. SNI를 대신할 수 없습니다. |
| WebSocket 경로 | 리버스 프록시가 요청을 해당 백엔드로 전달하도록 지정합니다. | 경로와 대소문자를 정확히 대조하고, 인증서 도메인과는 별도로 확인하세요. |
예를 들어 서버 주소에는 IP를 입력하고 SNI에는 인증서에 포함된 도메인을 입력할 수 있습니다. 두 값이 같을 필요는 없습니다. 다만 IP 주소로 인증서를 검증하려면 인증서의 주체 대체 이름(SAN)에 해당 IP 유형 항목이 있어야 합니다. 도메인 항목만으로는 충분하지 않습니다. 일반 도메인 인증서도 인증서 화면의 제목만 보지 말고 SAN, 즉 주체 대체 이름을 확인하세요.
- SNI에는
example.com과 같은 도메인만 입력하세요.https://, 포트, 슬래시, 공백은 포함하지 않습니다. *.example.com은 일반적으로a.example.com을 포함할 수 있지만,example.com이나a.b.example.com까지 포함한다고 볼 수는 없습니다.- 구독 정보의 ‘위장 도메인’은 Host를 가리킬 수도 있고 SNI를 가리킬 수도 있습니다. 각 항목의 용도를 확인하세요. ‘도메인’이라는 이름만 보고 모든 항목에 같은 값을 복사하면 안 됩니다.
결론: 인증서 이름이 일치하지 않으면 DNS보다 SNI부터 확인하세요
로그에 수신한 인증서 이름이 예상한 이름과 일치하지 않는다고 표시된다면, 연결이 적어도 어떤 TLS 서비스에는 도달한 상태입니다. 먼저 SNI, 대상 주소, 인증서 SAN을 확인하세요. 잘못된 서비스로 연결됐다고 의심될 때만 DNS 조회 결과를 점검하면 됩니다.
4. 불완전한 인증서 체인: 브라우저에서 열린다고 커널에서도 통과하는 것은 아닙니다
서버는 일반적으로 사이트 인증서와 필요한 중간 인증서를 함께 전송해야 합니다. 클라이언트는 자체 신뢰 루트를 사용해 인증서를 검증합니다. 브라우저에는 중간 인증서가 캐시되어 있거나 다른 신뢰 검증 방식이 적용될 수 있습니다. 따라서 ‘브라우저에서 같은 도메인이 정상적으로 열린다’는 사실만으로 서버의 인증서 체인 설정 오류를 배제할 수는 없습니다.
- 먼저 영향 범위 확인: 시간이 정확한 여러 기기에서 같은 노드에 알 수 없는 발급 기관 오류가 발생한다면, 관리자가 배포된 인증서와 중간 인증서를 우선 확인하도록 요청하세요.
- 기기별 차이 확인: 오래된 시스템에서만 실패한다면 시스템 업데이트와 신뢰 루트 상태를 확인하고, 클라이언트 버전과 실제 사용 중인 커널 버전을 기록하세요.
- 네트워크 개입 확인: 회사 네트워크에서만 발생하거나 HTTPS 검사 기능이 있는 보안 소프트웨어를 사용할 때만 문제가 생긴다면, 네트워크 관리자에게 인증서가 교체되는지 확인하세요.
- 사설 인증서 처리: 관리 범위가 명확한 환경에서만 관리 지침에 따라 신뢰할 인증서를 설정하세요. 출처를 알 수 없는 루트 인증서는 가져오지 마세요.
명령줄 환경에서 OpenSSL을 사용하면 서버가 반환하는 인증서를 확인할 수 있습니다. 아래 명령은 예약된 예시 도메인으로 명령 형식만 보여 줍니다. 실제로 점검할 때는 두 도메인을 각각 노드 연결 주소와 예상 SNI로 바꾸고, 포트도 노드 설정에 맞추세요.
openssl s_client -connect example.com:443 -servername example.com -showcerts -verify_hostname example.com -verify_return_error
-servername은 SNI를 보내는 옵션이고 -verify_hostname은 검증할 이름을 지정하는 옵션입니다. 두 옵션의 용도는 다릅니다. 이 명령이 사용하는 신뢰 저장소는 클라이언트 커널과 다를 수 있습니다. 로컬 OpenSSL에 신뢰할 수 있는 CA가 올바르게 설정되지 않았다면, 명령에서 오류가 나도 곧바로 서버 문제라고 판단할 수 없습니다. 재확인할 때는 반환된 인증서의 SAN, 유효 기간, 인증서 체인을 기록하고 마지막 줄만 캡처하지 마세요.
5. 인증서 검증 건너뛰기: 끈 상태로 두고 실제 설정을 수정하세요
‘안전하지 않은 연결 허용’ 또는 ‘인증서 검증 건너뛰기’는 일반적으로 allowInsecure에 해당합니다. 이 옵션을 켜면 신뢰할 수 없거나 이름이 일치하지 않는 인증서도 클라이언트가 거부하지 않을 수 있지만, 인증서 문제가 해결되는 것은 아닙니다. 연결 대상의 신원을 정상적으로 검증할 수 없게 됩니다. TCP 시간 초과, 잘못된 포트, WebSocket 경로 오류, 프록시 인증 실패도 해결하지 못합니다.
아래는 일반 TLS 아웃바운드의 streamSettings 일부를 보여 주는 예시입니다. 그대로 가져올 수 있는 완성된 설정이 아니며 REALITY에는 적용되지 않습니다. example.com은 항목 간 관계를 설명하기 위한 예시일 뿐입니다. 실제 값은 서버 설정에서 확인해야 하며, 예시 도메인으로 노드에 연결해서는 안 됩니다.
{
"streamSettings": {
"security": "tls",
"tlsSettings": {
"serverName": "example.com",
"allowInsecure": false
}
}
}
- 저장한 뒤 커널을 다시 시작하고, 새 설정이 실제 실행에 적용됐는지 확인하세요.
- 로그에 이전 도메인이 계속 표시되면 현재 선택한 노드와 구독 그룹을 확인하고, 현재 사용 중인 설정을 수정했는지 점검하세요.
- 임시 생성 파일을 직접 수정한 뒤 변경 사항이 계속 유지될 것으로 기대하지 마세요. 클라이언트를 다시 시작하거나 노드를 업데이트하면 파일이 다시 생성될 수 있습니다.
6. 인증서 검증 후에도 실패한다면 전송 계층과 서버 로그 확인하기
인증서 검증에 성공했다고 프록시 연결까지 성공한 것은 아닙니다. WebSocket 경로와 Host, gRPC 서비스 이름, 프록시 프로토콜의 사용자 식별 정보는 각각 해당 통신 단계에서 사용됩니다. 로그가 x509 오류에서 HTTP 상태 오류나 인증 실패로 바뀌었다면 새로운 오류를 기준으로 계속 점검하세요. 이때 인증서 검증 건너뛰기를 켜서는 안 됩니다.
오류: websocket: bad handshake
원인 및 해결 방법: WebSocket 업그레이드 요청이 예상한 응답을 받지 못한 상태입니다. Host, 경로, 리버스 프록시 전달 설정이 서로 일치하지 않을 수 있습니다. 노드의 전송 설정을 확인하고 서버 관리자에게 해당 시각의 HTTP 액세스 로그를 확인해 달라고 요청하세요.
오류: remote error: tls: handshake failure
원인 및 해결 방법: 원격 서버가 TLS 협상을 중단한 상태입니다. SNI 정책, 프로토콜 호환성, 서버 인증 요구 사항이 원인일 수 있습니다. 클라이언트에 표시된 이 한 줄만으로 원인을 확정할 수 없으므로 서버의 핸드셰이크 로그와 대조해야 합니다. 로컬 인증서 저장소 문제라고 바로 단정하지 마세요.
한 번에 항목 하나만 변경한 뒤 같은 노드로 다시 시도하세요. DNS, SNI, 커널, 포트를 동시에 바꾸면 연결이 복구되더라도 어떤 변경이 효과가 있었는지 파악하기 어렵습니다. 클라이언트나 커널을 업데이트하기 전에 설정을 저장하고, 노드에서 사용하는 프로토콜과 전송 방식이 지원되는지 확인하세요. 특정 오류를 없애려고 커널을 무작정 바꾸지 마세요.
- 기기 정보: 운영체제, 클라이언트 버전, 커널 이름과 버전, 시스템 시간 동기화 결과.
- 노드 정보: 연결 주소 유형, 포트, TLS 유형, SNI, 전송 유형. 사용자 식별 정보와 구독 인증 정보는 가려야 합니다.
- 로그 정보: 실패가 발생한 정확한 시각과 전체 오류 내용. 연결 단계, 인증서 검증 단계, 전송 단계 중 어느 단계에서 실패했는지 표시하세요.
- 서버 확인 사항: 현재 인증서의 유효 기간과 SAN, 중간 인증서 배포 여부, 인증서 갱신 후 관련 서비스가 다시 불러와졌는지 확인하세요.
7. 자주 묻는 질문: 오류 범위에 따라 다음 단계 선택하기
시간을 동기화했는데도 인증서가 만료됐다고 표시되는 이유는 무엇인가요?
방금 다시 시도한 노드의 오류인지, 이전 로그인지 먼저 확인하세요. 클라이언트가 실제로 받은 인증서의 유효 기간을 확인합니다. 서버에서 인증서 파일만 갱신하고 서비스를 다시 불러오지 않았거나, 일부 진입 지점만 업데이트했을 수 있습니다. 실패 시각, 연결 주소, 인증서 만료 시간을 서버 관리자에게 전달해 확인을 요청하세요.
서버 주소가 IP라면 SNI에도 IP를 입력해야 하나요?
그럴 필요는 없습니다. 연결 주소는 데이터가 전송될 대상을 지정하고, SNI에는 보통 서비스 제공자가 지정한 인증서 도메인을 입력합니다. IP를 검증 이름으로 사용하려면 인증서에 일치하는 IP 유형 SAN이 포함되어야 합니다. WebSocket Host가 SNI를 자동으로 대신한다고 생각하지 마세요.
인증서 검증을 건너뛰면 연결되는데, 계속 켜 둬도 되나요?
이 결과는 문제가 인증서 검증과 관련 있을 가능성만 보여 줍니다. 연결 대상이 신뢰할 만하다는 뜻은 아닙니다. 옵션을 다시 끄고 유효 기간, 이름 일치 여부, 인증서 체인 순으로 확인하세요. 구독 설정에서 잘못된 값이 반복해서 적용된다면 검증을 계속 우회하지 말고 제공자에게 수정을 요청하세요.
모든 노드에서 핸드셰이크 시간 초과가 발생하면 인증서가 모두 잘못된 건가요?
시간 초과만으로 결론을 내리면 안 됩니다. 먼저 시스템 네트워크와 시간을 확인한 다음 클라이언트가 실제로 연결을 시도하는지, 대상 포트에 접속할 수 있는지, 로그에 x509 오류가 명확히 표시되는지 살펴보세요. 사용이 허가된 다른 네트워크에서 같은 노드를 다시 시험하면 네트워크 차이를 바탕으로 문제 범위를 좁힐 수 있습니다.