多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

一键部署脚本:让旧电脑变身NAS家庭服务器

一键部署脚本:让旧电脑变身NAS家庭服务器 先说结论一台退役的旧电脑装好系统后跑一段我整理好的一键部署脚本就能变成全家都能用的NAS家庭服务器。这篇文章要聊的就是这套脚本合集里每一段脚本解决什么问题、怎么改参数、会踩哪些坑以及我拿J4105、3865U这些老平台反复折腾后留下的心得。我自己从前也是“谈NAS就头大”的那类人尤其是不想花钱买成品NAS又舍不得扔了吃灰的老笔记本结果装系统容易配Samba、配下载工具、配权限、做开机挂载这些步骤全摊开之后一个周末就没了。后来我把所有重复配置拆成脚本才发现家庭服务器的门槛大部分来自重复劳动而不是技术本身有多高。如果你也有一台旧电脑想搭共享存储、跑下载工具、备份手机相册又不想在系统配置里反复摔跟头这套方式能帮你节约大量时间。这篇文章不会教你买最贵的设备也不会让你背一肚子参数。我会先讲清楚为什么要用脚本搭NAS再把脚本里每个模块的作用和关键参数写明白最后附上可照抄的部署流程和一份实用排查清单。零基础可以直接上手有基础的也能拿去改成自己的版本。1. 我为什么把全家存储押注在“一键部署脚本”上1.1 家庭服务器的需求其实很少普通家庭里NAS真正被高频使用的功能掰着手指头数得过来手机照片自动备份、电脑和电视能直接播放下载好的影片、家人之间互传大文件、夜里挂个下载任务再往深一点是监控摄像头录像、智能家居联动这类加分项。需求简单但DIY的步骤并不简单。给旧电脑搭NAS你至少要做这些事装一个Linux系统选择文件系统划分目录安装Samba配置用户权限处理防火墙端口设置开机自动挂载硬盘再想方设法让Docker容器里的服务能稳定跑起来。每一项单独看都不复杂连起来却能吃掉一整个周末而且换一台机器、换一块硬盘这些坑大概率要重新走一遍。脚本化的核心价值就是把这些“我知道怎么配”的步骤变成“机器自己配”。1.2 脚本设计的三个原则我这套脚本从第一版到现在反复改过好几轮最终只保留了三个原则。第一个原则是幂等性。脚本可以重复执行不会因为跑了两遍就产生重复文件或冲突配置。这一点在调试时特别重要你改完参数后可以放心重跑不用提心吊胆怕把系统搞乱。第二个原则是分阶段。整个部署过程被拆成系统初始化、Docker安装、数据目录规划、容器栈部署四个相互独立的阶段。每个阶段单独执行、单独出日志哪一步出问题直接看对应阶段的日志就能定位。第三个原则是参数外部化。所有IP地址、用户名、密码、目录路径、端口号都集中放在一个config.env文件里脚本本身不硬编码任何和我家庭环境有关的信息。这样你拿到脚本后只需改这一个文件不用翻遍几十个配置文件去替换IP和密码。1.3 为什么不用成品NAS系统偏要自己写脚本群晖、绿联这类成品NAS系统真的很方便手机App和桌面客户端都给你做好了拿回来插上硬盘就能用。飞牛NAS这类国产系统近两年讨论度也很高安装教程铺天盖地。那为什么还要自己用脚本搭最直接的原因是硬件自由度。成品系统对自家硬件适配最好装到老电脑上偶尔会出现网卡认不出、休眠唤醒异常、App远程访问受限等奇怪问题。自己装Debian再跑脚本底层系统换成了通用Linux发行版硬件兼容面一下扩大很多。另一个原因是透明可控。脚本每一行都摆在那里出了问题能直接定位不用在一个封装好的黑盒里猜来猜去。对普通用户来说成品系统没问题但如果你手头正好有旧电脑又想真正了解NAS背后发生了什么脚本方案会是更合适的起点。2. 脚本合集全拆解每个模块到底帮你省掉什么2.1 系统初始化先把地基打稳第一阶段脚本做的事是系统初始化。包括更新软件包索引、升级系统、设置时区、开启SSH、安装后续会用到的常用工具比如curl、wget、nano、vim、rsync、unzip这些。很多人会觉得这一步没必要其实它是后面所有操作的基础。新装的Debian系统默认源在国外在国内下载速度往往很慢。脚本会把软件源自动切换成你所在区域更常用的镜像源然后才执行apt upgrade。更新和升级要分开跑避免升级过程中断网导致软件源状态异常。时区默认设为Asia/Shanghai这样日志时间和你的生活习惯一致排查问题的时候不用做时区换算。另外我建议在这步顺手做两件安全相关的事修改SSH默认端口并禁止root账号密码登录。NAS长期挂在家庭网络中如果把默认端口暴露到公网被扫描爆破只是时间问题。脚本只做基础加固更复杂的安全策略可以以后再补。2.2 存储挂载与目录规划给数据找一个固定座位第二阶段是存储挂载和目录规划这是整套脚本里最不能被跳过的一步。硬盘挂载如果做得随意后面所有应用都可能出奇奇怪怪的权限问题。脚本会读取config.env里的磁盘信息把数据盘格式化或直接挂载到 /data 目录然后生成一套固定的目录结构。我的习惯是分得细一点/data ├── downloads # 临时下载目录 ├── media # 电影、剧集、音乐 ├── photos # 手机相册备份 ├── backup # 各类备份产物 └── appdata # Docker容器配置和数据库目录规划好以后脚本会生成fstab条目实现开机自动挂载。这里有个关键细节fstab里必须写UUID不能写 /dev/sda 这种设备名。因为Linux在开机时检测硬盘的顺序不一定固定多块硬盘的情况下设备名可能互换出现过一次开机后挂载错盘的情况数据没坏也被吓得不轻。文件系统方面普通家用我建议直接ext4综合稳定性和恢复工具成熟度都是首选。如果你愿意折腾新特性Btrfs也可以支持CoW和快照但快照功能对新手来说容易把空间越吃越大我默认脚本走ext4想换Btrfs可以在变量文件里改。2.3 Docker安装与镜像源自动切换Docker是现代NAS生态的事实标准几乎所有开源家庭服务都提供Docker镜像容器隔离让服务之间互不干扰升级或卸载也干净。脚本第二件事就是安装Docker。系统是纯净Debian时安装Docker继续用官方脚本并不总是一帆风顺因为有些依赖源响应很慢。我的脚本会先换源再安装 docker-ce、docker compose插件同时顺手把当前用户加入docker用户组省去每次敲sudo的麻烦。然后是一个经常困扰群晖和自建NAS用户的环节容器镜像拉不下来。群晖的Container Manager有时在镜像下载阶段卡住自建Docker也有同样问题。这不是Docker本身坏了而是公共镜像仓库在特定网络环境下访问不稳定。脚本的做法是把Docker的registry mirror写入 /etc/docker/daemon.json并配置多个国内可达的公共镜像源。脚本在拉取镜像失败时还会自动重试并切换到下一个可用源。建议不要把镜像源写死到一个公共镜像源偶尔会调整多备几个能明显减少“明明照着教程做的镜像却拉不下来”的情况。daemon.json大致长这样{ registry-mirrors: [ https://mirror.example1.com, https://mirror.example2.com, https://mirror.example3.com ] }改完配置记得重启Docker服务才能生效脚本里已经做了这一步。2.4 用户权限与PUID/PGID容器不听话的根源权限问题大概是NAS自建过程中最容易让人抓狂的。Docker容器默认可以用root运行但如果所有容器都以root写文件宿主机的数据目录就会变成一堆root用户拥有却无法用普通账号管理的文件。脚本会创建名为nas的普通用户UID和GID默认为1000并把 /data 目录交由这个用户管理。然后每个容器模板里都设置了PUID和PGID这两个环境变量让容器内的进程以宿主机的nas用户身份运行。PUID1000 PGID1000原理其实不难理解容器里的进程虽然有独立的文件系统视角但写入宿主机目录时仍以内核看到的UID/GID为准。只要容器内的UID和宿主机上的UID一致两边就能认作同一个用户文件权限自然就理顺了。这个参数是几乎所有容器部署的通用约定哪怕你以后不用我的脚本自己写docker-compose时也建议遵守。2.5 容器模板用Compose统一管理服务第四阶段是容器栈部署脚本不直接docker run而是统一使用docker compose管理。每个服务单独一个yaml文件但最终都在同一个项目目录下方便整体启停和查看日志。典型的服务组成如下services: qbittorrent: image: lscr.io/linuxserver/qbittorrent:latest container_name: qbittorrent environment: - PUID1000 - PGID1000 - TZAsia/Shanghai volumes: - /data/appdata/qbittorrent:/config - /data/downloads:/downloads ports: - 8080:8080 - 6881:6881 - 6881:6881/udp restart: unless-stopped jellyfin: image: lscr.io/linuxserver/jellyfin:latest container_name: jellyfin environment: - PUID1000 - PGID1000 volumes: - /data/appdata/jellyfin:/config - /data/media:/media ports: - 8096:8096 restart: unless-stopped这里有两个容易忽略的设计所有容器都放了PUID/PGID所有持久化数据都放在 /data/appdata 下的独立子目录并且容器都设置了 restart: unless-stopped。意味着只要服务没被手动停止开机后就会自动拉起故障重启也不会让服务长期离线。后面加新服务时照着这个模板复制一份再改端口和卷即可。3. 手把手实操从小白到跑起家庭服务器的完整流程3.1 硬件准备与老平台选型一台旧电脑、一块硬盘、一个普通路由器差不多就是最低配置。实际部署中我更推荐用迷你主机或淘汰的笔记本因为相比老式ATX机箱这两类设备功耗更低、噪音更小放在客厅或弱电箱里不占地方。CPU方面很多人在J4105和3865U之间纠结。J4105是四核四线程TDP 10W支持4K硬解3865U是双核四线程TDP 6W省电但核显解码能力弱。如果你打算用Jellyfin做视频转码J4105明显更合适如果只是纯存储加下载工具3865U足够而且更安静。下面是实际使用中的对比对比项J41053865U核心线程4核4线程2核4线程默认TDP10W6W4K硬解支持基本不指望Jellyfin软转码可应付1080P吃力适合场景影音存储轻服务纯存储下载内存建议至少8GBDocker多开服务后4GB会经常看到内存告警。硬盘可以用机械盘如果预算允许加一块固态做系统盘Docker镜像和容器配置放在SSD上机械盘专门装数据性能感受会好很多。3.2 安装Debian后下载脚本系统建议装Debian 12的minimal版。安装过程中不需要选任何额外的桌面环境和软件包越纯净越好因为所有东西都由脚本接管。系统装好后用SSH登录把脚本合集拉到机器上。国内网络访问GitHub不稳定的话我一般都同步在Gitee代码仓库里有两个分支实际使用直接用Gitee地址就行。git clone https://gitee.com/example/nas-deploy-scripts.git cd nas-deploy-scripts cp config.env.example config.env打开config.env后你会看到这样一个结构# 基础设置 NAS_USERnas NAS_UID1000 NAS_GID1000 TIMEZONEAsia/Shanghai # 数据目录 DATA_DIR/data # 需要挂载的存储设备UUID多个用空格隔开 DISK_UUIDS # 各服务端口 QBITTORRENT_PORT8080 JELLYFIN_PORT8096 SAMBA_SHARE/data/media密码等敏感信息只写在这个文件里脚本会在本地引用不会打印到日志更不要把这个文件传到公开仓库。这一步值得多花五分钟逐项确认尤其磁盘UUID用blkid命令查好再填不要填错。3.3 核心脚本逐行解析以第二阶段脚本为例它其实就是一个严格按照顺序执行的bash脚本。关键部分类似这样#!/usr/bin/env bash set -euo pipefail # 加载变量 if [ -f config.env ]; then set -a source config.env set a fi # 创建数据目录 sudo mkdir -p ${DATA_DIR}/{downloads,media,photos,backup,appdata} # 将硬盘写入fstab for uuid in ${DISK_UUIDS}; do echo UUID${uuid} ${DATA_DIR} ext4 defaults,nofail 0 2 | sudo tee -a /etc/fstab done # 挂载全部 sudo mount -a # 修正权限 sudo chown -R ${NAS_USER}:${NAS_USER} ${DATA_DIR} sudo chmod 0755 ${DATA_DIR}set -euo pipefail 的作用是脚本任何一行出错就立刻停止变量没有定义就报错管道命令只要有一个环节失败整体算失败。这样不会出现脚本跑了半天、最后发现前面早已出错的情况。nofail选项很关键开机时即使某块硬盘没接上系统也不会卡在挂载步骤进不了系统。每执行完一个阶段脚本可以看一下输出的日志确认没有红色报错再进入下一阶段。第一次跑的时候建议用普通用户执行需要sudo的地方脚本会提示输入密码不要干脆用root跑完所有流程后面权限容易混乱。3.4 启动容器与首次访问容器部署脚本执行完后会自动运行docker compose up -d把模板里定义的所有服务拉起来。首次启动会拉取镜像时间取决于网络和机器性能耐心等就好。配置了镜像源的情况下大部分镜像几分钟内都能拉完。启动完成后你会得到一堆访问入口qBittorrent 管理界面: http://NAS_IP:8080 Jellyfin 媒体服务: http://NAS_IP:8096 Samba 网络共享: \\NAS_IP\media Immich 相册备份: http://NAS_IP:2283默认账号和初始化密码都写在config.env里首次登录时按容器提示修改即可。如果看到服务没有起来可以先执行docker compose logs查看容器日志这个命令比到处翻系统日志直观得多。4. 常见问题与排查技巧实录4.1 镜像拉不下来或超时这是自建NAS遇到频率最高的问题。表现是docker compose up时卡在Pulling或者在群晖Container Manager里镜像一直转圈。除了网络因素镜像源不稳定也是常见原因。我的排查顺序是先手动执行 docker pull 其中一个镜像看报错内容再确认daemon.json里的registry-mirrors是否生效最后重启Docker服务不要只重试不重启。脚本里已经内置了镜像源切换机制但还是建议你在部署方案里把常用镜像尽量用国内可达的源。另外有些老教程会让你写单个源遇到它失效整个环境就瘫痪了多源配置能明显降低这种风险。4.2 磁盘空间明明很大却提示写入失败新装系统有时会出现根分区只有几十GB数据盘却有好几TB的情况。Docker默认把镜像和容器数据放在 /var/lib/docker如果这个目录在根分区里下载几个镜像后根分区就满了而你的大硬盘还空着。遇到这个情况要么把Docker数据目录迁移到数据盘要么在挂载时直接把 /var/lib/docker 作为一个独立数据盘挂载点。脚本里我默认把 /data/appdata 和Docker数据目录都放在数据盘上避免系统盘被塞满。排查空间时用 df -h 一条命令先看哪个分区逼近100%再顺着目录用 du -sh * 找大文件。4.3 Windows网络共享连不上或拷贝文件掉速Samba配置看起来简单实际表现却经常让人意外。最常见的包括从Windows资源管理器输入 \IP 后提示无法访问、能看到共享文件夹但拷贝大文件速度只有几MB/s、过一会儿连接就断开。优先检查SMB协议版本。老的SMB1协议在默认配置里早就被禁了而网上的老教程还在让你改注册表开启SMB1完全不建议。Linuxserver的Samba镜像默认支持SMB2/3够用。其次是防火墙Debian自带的ufw或者路由器的防火墙如果拦了445端口Windows会提示很模糊的“无法访问”错误。速度慢时先确认是否连了WiFi2.4GHz频段跑满可能也就50Mbps换网线或5GHz频段会立即改善。再就是看机械盘是不是在同时做其他读写这不是Samba的问题而是硬盘性能到达瓶颈。4.4 容器内文件权限变成nobody或者无法删除这是新手最容易踩的坑。比如容器创建后外面看媒体文件的所有者变成了nobody或者想通过宿主机删除一个文件却提示没有权限。根本原因就是容器的UID和宿主机用户UID不一致。解决方案也很直接确定你希望哪个系统用户拥有数据就把所有相关容器的PUID和PGID设成这个用户的UID/GID。已经写坏权限的目录先在宿主机执行chown再重新创建容器。我不建议为了省事直接 chmod -R 777那会让所有服务都能读写你的数据一旦有一个容器被渗透或误操作整个资料库都暴露风险。正确做法是用chown把属主锁定到NAS账户然后给其他用户只读或不可访问权限。4.5 老电脑CPU占用高风扇半夜呼呼响旧处理器性能有限开了一堆容器后CPU长期50%以上很常见。但风扇吵不一定真是负载问题也可能是系统默认策略让风扇在高转速下不下来或者某个容器在后台做周期性扫描。先通过 docker stats 看每个容器的CPU和内存占用找到吃资源最狠的那一个。qBittorrent做种功能如果在跑大量任务CPU占用会直线上升Jellyfin如果没有硬解播放4K视频时会用CPU软解占用率瞬间飙满。脚本模板里会为每个容器设置内存限制例如deploy: resources: limits: memory: 1G这样单个容器最多占用1GB内存不会把整个NAS拖垮。如果你用的是3865U这类弱U还需要降低预期不要在同一台机器上同时跑转码、虚拟机和高负载下载。4.6 备份与还原容易踩的坑我在这上面吃过亏。最开始写的备份脚本只打包了容器配置目录结果系统需要重装时发现自己忘备份fstab和网络配置整个恢复流程变成了手工重配大战。正确的备份应该包含几部分数据目录、容器配置目录、数据库备份、系统关键配置文件。我的backup脚本会把 /etc/fstab、/etc/docker/daemon.json、config.env 一起打包再加一份容器列表清单。还原时先恢复系统配置文件再按脚本重新安装Docker最后拉取容器配置整体流程十五分钟就能完成。真正让我安心的是在备份后做恢复演练。备份文件能正常生成不代表能成功还原至少测试一次restore脚本把备份内容恢复到另一台机器或另一块硬盘上。这里面的常见错误是备份时没有排除缓存和日志文件tar包越来越大还原后Docker容器启动失败。备份脚本里我把每个容器的临时目录、cache、log都做了exclude具体排除规则可以参考tar的--exclude参数。5. 把脚本往外再延伸更聪明的家庭服务器5.1 成品NAS系统和脚本方案怎么选很多人在一开始都会纠结到底买群晖/绿联还是自己搭。这里我给一个不含偏见的对比对比项成品NAS系统脚本自建NAS上手难度低开箱即用中需要一次部署硬件兼容限定自家设备几乎兼容所有x86主机应用生态应用中心数量一般Docker生态丰富很多App体验官方App成熟依赖容器自带WebUI硬件成本较高旧电脑零成本可复用可定制性偏低完全透明飞牛NAS这类国产系统也很适合大众用户安装教程很详尽用起来比自建简单不少。但脚本方案最大的吸引力在于透明和复用配置好了就是这么一套流程以后换机器跑一遍脚本就能迁过去。两者没有高下只看你的目标是什么。如果希望全家人都能轻松用App操作成品系统更省心如果为了把旧物利用起来并完全掌控自己的数据脚本方案会越用越顺手。5.2 J4105 和 3865U 到底怎么选补充一点实操中的感受。J4105虽然TDP比3865U高4W但实际满载和待机功耗差距并没有参数上那么大多出来的性能换来的是Jellyfin硬解、家人在线看片、偶尔跑点同步任务的时候不会卡。3865U优势在绝对安静和低功耗适合长期只挂一块硬盘、跑Samba和下载工具的老旧设备。如果这块NAS还要做照片AI识别、视频转码这类重活3865U会明显力不从心。反过来如果只是做个“网络硬盘”连相册识别都不打算用3865U完全够。预算允许的话我更推荐关注J4125或N100这类更新平台它们功耗和性能更均衡但本文原则是不增加额外开销所以旧设备有什么就用什么。5.3 家庭NAS上值得跑的Docker应用清单分享一份我实际在用的应用清单这些都是社区活跃度很高、维护稳定的项目Jellyfin / Emby家庭影院中心统一刮削封面支持多端播放。qBittorrent / aria2下载工具网页管理挂到 /downloads 目录。Immich / PhotoPrism手机相册自动备份带人脸识别和相册分类。Home Assistant智能家居中枢把所有智能设备统一接入。Netdata / Zabbix AgentNAS运行状态监控能看CPU、内存、磁盘、网络。rclone定时同步到对象存储或远端目录做异地备份。Calibre-Web / Komga电子书和漫画管理家庭阅读库。这里有一个经验不要把一堆服务全塞在一个NAS上尤其老电脑性能有限。先跑存储、下载、媒体三个核心服务稳定运行一个月后再加Home Assistant或监控。每加一个新容器都要确认它不会和已有服务抢占端口不会因为共享同一个目录造成权限冲突。compose模板里端口冲突会直接报错看到Address already in use时在config.env里把端口换掉重跑即可。5.4 NAS下的IPTV设置与智能音箱联动最后聊两个有意思的扩展。一个是NAS下IPTV设置。运营商的IPTV信号在家庭内网中通常以组播方式传输普通WiFi设备直接播放组播流往往卡顿或无法播放。常见做法是在NAS上跑一个udpxy容器把组播流转换成HTTP单播流。比如IPTV源地址是 udp://239.x.x.x:5140udpxy会把它转成 http://NAS_IP:4022/udp/239.x.x.x:5140 这样的链接手机播放器、电视和电脑都能直接播放家里所有设备看直播就都顺了。脚本里可以单独加一个udpxy容器端口按需设置。另一个是飞牛NAS或自建NAS与小爱音箱、豆包的集成。实现路径一般是通过Home Assistant把NAS的磁盘状态、下载完成通知、备份结果通过小爱音箱播报或者通过豆包这类大模型接口让语音助手能回答家庭数据相关的简单问题。核心逻辑是让NAS在本地作为家庭自动化中枢通过API把消息推给音箱再通过云端的意图识别返回结果。API Key要保存在本地配置文件里不要进入git仓库或公开博客。这个玩法对NAS性能要求不高3865U也能带得动适合作为搭好NAS之后的进阶项目。这套脚本我前后迭代了很长时间刚开始也踩过不少坑第一次重装系统前没备份fstab结果所有容器配置全部清零一夜回到解放前。后来学乖了备份脚本里连系统关键配置一起打包之后再也没有慌过。如果你第一次搭NAS我的建议很朴素先跑通存储和共享稳定后再慢慢加应用。脚本能帮你省掉重复配置的时间但真正值得花心思的永远是数据目录怎么规划、备份怎么做那才是家庭服务器能不能长久用下去的关键。最后分享一个经常被忽略的小技巧每次执行脚本前把当前系统里的服务状态和磁盘分区信息导一份留存。以后排查“上次明明是好的”这种问题时至少有一份对照依据。希望这份记录能让你少走几段弯路也欢迎你把自己的经验沉淀到社区的讨论帖里让更多后来者少栽跟头。
返回列表