Cách khắc phục lỗi SSL: WRONG_VERSION_NUMBER một lần và mãi mãi

beginner🔒 SSL/TLS2026-04-25| Python (Requests, Urllib, Flask, Django), Nginx, Docker, Node.js, OpenSSL

Error Message

ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)
#ssl#python#gỡ lỗi#nginx#docker#devops

Giải mã lỗi

Ít có điều gì làm đình trệ một dự án Python nhanh hơn một lỗi SSL khó hiểu. Có lẽ bạn đang thấy thông báo này trong terminal của mình ngay bây giờ:

ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1129)

Đây là một lỗi dễ gây hiểu lầm. Mặc dù nó gợi ý rằng phiên bản TLS hoặc OpenSSL của bạn đã lỗi thời, nhưng thực tế hiếm khi như vậy. Trong 99% trường hợp, đây là sự không khớp về giao thức (protocol mismatch). Bạn đang cố gắng giao tiếp bằng "mã hóa" với một cổng (port) vốn chỉ hiểu "văn bản thuần túy" (plain text).

Nguyên nhân gốc rễ: Rào cản ngôn ngữ

Lỗi này xảy ra khi một client (như một script Python sử dụng requests) bắt đầu một quá trình bắt tay (handshake) TLS bảo mật với một cổng máy chủ được cấu hình cho HTTP tiêu chuẩn.

Hãy coi đó là một sự gián đoạn trong giao tiếp:

  • Client: Gửi một gói tin "Client Hello"—một chuỗi nhị phân nhằm bắt đầu một phiên mã hóa.
  • Server: Nó không được thiết lập để mã hóa. Nó thấy dữ liệu nhị phân, không nhận diện được và phản hồi bằng một chuỗi văn bản thuần túy như HTTP/1.1 400 Bad Request.
  • Sự không khớp: Client của bạn nhìn vào vài byte đầu tiên của phản hồi đó. Nó mong đợi một header phiên bản TLS (như 0x16 cho một quá trình bắt tay). Thay vào đó, nó thấy chữ "H" (0x48 ở dạng hex) từ "HTTP". OpenSSL cố gắng phân tích cú pháp "H-T-T-P" dưới dạng số phiên bản, thất bại và đưa ra lỗi WRONG_VERSION_NUMBER.

Cách khắc phục

1. Kiểm tra URL và Cổng (Port)

Bắt đầu với nguyên nhân rõ ràng nhất: lỗi đánh máy trong chuỗi kết nối của bạn. Các môi trường phát triển cục bộ thường gặp lỗi này. Nếu ứng dụng Flask hoặc Django của bạn đang chạy trên cổng 8000, nó thường không được bật SSL theo mặc định.

  • Sai: https://127.0.0.1:8000
  • Đúng: http://127.0.0.1:8000

Nếu bạn đang nhắm tới một API production trên một cổng không tiêu chuẩn (như 8080 hoặc 8443), hãy kiểm tra kỹ xem cổng cụ thể đó có thực sự hỗ trợ HTTPS hay không. Việc một trang web có chứng chỉ SSL không có nghĩa là mọi cổng trên máy chủ đó đều được mã hóa.

2. Kiểm tra cấu hình Nginx hoặc Apache

Người dùng Nginx thường vấp phải việc thiếu một từ khóa. Nếu bạn yêu cầu Nginx lắng nghe trên cổng 443 nhưng quên yêu cầu nó sử dụng SSL, nó sẽ phục vụ HTTP thuần túy trên một cổng mà mọi người đều mong đợi là được bảo mật.

Block server Nginx của bạn nên trông như thế này:

server {
    listen 443 ssl; # Từ khóa 'ssl' là phần quan trọng nhất ở đây
    server_name api.example.com;

    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
    }
}

Nếu không có flag ssl đó, Nginx sẽ bỏ qua các chứng chỉ của bạn và gửi văn bản thô, gây ra lỗi ở phía client.

3. Sửa lỗi Port Mapping trong Docker

Docker thêm một lớp khác nơi các cổng có thể bị nhầm lẫn. Một sai lầm phổ biến là map một cổng bên ngoài bảo mật với một cổng container bên trong không bảo mật. Ví dụ:

# Điều này sẽ bị lỗi nếu bạn cố gắng truy cập https://localhost
docker run -p 443:80 my-web-app

Trong lệnh này, host lắng nghe trên cổng 443, nhưng nó chuyển lưu lượng truy cập đến cổng 80 bên trong container. Vì container có khả năng đang phục vụ HTTP trên cổng 80, quá trình bắt tay sẽ thất bại ngay lập tức. Hãy làm cho các giao thức khớp nhau: nếu cổng host là 443, hãy đảm bảo ứng dụng trong container thực sự được cấu hình với chứng chỉ SSL.

4. Giải quyết vòng lặp Proxy và Load Balancer

Nếu bạn đang sử dụng AWS ALB, Cloudflare hoặc một Nginx reverse proxy, bạn có thể đang gặp phải tình trạng "SSL Offloading". Đây là nơi proxy xử lý kết nối HTTPS và giao tiếp với backend của bạn qua HTTP. Nếu mã nguồn backend của bạn cố gắng ép buộc một kết nối HTTPS tới một dịch vụ nội bộ khác chỉ lắng nghe trên cổng 80, bạn sẽ gặp lỗi này.

Xác minh bản sửa lỗi

Đừng đoán—hãy kiểm tra cổng trực tiếp bằng curl. Sử dụng flag -v (verbose) để xem chính xác những gì máy chủ gửi lại trước khi lỗi xảy ra.

curl -vI https://your-api-endpoint.com

Nếu đầu ra bao gồm * error:1408F10B:SSL routines:ssl3_get_record:wrong version number, máy chủ chắc chắn đang gửi văn bản thuần túy. Bạn cũng có thể sử dụng OpenSSL để xem phản hồi thô:

openssl s_client -connect your-api-endpoint.com:443

Nếu bạn thấy CONNECTED(00000003) theo sau là một trạng thái treo hoặc một lỗi HTTP văn bản thuần túy, cấu hình máy chủ của bạn mới là vấn đề, không phải mã Python của bạn.

Mẹo phòng ngừa

Các lỗi cấu hình thường ẩn nấp trong các tệp YAML hoặc JSON lộn xộn. Tôi nhận thấy rằng việc sử dụng một trình xác thực như YAML ↔ JSON Converter này giúp phát hiện các vấn đề về cấu trúc trong Docker Compose hoặc Kubernetes manifest trước khi chúng được đưa lên production.

  • Biến môi trường: Đừng bao giờ hardcode https://. Hãy sử dụng các biến để bạn có thể chuyển đổi giữa http khi kiểm tra cục bộ và https cho production.
  • Hãy tường minh: Khi debug, hãy luôn bao gồm cổng trong URL của bạn (ví dụ: :443) để đảm bảo bạn không truy cập vào một giá trị mặc định mà bạn không mong muốn.
  • Giám sát Header: Sử dụng header X-Forwarded-Proto để cho ứng dụng của bạn biết liệu yêu cầu ban đầu có an toàn hay không, ngay cả khi proxy đang giao tiếp với nó qua HTTP.

Related Error Notes