Cài Mosquitto trên Windows: cấu hình listener, tài khoản mật khẩu, TLS chứng chỉ tự tạo và ESP32
Cài broker MQTT Mosquitto trên Windows: dịch vụ, listener cho mạng nội bộ, mosquitto_passwd, mở tường lửa, TLS với CA tự tạo bằng openssl, thử mosquitto_sub/pub và ESP32 kết nối qua TLS.
Mosquitto là broker MQTT mã nguồn mở nhẹ và phổ biến nhất; cài trên một máy Windows trong nhà là có ngay một máy chủ MQTT riêng cho ESP32, Node-RED, điện thoại, không phụ thuộc broker công cộng. Bài này hướng dẫn cài Mosquitto trên Windows từ bộ cài chính thức, cấu hình cho máy khác kết nối, bắt buộc tài khoản và mật khẩu, bật TLS với chứng chỉ tự tạo, mở tường lửa, thử bằng mosquitto_sub, mosquitto_pub, và chương trình ESP32 kết nối qua TLS.
1. Mô hình: một máy Windows làm broker

Máy chạy broker nên có IP cố định trong mạng nội bộ (đặt IP tĩnh hoặc giữ IP theo địa chỉ MAC trên router), vì thiết bị kết nối tới broker bằng IP. Khái niệm broker, topic, QoS có ở bài MQTT là gì cùng cụm chủ đề.
2. Cài Mosquitto trên Windows

- Tải bộ cài Windows 64 bit ở trang chính thức mosquitto.org (mục Download), chạy với quyền Administrator, để chọn mục Service khi cài. Mosquitto được cài vào
C:\Program Files\mosquittovà tạo dịch vụ Windows tênmosquitto. - Thêm thư mục cài đặt vào biến môi trường PATH (hoặc luôn
cdvào thư mục đó) để gõ được lệnhmosquitto_sub,mosquitto_pub,mosquitto_passwdtrong cửa sổ lệnh. - Tạo thư mục
C:\mosquittođể chứa file mật khẩu và chứng chỉ (đường dẫn không có dấu cách cho dễ viết cấu hình).
Từ Mosquitto 2.0, nếu file cấu hình không có dòng listener, broker chỉ nhận kết nối từ chính máy đó (localhost). Đây là lý do hay gặp nhất khiến ESP32 không kết nối được dù dịch vụ đang chạy.
3. Bắt buộc tài khoản và mật khẩu
Mở cửa sổ lệnh bằng Run as administrator, tạo file mật khẩu với tài khoản đầu tiên (lệnh sẽ hỏi mật khẩu hai lần):
cd "C:\Program Files\mosquitto"
mosquitto_passwd -c C:\mosquitto\passwd esp32
mosquitto_passwd C:\mosquitto\passwd nodered # thêm tài khoản khác, không có -c
Tham số -c tạo file mới và xóa file cũ: chỉ dùng cho tài khoản đầu tiên. Mật khẩu trong file được băm, không lưu dạng chữ. Mở C:\Program Files\mosquitto\mosquitto.conf bằng Notepad chạy quyền Administrator, thêm vào cuối file:
# Cổng 1883 cho mạng nội bộ, bắt buộc đăng nhập
listener 1883
allow_anonymous false
password_file C:\mosquitto\passwd
Khởi động lại dịch vụ: net stop mosquitto rồi net start mosquitto. Nếu dịch vụ không chạy, file cấu hình có lỗi: chạy tay mosquitto -c mosquitto.conf -v trong thư mục cài đặt để xem dòng báo lỗi.
4. Mở cổng trong tường lửa Windows
Tường lửa Windows chặn kết nối vào mặc định. Mở cổng cho mạng riêng (Private) bằng PowerShell chạy quyền Administrator:
New-NetFirewallRule -DisplayName "Mosquitto MQTT" -Direction Inbound -Protocol TCP -LocalPort 1883,8883 -Action Allow -Profile Private
Kiểm tra mạng Wi-Fi của máy đang ở chế độ Private (Settings → Network → Properties). Không mở cổng MQTT ra Internet qua router: muốn truy cập từ xa, dùng VPN hoặc broker có TLS và mật khẩu mạnh.
5. Bật TLS với chứng chỉ tự tạo

Cổng 1883 gửi mật khẩu dạng chữ trên mạng; TLS mã hóa toàn bộ kết nối. Tạo một CA riêng rồi dùng nó ký chứng chỉ cho broker, bằng lệnh openssl (có sẵn trong Git for Windows, mở Git Bash). Thay 192.168.1.10 bằng IP máy Windows:
openssl req -new -x509 -days 3650 -keyout ca.key -out ca.crt -subj "/CN=PYWORLD MQTT CA"
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=192.168.1.10"
echo "subjectAltName=IP:192.168.1.10" > san.txt
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 825 -extfile san.txt
Lệnh đầu hỏi mật khẩu để bảo vệ ca.key: giữ kín file này, chỉ cần khi ký chứng chỉ mới. Chép ca.crt, server.crt, server.key vào C:\mosquitto\certs và thêm vào mosquitto.conf:
# Cổng 8883 có TLS, dùng chung tài khoản ở trên
listener 8883
cafile C:\mosquitto\certs\ca.crt
certfile C:\mosquitto\certs\server.crt
keyfile C:\mosquitto\certs\server.key
Dòng subjectAltName ghi IP của máy chủ vào chứng chỉ: máy khách kiểm tra chứng chỉ có đúng địa chỉ nó đang kết nối không. IP máy chủ đổi thì phải ký lại chứng chỉ.
6. Thử bằng mosquitto_sub, mosquitto_pub
Trên một máy khác trong mạng (cũng cài Mosquitto, hoặc dùng ứng dụng MQTT Explorer), chép ca.crt sang rồi chạy:
mosquitto_sub -h 192.168.1.10 -p 8883 --cafile ca.crt -u esp32 -P MAT_KHAU -t "pyworld/#" -v
mosquitto_pub -h 192.168.1.10 -p 8883 --cafile ca.crt -u esp32 -P MAT_KHAU -t pyworld/thu/lenh -m "xin chao"
Thử cổng 1883 thì bỏ -p 8883 --cafile ca.crt. Thử sai mật khẩu để chắc chắn broker từ chối.
7. ESP32 kết nối broker qua TLS
Chương trình dùng WiFiClientSecure của gói esp32 và thư viện PubSubClient (Library Manager). Mở ca.crt bằng Notepad, chép toàn bộ nội dung vào biến CA_CERT.
// PYWORLD.VN - ESP32 kết nối broker Mosquitto cài trên máy Windows qua TLS (cổng 8883), có tài khoản và mật khẩu
// PYWORLD.VN - Dán nội dung file ca.crt (chứng chỉ CA tự tạo) vào CA_CERT; chứng chỉ máy chủ phải ghi đúng IP trong MAY_CHU
// PYWORLD.VN - Thay TEN_WIFI, MAT_KHAU_WIFI, MAT_KHAU_MQTT; mỗi 5 giây gửi bộ đếm lên topic pyworld/thu/esp32
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
const char *TEN_WIFI = "TEN_WIFI";
const char *MAT_KHAU_WIFI = "MAT_KHAU_WIFI";
const char *MAY_CHU = "192.168.1.10"; // IP máy Windows chạy Mosquitto
const uint16_t CONG_TLS = 8883;
const char *TAI_KHOAN = "esp32";
const char *MAT_KHAU_MQTT = "MAT_KHAU_MQTT";
const char *TOPIC = "pyworld/thu/esp32";
// Mở ca.crt bằng Notepad, chép toàn bộ (kể cả hai dòng BEGIN, END) vào giữa hai dấu ngoặc
const char *CA_CERT = R"EOF(
-----BEGIN CERTIFICATE-----
DAN_NOI_DUNG_FILE_CA_CRT_VAO_DAY
-----END CERTIFICATE-----
)EOF";
WiFiClientSecure mangTls;
PubSubClient mqtt(mangTls);
uint32_t dem = 0;
uint32_t lanGui = 0;
void khiCoTin(char *topic, byte *duLieu, unsigned int doDai) {
Serial.printf("Nhan [%s]: %.*s\n", topic, (int)doDai, (const char *)duLieu);
}
void ketNoi() {
while (!mqtt.connected()) {
Serial.print("Ket noi TLS toi broker... ");
if (mqtt.connect("esp32-tls-01", TAI_KHOAN, MAT_KHAU_MQTT)) {
Serial.println("xong");
mqtt.subscribe("pyworld/thu/lenh");
} else {
// -2: không mở được TLS (sai IP, cổng, chứng chỉ); 4: sai tài khoản, mật khẩu; 5: không được phép
Serial.printf("loi %d\n", mqtt.state());
char loi[100];
if (mangTls.lastError(loi, sizeof(loi)) != 0) {
Serial.printf(" TLS: %s\n", loi);
}
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
WiFi.begin(TEN_WIFI, MAT_KHAU_WIFI);
while (WiFi.status() != WL_CONNECTED) {
delay(300);
}
Serial.printf("Wi-Fi: %s\n", WiFi.localIP().toString().c_str());
mangTls.setCACert(CA_CERT); // chỉ tin broker có chứng chỉ do CA này ký
mqtt.setServer(MAY_CHU, CONG_TLS);
mqtt.setCallback(khiCoTin);
}
void loop() {
if (!mqtt.connected()) {
ketNoi();
}
mqtt.loop();
if (millis() - lanGui >= 5000) {
lanGui = millis();
dem = dem + 1;
char chuoi[24];
snprintf(chuoi, sizeof(chuoi), "dem %lu", (unsigned long)dem);
mqtt.publish(TOPIC, chuoi);
Serial.printf("Gui [%s]: %s\n", TOPIC, chuoi);
}
}

Kết nối TLS tốn bộ nhớ và mất khoảng một giây cho lần bắt tay đầu; PubSubClient giữ kết nối lâu dài nên chỉ tốn một lần. Ví dụ MQTT không TLS và điều khiển relay có ở bài MQTT với ESP32 bằng PubSubClient.
8. Lỗi hay gặp

Xem thêm