在 VPS 上搭建 Minecraft 服务器
在 Ubuntu 24.04 VPS 上运行 Paper Minecraft 服务器:内存配置、Java 21、systemd 单元、两道防火墙上的 25565 端口、安全的世界备份,以及具体报错。
您将搭建什么
一个能持续在线的 Minecraft Java 版服务器:在 Ubuntu 24.04 上运行 Paper,以专用的 minecraft 用户身份在 systemd 下运行并带 Restart=on-failure,开启白名单,在玩家与 JVM 之间的两道防火墙上都放行 25565 端口,并以不会损坏世界的方式做备份,而世界正是这些备份存在的意义。服务器本身只是一个 jar 文件加一条 java 命令;真正把一个能陪朋友玩一年的服务器,与一个开服第一个周末就挂掉的服务器区分开来的所有东西,都围绕着那条命令,而这正是本指南要讲的内容。
在花钱之前有两句实话要说。第一,Minecraft 很吃内存,而且大体上是单线程的:1 GB 的 VPS 跑不出一个能玩的服务器,一个快核心胜过四个慢核心。第二,这是 Java 版。Bedrock(基岩版)玩家——主机、手机、Windows 上的 Bedrock 应用——无法加入 Java 服务器;基岩版需要不同的服务器软件,监听 UDP 19132,或者使用 Geyser 插件,这超出了本文的范围。
您需要一台全新的 Ubuntu 24.04 KVM VPS,具备 root 或 sudo 权限,以及大约三十分钟时间。
规格:一个朋友服真正需要多少
内存是最关键的数字,而真实的需求比模组整合包论坛所说的要低:
- 2 GB 能在较低视距下让 2 到 5 名玩家玩原版。能玩,但没有余量。
- 4 GB 是舒适的朋友服规格:在 Paper 上带几个插件、大约十名同时在线的玩家,还能给操作系统留下足够内存。
- 8 GB 及以上 属于模组整合包和 20 人以上的范畴,这时您还应该关注单核 CPU 速度,因为游戏主循环运行在一个线程上。
世界也会随着玩家探索而在磁盘上增长——一个玩得比较多的生存世界会达到好几 GB——所以要为世界以及它的备份预留空间。
原版还是 Paper? Paper 是官方 jar 的即插即用替代品:相同的世界、相同的客户端,不需要客户端模组。它重写了服务器最慢的那些路径——区块加载、实体刻、漏斗——并加入了插件 API。运行原版的唯一理由,是您需要位级精确的原版机制,用于那些 Paper 的优化可能会改变行为的技术红石农场;对其他所有人来说,Paper 每 GB 能容纳更多玩家。下面的一切对两者都适用。
第 1 步:安装 Java 21
Minecraft 1.20.5 以及此后的每个版本(整个 1.21.x)都需要 Java 21。Ubuntu 24.04 的默认软件源里就有它,而 headless(无界面)版本跳过了服务器永远用不到的桌面库:
sudo apt update && sudo apt install -y openjdk-21-jre-headless
java -version正确的结果:第一行显示 openjdk version "21.0.x"。如果显示的是 17 或 11,说明安装了另一个 JRE 并占了上风;用 sudo update-alternatives --config java 修复它,选择包含 java-21 的那一项。
跳过这项检查,会在稍后产生那个被搜索得最多的 Minecraft 服务器错误。用 Java 17 时,服务器 jar 会立刻崩溃并报:
Error: LinkageError occurred while loading main class net.minecraft.bundler.Main
java.lang.UnsupportedClassVersionError: net/minecraft/bundler/Main has been
compiled by a more recent version of the Java Runtime (class file version 65.0),
this version of the Java Runtime only recognizes class file versions up to 61.0这些数字解释了不匹配的原因:class file version 65.0 是 Java 21,61.0 是 Java 17,60.0 是 Java 16。无论您看到哪一对,修复方法都一样——安装更新的 JRE 并重新运行 update-alternatives。
第 2 步:用专用用户,绝不用 root
服务器会执行插件代码,并解析任何能连上端口的人发来的网络输入。如果这里出了问题,一个以 root 身份运行的被入侵进程会占据您整台 VPS;而一个以 minecraft 身份运行的进程只占据一个游戏世界。
sudo adduser --system --group --home /opt/minecraft minecraft--system 创建一个无密码、无法通过 SSH 登录的账户,以 /opt/minecraft 作为它的主目录和工作目录。从这里开始,每一条触及服务器的命令都以这个用户身份运行。
第 3 步:从官方来源下载服务器 jar
只有两个地方应该向您提供服务器 jar:原版从 minecraft.net 的官方服务器下载页,Paper 从 papermc.io 的下载页。第三方的"下载站"重新打包的服务器 jar 是一条由来已久的恶意软件渠道——服务器 jar 是您即将在一台面向互联网的机器上 24 小时全天候运行的任意代码。
从官方页面复制当前构建的下载链接(每个版本和构建的 URL 都会变,所以在这里硬编码一个链接会很快失效),然后:
cd /opt/minecraft
sudo -u minecraft wget -O server.jar 'PASTE-THE-COPIED-URL-HERE'正确的结果:一个大约 50 MB、属主为 minecraft 的 server.jar,用 ls -lh /opt/minecraft/server.jar 确认。
第 4 步:首次运行、EULA,以及给自己设为管理员
在动 systemd 之前,先交互式地运行一次服务器——首次运行有两件事只有实时控制台才能做好。
cd /opt/minecraft
sudo -u minecraft java -Xms1G -Xmx1G -jar server.jar nogui它会在几秒内退出——Paper 会先多花一点时间应用它的补丁——日志以人人都会遇到的那一行结束:
[ServerMain/INFO]: You need to agree to the EULA in order to run the server. Go to eula.txt for more info.这不是错误,而是一道许可协议门槛。这次运行在 jar 旁边写出了 eula.txt。如果您还没读过,请先阅读所链接的 EULA,然后翻转这个开关:
sudo -u minecraft sed -i 's/eula=false/eula=true/' /opt/minecraft/eula.txt再次运行同一条 java 命令。这次它会生成世界——首次启动需要一两分钟——然后停在:
[Server thread/INFO]: Done (9.204s)! For help, type "help"现在您有了一个实时控制台。用它来完成第二件事:输入 op YourMinecraftName(您确切的游戏内用户名),服务器会把您写入 ops.json,这样以后——当没有控制台连接时——您可以在游戏里运行所有管理命令。然后输入 stop 干净地保存并退出。
第 5 步:server.properties,以及为什么 online-mode 保持为 true
首次运行也写出了 server.properties。大多数默认值都没问题;下面这些行值得您慎重决定:
online-mode=true
white-list=true
enforce-whitelist=true
view-distance=8
max-players=10
motd=A private server for people I actually knowonline-mode=true 会让服务器针对 Mojang 的会话服务器核验每一个加入的用户名,证明玩家确实拥有该账户。把它设为 false——即"破解服"开关——意味着服务器会听信任何客户端对自己身份的说法:任何人都能以任何名字加入,包括您的名字,而由于管理员和白名单都是以名字为键的,冒充者会带着您的管理员权限走进来。它唯一合理为 false 的情形,是在像 Velocity 这样自行核验玩家的鉴权代理之后。在普通服务器上,它保持为 true,没有例外。
view-distance 是这个文件里最大的性能杠杆——CPU 和内存开销大致随它的平方增长。8 是一个合理的 VPS 默认值;10 是原版默认值,明显更重。
white-list=true 加上 enforce-whitelist=true 会把服务器对陌生人关闭,而下面的安全章节会说明这不是可选项。以管理员身份在游戏里用 /whitelist add TheirName 添加玩家。
第 6 步:内存参数——为什么 -Xms 和 -Xmx 应该相同
JVM 在 -Xms(起始大小)和 -Xmx(上限)之间分配它的堆。在一台专用的游戏服务器上,把它们设为相同的值:堆反正都会达到上限,而分步增长只会在游玩时增加垃圾回收器的额外开销。在一台 4 GB 的 VPS 上,合适的一对是:
/usr/bin/java -Xms3G -Xmx3G -jar server.jar nogui-Xmx 不是进程使用的总内存。JVM 会增加堆外开销——线程栈、JIT 缓存、直接缓冲区——大约半 GB 或更多,而 Ubuntu 本身也需要空间。经验法则是:-Xmx 最多为 VPS 内存减去 1 GB。超出后您会得到两种失败之一。如果分配一开始就失败,服务器会拒绝启动并报:
Error: Could not reserve enough space for object heap这一种是诚实且即时的。更讨厌的那种会正常启动,几小时后死掉,那时堆在负载下被填满,内核的 OOM killer 会挑中机器上最大的进程——也就是 JVM。服务器日志里什么都不会出现;证据在 sudo dmesg | grep -i oom 里,类似 Out of memory: Killed process 1234 (java) 这样一行。如果您的服务"随机"重启,先去那里检查,然后调低 -Xmx。
对于 Paper,项目文档给出了 Aikar 的参数——一套调优过的 G1GC 参数(-XX:+UseG1GC -XX:MaxGCPauseMillis=200 以及十几个搭档),能在较大的堆上平滑垃圾回收停顿。从 Paper 文档生成完整的那一行;在 2 到 4 GB 的堆上收益不大,但这些参数无害。
第 7 步:一个带 Restart=on-failure 的 systemd 单元
手动启动的服务器会随您的 SSH 会话一起死掉,并在重启后保持关闭。写一个 /etc/systemd/system/minecraft.service:
[Unit]
Description=Minecraft server (Paper)
After=network-online.target
Wants=network-online.target
[Service]
User=minecraft
Group=minecraft
WorkingDirectory=/opt/minecraft
ExecStart=/usr/bin/java -Xms3G -Xmx3G -jar server.jar nogui
Restart=on-failure
RestartSec=10
TimeoutStopSec=120
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now minecraft
systemctl status minecraft
journalctl -u minecraft -f正确的结果:status 显示 active (running),而日志——现在承载着服务器控制台输出——再次以 Done 那一行结束。
这个单元里有两个刻意的选择。Restart=on-failure 会在崩溃后把服务器带回来,但不会在干净的 stop 之后重启,这样维护仍然可行。而 TimeoutStopSec=120 比看上去更重要:systemctl stop 会发送 SIGTERM,Minecraft 服务器捕获它并在退出前保存每一个世界,而在一个大世界上这次保存需要时间。systemd 的默认超时可能会在保存进行到一半时 SIGKILL 掉 JVM,这正是区域文件损坏的方式。给它两分钟。
如果服务反复重启,而日志显示:
[Server thread/WARN]: **** FAILED TO BIND TO PORT!
[Server thread/WARN]: The exception was: io.netty.channel.unix.Errors$NativeIoException: bind(..) failed: Address already in use
[Server thread/WARN]: Perhaps a server is already running on that port?那么已经有东西占用了 25565——几乎总是您之前在另一个 SSH 会话里仍然活着的前台运行。用 sudo ss -tlnp | grep 25565 找到它并停掉那个副本;绝不要在一个端口上运行两个服务器。
第 8 步:在两道防火墙上放行 25565
Minecraft Java 版只用 TCP 25565(UDP 只是可选的查询协议,默认关闭)。在 VPS 上:
sudo ufw allow OpenSSH
sudo ufw allow 25565/tcp
sudo ufw enable那是第一道防火墙。大多数 VPS 提供商在控制面板里运行着第二道网络层防火墙,而这正是人们会忘掉的那道。在那里也放行 TCP 25565。只放行两者之一的症状让人抓狂地含糊:客户端卡在"正在连接到服务器...",然后以 Connection timed out: no further information 失败——没有拒绝,没有服务器错误,日志里什么都没有,因为数据包根本没到达。从 VPS 之外的一台机器用 nc -vz your.server.ip 25565 验证;succeeded 表示两道防火墙都开了,卡住则表示至少有一道没开。
既然您正在用 ufw,同一台机器还在一个公网 IP 上运行 SSH,而暴力破解的日志噪声会在几小时内开始——在 Ubuntu 24.04 上为 SSH 配置 Fail2ban,趁您还没忘。
现在连接:多人游戏、直接连接、输入服务器 IP。因为您在第 4 步给自己设了管理员,游戏内命令立即可用——为每名玩家 /whitelist add FriendName,如果计划如此就 /gamemode creative。
第 9 步:白名单,因为互联网会找到 25565 端口
把 Minecraft 服务器对互联网敞开不是一个理论上的风险:大规模扫描器持续地扫过整个 IPv4 空间寻找 25565 端口——业余的破坏项目就是用这种方式绘制出了几十万台开放服务器——而一台没有白名单的服务器会在几天、有时几小时内迎来不速之客。第 5 步的白名单就是解法:online-mode=true 证明身份,白名单把进入限制在您选定的身份上。这一对就是全部的安全模型,而对一个朋友服来说这已经足够。
对于不进游戏的控制台访问——脚本化备份、cron 任务——在 server.properties 里启用 RCON(enable-rcon=true、一个强 rcon.password、端口 25575),并在 VPS 上从 GitHub 源码构建那个小巧的 mcrcon 客户端;它不在 Ubuntu 的软件源里。不要在任何防火墙上放行 25575:RCON 以明文发送密码,所以它只留在回环地址上。
第 10 步:不会损坏世界的备份
唯一的规则:绝不要在服务器正在写入世界目录时复制它。区域文件在游玩期间被持续重写;一个与写入竞争的 tar 会产出一份带有半写入区块的归档,而当您最终恢复它时——那正是备份必须起作用的唯一时刻——日志会满是区块加载错误,地形上有窟窿。有两种做法可以避免这一点。
停止-复制-启动是简单的那种,代价是一分钟的停机:
sudo systemctl stop minecraft
sudo mkdir -p /opt/backups
sudo tar czf /opt/backups/world-$(date +%F-%H%M).tgz \
-C /opt/minecraft world world_nether world_the_end
sudo systemctl start minecraft(Paper 把各个维度拆成 world、world_nether 和 world_the_end;原版服务器把一切都放在 world 里,所以在那里去掉另外两个。)
关闭保存在服务器运行时备份:通过 RCON,发出 save-off(停止自动保存器),然后 save-all flush(强制把所有内容写到磁盘并等待),做 tar,然后 save-on。这是要放进凌晨 5 点 cron 里的版本。
无论哪种方式,一份和服务器躺在同一台 VPS 上的备份都不算备份——用 scp 或 rclone 把归档传出机器,并保留不止一份。而既然出问题时您不会盯着控制台,请给端口加一个外部检查:在另一台机器上用 Uptime Kuma 对 25565 做 TCP 检查,会在您的玩家之前告诉您服务器已经宕机。
插件与升级
在 Paper 上,一个插件就是把一个 jar 放进 /opt/minecraft/plugins/ 然后重启——这就是整个安装过程。只从插件的官方项目页(Hangar、Modrinth、SpigotMC)获取插件,原因和服务器 jar 一样:每一个都是以 minecraft 用户身份运行的任意代码。
升级服务器的过程是:停止、备份、把 server.jar 换成新 Minecraft 版本的构建、启动。有两点要注意。世界升级是单向的——被更新版本打开过的世界无法在更旧的版本里打开,这又是备份的一项工作。而且插件常常比新的 Minecraft 版本晚几天到几周,所以在发布首日就追新版本之前,请先检查兼容性。
如果您宁愿把这一切当作容器来管理——版本锁定、EULA 接受、内存参数都作为环境变量——那么被广泛使用的 itzg/minecraft-server 镜像会在 您 VPS 上的 Docker Compose 下运行相同的 Paper 服务器,采用完全相同的防火墙与备份纪律。
FAQ
Minecraft 服务器需要多少内存?
2 GB 能让 2 到 5 名玩家玩原版;4 GB 对一个大约十人、带几个插件的 Paper 朋友服来说很舒适;模组整合包和 20 人以上想要 8 GB 或更多。无论 VPS 多大,都把 -Xmx 设为最多总内存减去 1 GB——JVM 会使用堆之外的内存,超出后的结局是 Error: Could not reserve enough space for object heap,或者一次悄无声息的 OOM 击杀。
为什么我的朋友连不上我的 Minecraft 服务器?
一个以 Connection timed out: no further information 结束的客户端卡顿,几乎总是意味着防火墙,而防火墙有两道:VPS 上的 ufw,以及您提供商在控制面板里的网络防火墙。TCP 25565 必须在两者上都放行。先在机器上用 sudo ss -tlnp | grep 25565 确认服务器确实在监听,然后从外部用 nc -vz your.server.ip 25565 测试。
我应该在 server.properties 里设 online-mode=false 吗?
不应该。设了 online-mode=false 后,服务器会完全跳过 Mojang 鉴权,所以任何人都能以任何用户名加入——包括某个管理员的名字,并继承其权限——而且皮肤和稳定的 UUID 都会失效。唯一合理的用途是在像 Velocity 这样自行核验玩家的鉴权代理之后。对普通服务器来说,它保持 true。
Paper 比原版 Minecraft 服务器更好吗?
对几乎所有人来说,是的:Paper 是一个即插即用的 jar,能加载原版世界、接受未修改的客户端、更高效得多地处理实体刻和区块加载,并加入了插件生态。例外是需要位级精确原版行为的技术红石社区,而某些 Paper 优化会改变这种行为。在一台小 VPS 上,Paper 的效率实际上等于免费多出来的内存。
如何在不损坏世界的情况下备份 Minecraft 世界?
绝不要在服务器正在写入世界目录时归档它——一份与区域文件写入竞争的复制会产出损坏的区块,而您只会在恢复时才发现。要么停止服务器、tar 打包世界目录、再启动它,要么让它保持运行,通过 RCON 依次执行 save-off、save-all flush、tar、save-on。然后把归档移出 VPS。