简介:这是一份针对 RW-HPS 铁锈战争服务器在 Linux 环境下的自动安装脚本,专为希望快速搭建专属服务器的玩家与运营者设计,解决了手动配置依赖、权限和启动项的繁琐问题,即使不熟悉命令行的新手也能按提示完成部署。压缩包体积仅 2KB,含 2 个文件:主脚本为 shell 脚本,会先检查系统版本并创建独立用户,避免以 root 权限运行服务;随后自动安装 Java 等依赖、从官方源获取服务端文件,并配置 IP、端口、名称、最大玩家数等参数,同时提供启动、重启、停止、备份恢复及版本更新的一键命令;配套 README 为 md 文档,详细说明了脚本执行步骤、自定义配置项、常见问题排查与使用注意事项,方便对照操作。脚本还预留了高级配置入口,便于按需调整。已有 323 人浏览学习,适合所有想在 Linux 上体验 RW-HPS 的玩家使用。
1. 铁锈战争自建服为什么要用自动安装脚本:一条命令背后是四个重复劳动
在 Linux 上开一个铁锈战争服务器,绕不开 RW-HPS 这个社区服务端实现。它比官方自带的联机方式灵活,能挂插件、设权限、开多房间,但手动部署要过四道关:装 Java、下载核心 jar、写配置、保活。单看哪一关都不难,连起来却能耗掉一个晚上,尤其是 Java 版本不对或防火墙只放了 TCP 这类问题,新手经常对着黑屏日志干瞪眼。rw-hps 铁锈战争服务器 linux 自动安装脚本这类项目,就是把环境预检、核心下载、配置生成、后台服务注册打包成一次执行。RW-HXScript.zip 是这种打包思路的一个具体产物,下面按它的通用设计拆开讲,说清楚自动装了什么、手动怎么复现、装完哪些坑值得提前躲。
2. 拆解 RW-HXScript 的安装流程:环境预检、核心下载与目录规划
拿到一个自称“自动安装”的 zip 包,我的第一反应不是直接执行里面的 install.sh,而是先解压看它的模块划分。RW-HXScript.zip 传到服务器上先解压,纯 Linux 服务器大多没装 unzip,先apt install unzip或yum install unzip -y,解压后别急着跑脚本,先看说明文件里写了安装目标、数据目录和运行账号。这类脚本不管外壳怎么变,核心都是三段:环境预检、拉取核心、铺目录。下面逐段拆。
2.1 环境预检先于一切:Java 版本和 CPU 架构在脚本里怎么判
RW-HPS 是跑在 JVM 上的服务端,以 jar 包分发。jar 的好处是跨平台,前提是 Java 运行时版本匹配。最典型的历史遗留问题:服务器自带 Java 8,RW-HPS 当前主线要求 Java 17,直接java -jar会抛 UnsupportedClassVersionError,报错里是一串看不清的 major/minor 数字。自动安装脚本的第一段逻辑基本都是在解析java -version的输出,提前判断而不是等启动时炸。
#!/usr/bin/env bash # 环境预检:判断架构与 Java 版本,不满足就退出并给明确提示 set -euo pipefail ARCH=$(uname -m) case "$ARCH" in x86_64) echo "[OK] 架构 amd64,使用官方 amd64 构建" ;; aarch64) echo "[WARN] 架构 arm64,确认核心是否提供 arm 构建,否则只能换机器" ;; *) echo "[ERR] 不认识的架构 $ARCH,建议换 x86_64 机器" exit 1 ;; esac if ! command -v java >/dev/null 2>&1; then echo "[ERR] 未找到 java,请先安装 JDK 17 再运行本脚本" exit 2 fi JAVA_MAJOR=$(java -version 2>&1 | head -n1 | sed -E 's/.*version "([0-9]+).*/\1/') if [ "$JAVA_MAJOR" -lt 17 ]; then echo "[ERR] RW-HPS 主线需要 Java 17+,当前是 $JAVA_MAJOR" exit 3 fi echo "[INFO] Java 主版本: $JAVA_MAJOR,环境通过"这段脚本的逻辑分三层。先用set -euo pipefail让任何一条命令出错就终止,避免带着残缺环境继续跑;再用uname -m区分 x86_64 和 aarch64,云厂商的便宜机器里 ARM 实例很常见,架构与核心包不匹配会在启动时以极其晦涩的方式崩掉;最后解析 java 版本。java -version输出里,Java 8 显示为1.8.0_292,这个正则只抓第一段数字,拿到的值是 1,小于 17 直接退出,反而比纠结1.8的转换更省事。退出码 1/2/3 分别对应架构、Java 缺失、Java 版本不够,脚本调用方可以据此决定要不要自动装 JDK。如果你在容器里部署,架构判断要以镜像平台为准,不能看宿主机,不过自动安装脚本方案一般不碰容器编排,裸机云服务器是主场景。
2.2 核心 jar 的下载与校验:拉错架构比拉不到更糟
环境过关后进入下载阶段。这里最容易翻车的是架构与包不匹配,其次是没有校验和。下载源如果走 CDN 分发,断流会留下一个只有预期一半大小的残缺 jar,启动报错千奇百怪,不到最后一刻根本想不到是文件坏了。规范的脚本会在下载后做 sha256 校验,失败就删掉重来,而不是拿着坏文件反复启动。
# 下载与校验:架构变量由 2.1 的预检结果赋值,版本号固定为一个 release 版本 ARCH_DIR="amd64" # arm64 机器改为 arm64 CORE_VERSION="2024.10.1" # 固定版本,不建议每次都用 latest BASE_URL="https://your-release-host.example/rw-hps" # 替换为实际 release 源 JAR_NAME="rw-hps-${CORE_VERSION}-${ARCH_DIR}.jar" wget -q "${BASE_URL}/${JAR_NAME}" -O rw-hps.jar wget -q "${BASE_URL}/${JAR_NAME}.sha256" -O rw-hps.jar.sha256 # 校验失败就删掉文件并退出,避免把坏 jar 拿去做 systemd 服务 sha256sum -c rw-hps.jar.sha256 || { rm -f rw-hps.jar rw-hps.jar.sha256; exit 1; }下载这步有几个参数值得解释。-O rw-hps.jar把远端带版本号的文件名统一成固定名,后续 systemd unit 和启动脚本都不用跟着版本号改;.sha256文件里通常是一行“哈希值 文件名”,sha256sum -c按这个文件名去找同名文件校验,所以本地文件名最好不要改。BASE_URL 是占位,实际地址以你拿到脚本时附带的发布渠道为准,不要从网上随手抄一个地址就填进去。版本号固定成具体的 release 而不是用 latest 这类浮动标签,是为了保证同一套脚本在任何时间重跑,得到的核心行为一致。如果发布渠道没有对应架构的现成构建,那就得本地打包,涉及 JDK 与构建环境,自动安装脚本一般不做这一步,它只负责把现成构建拿下来、校验、放到位。
2.3 目录规划决定维护成本:data、plugins、config 各归其位
下载完不是立刻启动,而是先把目录铺好。RW-HPS 工作目录下会生成配置、存档、日志和插件目录,不同版本的目录名略有差异,有的叫 data 有的叫 world,以首次启动生成的为准。脚本要做的是把整个服务隔离在 /opt/rw-hps 这样的专用目录里,而不是让文件散落在登录用户主目录或 /root 下。
| 路径 | 内容 | 备份策略 |
|---|---|---|
| /opt/rw-hps/rw-hps.jar | 核心程序本体 | 不用备份,随时可重下 |
| /opt/rw-hps/data | 存档与房间数据 | 必须备份,丢失即玩家进度清零 |
| /opt/rw-hps/config | 端口、房间数等配置 | 必须备份,改错可回滚 |
| /opt/rw-hps/plugins | 第三方插件 jar | 建议备份,版本匹配是个坑 |
| /opt/rw-hps/logs | 运行日志 | 轮转,不长期保留 |
这个表想说明的是备份的优先级。logs 看似最占空间,其实最不值钱,配置好轮转即可;data 和 config 才是命根子。很多新手在服务器上装了服务,备份时把整个目录打包,几 GB 的日志挤占存储,真正要的存档却没进备份包。另外,目录建好之后脚本一般会顺手创建一个低权限用户,比如 rwuser,后面 systemd 里的User=rwuser就是指它。这一步不做,后续极大概率踩中第 5 章的权限坑。目录一旦固定也不要随便迁移,config 里有些路径是相对 data 目录记录的,挪了位置要同步改配置,这也是自动安装脚本要把目录规划写进说明而不是让用户随手 mkdir 的原因。
3. 手动跑通 RW-HPS 最小流程:Java 17、首次启动与 systemd 后台化
自动安装脚本替你做的事,最好自己心里过一遍。不是让你放弃脚本回去全手工,而是当一键脚本在某个环节失败时,你能从断点接上,而不是从头再来。最小流程就三步:装 Java、前台启动一次、写 systemd 服务。
3.1 装 JDK 17 并确认 JAVA_HOME:Debian 系和 CentOS 系两条路
常见做法是装 OpenJDK 的 headless 版本。服务端没有图形界面,连桌面环境都不需要,headless 版去掉 GUI 组件,体积小、依赖少。Debian/Ubuntu 用 apt,CentOS/Rocky/Alma 用 dnf,包名就差一个字母。
# Debian / Ubuntu sudo apt update sudo apt install -y openjdk-17-jre-headless # CentOS / Rocky / AlmaLinux # sudo dnf install -y java-17-openjdk-headless装完别急着跑服务,先把 Java 情况确认清楚。java -version只告诉你版本,readlink -f "$(which java)"才告诉你真实的安装路径。很多发行版里 java 是指向 alternatives 的软链,直接写死/usr/bin/java到 systemd 里,升级或切换版本时容易埋雷。手动管理多个 Java 版本时可以用update-alternatives --config java切换生效版本,但自建服场景装 17 就够了。
java -version which java readlink -f "$(which java)"三条命令的输出要配合看。java -version确认主版本是 17,which和readlink的结果记下来,写 systemd 的 ExecStart 时要填绝对路径。有一点容易误解:很多自动安装脚本会顺手把 JAVA_HOME 写进 /etc/profile 或 /etc/environment,但 systemd 服务不读 /etc/profile,所以这个变量只影响手动交互执行,不必对 systemd 生效抱期待。
3.2 首次启动 RW-HPS:前台跑一次,读日志再谈后台
下载好 jar 之后,第一次启动我建议前台执行,不要直接上 systemd。前台能看到控制台输出,首次启动会初始化数据目录并生成配置,有些构建还会提示管理员账号怎么设置;直接扔进后台,这些信息要么被 journald 吞掉,要么因为你没盯着而错过。前台先跑,是最便宜的排错手段。
sudo useradd -r -s /usr/sbin/nologin rwuser || true sudo mkdir -p /opt/rw-hps sudo chown rwuser:rwuser /opt/rw-hps cd /opt/rw-hps sudo -u rwuser java -Xmx2G -jar rw-hps.jar顺序有讲究。先建一个不能登录的系统用户 rwuser(-r是系统用户,-s /usr/sbin/nologin禁止交互登录,|| true防止用户已存在时报错退出),再把目录属主交给它,最后用sudo -u rwuser而不是 root 启动。这一步对齐了后面 systemd 里User=rwuser,保证手动启动和开机自启跑在同一个权限模型下。-Xmx2G是起步内存,2C4G 的机器后续可以提到 3G 左右,但别超过物理内存的一半,具体原因见 5.2。启动后观察输出:没有异常栈、日志里出现监听地址和端口、data 目录开始生成文件,满足三条就可以 Ctrl+C 停掉。首次生成的端口常见默认是 5124(UDP),如果日志显示别的值,以你的构建实际输出为准,后面防火墙和 systemd 配置都跟着这个端口走。注意区分 INFO 和 ERROR,首次启动如果报初始化失败,多半是路径或权限问题,和 5.5 是同一类根源。
3.3 用 systemd 把服务钉在后台:Unit 文件参数逐行拆
前台验证通过,下一步写 systemd unit。这里三个关键点:User 不能是 root,WorkingDirectory 必须和手动启动时一致,ExecStart 用绝对路径。缺一个,后面都会以很隐蔽的方式出问题。
sudo tee /etc/systemd/system/rw-hps.service >/dev/null <<'EOF' [Unit] Description=RW-HPS Rusted Warfare Server After=network-online.target Wants=network-online.target [Service] User=rwuser Group=rwuser WorkingDirectory=/opt/rw-hps ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -Xmx2G -Xms512M -jar /opt/rw-hps/rw-hps.jar Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now rw-hps sudo systemctl status rw-hps --no-pager这个 unit 里最需要注意的是 ExecStart。Java 路径就是 3.1 里用 readlink 查到的绝对路径,不同发行版路径不一样,按实际输出改;-Xms512M略小于-Xmx2G,让 JVM 启动阶段先占 512M,随负载再向上扩,而不是启动瞬间抓走 2G。Restart=on-failure而不是 always,是为了避免 OOM 或配置错误导致的反复拉死——内存不足被内核杀时,always 会让 systemd 无限重启一个必死的进程,反而拖垮整台机器。WorkingDirectory必须指向 /opt/rw-hps,因为 RW-HPS 按相对路径读写 data 和 config,工作目录错乱的表现就是“配置全丢了”。unit 文件每次改动后都要daemon-reload,否则 systemd 用的还是旧配置;在线追日志用journalctl -u rw-hps -f,这个命令在后面的避坑章会反复出现。
注意:改完 systemd unit 后,
systemctl daemon-reload是必须的,否则 systemd 用的还是旧配置。
4. 把自动安装脚本改造成自己的:内存端口、日志备份与卸载重装
一键脚本能跑通是一回事,跑起来之后怎么维护是另一回事。这一章讲装完之后立刻要做的三件改造,别等服务器出问题了再补。
4.1 内存、端口、房间数:安装参数从哪改才生效
关于参数有个高频误区:以为所有设置都在启动命令里,实际上业务参数大多在配置文件里,JVM 参数才在启动命令里。端口、房间数、最大玩家数这些要看 config,--port这类命令行参数只有部分构建支持,不支持的版本直接改 config。内存是 JVM 的范畴,写在启动脚本或 systemd 的 ExecStart 里。
#!/usr/bin/env bash # 自定义启动脚本:内存做成环境变量,不动 systemd unit 也能临时调参 export RW_HPS_MEM="${RW_HPS_MEM:-2G}" exec java -Xmx"${RW_HPS_MEM}" -Xms1G -jar /opt/rw-hps/rw-hps.jar这个脚本的用意是:日常调内存不必改 systemd unit,编辑脚本里的默认值然后systemctl restart就行。-Xms1G给到-Xmx的一半,够 JVM 在启动阶段不频繁扩容。业务参数先看 config 里有没有现成项,没有再看启动参数,顺序别搞反。改完参数重启服务,再用ss -ulpn | grep 端口号确认实际监听的是新端口。多开场景要单独说:如果你想在同一台机器开第二个房间服,不要在同目录启动第二份进程,两个进程共享 data 会互相踩存档。常见做法是把整个 /opt/rw-hps 复制一份到 /opt/rw-hps2,改端口和内存,再做第二个 systemd unit,自动安装脚本一般不支持这个操作,得手动来。
提示:端口或内存参数改完后,记得用
ss -ulpn确认实际监听结果。配置文件里的端口和进程实际绑定的端口不一致,经常是“改了没生效”的真相。
4.2 日志轮转与定期备份:给存档留后悔药
日志无限增长不被处理,小磁盘会被写满,服务开始出现各种诡异行为。配置 logrotate 让日志按天滚动,保留两周,压缩保存,这是标准做法。
# /etc/logrotate.d/rw-hps /opt/rw-hps/logs/*.log { daily rotate 14 compress delaycompress missingok copytruncate }要点是copytruncate:把当前日志文件复制一份再清空原文,进程不需要重启,文件句柄不受影响。delaycompress让昨天那份日志先不压缩,等今天的日志轮转时再压缩昨天的,避免 copytruncate 和压缩抢同一份文件。备份脚本则要挑重点目录打 tar,而不是把整个 /opt/rw-hps 无脑打包。
#!/usr/bin/env bash # 备份脚本:只打包 data/config/plugins,logs 交给 logrotate 管 BACKUP_DIR="/opt/backups/rw-hps" mkdir -p "${BACKUP_DIR}" tar czf "${BACKUP_DIR}/rw-hps-$(date +%Y%m%d-%H%M).tar.gz" \ -C /opt/rw-hps data config plugins find "${BACKUP_DIR}" -name '*.tar.gz' -mtime +7 -delete这里的-C /opt/rw-hps很有用:先切到服务目录,再对 data/config/plugins 做相对路径打包,解压出来直接就是这三个目录,不会带一长串绝对路径前缀。find -mtime +7 -delete保留最近 7 天备份,按 2C4G 机器的磁盘容量,7 天足够覆盖“今天才发现昨天就坏了”的场景。再用 crontab 每天凌晨执行一次:
17 4 * * * /opt/scripts/backup-rw-hps.sh >> /var/log/rw-hps-backup.log 2>&1固定错开高峰时间,输出打到独立日志,备份失败时能第一时间在 /var/log 里看到原因。运行中直接 tar 备份,data 可能正在写入,掉电场景下备份出来的存档会有极小概率不一致;更稳妥是凌晨停服备份,但小服务器通常不可行,退而求其次接受这个窗口,恢复时以最近的完整备份为准。
4.3 卸载与重装:脚本留下的干净退出路径
卸载比安装更考验纪律。最怕的不是卸不干净,而是手一快把存档一起删了。顺序应该是:先停服务,再禁用开机自启,最后删 unit 文件,数据目录默认保留,确认彻底不玩了再删。
sudo systemctl stop rw-hps sudo systemctl disable rw-hps sudo rm -f /etc/systemd/system/rw-hps.service sudo systemctl daemon-reload # 数据目录默认保留,确认不玩了再删 # sudo rm -rf /opt/rw-hpsdaemon-reload一定要在删完 unit 文件后执行,否则 systemd 还会记忆旧的 unit。重装场景更简单:保留 /opt/rw-hps 下的 data 和 config,重新下载核心 jar 放回去,启动后存档和配置原样回来。这也是前面强调目录规划的原因,散落在各处的文件根本无法这样无缝重装。重装后建议做个新旧配置 diff,确认端口和房间数没变,再开放公网对外,避免玩家连不上才发现参数漂移。
5. RW-HPS Linux 部署避坑指南:启动失败到权限失控的 5 个典型问题
部署类问题排错有个套路:先看日志,再看端口,最后看权限,顺序反了容易在错误方向上浪费一小时。下面的五条按出现频率排序,都是我在 Linux 上折腾 RW-HPS 时见过不止一次的现场。
5.1 端口被占:java.net.BindException: Address already in use
现象:启动几秒后进程退出,日志尾部出现 BindException 指向某个端口。原因:上一个实例没死干净,或者同一台机器跑了两份脚本。解决:先看占用再清进程。
ss -ulpn | grep 5124 pkill -f rw-hps.jar sudo systemctl restart rw-hps注意ss -ulpn里u是 UDP。游戏通信走 UDP,你用ss -tlnp查会得到“没有进程监听”的假象,这是新手最容易迷惑的点。pkill -f按命令行匹配,能把残留的 java 进程带走,之后再让 systemd 拉起来。
5.2 内存分配过大:OOM 被杀,退出码 137
现象:服务跑了一段时间,玩家一多就消失;systemctl status看到 Main process exited, code=killed, status=137/OOM。原因:-Xmx设得比物理内存还高,或者机器本身内存紧张,Java 堆和系统其他进程抢内存,被内核 OOM killer 点名。解决:看实际内存再调。
free -h dmesg | grep -i oom | tail -n 10 journalctl -u rw-hps --no-pager | tail -n 30free -h看总量,dmesg里会留下内核杀进程的确凿记录。对 2G 内存的机器,-Xmx2G就是雷,Java 堆之外还有 Metaspace 和线程栈,凑起来超过 2G,系统直接就崩。经验值:JVM 堆设到物理内存的 40%-50%,留一半给系统和文件缓存。
5.3 systemd 环境下配置错乱:工作目录和 PATH 不对
现象:手动前台启动一切正常,注册成 systemd 服务后,配置读取不到、存档路径找不到,表现像“配置全丢”。原因:Unit 里没写 WorkingDirectory,进程以 / 为工作目录,RW-HPS 按相对路径找 data 和 config,自然全扑空。解决:在 [Service] 段补上WorkingDirectory=/opt/rw-hps,ExecStart 里的路径全部用绝对路径。这也是 3.3 里反复强调的原因。每次改完 unit 文件记得daemon-reload,否则 systemd 用的还是旧配置。
5.4 防火墙只放行 TCP:UDP 不通,玩家卡在加入中
现象:服务进程正常,日志干净,能看到房间,但玩家点加入后一直转圈。原因:游戏通信走 UDP,云平台安全组和本机防火墙通常只放了 TCP,把 UDP 漏了。解决:按端口放行 UDP。
sudo ufw allow 5124/udp # 云安全组:控制台加一条 UDP 入站规则,端口与 config 一致 # firewalld: sudo firewall-cmd --permanent --add-port=5124/udp && sudo firewall-cmd --reload这类问题是最典型的黑匣子:进程层面没有任何报错,纯粹是网络层静默丢包。排查时先确认端口和协议,再查防火墙,顺序别反。如果用了 Docker 部署,还要多查一层容器端口映射,不过自动安装脚本方案一般不碰容器,直接宿主机跑更省心。
5.5 存档写不进:目录权限被 root 接管
现象:开服一两周后出现存档失败、新建房间报错,日志里是 Permission denied。原因:某次维护时用 root 手动改过目录,或某次直接 root 启动过服务,data 属主变成 root;systemd 里User=rwuser,普通用户写不进 root 的目录。解决:把属主统一交还给运行账号。
sudo chown -R rwuser:rwuser /opt/rw-hps这条命令在使用 sudo 频繁的机器上几乎必然遇到。根因不是 RW-HPS 的问题,而是运维习惯:root 操作完没有把权限还回去。规范的做法是平时维护也尽量切到服务用户,需要 root 时再 sudo,避免存档目录属主在 root 和服务用户之间反复横跳。
6. 安装完成后的三件事:插件版本匹配、备份可恢复性与版本锁定
6.1 插件不是扔进 plugins 就能用
RW-HPS 吸引人的地方在插件,但插件是黑匣子。装完不生效,先看核心日志有没有加载插件的记录,再看插件编译时对应的核心版本,跨版本插件最常见的结局是装了毫无反应。把插件 jar 放进去后重启服务,看日志里插件是否被识别,这一步能筛掉八成“插件无效”问题。
6.2 备份有没有用,取决于能不能恢复
备份脚本跑起来不代表万事大吉。我习惯每个月挑一天,把最新备份解压到临时目录,写一个最小的启动配置验证 data 和 config 能正常加载。能恢复的备份才是后悔药,不能恢复的备份只是心理安慰。发现备份恢复不了,趁早调整备份脚本,别等存档丢了才发现 tar 包里少了关键目录。
6.3 版本不是越新越好
核心追新要克制。升级前先看发布说明里有没有配置格式或数据存储结构变化,小版本没必要追。我的教训是有一次看到新发布很兴奋,升完才发现插件全不兼容,又回滚,来来回回折腾一晚上。从此定了规矩:只有确认大版本兼容、且确实需要新功能时才动核心,平时保持原版本。这条血泪经验希望帮到你。
本文还有配套的精品资源,点击获取