Recently, I noticed that the WebUI of NapCatQQ has been fully developed and is quite suitable for beginners to get started. Therefore, I wrote this article.
This article only covers basic usage methods and may lack some advanced features. However, it's still necessary to understand the basics: command line, HTTP protocol, Docker, Python—this is not completely zero-level knowledge. (If you only want to use Webhook for notifications or use existing NoneBot plugins, there's no need to do Python programming.)
The tools used are NapCatQQ and NoneBot. The former runs QQ and connects to protocols like OneBot11, while the latter is a framework based on Python that calls the protocol. You can refer to the official documentation when encountering issues. (If you only want to use Webhook for notifications, setting up NapCatQQ alone is sufficient.)
QQ can detect if plugins are being used, and your account might face issues such as forced logout, login restrictions, or freezing. Please assess based on your own situation before deciding whether to proceed. The author assumes no responsibility for any consequences arising from following this guide to build a bot.
NapCatQQ offers multiple installation methods, but since it's intended as a service, I recommend using the Docker Shell version: https://napneko.github.io/guide/boot/Shell#napcat-docker-linux-containerized-deployment nThe Docker container comes with NTQQ itself, so there's no need to install a separate version of QQ.
At this point, accessing http://[IP]:6099/webui will show the NTQQ Web interface, where you can log in and set up. The login password can be found in the log file (default: napcat); it's recommended to change it after logging in.
Alternatively, you can check logs via docker logs napcat or scan a QR code to log in. When scanning, it's recommended to check "no further mobile verification required".
In the WebUI, go to Network Configuration -> New -> HTTP Server. You can freely choose the name, Host, and port. Message format is recommended to be Array, which actually works with String as well. It supports sending mixed text and image messages, and it's strongly advised to fill in a Token to prevent malicious requests.
After enabling, you can test it in API Debug -> HTTP or any other API testing tool you're comfortable with. API references: https://napcat.apifox.cn/
Token can be used in two ways:
Authorization: [Token] in the request header.?access_token=[Token] to the URL.The most important interfaces here are sending private messages and sending group messages. You can find the corresponding APIs in API Debug -> HTTP, which also includes message construction functionality—quite simple.
Here’s an example of sending a private message:

Some applications use shoutrrr as the Webhook implementation. Here’s an example configuration:
Some applications may already support the OneBot11 protocol. In that case, just enter http://[IP]:3000, the Token, and the target QQ number.
If you have a domain name, you can refer to the following Nginx configuration example for NapCatQQ:
The documentation is already very comprehensive, so I won't repeat it here.
docker run -d \
-v /data/napcat/QQdata:/app/.config/QQ \\ # QQ data directory
-v /data/napcat/logs:/app/napcat/logs \\ # Log directory
-v /data/napcat/config:/app/napcat/config \\ # Configuration directory
-v /etc/localtime:/etc/localtime:ro \
--net=host \\ # It's recommended to use host network for connecting to the subsequent NoneBot
--name napcat \
--restart=always \
mlikiowa/napcat-docker:latest
curl -X GET 'http://[IP]:3000/get_friend_list' -H 'Authorization: [Token]'
curl -X GET 'http://[IP]:3000/get_friend_list?access_token=[Token]'
curl -X POST 'http://[IP]:3000/send_private_msg' -H 'Content-Type: application/json' -H 'Authorization: [Token]' -d '{
"user_id": "[TargetQQ]",
"message": [
{
"type": "text",
"data": {
"text": "Hello World!"
}
},
{
"type": "face",
"data": {
"id": "63"
}
},
{
"type": "image",
"data": {
"file": "https://napneko.github.io/assets/newlogo.png"
}
}
]
}'
generic://[IP]:3000/send_private_msg?access_token=[Token]&template=json&titleKey=user_id&messageKey=message&@Content-Type=application/json&$user_id=[TargetQQ]
server {
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
server_name qq.example.cn;
access_log /var/log/nginx/access.qq.log;
error_log /var/log/nginx/error.qq.log;
location /webui {
proxy_pass http://127.0.0.1:6099$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /api {
proxy_pass http://127.0.0.1:6099$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /files {
proxy_pass http://127.0.0.1:6099$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
if ($request_method = POST) {
access_log /var/log/nginx/post.qq.log postdata;
}
proxy_pass http://127.0.0.1:3000$request_uri;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}