N100 小主机搭配甲骨文 VPS,对 AIO 说拜拜


去年 6 月升级了 N5105 核心的 NAS, 目前为止几乎是 7x24h 在运行。PT、视频硬解、相册备份、甚至一些轻量计算任务统统不在话下,配合公网 ip 以及 20 多 T 的超大硬盘,拿捏几乎所有的 web 微服务。尽管用着很爽,时间长了缺点也渐渐显现:

  1. 硬盘处于最大损耗状态,特别是眼下机械盘价格攀升,算上电费的成本有点高
  2. 一旦关机,所有服务都将不可用
  3. 早就眼馋 N100/N305 了,折腾的心又开始躁动

正好前段时间让我成功注册了甲骨文,一台首尔线路的 4C+24G ARM 顺利开机。又遇上政府消费补贴,果断入手了一个自带 12G 内存和 256G 系统盘的入门款 N100 小主机。于是 NAS 减负之路正式开启。

首先是 ARM 云主机,这个主要跑一些日常服务,不需要太多配置那种,主要也是担心会随时失联,降低重建成本。为了安全,也没有开放全部端口。目前搭好的包括:

  1. 一键出国脚本,给机场上个保险;
  2. acme.sh 泛域名证书,配合 nginx 作为 ssl 应用的基础;
  3. coturn 服务,跑 TURN 协议给文件传输工具用;
  4. pairdrop docker,基于 web 的跨端文件传输,不算稳定,等新版;
  5. rustdesk docker,开源的远程控制,跨端,非常好用;
  6. alist 一键脚本,方便文件管理;
  7. yt-dlp,下视频;
  8. html 静态 web 工具箱,方便处理 base64、url 编码什么的。
  9. lazyvim

小主机拿到手就装了 ubuntu server 22.04.5,暂时不考虑 pve、ESXi 这类 All in One 方案。插上闲置许久的 256G 2.5 寸 ssd,不看任何教程顺利完成系统安装。通过测试,上海电信下的最佳线路选择是中科院的源镜像。后来发现旧 linux 内核 对 N100 的支持不太好,又重装(直接升级据说有概率出现 bug)了最新的 Ubuntu 24.10,内核也升到了 6.11.0。

了解到默认分区采用的是 LVM 方案,只分配了 100G 可用空间。参考皓然的教程顺利完成改造,核心思想就是partition👉PV👉VG👉LV👉FS,简单易懂,有点类似 Raid 的作法。我没有选择直接扩容到 100%,等后面容量不够的时候再扩也来得及。

记得先 umount 再操作分区

本来还想安装硬件监控(glances、netdata 之类的)、docker 管理界面啥的,想了想感觉都有点鸡肋。后面还要补上 NAS 的全套 php 服务,加上数据库迁移,也算是个大工程。装上新版 jellyfin(参考 Chiphell 上网友的经验先行体验,继续等待 N 大的特供版更新,或者Ubuntu 22.04 下修改驱动使 Intel DG1 可以在 Jellyfin 下解码)。NAS 用来保存,小主机以后就是观影主力。在此之前,还要装一个 wireguard 用来远程连接。touch /etc/cloud/cloud-init.disabled文件默认存在,所以 cloud-init 一般不启动。

搞完这些就可以给 NAS 关机了,然后一个月开机一周这样子,顺便同步一下备份。小主机则直接扔到显示器后面,发热和噪音对比 NAS 有明显改善,待机功耗也从 30w 左右降到 8W。后面还可以搞搞远程唤醒,这样就更灵活了。

禁止密码登录 SSH

新版不建议直接修改/etc/ssh/sshd_config,而是直接改/etc/ssh/sshd_config.d/文件夹下的自定义配置:

PubkeyAuthentication yes #启用密钥认证
AuthorizedKeysFile .ssh/id_rsa.pub #公钥路径
PasswordAuthentication no #禁用密码登录
PermitEmptyPasswords no #禁用空密码

安装 Wireguard

参考官方文档提示,linux 软件仓库的版本有点旧,点击out of date还会自动弹出一封写好的催更邮件,幽默。所以我选择手动编译,因为我安装的是最新的 ubuntu 22.04,内核已经自带 wireguard 模块,再次编译会报错

WireGuard has been merged into Linux >= 5.6 and therefore this compatibility module is no longer required.

所以只需编译安装wireguard-tools。成功后试一下wg -h能否正常输出

配置方法可以参考 digitalocean 的文档,写得比较全面,他们家其他文档也挺值得借鉴的,不足之处是缺少对 pre-shared key(预共享密钥)的说明。关于流量转发(当 VPN 使)的配置可以参考这个,如果 peer 客户端只能连接到服务器而不能连通服务器所在的局域网和广域网,查一下有没有开启转发(net.ipv4.ip_forward=1),wg0.conf 中的 iptables NAT 设置,以及客户端AllowedIPs是不是设置为0.0.0.0/0,这几个是必需的。我的服务端没有启用防火墙,所以 ufw 相关的就没必要设置了。假如还是上不了外网,检查一下子网掩码是不是写对了(/24 和 /32 不是随意写的),我因为这个问题折腾了一天多😭 总体来说,wireguard 还是挺容易配置的。

充分利用 2.5g 网口

因为路由器只有一个 2.5g 网口,之前分配给了 NAS。所以 NAS 和小主机都富余一个 2.5g 的网口。目前的想法是用网线把它们连起来,用来快速转移 NAS 上的视频到小主机上,毕竟后者的硬盘容量只有 500G。参考《主板双网卡应用实例 直连NAS》,这里把 windows 替换为 ubuntu server,逻辑是一样的,只需要为两台机器手动配置 IP 即可点亮网卡指示灯。一番尝试,发现手动 mount 搭配 cp 命令是最快最稳定最简约的文件传输方式。美中不足就是要在 QNAP 后台手动开启各个共享文件夹的 NFS 远程连接权限。为了进一步方便局域网其他设备跟小主机之间传输文件,打开了小主机上的 rsync 服务。然而,win 系统笔记本通过无线路由器上传文件只有可怜的 2Mbps,不过这也比 SCP 直接上传的 Kbps 级别的速度要快了。

用了一段时间,发现还是 smb 方便,主要是内置支持的设备更多。这里又遇到一个坑,samba 服务如果要复用系统用户鉴权,需要通过 smbpasswd 单独设置登录密码。否则就是各种无法登录。

安装 V2rayA ShellCrash

原本准备跟 NAS 一样装个 V2rayA docker,无奈新的流量计费机场用的是 Clash 订阅格式,也没找到兼容性比较好的订阅转换工具。于是切换到命令行的 ShellCrash,使用下来也挺方便。默认是走自带的路由规则,无感代理,后续有空了再研究怎么自定义。关于 web 后台有个坑,通过局域网其他机器(NAS)的 wireguard 可以打开网页,而本机的 wg 隧道却打不开。折腾半天,发现开启 ShellCrash 的公网访问Dashboard面板就 OK 了。另外,如果要通过 wireguard 远程共享代理需要两个步骤:1. 在命令行(7-5-1)设置 Http/Sock5 端口,web 的设置页打开允许局域网访问;2. 在命令行(7-3-3)添加 wg0 的网段,比如 192.168.10.1/24。

Mariadb 数据库、php 和 nginx

这个部分没啥好讲的,按照官方文档一路装下来,然后就是导入数据库,恢复/var/www下的网站目录。需要注意的是,nginx 和 php-fpm 的用户最好统一成www-data,然后手动设置权限:

sudo chown ubuntu:www-data -R /var/www/app
sudo chmod -R u=rwX,g=rX,o= /var/www/app

如果是软链接,源目录最好别放在 home 文件夹,因为/home/xxx文件夹针对xxx之外的 user 是没有执行权限的!也就意味着其他用户无法读取当前用户文件夹下的任何文件,即使子文件夹修改拥有着和权限也是不行的!因此,建议放在公共区域,比如/opt下面。

安装 FreshRss 之后记得增加 Systemd timer。

安装 qbittorrent-nox、IYUUPlus 和 Jellyfin

因为都是要开放 web 服务,建议单独建立一个用户,比如 pter,设置完之后取消 shell 登录权限增加安全性。qbittorrent 服务端安装参考 wiki 文档,如果经常批量上传种子,记得调大 Nginx 配置中的client_max_body_size。这里没有使用官方仓库,而是使用 4.6.7 的静态编译版本进行替代。官方版在运行一天之后内存占用直接干到 80%,所以还是用回 Libtorrent v1。

apt 方式安装完 Docker 之后可以将/etc/apt/sources.list.d/docker.list改名为docker.list.bak提高apt update加载速度。jellyfin 的 docker 使用 pter 用户,IYUUPlus 就必须使用 root 了,因为内置了 MySQL 数据库(搞不懂为啥不用 sqlite)。这里贴一下命令行和 compose 供参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
services:
jellyfin:
image: nyanmisaka/jellyfin
container_name: jellyfin
user: 1001:1001
network_mode: 'host'
# privileged: true
group_add:
- '993' # render
volumes:
- /home/xxx/.config/jellyfin/config:/config
- /home/xxx/.config/jellyfin/cache:/cache
- type: bind
source: /home/xxx/media
target: /media
restart: 'unless-stopped'
devices:
- "/dev/dri:/dev/dri"
# - "/dev/dri/renderD128:/dev/dri/renderD128"
# Optional - alternative address used for autodiscovery
environment:
- JELLYFIN_PublishedServerUrl=192.168.x.xxx
- TZ=Asia/Shanghai
# Optional - may be necessary for docker healthcheck to pass if running in host network mode
extra_hosts:
- 'host.docker.internal:host-gateway'
su && cd /home/pter/.config/jellyin
docker compose pull
docker compose up -d --remove-orphans
docker image prune
#!/bin/bash
docker run -itd \
-v /home/xxx/.config/iyuu/src:/iyuu \
-v /home/xxx/.config/iyuu/data:/data \
-p 8780:8780 \
--group-add 1001 \
--name IYUUPlus \
--restart=unless-stopped \
iyuucn/iyuuplus-dev:latest