使用 Macmini 当作家庭服务器的一系列问题
需求
- 我买了一台 Macmini,想放在家里当服务器。需求如下:
- 远程启动我的主力台式电脑,使用 ToDesk 远程唤醒,这个软件要求在路由器或光猫上进行 mac 绑定;
- 提供一些比如 n2n 的游戏联机服务;
- 挂载 Telegram Bot;
- 挂载 UsbEAM Lan Party 服务器;
- 有可能会开 Minecraft 或者 Terraria(Tmodloader) 服务器;
- 部署博客。
- 现在已知如下条件:
- 一根中国电信家用宽带,终端为光纤进网口出的光猫,天翼网关中未动过任何设置;
- 两根网线,用来连接 Macmini 和主力台式电脑;
- 光猫已经改为桥接,路由器已经拨号上网配置好。
参考解决方案
- 光猫路由改桥接,ARP 绑定 DHCP 分配的 IP 和机器的 MAC 地址。
- 用 ipv6(因为 ipv4 申请不到),绑一个免费域名,然后跑 ddns 服务。
- Tailscale 内网隧穿打洞。
- 用 tailscale 打洞连上 ssh 之后,一切就好办了。
- 远程启动主力机,直接用 brew install 下来的 wakeonlan,命令行起主力机的有线网卡即可,验证测试通过了。
- 唤醒主力机之后,用 tailscale + rdp 远程桌面。
- 至于其他挂载的服务,用 ipv6 域名或者 openfrp。
- 以上方案暂时均未经过大面积验证(2026.4.26)。
实际方案(废弃)
- 光猫路由改桥接,进行 arp 静态路由绑定。
- Tailscale SSO 注册,各设备下载其客户端,disable 其 key expiry,加入同一个账号地 tailnet,打洞成功,手机、Mac 和 Windows 均能访问 Macmini;
- 上 dynv6 注册账号,绑一个域名 tinysnow.dynv6.net(不能自定义后缀,只能用他的),复制 mini 最稳定的 ipv6 地址(autoconf secured 那个,由网卡 MAC 地址派生,一般来说只要网络前缀不变就不会变)填入 ipv6 prefix;
- 下载 ddns-go;
- 注册好域名后,将 dynv6 里面 zone 下 instructions 里 ddclient 的 password 值,填入 ddns-go 里面的 token,保存;
- 上路由器后台管理页面,关闭防火墙(为了放行 ipv6 流量),ping6 测试公网访问 mini;
- 启动各类服务。
改版方案(2026.5.10)
- 光猫路由改桥接,进行 arp 静态路由绑定。
- Tailscale SSO 注册,各设备下载其客户端,disable 其 key expiry,加入同一个账号地 tailnet,打洞成功,手机、Mac 和 Windows 均能访问 Macmini;
- 部署博客:使用 Cloudflare Tunnel,需要一个自己的域名。
- 所有其他服务用 Docker 起(Mac 上使用轻量替代品客户端 OrbStack,使用 Portainer 管理容器)。需要公网展示的,除博客外均用 OpenFRP。
- 泰拉瑞亚和 tmodloader 服务器使用 ipv6 直连。
启动服务
Telegram Bot
- 需要修改源代码,在代码层面加入代理直连。以下代码均改自 https://github.com/TinySnow/telegram-typeseter-bot 的 self-use 分支。改动文件为 main.ts,找准首尾直接粘贴即可。注意代理需要改成自己的。
import { SocksProxyAgent } from "socks-proxy-agent";
const token = process.env.BOT_TOKEN;
if (!token) {
throw new Error("BOT_TOKEN is not set");
}
const targetChatId = -1001782968835;
const chunkLimit = normalizeChunkLen(3820);
const bot = new Bot(token, {
client: {
baseFetchConfig: {
agent: new SocksProxyAgent("socks5h://127.0.0.1:7890"),
},
},
});
- 将 package.json 文件中添加 socks-proxy-agent 依赖。
"socks-proxy-agent": "^10.0.0",
- 新建 .env 文件,填入 BOT_TOKEN。
BOT_TOKEN=000000000:XXXXXXXXXXXXXXXXXXXXXXXX
- 新建 Dockerfile,用 Orbstack(Mac)或者 Docker Desktop(其他)起 Docker。
FROM node:22-alpine
WORKDIR /app
RUN apk add --no-cache git vim curl
COPY package.json ./
RUN npm install
COPY . .
CMD ["npm", "run", "start"]
- 注意,装 git 是必须的,要拉 typeseter 的核心逻辑,未发布到 npm,直接拉 github。vim 和 curl 是可选的,用于修改文件和测试 url。alpine 的包管理器不是 apt,是 apk 请注意。最后的 CMD 命令其实可以改一下,减少资源占用。
- 接下来编写 docker-compose.yml 编排容器。
services:
telegram-typeseter-bot:
build: .
container_name: telegram-typeseter-bot
env_file:
- .env
restart: unless-stopped
network_mode: host
- 网络模式要简单的话就像上面这样,直接使用宿主机的网络模式,不通过 docker 的 network 绕。问题会比较少一点。
n2n 服务端
UsbEAM Lan Party 服务端
Minecraft 服务端
Terraria(Tmodloader)服务端
泰拉瑞亚服务器
- 直接拉别人制作好的 docker 镜像,写 docker-compose.yml 即可。
version: '3'
services:
terraria-server:
image: hexlo/terraria-server-docker-arm64:latest
container_name: terraria
restart: unless-stopped
stdin_open: true
tty: true
ports:
- 7777:7777
volumes:
- ../../data/terraria/worlds:/root/.local/share/Terraria/Worlds/
environment:
- world=/root/.local/share/Terraria/Worlds/tmp.wld
- autocreate=2
- worldname=world1
- difficulty=1
- maxplayers=8
- port=7777
- password=
- motd="欢迎来到微雪的服务器:)"
- 注意一下挂载的数据卷 volumes 路径,我不确定是否可以往上爬路径,也没有测试是否可以连进服务器。还有下面的 environment 环境变量,这些玩意儿都是可以改的,改成自己需要的即可。
- 但是听说 terraria 不支持原生的 ipv6,所以也许开了服务器也连不进去。我不知道。
- 注意这儿拉的镜像是 arm64 的镜像。
tmodloader 服务器
- 这个玩意儿开起来非常之麻烦,我整了一天。大体上遵循 https://github.com/cubebuc/tmodloader-docker 的结构(找这个东西也找了很久,如果拉官方的 Dockerfile 和 Docker Compose,会遇到各种各样的 amd64 架构和 arm64 架构的问题,还要下什么虚拟机之类的,这是 tmodloader 官方 issue 里面说的,非常、非常麻烦),这个仓库里的 dockerfile 和 compose 文件都是 multi 架构的。
- 按照里面的 README 说的,要拉他的仓库,但是我看了一下也没有什么别的东西,主要是 Dockerfile 和 Docker Compose 比较重要,就直接抄了。参考了一下这个仓库,下面给出我自己编的两个文件。
FROM mcr.microsoft.com/dotnet/sdk:8.0
ARG TML_VERSION
WORKDIR /app
RUN apt-get update && apt-get install -y unzip && rm -rf /var/lib/apt/lists/*
RUN wget https://github.com/tModLoader/tModLoader/releases/download/${TML_VERSION}/tModLoader.zip \
&& unzip tModLoader.zip \
&& rm tModLoader.zip \
&& chmod +x *.sh
RUN chown -R 1001:1001 /app
COPY ./mod /app/mod
EXPOSE 7777
# CMD ["./start-tModLoaderServer.sh", "-savedirectory", "/app/data"]
- 大体上按照 cubebuc 的来,我自己加了一点。从微软官方给的 .NET docker 镜像拉,拉完之后用 TML_VERSION 控制版本,不然服务端和客户端版本对不上就进不去。然后就是更新包、拉 tmodloader 官方的 release、解压、建文件夹。我自己最后加了一个把当前路径下的 mod 文件夹拷贝到 /app/mod 文件夹下,先搬到这个文件夹,最后才往 /root/.local/share/Terraria/tModLoader/Mods 文件夹下搬。
services:
tml:
image: tmodloader
container_name: tml
build:
context: .
args:
TML_VERSION: ${TML_VERSION:-v2026.03.3.0}
restart: unless-stopped
#user: "1001:1001"
ports:
- "7779:7777"
volumes:
- ./data:/root/.local/share/Terraria/tModLoader/
# command: ["./start-tModLoaderServer.sh", "-savedirectory", "/app/data", "-config", "/app/data/serverconfig.txt"]
stdin_open: true
tty: true
networks:
- homelab # 加入现有的 homelab 网络
command: >
/app/start-tModLoaderServer.sh
-config /root/.local/share/Terraria/tModLoader/serverconfig.txt
networks:
homelab: # 这个是原来的 homelab 网络,保持不动
external: true
- TML_VERSION 参数在 compose 文件里面传入,注意端口映射是宿主机的 7779 端口对应容器的 7777 端口。因为宿主机的 7777 端口已经给 terraria 服务端用了。注意一下挂载的数据卷 volumes 路径。我自己是建立了一个 homelab 网络,如果不需要加入 docker 的这个网络,最外层的 networks 和 services.tml.networks 标签都可以删了不要。最后就是容器起来之后执行 command 里面的开服命令。但是好像没啥用?每次我都是手动进容器执行的。
- 执行
docker compose up -d起 tml 容器。刚开始起镜像要一段时间拉文件。 - 起来之后执行
docker exec -it tml bash进容器。
mv /app/mod/* /root/.local/share/Terraria/tModLoader/Mods/ # 复制 mod 文件到 tml 的真实运行目录
./start-tModLoaderServer.sh # 开启服务器
- 开服过程中会检查有没有 .NET 环境,没有就要从微软那拉,确保网络良好,不然失败就有些头疼了,要拉一段时间。拉完了之后就会问进入哪个世界,启用哪个 mod,到时候按照提示一步步操作就好了。
- 然后就是客户端开始连接。
- 确保服务器机器的 Docker Desktop 或者 OrbStack 开启了 ipv6 支持!确保客户端机器开启了 ipv6 支持!
- 我爆哭,在这查了一天为啥不通,结果发现是没开 ipv6 这种极其低级的错误。
- 然后服务器机器 ipconfig 或者 ifconfig 查看 ipv6 公网地址,对于 Mac 来说,一般 en0 里面的 autoconf secured 的地址比较稳定一点。但其实掉电或者强关之后这个地址也会变,所以最好的还是起一个 ddns。推荐 dynv6+ddns-go,都是免费。
- 找到公网 ipv6 地址,客户端 ip 连接,输入 ip 和端口号(对于上面的 compose 文件是 7779 端口),连进去就可以。
- 注意
- tmodloader 配的 mod 最好有 ipv6 支持模组,我个人是配了 IPv6Remapper 模组(Steam mod ID:3604655108),搜 ipv6 就能搜到。我不知道不配 ipv6 支持模组能不能进服务器,反正配了是能进服务器的。
- 如果半天拉不下来文件的话,可以给 docker desktop 或者 orbstack 配镜像和代理。
- 需要客户端机器的路由器也启用 ipv6,不然有可能被路由器防火墙拦在外面
部署博客
- 采用 Cloudflare Tunnel 方案
- 还有备选方案
- Cloudflare Pages,已有: https://tinysnow.pages.dev, https://telegram-tinysnow.pages.dev
- AtomGit,现在好像没有 Pages 了
- Coding Pages,不允许新增,现在不让用了
- Netlify,已有:https://tinysnow.netlify.app/
- EdgeOne Pages,要备案,好像有时间限制,部署后 3 小时,可以试试 https://tiny-snow-blog.zh-cn.edgeone.cool
- Vercel,已有:https://tinysnow.vercel.app 或者 https://tinysnowblog.vercel.app
- Gitlink
- 暂未开始,也不知道到底需不需要,毕竟用这个方案还要买域名花钱呢,目前来看延迟最低的是 netlify,可以将就着用
DDNS
- brew install ddns-go,安装 ddns-go,然后去 dynv6.com 申请一个免费的 v6 域名
- sudo ddns-go -s install,安装为系统服务,然后访问 http://localhost:9876, DNS 供应商选择 Callback 进行手动回调,不要选 Dynv6!
- ddns-go 里面需要做的工作:
-
DNS Provider
-
RequestBody:注册好域名后,填入 dynv6 里面 zone 下 instructions 里 ddclient 的 password 值
-
URL:https://dynv6.com/api/update?zone=
&token= &ipv6=#{ip} - 里面的
和 都需要替换 - #{ip} 不需要替换
- 详见 ddns-go 里面的提示,以及 dynv6 的官方文档
- 里面的
-
DNS Provider 下的其他设置项都默认
-
-
启用 ipv6,然后选择网卡获取 ip,Domains 填自己的域名,其他不管
-
Webhook
- 可填可不填,个人是填了一个通知 TGBOT 往一个私人群里发消息 “DDNS Updated”
- Webhook URL:https://api.telegram.org/bot<bot_token>/sendMessage?chat_id=<chat_id>&text=DDNS%20Updated
- RequestBody 和 Headers 都可以不用填
- 可填可不填,个人是填了一个通知 TGBOT 往一个私人群里发消息 “DDNS Updated”
-
感谢
- 感谢三幻神 Chatgpt Claude Gemini 出主意,Deepseek 也帮了很大忙,就不贴对话记录了。