由于我的一个朋友最近厌倦了网易的MC,想要体验一下之前玩过的Java版,
还想玩AoA3这个模组玩刺激的RPG。
正好我手头有空闲的计算资源,用本文来记录一下搭建过程和遇到的问题。
准备工作调研的时候自然是优先打算采取Docker方案的,
毕竟上次开服务器的时候Docker证明了它的易用性和稳定性。
但是很快遇到了和搭建CI系统时一样的问题,
我用于搭建MC服务器的主机并非我家里的主机一样有透明代理,
本地代理显然也不是一个优雅的解决方案,
而且该主机上面也挂了不少服务,考虑之下还是上传jar包手动搭建。
由于这个朋友的朋友们都是萌新肝帝,有正版的人很少数,
再考虑到之前搭建MC服务器的时候有被顶替爆破的问题,
最后还是顺手又搭建了一个基于Blessing Skin的皮肤站,
并开启了验证码、正版验证
和世界树API三个功能。
游戏要求AoA3模组在MCWiki下列出的一般要求是:
MineCraft Java Edition 1.16.5ForgeMC 1.16.5版本主要使用Java8运行,
但是通过ModernFix这个模组,
可以让1.16版本的MC在更改虚拟机参数的前提下使用Java17运行,
所以这里服务端和客户端都采用Java17。
也是因为Debian Bullseye已经不提供Java8的JRE包了
游戏服务器搭建Minecraft服务器用的主机是一台Debian Bullseye的LXC虚拟机,没有Java环境。
安装Java环境Java环境可以从Oracle的Adoptium还有IBM的openj9当中选择。
清华大学提供了Adoptium的Repo镜像,
以及openj9的Github Release镜像,
或者直接从Debian Bullseye源安装。
从Debian源安装 openjdk-17-jre-headless$ sudo apt install openjdk-17-jre-headless
查看实际的Java文件执行位置:
$ readlink $(readlink /usr/bin/java)
/usr/lib/jvm/java-17-openjdk-amd64/bin/java
两次readlink是因为Debian会将Java的可执行文件/usr/bin/java
连接到版本控制软链接/etc/alternatives/java上。
创建用户用户目录放在/opt/minecraft下。
$ sudo mkdir -p /opt/minecraft
$ sudo useradd -M -d /opt/minecraft -s /bin/bash mc-server
$ sudo chown -R mc-server:mc-server /opt/minecraft
$ sudo su - mc-server
可执行文件下载Minecraft JE 1.16.5Forge 1.16.5-36.2.39Forge的下载界面需要点右上角的Skip才会开始下载大量优化性和辅助性的mod(如ModernFix)皮肤站依赖要求新版Blessing Skin需要PHP8.0和一个后端数据库,这里选择Postgresql,并用Redis作为缓存。
Debian Bullseye的仓库里面并没有PHP8(虽然Bookworm已经支持了),
所以需要第三方源安装,这里选取的是sury的第三方PHP仓库。
安装第三方源:
$ sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
$ sudo echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
$ sudo apt update
安装相应的PHP依赖:
$ sudo apt install php8.0-fpm php8.0-zip php8.0-gd php8.0-mbstring php8.0-xml php8.0-redis
为Blessing Skin创建Postgres数据库:
$ sudo -u postgres psql
psql (13.9 (Debian 13.9-0+deb11u1))
Type "help" for help.
postgres=# CREATE ROLE minecraft WITH LOGIN PASSWORD 'APASSWORD';
postgres=# CREATE DATABASE blessingskin WITH OWNER minecraft TEMPLATE template0 ENCODING UTF8 LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';
调整数据库访问权限:
$ sudo -e /etc/postgresql/13/main/pg_hba.conf
host blessingskin minecraft 127.0.0.1/32 scram-sha-256
local blessingskin minecraft scram-sha-256
为访问Postgresql数据库的php用户加上postgres和redis的unix socket访问权限:
$ sudo usermod -aG pgsock www-data
$ sudo usermod -aG redis www-data
可执行文件下载Blessing Skin Server 6.0.2搭建过程游戏服务器安装server和forge将服务器放在/opt/minecraft/aoa3-1.16.5目录下,Forge安装包放在/opt/minecraft下。
新建一个原版服务器:
$ pwd
/opt/minecraft
$ pushd aoa3-1.16.5
$ java -jar server.jar nogui
在服务器成功运行之后,使用Ctrl-C停止,
安装Forge:
$ popd
$ java -jar forge-1.16.5-36.2.39-installer.jar --installServer aoa3-1.16.5 nogui
该过程需要稳定的网络连接。
安装完成之后,就可以删除Forge的安装包,并且配置server.properties和放置mod。
编写启动脚本由于使用Java17启动Minecraft 1.16.5 + Forge,所以必须对虚拟机参数做一定的修改,
并且限制MC本身分配的内存。
#!/bin/sh
/usr/lib/jvm/java-17-openjdk-amd64/bin/java \
-Xms4G -Xmx8G \
-Djava.security.manager=allow \
-Dfile.encoding=UTF-8 \
--add-opens java.base/jdk.internal.loader=ALL-UNNAMED \
--add-opens java.base/java.net=ALL-UNNAMED \
--add-opens java.base/java.nio=ALL-UNNAMED \
--add-opens java.base/java.io=ALL-UNNAMED \
--add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.lang.reflect=ALL-UNNAMED \
--add-opens java.base/java.text=ALL-UNNAMED \
--add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/jdk.internal.reflect=ALL-UNNAMED \
--add-opens java.base/sun.nio.ch=ALL-UNNAMED \
--add-opens jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED,java.naming \
--add-opens java.desktop/sun.awt.image=ALL-UNNAMED \
--add-modules jdk.dynalink \
--add-opens jdk.dynalink/jdk.dynalink.beans=ALL-UNNAMED \
--add-modules java.sql.rowset \
--add-opens java.sql.rowset/javax.sql.rowset.serial=ALL-UNNAMED \
--add-exports java.base/sun.security.util=ALL-UNNAMED \
--add-opens java.base/java.util.jar=ALL-UNNAMED \
-javaagent:authlib-injector-1.2.2.jar=https://mc.azurcrystal.com/api/yggdrasil \
-jar forge-1.16.5-36.2.39.jar nogui
之后可以根据这个启动脚本编写systemd文件或者使用tmux直接管理,
由于MC服务器并不要求自动启动和自动重启,
而且为了方便快捷的使用forge内置的Shell,我这里选择了tmux。
皮肤站检查PHP环境首先查看php-fpm是否在正常运行:
$ sudo systemctl status php8.0-fpm
查看php-fpm默认的unix-socket位置:
$ grep "listen =" /etc/php/8.0/fpm/pool.d/www.conf
listen = /run/php/php8.0-fpm.sock
;pm.status_listen = 127.0.0.1:9001
当然,也可以为站点独立配置一个php-unixsocket:
$ cp /etc/php/8.0/fpm/pool.d/www.conf /etc/php/8.0/fpm/pool.d/mc.conf
$ sed -i s/php8.0-fpm.sock/blessingskin.sock/g /etc/php/8.0/fpm/pool.d/mc.conf
配置站点将站点文件放置于/opt/www/blessingskin/下,
复制环境文件并生成设置密钥:
$ unzip -d /opt/www/blessingskin blessing-skin-server-6.0.2.zip
$ pushd /opt/www/blessingskin
$ cp .env.example .env
$ php artisan key:generate
配置.envDB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=blessingskin
DB_USERNAME=minecraft
DB_PASSWORD=APASSWORD
DB_PREFIX=
...
BlessingSkin访问Postgresql的unix socket会出现无法插入的问题,
这里使用IP:Port作为临时解决方案。
...
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=sync
REDIS_CLIENT=phpredis
REDIS_SCHEME=unix
REDIS_SOCKET_PATH=/var/run/redis/redis-server.sock
REDIS_PASSWORD=null
并没有向站内用户发信的需求,所以直接使用sync节省资源。
配置nginx虚拟主机在配置之前使用acme.sh申请了ecc的域名证书。
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name mc.example.com;
ssl_certificate /path/to/ecc.crt;
ssl_certificate_key /path/to/ecc.key;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;
ssl_protocols TLSv1.3;
ssl_session_timeout 5m;
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=63072000" always;
root /opt/www/blessingskin/public;
location / {
index index.php index.html index.htm;
try_files $uri $uri/ /index.php?$query_string;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location ~ [^/]\.php(/|$){
# try_files $uri =404;
fastcgi_pass unix:/run/php/php8.0-fpm.sock;
include fastcgi.conf;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
}
后续优化皮肤站镜像插件市场鉴于插件市场的迁移,且git.qvq.network在国内的连接并不理想,
遂在服务器端本地复制了一份插件市场,
并将其registry_zh_CN.json和registry_en.json中的registry地址进行替换:
$ sed -i s/git.qvq.network\/bs-community\/plugins-dist\/-/git.azurcrystal.com\/AzurCrystal\/plugins-dist/g registry_en.conf
registry_zh_CN.conf
相当于在本地镜像了一份插件市场,之后更改.env:
PLUGINS_REGISTRY=https://git.azurcrystal.com/AzurCrystal/plugins-dist/raw/master/registry_{lang}.json
之后只需要定时向上游拉取并自动打上Patch就可以在本地镜像了。
正版验证由于劫持了世界树API,实际上正版验证在这个环节中已经成为可有可无的部分了。
在yggdrasil api由皮肤站运营的前提下,所有通过皮肤站账户连入的用户都是正版,
唯一的区别可能就是使用的UUID与实际正版账户不同了。
保持各个采用世界树API的UUID不同是一个明智的选择。
环境配置为了启用正版验证,需要在.env中配置以下三个值:
MICROSOFT_KEY=9fce0559-44b4-4c95-a144-d3ccf50ea62b
MICROSOFT_SECRET=secret@123
MICROSOFT_REDIRECT_URI=https://skin.bs-community.dev/mojang/callback
注册微软应用打开https://aka.ms/aad后,实际上会跳转到https://azure.microsoft.com/en-us/products/active-directory/,
也就是微软官方的身份验证服务。
点击登录(Signin) 并用微软账户登录以后,可以进到主控制台界面。
找到顶部的Azure服务中的Azur Active Directory,进入后选择添加-应用注册,输入应用名称(随意输入);
勾选受支持的账户类型为以下的其中一项,
任何组织目录(任何 Azure AD 目录 - 多租户)中的帐户和个人 Microsoft 帐户(例如,Skype、Xbox)仅 Microsoft 个人帐户并将重定向URI设置为Web,值为https://mc.example.com/mojang/callback。
之后点击完成创建,完成创建后的应用的应用程序(客户端)ID即是MICROSOFT_KEY。
MICROSOFT_SECRET则需点击左侧列表中的证书和密码,新建一个客户端密码,其值(非机密ID)即为变量值。
需注意,客户端密码值出现一次后就无法再查看,请及时保存。
之后按照所设置的变量更改.env,即可启用基于Microsoft账户的皮肤站内正版验证。
问题皮肤站无法直接从皮肤站的上传页面上传皮肤推测是php8的处理问题,正在考虑编译一份php8.0.2目前可以直接从启动器中上传皮肤正版验证无法更改玩家UUID属于良性BUG更改UUID会导致玩家存档消失,而且容易混淆,反而不应当更改如需正版皮肤和披风应当使用CustomSkinLoader这个插件