Minecraft 服务器的安全性始终是个难题。对于离线服务器,可以通过配置皮肤站和登录插件来增强安全性,防止被爬虫暴力破解。但正版验证服务器只能依赖白名单来主动控制可进入的玩家列表,虽然保障了安全,却给管理带来了不便。
无论是服主亲自添加白名单,还是通过 MCSManager 等面板让其他管理员协同操作,终究都需要手动处理。因此,我们需要寻找某种自动化方案,让玩家能够自助通过白名单。考虑到群友大多是可信的,只需部署一个 QQ 机器人来实现白名单自动化审核,或者允许管理员在群内直接向服务器发送指令,就能大大方便服务器的管理。
申请QQ官方机器人权限并接入Koishi
非官方机器人虽然自由灵活、部署方便,但稳定性往往不佳。考虑到管理服务器的功能并不涉及 AI 等复杂需求,申请官方机器人权限反而是最省事的选择。
它的缺点在于上线时需要等待腾讯审核,通常要好几天,并且 QQ 官方机器人要求配置 IP 白名单,这意味着你需要一台拥有固定公网 IP 的服务器(这应该不算难事)。
申请和接入流程本身没有门槛,只要按步骤操作,任何人都可以顺利完成。Koishi 论坛上已有详尽教程:
QQ/QQ 频道 登录指南 (布丁) - 技术分享 - Koishi Forum
配置MC服务器
MC的rcon虽然年久失修,有些小bug,但是无伤大雅,用来远程管理服务器再合适不过了
我们需要配置并开启rcon,找到服务器的server.properties 并编辑
rcon的配置就几行,根据实际情况修改即可,同时别忘了开启服务器的whitelist
但是rcon端口直接暴露在公网并不安全,请尽量使用Wireguard组网并在虚拟局域网中进行访问
enable-rcon=true
rcon.password=XXXXXXXXXXXXXXXXX
rcon.port=25575
white-list=trueKoishi插件配置
接下来的工作其实很简单了,Koishi插件市场中有大量的关于MC rcon和whitelist的插件,找到一个能用的安装就行
当然也可以自己写一个插件,不论是模板项目还是上传到插件市场都挺方便
我的需求是可以支持配置多个服务器进行管理
使用npm的rcon-client项目:rcon-client - npm
大致的方案如下
// 引用
const { Rcon } = require("rcon-client");
// 配置项定义
exports.Config = koishi_1.Schema.object({
servers: koishi_1.Schema.array(koishi_1.Schema.object({
name: koishi_1.Schema.string().required().description('服务器名 (用于指令匹配)'),
address: koishi_1.Schema.string().required().description('RCON地址 (格式 IP:端口)'),
password: koishi_1.Schema.string().role('secret').required().description('RCON密码')
})).description('服务器配置组列表'),
});
// 具体实现
ctx.command('whitelist <serverName> <mcId>', '添加Minecraft白名单', { authority: 1 })
.action(async ({ session }, serverName, mcId) => {
if (!serverName) {
const serverList = config.servers && config.servers.length > 0 ?
config.servers.map((s, index) => `${index + 1}、${s.name}`).join('\n') :
'暂无配置的服务器';
return `请输入服务器名\n当前服务器列表\n${serverList}`;
}
const serverConf = config.servers?.find(s => s.name === serverName);
if (!serverConf) {
return `未找到名为 "${serverName}" 的服务器配置,请检查插件配置。`;
}
if (!mcId) return '请输入玩家MC ID';
let rcon;
try {
await session.send(`正在连接到 ${serverName} ...`);
rcon = await connectRcon(serverConf);
const response = await rcon.send(`whitelist add ${mcId}`);
return `[${serverName}] 执行结果:\n${response}`;
} catch (error) {
console.error(error);
return `操作失败: ${error.message}`;
} finally {
if (rcon) {
try {
await rcon.end();
} catch (e) {}
}
}
});
ctx.command('rcon <serverName> <mcCommand:text>', '通过RCON向指定服务器发送任意Minecraft指令', { authority: 4 })
.action(async ({ session }, serverName, mcCommand) => {
if (!serverName) {
const serverList = config.servers && config.servers.length > 0 ?
config.servers.map((s, index) => `${index + 1}、${s.name}`).join('\n') :
'暂无配置的服务器';
return `请输入服务器名\n当前服务器列表\n${serverList}`;
}
const serverConf = config.servers?.find(s => s.name === serverName);
if (!serverConf) {
return `未找到名为 "${serverName}" 的服务器配置,请检查插件配置。`;
}
if (!mcCommand || !mcCommand.trim()) {
return '请输入要执行的MC指令';
}
const commandToSend = mcCommand.trim().replace(/^\/+/, '');
if (!commandToSend) {
return '指令内容不能为空';
}
let rcon;
try {
await session.send(`正在连接到 ${serverName} ...`);
rcon = await connectRcon(serverConf);
const response = await rcon.send(commandToSend);
return `[${serverName}] 命令执行结果
> ${commandToSend}
${response ? `\n${response}` : '\n无返回内容'}`;
} catch (error) {
console.error(error);
return `执行失败: ${error.message}`;
} finally {
if (rcon) {
try {
await rcon.end();
} catch (e) {}
}
}
});