第一步,先安装mosquito
docker安装mosquitto(2选1)
先拉取本地镜像,这里拉取的是1.6.15版,因为latest版会有各种问题,暂时无解
docker pull eclipse-mosquitto:1.6.15
执行如下命令创建目录
mkdir -p /mosquitto/config mkdir -p /mosquitto/data mkdir -p /mosquitto/log
执行如下命令创建初始化配置文件
vim /mosquitto/config/mosquitto.conf
在配置文件中添加如下内容,然后保存退出
persistence true persistence_location /mosquitto/data log_dest file /mosquitto/log/mosquitto.log
执行如下命令为目录授权(其中日志目录要最大权限)
chmod -R 755 /mosquitto chmod -R 777 /mosquitto/log
执行如下命令即可启动 mosquitto 容器
docker run -d --name=mosquitto --privileged \ -p 1883:1883 -p 9001:9001 \ -v /mosquitto/config/mosquitto.conf:/mosquitto/config/mosquitto.conf \ -v /mosquitto/data:/mosquitto/data \ -v /mosquitto/log:/mosquitto/log \ eclipse-mosquitto:1.6.15
若还需要配置权限,则还需要以下操作,注:在docker的mosquitto服务已启动的情况下执行
打开配置文件(/mosquitto/config/mosquitto.conf),添加以下配置
# 关闭匿名模式 allow_anonymous false # 指定密码文件 password_file /mosquitto/config/pwfile.conf
接着执行如下命令进入容器
docker exec -it mosquitto sh
执行如下命令建立 pwfile.conf 文件,并设置权限
touch /mosquitto/config/pwfile.conf chmod -R 755 /mosquitto/config/pwfile.conf
然后使用 mosquitto_passwd 命令创建用户(比如下面我们创建了一个名为 lzl 的用户,密码为 123)
mosquitto_passwd -b /mosquitto/config/pwfile.conf lzl 123
添加完毕后执行 exit 退出容器,并重启docker的mosquitto服务
docker restart mosquitto
至此,配置账户密码完成,详情也可以参考 https://www.hangge.com/blog/cache/detail_2896.html
正常安装mosquitto(2选1)
在root目录中下载mosquitto1.6.15版
wget http://mosquitto.org/files/source/mosquitto-1.6.15.tar.gz
解压文件
tar -zxvf mosquitto-1.6.15.tar.gz
进入目录,执行make和make install
cd mosquitto-1.6.15/
make
make install
可以配置指定用户发布指定主题,或者订阅指定主题
在/etc/mosquitto中参考aclfile.example即可,如tom只能订阅company/building/floor这个主题
user tom topic read company/building/floor
例如tim只能发布company/building这个主题
user tim topic write company/building
例如tam只能发布和订阅company/#下的主题
user tam topic readwrite company/#
第二步,安装mosquitto时使得其支持websocket链接
扩展,若想要mosquitto支持websocket连接,则需要在以上安装步骤前(若已经执行了以上第一步的步骤,则需要卸载或删除掉/root/mosquitto/整个目录先)执行以下
登录https://github.com/warmcat/libwebsockets上下载websocket源码,放到root目录下
wget https://github.com/warmcat/libwebsockets/archive/refs/heads/main.zip
使用unzip 命令解压后,进入解压后的/root/libwebsockets-main/目录
unzip libwebsockets-main.zip
创建一个build目录,进入build目录,cmake..,然后 make & make install,大致命令如下
cd libwebsockets-main/
mkdir build
cd build
cmake ..
make & make install
安装完成libwebsockets后,再执行第一步中的重新编译安装步骤,注意 make & make install前需要先vim修改/root/mosquitto-1.6.15/config.mk,开启其支持websocket
WITH_WEBSOCKETS:=yes
再继续第一步中的步骤,即make , make install等
安装成功后,修改/etc/mosquitto/mosquitto.conf,在最底部添加如下
port 1883 listener 9001 protocol websockets
以下两个是数据持久化设置,也可以在/etc/mosquitto/mosquitto.conf的最底部添加上即可
autosave_on_changes 1 autosave_interval 1
然后启动mosquitto
mosquitto -c /etc/mosquitto/mosquitto.conf -d
启动时可能会报错 error while loading share libraries libwebsockets什么的,则添加以下软连接即可
ln -s /usr/local/lib/libwebsockets.so.19 /usr/lib64/libwebsockets.so.19
再次重新启动mosquitto
mosquitto -c /etc/mosquitto/mosquitto.conf -d
重启时可能会没反应,netstat观察也没发觉有1883端口启动,使用mosquito命令查看报错如下
mosquito
1656653967: mosquitto version 1.6.15 starting
1656653967: Using default config.
1656653967: Opening ipv4 listen socket on port 1883.
1656653967: Opening ipv6 listen socket on port 1883.
1656653967: Error: Invalid user 'mosquitto'.
则是不能使用默认的“mosquito”用户去启动mosquito
解决方案,查看下文红色部分即可(方案1方案2任选其一)
netstat -ntlp 查看端口,已经开启9001以及1883端口,且支持websocket链接
netstat -ntlp
第三步,使用ssl证书配置mosquitto连接
在随便一个目录中生成ca证书(以下命令会生成ca.key)
openssl genrsa -des3 -out ca.key 2048
输入密码 123456, 确认密码 123456(以下命令会生成ca.crt)
openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
输入刚才设置的密码 123456,然后按照一步步的步骤设置即可(注意common name不能与server和client的common name一样,这里设置为0.0.0.0即可)
Country Name (2 letter code) [XX]:CN 【国家代码,两个字母】 State or Province Name (full name) []:guangdong 【省,可省略不填】 Locality Name (eg, city) [Default City]:guangdong 【市,可省略不填】 Organization Name (eg, company) [Default Company Ltd]:zmkm 【证书持有者所属组织或公司】 Organizational Unit Name (eg, section) []: 【证书持有者所属部门,可以不填】 Common Name (eg, your name or your server's hostname) []:0.0.0.0 【域名,一定不要和sever、client端证书的这个字段相同】 Email Address []: 【邮件,可以不填】 Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: 【自定义密码,可以不填】 An optional company name []: 【可选公司名称,可以不填】
生成server证书(以下命令会生成server.key)
openssl genrsa -out server.key 2048
输入密码 123456, 确认密码 123456
openssl req -new -out server.csr -key server.key
输入刚才设置的密码 123456,然后按照一步步的步骤设置即可(注意common name不能与上面的ca的common name一样,这里设置为服务的ip即可)
Country Name (2 letter code) [XX]:CN 【国家代码,两个字母】 State or Province Name (full name) []:guangdong 【省,可省略不填】 Locality Name (eg, city) [Default City]:guangdong 【市,可省略不填】 Organization Name (eg, company) [Default Company Ltd]:zmkm 【证书持有者所属组织或公司】 Organizational Unit Name (eg, section) []: 【证书持有者所属部门,可以不填】 Common Name (eg, your name or your server's hostname) []:**.**.**.** 【域名,这里不跟上面的ca的0.0.0.0相同即可】 Email Address []: 【邮件,可以不填】 Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: 【自定义密码,可以不填】 An optional company name []:
最后输入以下命令(以下命令会生成server.crt)
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360
生成client证书(以下命令会生成client.key)
openssl genrsa -out client.key 2048
输入密码 123456, 确认密码 123456
openssl req -new -out client.csr -key client.key
输入刚才设置的密码 123456,然后按照一步步的步骤设置即可(注意common name不能与上面的ca的common name一样,这里设置为服务的ip即可)
Country Name (2 letter code) [XX]:CN 【国家代码,两个字母】 State or Province Name (full name) []:guangdong 【省,可省略不填】 Locality Name (eg, city) [Default City]:guangdong 【市,可省略不填】 Organization Name (eg, company) [Default Company Ltd]:zmkm 【证书持有者所属组织或公司】 Organizational Unit Name (eg, section) []: 【证书持有者所属部门,可以不填】 Common Name (eg, your name or your server's hostname) []:**.**.**.** 【域名,这里不跟上面的ca的0.0.0.0相同即可】 Email Address []: 【邮件,可以不填】 Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: 【自定义密码,可以不填】 An optional company name []:
最后输入以下命令(以下命令会生成client.crt)
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 360
完成以上后,可以使用以下命令验证以下,若输出server.crt ok即可
openssl verify -CAfile ca.crt server.crt
最后,在/etc/mosquitto/mosquitto.conf的最底部添加以下即可
port 1883 cafile /etc/mosquitto/ca/ca.crt certfile /etc/mosquitto/ca/server.crt keyfile /etc/mosquitto/ca/server.key #开启双向认证 require_certificate true listener 9001 protocol websockets autosave_on_changes 1 autosave_interval 1
启动mosquitto服务
mosquitto -c /etc/mosquitto/mosquitto.conf -d
若启动没有任何效果,netstat查看也没有正常的端口启动,且使用 mosquitto -v命令查看时,显示invalid的user mosquitto等信息,则是用户与用户组的问题,解决方案有2个
方案1,可以修改mosquitto.conf中的user mosquitto前的#去掉,更改为以下(已验证OK)
user root
方案2,或者也可以新建一个mosquitto的用户或组什么的(已验证OK)
groupadd mosquitto useradd -g mosquitto mosquitto
可以使用命令测试一下是否OK
订阅
mosquitto_sub -h 127.0.0.1 -p 1883 -t "aaa" -u lzl -P a123 --cafile /etc/mosquitto/ca/ca.crt --cert /etc/mosquitto/ca/client.crt --key /etc/mosquitto/ca/client.key --insecure
发布
mosquitto_pub -h 127.0.0.1 -p 1883 -t "aaa" -m 'nihaoa' -u lzl -P a123 --cafile /etc/mosquitto/ca/ca.crt --cert /etc/mosquitto/ca/client.crt --key /etc/mosquitto/ca/client.key --insecure
第四步,若需要分布式集群部署,可直接使用mosquitto的桥接配置
集群目的 无论在那台服务器中订阅了信息,无论在那台服务器上发布信息,订阅者都可以收到发布的信息。集群部署有一个 专有名词叫做“桥接”,实现桥接的方式需要修改config.mk与mosquitto.conf文件。值得说明的是如果有10台服务器做 mosquitto集群,每台服务器上将桥连接打开,然后只需要更改一台服务器上的mosquitto.conf文件即可,其他服务器 的mosquitto.conf文件不需要做任何改动。大大方便了集群的维护。如果有新的服务器加入或删除只需要修改主服务器 的mosquitto.conf即可
例如
192.168.20.38 主节点
192.168.20.52 从节点
192.168.20.111 从节点
确保三台服务器编译的mosquitto时已经打开了桥接的设置
vim config.mk
WITH_BRIDGE:=yes
分别在三台服务器上创建桥接专用的用户和密码
mosquitto_passwd -b /etc/mosquitto/pwfile hthl_bridge 123456
在三个节点的aclfile文件中控制桥接用户的权限(可忽略)
# This is a bridge user. user hthl_bridge topic #
重启三台服务器的mosquitto服务
配置主节点mosquitto.conf的桥连接属性,注意:其他从节点千万不要增加此信息否则消息会死循环
# bridge # ================================================================= # 桥接名称 connection broker52 # 节点地址 address 192.168.20.52:1883 # 消息主题 topic # both 2 "" "" # 桥连接用户名 remote_username hthl_bridge # 桥连接密码 remote_password 123456 # 桥接名称 connection broker111 # 节点地址 address 192.168.20.111:1883 # 消息主题 topic # both 2 "" "" # 桥连接用户名 remote_username hthl_bridge # 桥连接密码 remote_password 123456 # 桥连接协议版本MQTT3.11 bridge_protocol_version mqttv311 # 是否发布桥接的状态信息 notifications true # 桥接断开时,是否清除远程服务器中的消息 cleansession true # 桥连接是否可用的检测开关 try_private true # 桥接模式 start_type automatic
测试在主节点发布从节点订阅没问题,至此mosquitto分布式集群部署完成
第五步,使用wss连接mosquito的websocket端口
以上第三部使用的自建ssl证书方式可以连接mqtt协议,但使用wss的连接时死活连不上,原因是wss中浏览器不识别ssl证书,需要到阿里云生成域名对应的证书
例如,当前mosquito的ssl websocket的端口为9002,ip为1.2.3.4,绑定的域名为websocket.baidu.com,则需要登录阿里云,生成免费的websocket.baidu.com的证书并下载nginx版的key和pem,把key和pem上传到mosquito服务器的某个文件夹中,并更改mosquito.conf的websocket 9002端口如下(注意:9002端口下的cafile设置可不写,且9002端口下的require_certificate true必须注释掉否则wss还是连不上)
listener 9002 protocol websockets certfile /xxx/xxx/xxx/xxx/xxxwebsocket.baidu.com.pem keyfile /xxx/xxx/xxx/xxx/xxxwebsocket.baidu.com.key
重启mosquito后,使用mqtt.js客户端连接即可,具体代码可参考
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="shortcut icon" href="./image/favicon.png" /> <link rel="bookmark" href="./image/favicon.png" type="image/x-icon" /> <title>wss mqtt连接</title> </head> <body> <script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script> </body> <script> console.log(mqtt); const clientId = 'mqttjs_' + Math.random().toString(16).substr(2, 8) console.log(clientId); const host = 'wss://websocket.baidu.com:9002' const options = { keepalive: 60, clientId: clientId, username: 'lzl', password: 'a123', protocolId: 'MQTT', protocolVersion: 5, clean: true, reconnectPeriod: 0, connectTimeout: 30 * 1000, will: { topic: 'WillMsg', payload: 'Connection Closed abnormally..!', qos: 0, retain: false }, } const client = mqtt.connect(host, options) console.log(client) client.subscribe('testtopic/2') client.subscribe('WillMsg') client.on('error', (err) => { console.log('Connection error: ', err) client.end() }) client.on('reconnect', () => { console.log('Reconnecting...') }) client.on('message', (topic, message, packet) => { console.log('Received Message: ' + message.toString() + '\nOn topic: ' + topic) }) </script> </html>
使用以下命令可以观察mosquito服务器的启动句柄多少(用于压力测试时观察数据)
ls /proc/20436/fd -l | grep socket: | wc -l
注意事项:若需要使用wss的websocket方式链接到mqtt.xxx.com,则需要
1、把mqtt.xxx.com的域名解析指向服务器ip
2、生成mqtt.xxx.com的ssl证书,并设置到/etc/mosquitto/mosquitto.conf.example文件中的certfile和keyfile参数中
3、若mqtt.xxx.com的ssl证书失效,则会影响wss的websocket的链接,需要更新证书