1. 部署前的真实需求与方案选择1.1 为什么需要在NAS上做图片压缩家里NAS跑了大半年我最直观的感受是真正占空间的往往不是4K电影反而是相机导出的原图、手机备份的照片截图、还有群聊里存下来的各种大图。一张iPhone拍的RAW或HEIC原图动不动就5到10MB家里三台手机一开自动备份一个月的增量就轻松破几十GB。存了舍不得删不处理的话硬盘迟早被图片塞满。后来我意识到我需要的不是再买一块硬盘而是一个能自动处理图片的入口把图片按设定规则压缩、转换格式再归档到对应目录。找了一圈开源方案最后选定了mazanoke这套工具。它本身是主打图片压缩和格式转换的轻量服务可以用Docker跑在NAS上自带Web界面和API能够对JPEG、PNG、WebP、AVIF这些常见格式做统一处理。部署在绿联NAS上之后等于给家里的照片流加了一个自定义的“中转站”手机备份的原图先进来处理完再落盘容量压力一下子小了很多。这套方案适合动手能力中等偏上的NAS玩家会打开Docker面板、懂一点点路径映射概念就行。如果你只是想要一个网页版压缩器那在线网站随便用但如果你的诉求是批量处理、格式统一、API调用那就值得在NAS里跑一个常驻服务。我下面写的部署过程全部基于绿联的UGOS Pro系统群晖和白群晖用户也可以参考思路基本一致只是面板操作略有区别。1.2 同类工具对比与选择mazanoke的理由在选型阶段我其实对比过几套常见的方案工具部署方式功能侧重适合场景TinyPNG/GIF无损压缩在线服务/API压缩率高但免费额度有限少量临时处理SquooshWeb端/命令行Google出品支持多种格式单张图片快速调整PicFitDocker图片缩略图生成侧重裁剪图床/CDN分发mazanokeDocker压缩转换一体化带Web/APINAS批处理、自动化归档选择mazanoke有几个关键原因。第一它把压缩和格式转换放在同一个服务里不需要再组合两三个工具部署和维护成本低。第二它提供API接口配合脚本可以做到目录自动监听这和NAS的“无人值守”定位很契合。第三镜像体积不大CPU和内存占用比较克制跑在绿联的N100或N5105这种平台上绰绰有余。当然也有不足的地方比如文档不算丰富部分细节要靠试错但正因为如此我才想把踩过的坑写出来方便后面的人少走弯路。2. 绿联NAS环境准备与镜像获取2.1 绿联UGOS Pro下Docker环境的前置检查绿联NAS现在的系统版本是UGOS Pro自带Docker应用不需要像早期版本那样通过第三方包安装。打开“应用中心”确认Docker已经安装并启动即可。首次使用Docker面板之前建议先做三件基础检查存储空间确认mazanoke本体占用的磁盘空间很小但日志、缓存和临时文件会持续增长建议预留至少5GB可用空间。如果后续处理大量高分辨率图片缓存目录可能膨胀得很快。端口占用排查默认服务会监听某个Web端口如果你NAS上已经跑了其他服务注意避开冲突。绿联自带的应用商店会占用一部分端口比如8000、8080这些常见端口经常被其他容器占用最好提前确认。目录结构规划一个清晰、可预期的目录结构能省掉后续很多麻烦。我的习惯是在/volume1/docker/mazanoke下建立三个子目录input、output、config。input放待处理的原始图片output放处理完成的结果config用来保存服务自身的配置。提示绿联的文件管理器里能直接看到/volume1这样的卷路径但Docker容器内看到的挂载路径完全可以自己定义。映射时建议用绝对路径别用相对路径避免容器重启后找不到目录。2.2 镜像获取的两种路径与网络加速方式获取镜像通常有两种方式。第一种是直接在绿联Docker面板的“镜像”页面搜索mazanoke选择对应镜像后点击下载。这种方式最直观适合大多数用户。第二种是SSH登录NAS通过命令行拉取。如果你已经开好了SSH权限执行一条简单的docker pull命令就能完成这种方式在网络异常时更容易排查问题。这里有一个实际遇到的情况因为网络环境的问题直接从镜像仓库拉取时速度可能不理想。建议在Docker面板的“镜像加速器”里配置国内可用的加速地址。绿联UGOS Pro的Docker设置里已经内置了几个可选的加速源也可以手动填写镜像加速器地址。配置完成后重启Docker服务再重新拉取镜像速度会明显提升。如果换了加速源之后还是拉不下来不要反复重试先检查一下DNS解析是否正常或者考虑用SSH代理的方式拉取。另外注意在绿联面板上拉取镜像时保持当前账号对Docker目录有读写权限否则会出现“拉取成功但无法启动容器”的怪问题。2.3 镜像版本选择与标签说明mazanoke在镜像仓库里会存在不同的标签比如latest、stable或者带具体版本号的标签。日常使用建议选择stable而不是latest因为latest指向的可能是最新的开发构建虽然功能更新但稳定性不一定有保障。如果确定要长期跑在NAS上锁定一个已知稳定的版本后续再手动升级比被动追latest更省心。确定版本后可以顺手把镜像打上自定义标签比如mazanoke:stable-202408这样回滚时可以直接指向旧版本不用重新拉取。3. 通过Docker容器部署mazanoke的完整步骤3.1 创建目录结构与权限设置我强烈建议在真正创建容器之前先在NAS的文件管理器里把目录建好。这样做的原因有两个一是可以在创建容器时直接挂载已有目录避免容器因为目录不存在而启动失败二是方便未来备份和迁移。我使用的目录结构如下/volume1/docker/mazanoke ├── config ├── data │ ├── input │ └── output └── logs创建完成后在绿联文件管理器里右键点击mazanoke文件夹选择“属性”把所属用户和用户组调整为Docker运行所需的账号。如果这一步不做容器在挂载目录时会因为没有写权限而无法处理图片最终表现为“everything fine但你上传的图片全部处理失败”。3.2 使用绿联Docker面板创建容器的全过程打开绿联的Docker应用进入“容器”页面点击“创建”按钮。这里我们一步步来镜像选择在镜像列表里找到之前拉取好的mazanoke点击“下一步”。容器名称可以随意取一个容易识别的名字比如mazanoke。端口映射这是最关键的一步。如果容器内的默认服务端口是8080那么宿主机端口可以映射为8855这样以后访问地址就是http://NAS的IP:8855。把宿主机端口设置成不常用的端口能减少与NAS其他服务的冲突概率也更安全。存储空间映射把前面建好的input目录挂载到容器内的/data/input把output目录挂载到/data/output。挂载方式的示例如下- /volume1/docker/mazanoke/data/input:/data/input - /volume1/docker/mazanoke/data/output:/data/output - /volume1/docker/mazanoke/config:/data/config环境变量配置根据mazanoke的默认约定需要设置一些基本环境变量比如时区TZAsia/Shanghai、允许访问的API_TOKEN建议设置一个强密码避免局域网内的其他设备乱调用接口。如果不确定具体变量名可以先不设置启动后通过Web界面调整但TZ建议还是配上否则日志时间会错乱。资源限制绿联的Docker面板里可以设置CPU和内存限制。对于图片处理服务建议给2核和2GB内存这样既能保证处理速度又不会因为内存被占满而拖垮NAS上的其他服务。完成以上步骤后点击“创建”即可。容器启动正常的话在容器列表里能看到状态为“运行中”。3.3 通过docker-compose方式部署的备选方案如果你更习惯用命令行或者想把整个部署过程用配置文件沉淀下来可以走docker-compose的路线。在绿联NAS上开启SSH后创建docker-compose.yml文件写入以下内容version: 3.8 services: mazanoke: image: mazanoke:stable container_name: mazanoke restart: unless-stopped ports: - 8855:8080 environment: - TZAsia/Shanghai - PUID1000 - PGID1000 - API_TOKENyour_strong_token_here volumes: - /volume1/docker/mazanoke/data/input:/data/input - /volume1/docker/mazanoke/data/output:/data/output - /volume1/docker/mazanoke/config:/data/config logging: driver: json-file options: max-size: 10m max-file: 3然后在docker-compose.yml所在目录执行docker-compose up -d这里解释几个配置项restart: unless-stopped保证NAS重启后容器自动拉起不用手动干预。PUID/PGID让容器内进程以指定宿主用户身份运行避免文件权限混乱。具体值可以在SSH里通过id命令查看。logging限制因为图片处理会产生大量日志如果不加日志大小限制时间久了/var/lib/docker/containers会被日志文件塞满。两种部署方式的效果是一样的选择哪种主要看个人习惯。4. 功能配置与图片处理的实操体验4.1 首次访问与Web界面功能概览容器启动后在浏览器输入http://绿联NAS的IP:8855就能看到mazanoke的Web界面。界面做得比较简洁主要分为三个区域上传区域、处理参数设置、输出预览。首次体验我建议先拿几张有代表性的图片试用一张手机拍摄的JPG照片约4~8MB一张带透明通道的PNG截图一张高分辨率的长图这三种类型能覆盖大多数使用场景。把图片拖到上传区后会让你选择目标格式和压缩质量。mazanoke支持的格式转换链路中最实用的是把RAW/HEIC转成JPG或WebP把PNG压成WebP以及在JPG和PNG之间做互转。质量参数方面85%的压缩质量是人眼看不出损伤的下限。对网页展示场景70%~80%就足够了对需要印刷或留档的图片建议至少保持90%。4.2 API接口与NAS无人值守自动化真正让mazanoke发挥价值的是它的API接口。日常使用中我很少打开Web界面上传图片更多是让群晖的Synology Photos、绿联的相册备份或者qBittorrent下载完的目录通过脚本自动把图片丢到input目录然后定时调用API处理。一个最简单的命令行调用方式curl -X POST http://localhost:8855/convert \ -H Authorization: Bearer your_strong_token_here \ -F file/volume1/docker/mazanoke/data/input/test.jpg \ -F formatwebp \ -F quality80 \ -o /volume1/docker/mazanoke/data/output/test.webp如果你有多个文件可以写一个简单的循环脚本。比如批量把目录下所有.png转换为.webpfor file in /volume1/docker/mazanoke/data/input/*.png; do filename$(basename $file .png) curl -s -X POST http://localhost:8855/convert \ -H Authorization: Bearer your_strong_token_here \ -F file$file \ -F formatwebp \ -F quality80 \ -o /volume1/docker/mazanoke/data/output/$filename.webp done这一段脚本写得很简单但对于日常批量处理足够用了。如果你家里有群晖、绿联或其他品牌的NAS直接在系统自带的任务计划程序里设置每天凌晨2点运行处理完的结果自动归档到指定共享文件夹基本就能做到“无人值守”。4.3 处理效果的实测数据对比为了让大家有个直观的感觉我把自己实际处理过的几组数据整理成了表格原图信息原始大小处理后大小处理方式压缩率iPhone 15 Pro拍摄的JPG (4032×3024)6.8MB1.1MBJPG→WebP, quality 8083.8%相机RAW转出的TIFF (6000×4000)24MB2.4MBTIFF→JPG, quality 9090%设计源文件PNG截图 (1920×1080)3.5MB380KBPNG→WebP, quality 8589.1%扫描件 (黑白文档, 300DPI)2.2MB640KBJPG→JPG, quality 7570.9%从结果看图片体积平均能压缩70%以上肉眼几乎看不出质量差异。WebP格式对照片和网页图片的优化效果非常明显如果你的相册App、图床程序支持WebP建议优先转成WebP。4.4 定时任务与目录监听的联动设置如果你用的是绿联UGOS Pro系统自带的任务计划可以设置定时执行Shell脚本。在“控制面板”中找到“任务计划”新建一个用户自定义脚本内容就是上面那个批量转换循环再设置执行时间为每天凌晨2点。这样NAS在夜间自动把input目录里的新图片处理完早上打开output目录就能拿到压缩好的结果。如果你想要更实时的效果可以配合inotifywait监控目录变化一旦有新文件进入就触发处理。但这个方案对NAS的小内存平台来说负担略重我实测下来更推荐定时任务简单、可靠也不会因为频繁监听而消耗资源。5. 部署和运行中的常见问题与排查技巧5.1 容器启动失败与端口冲突我在首次部署时遇到过容器启动后立即退出的情况。排查步骤如下查看日志在绿联Docker面板的容器详情页点“日志”看有没有报错。最常见的错误是端口被占用提示bind: address already in use。换端口如果8855被占用改成8856或者其他端口。检查环境变量某些服务如果缺少必要环境变量会直接退出对照官方文档确认必填项是否已设置。如果日志提示Permission denied那基本就是目录权限问题。回到文件管理器把挂载目录的权限设置好再重启容器。5.2 图片处理时报错“无法读取源文件”这个问题的典型原因是容器内用户没有宿主机目录的读取权限。在docker-compose方案中通过设置PUID和PGID为当前登录用户即可解决。先查看当前用户的UID和GIDid假设输出是uid1024(admin) gid100(users)那么在docker-compose.yml里写入environment: - PUID1024 - PGID100重新创建容器即可。5.3 输出目录不生成文件或生成空白文件这种情况通常不是权限问题而是路径映射写错了。确认挂载时/volume1/docker/mazanoke/data/output对应容器内的/data/output且脚本输出的文件名后缀与转换格式一致。如果formatwebp但输出文件命名为.jpg某些浏览器打开时会显示空白。5.4 容器长时间运行后NAS响应变慢mazanoke本身不占资源但如果你让日志无限制增长磁盘I/O会被拖累。建议开启日志轮转logging: driver: json-file options: max-size: 10m max-file: 3通过docker stats mazanoke查看实时资源占用正常空闲时内存占用应该在100MB以内。如果内存不断增长大概率是处理大图时产生了内存泄漏重启容器即可这也是我不推荐latest镜像的原因之一。5.5 外网访问的端口与安全性权衡如果需要在外面随时访问NAS上的mazanoke服务不建议直接把8855端口暴露到公网。更稳妥的方案是走反向代理或者在路由器层面对访问IP做白名单限制。因为这类图片处理服务如果被陌生人调用轻则消耗NAS资源重则可能被利用做图片代理缓存。我只是在家里局域网内使用所以没有做公网暴露但如果你有远程处理需求务必在反向代理层加上简单的Basic Auth或IP限制。6. 部署过程中关于路径、权限与数据备份的提醒6.1 路径规划统一管理方便迁移很多NAS用户习惯把所有容器目录散放在共享文件夹各处一开始很爽后来找配置和备份时就很痛苦。我的习惯是把所有容器相关目录集中在/volume1/docker下每个容器一个独立子目录。这样做的好处是以后换NAS或需要迁移时只需要打包这个目录再配合容器编排文件几个命令就能完整恢复服务。mazanoke本身不会存任何持久化数据处理过程中的临时文件都在容器可写层里所以备份时只需要关注config目录里的配置文件以及input/output目录里你自己的原始图片和处理后图片。凡是自己生成的数据一定要纳入定期备份计划。6.2 SHELL脚本里的路径坑容器路径与宿主路径的区别写定时任务脚本时需要注意脚本运行的位置是宿主机不是容器。因此在脚本里访问/data/input是行不通的必须写宿主机的绝对路径例如/volume1/docker/mazanoke/data/input。如果你希望脚本在容器内运行也有办法通过docker exec进入容器执行命令docker exec -it mazanoke sh -c ls /data/input不过日常建议只在宿主机层用curl调用API不在容器内做文件操作这样逻辑更清晰排查问题也更方便。6.3 权限设置最终自查清单最后给大家一个权限自查清单部署完成后逐项确认input和output目录所属用户与Docker容器的PUID/PGID一致。宿主机映射目录的权限至少为755目录可读可执行文件可读。如果通过Web界面上传处理后的文件下载失败检查浏览器是否拦截了“多文件下载”而不是怀疑服务有问题。开启NAS防火墙时确认8855端口在局域网规则中放行。7. 我的一点实操感受这套部署方案我实际跑了大概一个多月稳定性相当能打。图片压缩效果肉眼不可感知但容量节省非常明显。现在手机照片备份到NAS后第二天的定时任务会统一把新照片转换成WebP并归档到“已压缩”目录原始文件保留90天再自动清理这套流程让我彻底告别了“硬盘又满了”的焦虑。如果你也想在绿联NAS上部署类似的服务先跑通Web界面再慢慢加脚本自动化遇到问题多看看容器日志大部分坑都能自己解决。mazanoke虽然知名度不算高但只要是自部署图片处理它确实是个省心的选择。希望这篇文章能帮你少走弯路把NAS这台“家庭服务器”压榨得更彻底一点。