前言

自打小神兽落地以后,个人数据存储需求是越发的强烈,故打算整合一下现有资源,打造一个家庭服务器,以下是我的几个痛点:

  1. 找图片麻烦:日积月累的数据太多,需要查找的时候非常麻烦,手机存储的照片视频成千上万,找一张照片如同大海捞针

  2. 存储焦虑:无论换再多手机,容量始终是有上限的,即便是换了更大容量的手机,数据始终是要迁移的,现在一台手机容量上限也就1T

  3. 数据安全:各个网盘厂家都是冲着马内去的,且数据在他们手上,被拿过去了,谁知道会用于什么途径,去做什么事情

  4. 性能下降:手机存储<25%卡顿会非常严重

  5. PC功耗太高:设想过使用x86架构的设备搭建NAS服务,但考虑到作为家庭服务器需要常年开机,再一寻思功耗及散热问题的便放弃了,但是不得不说x86架构的设备生态是很友好的,黑群晖、飞牛os等,在我了解这些产品的时候,飞牛已经有了超越黑群晖的趋势

总的来说,我对家庭服务器的需求如下:

  • 低功耗

  • 大容量,支持扩容

  • 支持AI搜索

  • 支持硬编解码

  • 多线程,大内存(需要部署多个服务)

硬件选择:

  • SOC:这里选择的是ARM架构的RK3588,8核心(1.8Ghz-2.4Ghz)、6TOPS算力、8K硬编解码

  • 内存(RAM):32G

  • eMMC(板载ROM):256G

  • 外置存储(外置ROM):拼夕夕14T硬盘

  • 散热:板载被动散热

软件选择:

  • immich:自动备份照片和视频到自建服务器。支持多客户端上传,提供便捷的Web界面管理媒体文件。

  • nginx:高性能HTTP服务器与反向代理,擅长处理高并发请求,低资源消耗,并支持SSL/TLS加密。

  • ddns-go:简单易用的动态域名解析工具,自动更新域名指向最新的公网IP地址,无需复杂配置。

  • portainer:轻量级Docker管理UI,轻松管理容器、镜像和网络,支持Swarm集群管理,提升运维效率。

  • certd:自动化获取和更新SSL/TLS证书,确保网站和服务的安全通信,简化HTTPS部署流程。

  • halo:现代化的个人出版平台,专为博客设计,支持Markdown写作,拥有丰富的主题和插件,易于搭建个人网站。

相比起x86架构生态的完善方便快捷,这里选择的路线更为折腾和定制化,下面开始搞起。

e4e059c1d566b8b5ba313f2fe17fd47.jpg

image-3dcx.png

系统安装

镜像选择

如果没有特殊的需求,就选择官方的镜像下载就好了。

比如说immich如果想要开启硬件加速机器学习,就需要rknpu打到v0.9.8的版本及以上Hardware-Accelerated Machine Learning | Immich,但是香橙派最新的官方镜像支持到的rknpu的版本只到0.9.6,而上面提供的镜像,RKNPU driver的版本为:v0.9.8,虽然只差了两个小版本,但是二者的差别还是挺大的。

rknpu driver 0.9.8 相对于 0.9.6 主要有以下一些区别:

  • 更好的芯片适配性3:0.9.8 版本主要是为了更好地适配 rk3588 和 rk3576 芯片对大模型端的支持。在 0.9.8 版本的内核代码中存在一段对 rk3576 的一个类型的引用,不过在驱动源码中一开始未定义,需要将其注释掉或修改为提示的MONITOR_TPYE_DEV(作者内核版本是 5.10),以解决编译报错问题,而 0.9.6 版本可能在这些芯片的大模型支持方面存在不足。

  • 功能完善与优化:通常情况下,驱动程序的版本升级会对一些功能进行完善和优化,可能包括提高 NPU 的性能、稳定性,或者修复了 0.9.6 版本中存在的一些漏洞和问题,使 NPU 在处理神经网络推理计算等任务时更加高效和可靠。例如,可能优化了数据传输、处理的流程,减少了延迟或提高了运算速度,但具体的优化细节可能因芯片厂商的更新日志和实际测试情况而异。

下载到所需的镜像后,下面就开始正式进行系统的安装,这里使用的是内存卡进行安装镜像系统,你需要准备以下东西:

安装过程

执行过程:

  1. 使用SD Card Formatter将内存卡快速格式化

  2. 使用usbimager将下载好的镜像文件烧录到格式化的内存卡中,注意:只支持.xz或img后缀的镜像,若你的下载的镜像是上面提供的高rknpu driver的版本,那么你得到的可能是个.gz的压缩文件,你需要解压并得到.img的文件,以便于镜像的安装

  3. 安装完成后,将内存卡插入开发板,稍等片刻,便会出现登录窗口

  4. 配置系统

香橙派默认账号密码:

  • root:orangepi

  • orangepi:orangepi

armbian默认账号密码:

  • root:1234

若希望将系统安装到emmc中,请参考这里:

香橙派:用户手册_免费高速下载|百度网盘-分享无限制

Armbian:入门 - Armbian Documentation

期间,可能需要apt updateapt upgrade,可以替换为国内的镜像源,这里使用清华大学的镜像源,注意选择自己系统对应的镜像源,当前系统是armbian:armbian | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror

环境配置

系统信息

root@orangepi5plus:/# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 24.04.2 LTS
Release:        24.04
Codename:       noble
root@orangepi5plus:/# uname -r
6.1.43-rockchip-rk3588
root@orangepi5plus:/# lscpu
Architecture:           aarch64
  CPU op-mode(s):       32-bit, 64-bit
  Byte Order:           Little Endian
root@orangepi5plus:/# docker --version
Docker version 28.0.4, build b8034c0
root@orangepi5plus:/# docker compose version
Docker Compose version v2.34.0
root@orangepi5plus:/# cat /sys/kernel/debug/rknpu/version
RKNPU driver: v0.9.6

更改镜像源

这里选择Ubuntu Ports镜像,Ubuntu Ports是Arm64,Armhf等平台的Ubuntu软件仓库

官方镜像地址:https://developer.aliyun.com/mirror/ubuntu-ports?spm=a2c6h.13651102.0.0.1ecc1b11fC2McV

修改镜像源文件:/etc/apt/sources.list

deb https://mirrors.aliyun.com/ubuntu-ports/ noble main restricted universe multiverse
deb-src https://mirrors.aliyun.com/ubuntu-ports/ noble main restricted universe multiverse
​
deb https://mirrors.aliyun.com/ubuntu-ports/ noble-security main restricted universe multiverse
deb-src https://mirrors.aliyun.com/ubuntu-ports/ noble-security main restricted universe multiverse
​
deb https://mirrors.aliyun.com/ubuntu-ports/ noble-updates main restricted universe multiverse
deb-src https://mirrors.aliyun.com/ubuntu-ports/ noble-updates main restricted universe multiverse
​
# deb https://mirrors.aliyun.com/ubuntu-ports/ noble-proposed main restricted universe multiverse
# deb-src https://mirrors.aliyun.com/ubuntu-ports/ noble-proposed main restricted universe multiverse
​
deb https://mirrors.aliyun.com/ubuntu-ports/ noble-backports main restricted universe multiverse
deb-src https://mirrors.aliyun.com/ubuntu-ports/ noble-backports main restricted universe multiverse

随后执行apt update更新镜像源包

挂载硬盘

下载挂载硬盘所需包:exfat-fuse以及exfatprogs

root@orangepi5plus:/etc/apt# apt-get install exfat-fuse
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  exfat-fuse
0 upgraded, 1 newly installed, 0 to remove and 324 not upgraded.
Need to get 25.6 kB of archives.
After this operation, 82.9 kB of additional disk space will be used.
Get:1 https://mirrors.aliyun.com/ubuntu-ports noble/universe arm64 exfat-fuse arm64 1.4.0-2 [25.6 kB]
Fetched 25.6 kB in 0s (88.2 kB/s)     
Selecting previously unselected package exfat-fuse.
(Reading database ... 39869 files and directories currently installed.)
Preparing to unpack .../exfat-fuse_1.4.0-2_arm64.deb ...
Unpacking exfat-fuse (1.4.0-2) ...
Setting up exfat-fuse (1.4.0-2) ...
Processing triggers for man-db (2.10.2-1) ...
​
root@orangepi5plus:/etc/apt# sudo apt-get install exfatprogs
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  exfatprogs
0 upgraded, 1 newly installed, 0 to remove and 324 not upgraded.
Need to get 64.9 kB of archives.
After this operation, 435 kB of additional disk space will be used.
Get:1 https://mirrors.aliyun.com/ubuntu-ports noble/universe arm64 exfatprogs arm64 1.2.2-1build1 [64.9 kB]
Fetched 64.9 kB in 0s (244 kB/s)    
Selecting previously unselected package exfatprogs.
(Reading database ... 39854 files and directories currently installed.)
Preparing to unpack .../exfatprogs_1.2.2-1build1_arm64.deb ...
Unpacking exfatprogs (1.2.2-1build1) ...
Setting up exfatprogs (1.2.2-1build1) ...
Processing triggers for man-db (2.10.2-1) ...
​

查看硬盘设备地址,找到最大的分区,这里是sda2,一会儿就用它挂载到系统

root@orangepi5plus:/etc/apt# lsblk
NAME         MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda            8:0    0  12.7T  0 disk 
├─sda1         8:1    0    16M  0 part 
└─sda2         8:2    0  12.7T  0 part 
mtdblock0     31:0    0    16M  0 disk 
mmcblk0      179:0    0 233.3G  0 disk 
├─mmcblk0p1  179:1    0     1G  0 part /boot
└─mmcblk0p2  179:2    0 229.9G  0 part /var/log.hdd

创建硬盘要挂载到系统的目录,并挂载

root@orangepi5plus:/etc/apt# mkdir -m 777 /mnt/wukong
root@orangepi5plus:/etc/apt# mount -t exfat-fuse /dev/sda2 /mnt/wukong/
FUSE exfat 1.4.0 (libfuse3)
WARN: volume was not unmounted cleanly.

查看/dev/sda2分区是否挂载到/mnt/wukong

root@orangepi5plus:/etc/apt# df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           3.2G   17M  3.1G   1% /run
/dev/mmcblk0p2  227G  2.2G  222G   1% /
tmpfs            16G     0   16G   0% /dev/shm
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs            16G  4.0K   16G   1% /tmp
/dev/mmcblk0p1 1022M  120M  903M  12% /boot
/dev/zram1      188M  2.6M  171M   2% /var/log
tmpfs           3.2G     0  3.2G   0% /run/user/1000
tmpfs           3.2G     0  3.2G   0% /run/user/0
/dev/sda2        13T  267G   13T   3% /mnt/wukong

开机自动挂载硬盘

获取分区UUID

root@orangepi5plus:~# sudo blkid /dev/sda2
/dev/sda2: LABEL="EXFAT_14T" UUID="3A34-BB7F" BLOCK_SIZE="512" TYPE="exfat" PARTLABEL="Basic data partition" PARTUUID="3d6c752f-c336-405e-ab51-2eb0966a0e84"

编辑/etc/fstab,追加以下内容

UUID=3A34-BB7F /mnt/wukong exfat-fuse defaults,uid=1000,gid=1000,umask=0000,allow_other 0 0

完整内容

root@orangepi5plus:~# cat /etc/fstab 
UUID=4694b5ee-9f59-4564-8f67-d51ccf671fe4 / ext4 defaults,noatime,commit=600,errors=remount-ro 0 1
UUID=B7B5-A91A /boot vfat defaults 0 2
tmpfs /tmp tmpfs defaults,nosuid 0 0
UUID=3A34-BB7F /mnt/wukong exfat-fuse defaults,uid=1000,gid=1000,umask=0000,allow_other 0 0

定时挂载

由于某些特殊情况,如磁盘高温保护,断电,磁盘挂载延时等情况,磁盘可能未能正常挂载到系统,这里设定每隔五分钟自动挂载设备,编辑/etc/crontab文件,追加以下内容:

*/5 * * * * root mount -a >> /var/log/mount_a.log 2>&1

完整内容:

root@orangepi5-plus:/var/log# cat /etc/cron
cron.d/       cron.daily/   cron.hourly/  cron.monthly/ crontab       cron.weekly/  
root@orangepi5-plus:/var/log# cat /etc/crontab 
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
# You can also override PATH, but by default, newer versions inherit it from the environment
#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
# 每天凌晨3点自动备份
0 3 * * * root RESTIC_PASSWORD=****** restic backup --repo /mnt/wukong/os/backup/ / --exclude /dev --exclude /proc --exclude /sys --exclude /tmp --exclude /run --exclude /mnt >> /var/log/restic_backup.log 2>&1 
# 每隔五分钟自动挂载设备
*/5 * * * * root mount -a >> /var/log/mount_a.log 2>&1

指令详解:

mount -a 是 Linux 系统中的一个命令,用于挂载 /etc/fstab 文件中列出的所有文件系统。

- *mount:** 是 Linux 中用于挂载文件系统的命令。挂载是指将一个文件系统 (例如硬盘分区、USB 设备、网络共享) 连接到文件系统树中的一个目录 (称为挂载点),使得可以通过该目录访问文件系统中的文件和目录。

- *-a:** 是 mount 命令的一个选项,表示 "all",即挂载所有在 /etc/fstab 文件中定义的文件系统。

执行 mount -a 命令后,系统会读取 /etc/fstab 文件,并尝试挂载其中列出的所有文件系统。如果某个文件系统已经挂载,则 mount -a 会跳过该文件系统。

系统启动时会自动执行 mount -a 命令,挂载 /etc/fstab 中定义的所有文件系统。

如果某些文件系统由于某种原因未正确挂载,可以使用 mount -a 命令尝试重新挂载。

关于是否需要手动重启服务:

tips:cron 守护进程会定期扫描 /etc/crontab 文件以及 /etc/cron.d/ 目录下的所有文件,以查找新的或修改过的定时任务。当 cron 守护进程检测到文件发生更改时,它会自动重新加载配置文件,而无需手动重启服务。

安装代理客户端

在服务搭建的过程中,很多时候我们所用到的资源,如:镜像、模型、开源项目等,这些资源不可避免的很多都在国外,在搭建自己的服务过程中,最头疼的也是这个问题,很多时候,尤其是在linux服务器上,经常会因为网络受限,导致服务器软件包更新失败、源码拉取失败、镜像拉取失败等等问题,为了解决这些问题,这里找到一个基于Linux系统的代理软件

工具地址:Elegycloud/clash-for-linux-backup: 基于Clash Core 制作的Clash For Linux备份仓库 A Clash For Linux Backup Warehouse Based on Clash Core

开始安装,clone项目

root@orangepi5plus:/app/docker/immich# cd /etc/
root@orangepi5plus:/etc# mkdir -m 777 clash
root@orangepi5plus:/etc# cd clash/
root@orangepi5plus:/etc/clash# $ git clone https://github.com/Elegycloud/clash-for-linux-backup.git clash-for-linux
Cloning into 'clash-for-linux'...
remote: Enumerating objects: 681, done.
remote: Counting objects: 100% (59/59), done.
remote: Compressing objects: 100% (22/22), done.
remote: Total 681 (delta 49), reused 37 (delta 37), pack-reused 622 (from 2)
Receiving objects: 100% (681/681), 18.42 MiB | 7.95 MiB/s, done.
Resolving deltas: 100% (243/243), done.
root@orangepi5plus:/etc/clash# cd clash-for-linux/

编辑.env文件,添加订阅url,由于各大vpn厂商提供的代理节点列表格式不统一,这里需要将地址转换为clash需要json格式

转换地址网站:SoCloud 订阅转换飞鸟云

订阅地址:https://fn1.476579.xyz/api/v1/client/subscribe?token=s9d9c3c1a7h4e3b9n7q0f4g9t1r5e8j6

转换后的地址:

root@orangepi5plus:/etc/clash/clash-for-linux# nano .env

修改代理启动脚本,找到sed -n 开头的代码替换:

## Clash 配置文件重新格式化及配置
# 取出代理相关配置 
#sed -n '/^proxies:/,$p' $Temp_Dir/clash.yaml > $Temp_Dir/proxy.txt
sed -n '/^proxies:/,$p' $Temp_Dir/clash_config.yaml > $Temp_Dir/proxy.txt
​
# 合并形成新的config.yaml
cat $Temp_Dir/templete_config.yaml > $Temp_Dir/config.yaml
cat $Temp_Dir/proxy.txt >> $Temp_Dir/config.yaml
\cp $Temp_Dir/config.yaml $Conf_Dir/

启动代理:

root@orangepi5plus:/etc/clash/clash-for-linux# bash start.sh
CPU architecture: arm64
​
正在检测订阅地址...
Clash订阅地址可访问!                                      [  OK  ]
​
正在下载Clash配置文件...
配置文件config.yaml下载成功!                              [  OK  ]
​
判断订阅内容是否符合clash配置文件标准:
订阅内容符合clash标准
​
正在启动Clash服务...
服务启动成功!                                             [  OK  ]
​
Clash Dashboard 访问地址: http://<ip>:9090/ui
Secret: a2s7m4l7b4e5t2s7b1j0t1m2t6v5j5r8r7a0m1g7d4s2w1z0i9a2a9o9e4o6n5b5
​
     く__,.ヘヽ.        /  ,ー、 〉
           \ ', !-─‐-i  /  /´
          /`ー'       L//`ヽ、
         /   /,   /|   ,   ,       ',
        イ   / /-‐/  i  L_ ハ ヽ!   i
        レ ヘ 7イ`ト   レ'ァ-ト、!ハ|   |
          !,/7 '0'     ´0iソ|    |
          |.从     _     ,,,, / |./    |
          レ'| i>.、,,__  _,.イ /   .i   |
           レ'| | / k_7_/レ'ヽ,  ハ.  |
             | |/i 〈|/   i  ,.ヘ |  i  |
            .|/ /  i:    ヘ!    \  |
             kヽ>、ハ    _,.ヘ、    /、!
             !'〈//`T´', \ `'7'ーr'
             レ'ヽL__|___i,___,ンレ|ノ
                  ト-,/  |___./
                  'ー'    !_,.:
本项目完全免费,若你是收费买的,恭喜您,您被骗了!
项目地址:https://github.com/Elegycloud/clash-for-linux-backup
项目随时会寄,且行且珍惜!
请执行以下命令加载环境变量: source /etc/profile.d/clash.sh
​
请执行以下命令开启系统代理: proxy_on
​
若要临时关闭系统代理,请执行: proxy_off
root@orangepi5plus:/etc/clash/clash-for-linux# source /etc/profile.d/clash.sh
root@orangepi5plus:/etc/clash/clash-for-linux# proxy_on
[√] 已开启代理
​

安装GPU驱动

根据immich官网提供的资料,若我们想要开启immich的硬件转码功能,需要设备拥有GPU驱动,详细介绍如下

这里要求我们安装libmali,根据提供的网址以及我们RK3588所需对应版本(libmali-valhall-g610-g13p0-gbm_1.9-1_arm64.deb),我这里下载的是最新的发布版本

下载完成之后,进入服务器进行安装。

要安装 libmali-valhall-g610-g13p0-gbm 并确保 /usr/lib/aarch64-linux-gnu/libmali.so.1 存在,我们按照以下步骤操作:

步骤 1:安装依赖项

sudo apt update
sudo apt install -f libdrm2 libgbm1  # 确保基础依赖已安装

步骤 2:安装下载的 .deb 文件

sudo dpkg -i libmali-valhall-g610-g13p0-gbm_1.9-1_arm64.deb

步骤 3:确认库文件位置

安装后库文件默认会出现在以下路径之一:

  • /usr/lib/libmali.so.1

  • /usr/lib/aarch64-linux-gnu/libmali.so.1

检查是否已存在:

ls /usr/lib/aarch64-linux-gnu/libmali.so.1
ls /usr/lib/libmali.so.1

步骤 4:若文件不存在,手动创建符号链接

如果库文件在 /usr/lib/libmali.so.1 但不在目标路径:

sudo ln -s /usr/lib/libmali.so.1 /usr/lib/aarch64-linux-gnu/libmali.so.1

步骤 5:更新动态链接库缓存

sudo ldconfig

步骤 6:验证安装

ls /usr/lib/aarch64-linux-gnu/libmali.so.1  # 确认文件存在
ldconfig -p | grep libmali.so.1            # 检查是否被缓存识别

系统备份

Restic 简介

Restic 是一个现代化的备份程序,可以备份你的文件:

- 支持 Linux, BSD, macOS 和 Windows 系统 [6](https://restic.net/)

- 支持多种存储类型,包括本地目录、远程服务器、云存储等 [6](https://restic.net/)

- 易于使用,只需一个可执行文件 [3](https://tech.coe.drexel.edu/data/backups/restic/)

- 执行增量备份,只传输更改的部分 [3](https://tech.coe.drexel.edu/data/backups/restic/)

- 数据去重,节省存储空间 [3](https://tech.coe.drexel.edu/data/backups/restic/)

- 安全,使用加密技术 [3](https://tech.coe.drexel.edu/data/backups/restic/)

- 可以轻松验证备份,确保文件可以恢复

1. 安装 Restic
root@orangepi5-plus:~# apt install restic

正在读取软件包列表... 完成

正在分析软件包的依赖关系树... 完成

正在读取状态信息... 完成                 

下列软件包是自动安装的并且现在不需要了:

  libpython2-stdlib libpython2.7-minimal libpython2.7-stdlib python-pkg-resources python-setuptools python2 python2-minimal python2.7 python2.7-minimal

使用'apt autoremove'来卸载它(它们)。

建议安装:

  libjs-sphinxdoc sphinx-rtd-theme-common

下列【新】软件包将被安装:

  restic

升级了 0 个软件包,新安装了 1 个软件包,要卸载 0 个软件包,有 1 个软件包未被升级。

需要下载 6,859 kB 的归档。

解压缩后会消耗 19.5 MB 的额外空间。

获取:1 http://ports.ubuntu.com jammy-security/universe arm64 restic arm64 0.12.1-2ubuntu0.3 [6,859 kB]

已下载 6,859 kB,耗时 4秒 (1,923 kB/s)

正在选中未选择的软件包 restic。

(正在读取数据库 ... 系统当前共安装有 40382 个文件和目录。)

准备解压 .../restic_0.12.1-2ubuntu0.3_arm64.deb  ...

进度:[  0%] [..................................................................................................................................................................................................................................................] 

正在解压 restic (0.12.1-2ubuntu0.3) ...#######################..................................................................................................................................................................................................] 

正在设置 restic (0.12.1-2ubuntu0.3) ...#######################################################################..................................................................................................................................................] 

进度:[ 60%] [#################################################################################################################################################.................................................................................................] 

正在处理用于 man-db (2.10.2-1) 的触发器 ...####################################################################################################################################################################.................................................] 
2. 更新 Restic
root@orangepi5-plus:~# restic version

restic 0.12.1 compiled with go1.18.1 on linux/arm64

root@orangepi5-plus:~# restic self-update

writing restic to /usr/bin/restic

find latest release of restic at GitHub

latest version is 0.18.0

download SHA256SUMS

download SHA256SUMS.asc

GPG signature verification succeeded

download restic_0.18.0_linux_arm64.bz2

downloaded restic_0.18.0_linux_arm64.bz2

saved 28180664 bytes in /usr/bin/restic

successfully updated restic to version 0.18.0

root@orangepi5-plus:~# restic version

restic 0.18.0 compiled with go1.24.1 on linux/arm64
3. 初始化 Restic 仓库
root@orangepi5-plus:/mnt/wukong/os/backup# restic init --repo /mnt/wukong/os/backup/

enter password for new repository: 

enter password again: 

created restic repository c89fe5815b at /mnt/wukong/os/backup/

Please note that knowledge of your password is required to access

the repository. Losing your password means that your data is

irrecoverably lost.
4. 首次备份

这里使--exclude指定要排除备份的目录,首次备份大约需要几分钟

root@orangepi5-plus:/mnt/wukong/os/backup# restic backup --repo /mnt/wukong/os/backup/ / --exclude /dev --exclude /proc --exclude /sys --exclude /tmp --exclude /run --exclude /mnt

enter password for repository: 

repository c89fe581 opened (version 2, compression level auto)

created new cache in /root/.cache/restic

no parent snapshot found, will read all files

[0:00]          0 index files loaded

Files:       431376 new,     0 changed,     0 unmodified

Dirs:        65819 new,     0 changed,     0 unmodified

Added to the repository: 15.391 GiB (10.213 GiB stored)
5. 自动备份

后续的自动备份这里使用系统自带的crontab添加一条任务:

/etc/crontab文件,追加以下内容:

0 3    * * *    root    RESTIC_PASSWORD=***** restic backup --repo /mnt/wukong/os/backup/ / --exclude /dev --exclude /proc --exclude /sys --exclude /tmp --exclude /run --exclude /mnt >> /var/log/restic_backup.log 2>&1

完整内容:

root@orangepi5-plus:/mnt/wukong/os/backup# cat /etc/cron

cron.d/       cron.daily/   cron.hourly/  cron.monthly/ crontab       cron.weekly/  

root@orangepi5-plus:/mnt/wukong/os/backup# cat /etc/crontab 

# /etc/crontab: system-wide crontab

# Unlike any other crontab you don't have to run the `crontab'

# command to install the new version when you edit this file

# and files in /etc/cron.d. These files also have username fields,

# that none of the other crontabs do.

SHELL=/bin/sh

# You can also override PATH, but by default, newer versions inherit it from the environment

#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# Example of job definition:

# .---------------- minute (0 - 59)

# |  .------------- hour (0 - 23)

# |  |  .---------- day of month (1 - 31)

# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...

# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat

# |  |  |  |  |

# *  *  *  *  * user-name command to be executed

17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly

25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )

47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )

52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

#

0 3    * * *    root    RESTIC_PASSWORD=***** restic backup --repo /mnt/wukong/os/backup/ / --exclude /dev --exclude /proc --exclude /sys --exclude /tmp --exclude /run --exclude /mnt >> /var/log/restic_backup.log 2>&1

首次备份完后,后续的备份就很快速了,不管是首次还是后续备份,命令都是一样的。

root@orangepi5-plus:/mnt/wukong/os/backup# RESTIC_PASSWORD=******* restic backup --repo /mnt/wukong/os/backup/ / --exclude /dev --exclude /proc --exclude sys --exclude /tmp --exclude /run --exclude /mnt

repository c89fe581 opened (version 2, compression level auto)

using parent snapshot 60b8b6be

[0:00] 100.00%  5 / 5 index files loaded

Files:           0 new,    16 changed, 431360 unmodified

Dirs:            0 new,    23 changed, 65796 unmodified

Added to the repository: 5.022 MiB (1.457 MiB stored)

processed 431376 files, 45.882 GiB in 0:45

snapshot d1758662 saved
6. 恢复系统

要恢复系统,你需要使用 restic restore 命令。

restic restore latest --repo /mnt/wukong/os/backup --target /

Docker安装及配置

由于 Ubuntu 官方仓库中的 Docker 版本可能不是最新的,我们将从 Docker 官方仓库安装 2

  1. 更新软件包列表:

    sudo apt update
  2. 安装必要的依赖包,以便 apt 可以通过 HTTPS 使用仓库:

    sudo apt install apt-transport-https ca-certificates curl software-properties-common
  3. 添加 Docker 官方 GPG 密钥:

    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
  4. 添加 Docker 仓库到 APT 源:

    sudo add-apt-repository "deb [arch=arm64] https://download.docker.com/linux/ubuntu jammy stable"

    注意:这里指定了 arch=arm64,因为您的系统是 aarch64 架构。同时,jammy 是 Ubuntu 22.04 的代号。

  5. 再次更新软件包列表,以应用新的仓库:

    sudo apt update
  6. 安装 Docker Engine:

    sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  7. 验证 Docker 是否成功安装并运行:

    sudo systemctl status docker

    如果 Docker 正在运行,您应该看到类似以下的输出:

    ● docker.service - Docker Application Container Engine
         Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
         Active: active (running) since ...
           Docs: https://docs.docker.com
  8. (可选) 允许非 root 用户执行 Docker 命令:

    默认情况下,只有 root 用户或 docker 组的用户才能运行 Docker 命令。要允许您的用户执行 Docker 命令而无需 sudo,请执行以下操作:

    bashsudo usermod -aG docker $USER
    newgrp docker

    注销并重新登录,或运行 newgrp docker 命令以使更改生效。

步骤 2:安装 Docker Compose

从 Docker CE 20.10 开始,Docker Compose 已经集成为 Docker 的一个插件。在上面的步骤中,我们已经安装了 docker-compose-plugin,所以您现在可以使用 docker compose 命令。

  1. 验证 Docker Compose 是否安装成功:

    docker compose version

    如果安装成功,您应该看到 Docker Compose 的版本信息。

更改docker镜像源

sudo nano /etc/docker/daemon.json

完整内容

{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "experimental": false,
  "registry-mirrors": [
    "https://0c105db5188026850f80c001def654a0.mirror.swr.myhuaweicloud.com",
  	"https://5tqw56kt.mirror.aliyuncs.com",
	"https://docker.ckyl.me/",
    "https://docker.hpcloud.cloud",
    "https://docker.m.daocloud.io",
    "https://docker.unsee.tech",
    "https://docker.1panel.live",
    "http://mirrors.ustc.edu.cn",
    "https://docker.chenby.cn",
    "http://mirror.azure.cn",
    "https://dockerpull.org",
    "https://dockerhub.icu",
    "https://hub.rat.dev",
    "https://proxy.1panel.live",
    "https://docker.1panel.top",
    "https://docker.m.daocloud.io",
    "https://docker.1ms.run",
    "https://docker.ketches.cn"
  ]
}

保存后,重启docker服务

sudo systemctl restart docker

验证镜像源是否修改成功,在输出信息中,找到 Registry Mirrors 字段,若显示了你添加的镜像源地址,则表示修改成功。

sudo docker info

自建服务

Portainer服务

Docker Portainer是一个开源的轻量级容器管理界面,用于简化Docker环境的管理。以下是关于Portainer的简要介绍:

功能介绍

  • 直观的Web界面:提供易于使用的图形界面,无需深入了解Docker命令。

  • 资源管理:管理容器、镜像、卷、网络等Docker资源。

  • 多环境支持:支持本地和远程Docker环境的管理。

  • 访问控制:提供用户管理和权限控制,确保安全访问。

  • 应用模板:支持快速部署常见应用。

Docker配置

创建portainer的docker-compose.yml文件存放目录:

root@orangepi5plus:/# mkdir -m 777 app
root@orangepi5plus:/# cd app/
root@orangepi5plus:/app# mkdir -m 777 docker
root@orangepi5plus:/app# cd docker/
root@orangepi5plus:/app/docker# mkdir -m 777 portainer
root@orangepi5plus:/app/docker# cd portainer/

新增docker-compose.yml配置文件

services:
  portainer:
    image: 6053537/portainer-ce
    container_name: portainer
    restart: unless-stopped
    ports:
      - "9443:9443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data
volumes:
  portainer_data:

运行Portainer容器

docker compose up -d

访问Portainer

https://<your_server_ip>:9443

这个网站要求密码长度必须至少为 12 个字符。

使用该网站生成一个密码:随机密码生成器 | 菜鸟工具

用户名:admin

密码:rC4-oO7>iS9)

设置开机自启

修改docker-compose.yml文件,主要新增:restart: unless-stopped

version: '3.9'
​
services:
  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer
    restart: unless-stopped
    ports:
      - "9443:9443"
      - "8000:8000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data
​
volumes:
  portainer_data:

设置docker自启

sudo systemctl enable docker

检查是否设置成功

sudo systemctl is-enabled docker  # 应返回enabled

重启,检查是否成功

# 模拟重启测试
sudo reboot
docker ps | grep portainer

Immich服务

简要介绍

Immich是一款开源的、自托管的照片和视频备份解决方案,允许用户在私有服务器上存储、管理和分享他们的媒体文件。以下是Immich的主要特点:

  • 自托管:所有数据存储在用户自己的服务器上,确保数据隐私和安全。

  • 自动备份:支持移动设备中的照片和视频自动备份,确保数据安全无忧。

  • 跨平台支持:提供移动端(iOS和Android)和Web端应用,方便用户随时随地访问和管理备份内容。

  • 隐私保护:由于数据存储在自己的服务器上,用户的照片和视频不会被未经授权的第三方访问。

  • 开源免费:项目在GitHub上开源,用户可以自由查看、修改和分发。

  • 易于部署:支持Docker容器化部署,安装和维护简单。

安装配置

安装方式有很多种,这里使用之前安装的portainer来安装immich,以便于管理 参考官网安装方式:Portainer | Immich

完整配置截图:

点击部署后会自动拉取容器并运行,看到下面的服务都启动后便可使用immich了

常规配置,我们这里不做过多介绍,参考官方文档即可,下面我们针对两种特殊情况进行配置。

开启GPU硬件转码

在前面的步骤,我们已经安装好了GPU驱动,符合immich服务开启硬件转码的条件,下面是关于硬件转码的介绍

  • 硬件转码:

    此功能允许您使用GPU来加速转码并减少CPU负载。 请注意,与具有类似设置的软件转码相比,硬件转码产生的视频要大得多,通常质量较低。使用慢速预设和首选更高效的编解码器可以缩小这一差距。

所以,这里就按照官方的说法,添加immich-server开启GPU加速的参数(官方示例):

services:
  rkmpp:
    security_opt: # enables full access to /sys and /proc, still far better than privileged: true
      - systempaths=unconfined
      - apparmor=unconfined
    group_add:
      - video
    devices:
      - /dev/rga:/dev/rga
      - /dev/dri:/dev/dri
      - /dev/dma_heap:/dev/dma_heap
      - /dev/mpp_service:/dev/mpp_service
      #- /dev/mali0:/dev/mali0 # only required to enable OpenCL-accelerated HDR -> SDR tonemapping
    volumes:
      #- /etc/OpenCL:/etc/OpenCL:ro # only required to enable OpenCL-accelerated HDR -> SDR tonemapping
      #- /usr/lib/aarch64-linux-gnu/libmali.so.1:/usr/lib/aarch64-linux-gnu/libmali.so.1:ro # only required to enable OpenCL-accelerated HDR -> SDR tonemapping

配置完成后,记得重新启动immich-server服务。

开启机器学习加速

在安装当前系统的时候,我们选择的是Armbian24.11的镜像,系统自带NPU 0.9.8的驱动,这里我们天然的具备了immich-machine-learning服务开启硬件加速机器学习的条件,以下是相关介绍

  • 硬件加速的机器学习:

    此功能允许您使用GPU来加速机器学习任务,例如智能搜索和面部识别,同时降低CPU负载。

理论上我们可以使用GPU进行加速的,但是我们使用的SOC是RK3588,它内置了一个NPU芯片,具有6Tops的算力,关于为什么使用NPU加速而不是GPU加速,这里给出我找到的说法:

  • RKNPU:专为加速人工智能任务,特别是神经网络计算而设计,针对矩阵乘法、卷积等操作进行优化。

  • GPU:最初用于图形渲染,擅长并行计算,适合同时处理大量简单任务。

以及immich官方给出的说法:

  • 与ARM NN(GPU)相比,RKNPU具有:

    • 更广泛的模型支持 (包括搜索,其中ARM NN不加速)

    • 更少的热量产生

    • 精度略低 (RKNPU始终使用FP16,而ARM NN默认情况下使用更高的精度FP32,除非MACHINE_LEARNING_ANN_FP16_TURBO已启用)

    • 变速 (在RK3588上测试):

      • 如果MACHINE_LEARNING_RKNN_THREADS默认值为1,则在大多数情况下,RKNPU的ML作业吞吐量将比ARM NN低得多,但延迟相似 (例如在搜索时)

      • 如果MACHINE_LEARNING_RKNN_THREADS设置为3时,它将比FP32处的ARM NN快一些,但比ARM NN慢一些,如果MACHINE_LEARNING_ANN_FP16_TURBO已启用

      • 当其他任务也使用GPU (如转码) 时,RKNPU比ARM NN具有显着优势,因为它使用其他空闲的NPU而不是竞争GPU使用

    • 降低RAM使用率,如果MACHINE_LEARNING_RKNN_THREADS默认值为1,但如果大于1 (这是充分利用NPU所必需的,因此速度与ARM NN相当)

所以我们这里选择的是使用官方提供的rknn驱动而不是armnn(理论上我们拥有GPU驱动,这里是没问题的,但是没测)驱动的方式来启用加速。

添加immich-machine-learning开启NPU机器加速的参数(官方示例):

  1. 更改镜像名称,名称后追加"-rknn"

    services:
      immich-machine-learning:
        # For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
        # Example tag: ${IMMICH_VERSION:-release}-cuda
        image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-rknn
  1. 增加配置

    services:
      rknn:
        security_opt:
          - systempaths=unconfined
          - apparmor=unconfined
        devices:
          - /dev/dri:/dev/dri

更改完配置后,需要重新拉取新的immich-machine-learning镜像并重新部署。

完整配置

#
# WARNING: To install Immich, follow our guide: https://immich.app/docs/install/docker-compose
#
# Make sure to use the docker-compose.yml of the current release:
#
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
#
# The compose file on main may not be compatible with the latest release.
​
name: immich
​
services:
  immich-server:
    container_name: immich_server
    image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
    # extends:
    #   file: hwaccel.transcoding.yml
    #   service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
    security_opt: # enables full access to /sys and /proc, still far better than privileged: true
      - systempaths=unconfined
      - apparmor=unconfined
    group_add:
      - video
    devices:
      - /dev/rga:/dev/rga
      - /dev/dri:/dev/dri
      - /dev/dma_heap:/dev/dma_heap
      - /dev/mpp_service:/dev/mpp_service
      #- /dev/mali0:/dev/mali0 # only required to enable OpenCL-accelerated HDR -> SDR tonemapping
    volumes:
      # Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
      - ${UPLOAD_LOCATION}:/usr/src/app/upload
      - /etc/localtime:/etc/localtime:ro
      #- /usr/local/etc/OpenCL:/etc/OpenCL:ro # only required to enable OpenCL-accelerated HDR -> SDR tonemapping
      #- /usr/local/lib/aarch64-linux-gnu/libmali.so.1:/usr/lib/aarch64-linux-gnu/libmali.so.1:ro # only required to enable OpenCL-accelerated HDR -> SDR tonemapping
​
    env_file:
      - stack.env
    ports:
      - '2283:2283'
    depends_on:
      - redis
      - database
    restart: always
    healthcheck:
      disable: false
​
  immich-machine-learning:
    container_name: immich_machine_learning
    # For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
    # Example tag: ${IMMICH_VERSION:-release}-cuda
    image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-rknn
    # extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
    #   file: hwaccel.ml.yml
    #   service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
    security_opt:
      - systempaths=unconfined
      - apparmor=unconfined
    devices:
      - /dev/dri:/dev/dri
    volumes:
      - /app/immich/cache:/cache
    env_file:
      - stack.env
    restart: always
    healthcheck:
      disable: false
​
  redis:
    container_name: immich_redis
    image: docker.io/redis:6.2-alpine@sha256:148bb5411c184abd288d9aaed139c98123eeb8824c5d3fce03cf721db58066d8
    healthcheck:
      test: redis-cli ping || exit 1
    restart: always
​
  database:
    container_name: immich_postgres
    image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_DB: ${DB_DATABASE_NAME}
      POSTGRES_INITDB_ARGS: '--data-checksums'
    volumes:
      # Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
      - ${DB_DATA_LOCATION}:/var/lib/postgresql/data
    healthcheck:
      test: >-
        pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1; Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
      interval: 5m
      start_interval: 30s
      start_period: 5m
    command: >-
      postgres -c shared_preload_libraries=vectors.so -c 'search_path="$$user", public, vectors' -c logging_collector=on -c max_wal_size=2GB -c shared_buffers=512MB -c wal_compression=on
    restart: always
​
volumes:
  model-cache:
​

环境变量:

UPLOAD_LOCATION=/mnt/wukong/immich
DB_DATA_LOCATION=./postgres
IMMICH_VERSION=release
DB_PASSWORD=postgres
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
TZ=Asia/Shanghai
TRANSFORMERS_CACHE=/app/immich/cache

访问Immich:

http://<your_server_ip>:2283

地图主题

Maps | MapTiler Cloud

白天:https://api.maptiler.com/maps/0196478b-b975-7544-8351-edf924529259/style.json?key=pK9cG6gV1aP1iN4gL2eX

晚上:https://api.maptiler.com/maps/019647a0-8fd8-7e18-b21f-4ed943568b0f/style.json?key=pT5zT6dB2tS7lO7hG2mT

模型配置

模型选择

我们在创建immich服务的时候会涉及到以下几种模型,主要用于机器学习的设置,当然这些模型也源自于官方推荐的模型

人脸识别模型(immich-人脸识别-人脸识别模型):

  • immich-app/antelopev2

  • immich-app/buffalo_l

智能搜索模型(immich-智能搜索-CLIP模型):

  • immich-app/XLM-Roberta-Large-Vit-B-16Plus(注意:若为aarch64架构的设备,仅支持cpu运行,不支持RKNN (Rockchip)的硬件加速机器学习)

  • ViT-L-16-SigLIP2-384__webli(这个模型也是经历过使用上面的模型遇到的问题,在issue中找到的解决方案,该模型支持RKNN加速)

模型下载

模型下载地址:

1、huggingface镜像网:HF-Mirror

2、异性岛:https://aliendao.cn

3、国内替代:https://modelscope.cn/home

4、模力方舟(Gitee AI)https://ai.gitee.com/

模型下载解决办法:

参考知乎(https://zhuanlan.zhihu.com/p/663712983

这里使用推荐的huggingface-cli 进行下载的方式

# 按需修改参数
# 修改1:模型名称-immich-app/ViT-L-16-SigLIP2-384
# 修改2:模型下载目录名称-ViT-L-16-SigLIP2-384__webli
huggingface-cli download immich-app/ViT-L-16-SigLIP2-384__webli --local-dir ViT-L-16-SigLIP2-384__webli

部分执行日志如下:

部分情况可能下载不成功,大概率是网络问题,这里建议使用科学工具下载,并将代理更改为TUN模式(不懂的可以百度:TUN模式和系统代理模式的区别)

PS E:\leeleo\immich模型> huggingface-cli download immich-app/ViT-L-16-SigLIP2-384__webli --local-dir ViT-L-16-SigLIP2-384__webli
⚠️  Warning: 'huggingface-cli download' is deprecated. Use 'hf download' instead.
Fetching 164 files:   1%|▊                                                                                                                              | 1/164 [00:00<00:53,  3.07it/s]Downloading 'textual/onnx__MatMul_4693' to 'ViT-L-16-SigLIP2-384__webli\.cache\huggingface\download\textual\6umd0cxo5zyrYxJ1oQuQ9JrZ0fo=.045527ee754ccf37d05cc3d8e12a4476921efed6bb63c0015079d468288b60f4.incomplete'
Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. Falling back to regular HTTP download. For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet`
Downloading 'textual/onnx__MatMul_4651' to 'ViT-L-16-SigLIP2-384__webli\.cache\huggingface\download\textual\xAPNXXnW_3oVaPjX6ojjYZklE8o=.d3328f759a8a1c78188083313f57a96ae09f03842c531df8e24b9734c2bab5fa.incomplete'
Downloading 'textual/onnx__MatMul_4612' to 'ViT-L-16-SigLIP2-384__webli\.cache\huggingface\download\textual\mg1mkykMcSkL2Cmo8jlvsRL1tt0=.575e95b60986547dce34e2a663908dc2852cdde5ea7ead78849e5ff8ce7a5ecf.incomplete'
Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. Falling back to regular HTTP download. For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet`
Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. Falling back to regular HTTP download. For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet`
Downloading 'textual/onnx__MatMul_4692' to 'ViT-L-16-SigLIP2-384__webli\.cache\huggingface\download\textual\CaogzFCi0wzG5zDpSi1gGWsQxWU=.6eb18939b8285643d2f762eeaab656166f104a915a53699dd8c3a64143782628.incomplete'
Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. Falling back to regular HTTP download. For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet`
Downloading 'textual/onnx__MatMul_4694' to 'ViT-L-16-SigLIP2-384__webli\.cache\huggingface\download\textual\g2AMHBkBmE2vZEnBWMBhHaLc10c=.72d923170816fc964ec8f5e51bdebddae0ca8c7e2a47108c1342621560abd698.incomplete'
Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. Falling back to regular HTTP download. For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet`
Downloading 'textual/onnx__MatMul_4652' to 'ViT-L-16-SigLIP2-384__webli\.cache\huggingface\download\textual\oLFFiVwLDVvx_4R1Xrzg33LZ0pA=.ebf2a071cb262d814953b09f1ee49976fbf90bd503057cb9a315b99314db6d50.incomplete'
Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. Falling back to regular HTTP download. For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet`
Downloading 'README.md' to 'ViT-L-16-SigLIP2-384__webli\.cache\huggingface\download\Xn7B-BWUGOee2Y6hCZtEhtFu4BE=.0bddbb6d5331139dc8614a4db1273df336f655af.incomplete'
Downloading 'textual/onnx__MatMul_4653' to 'ViT-L-16-SigLIP2-384__webli\.cache\huggingface\download\textual\JvaR6sD9DPwUH3vwOzFIkHubW9Q=.549d4236a1c5fcd1b3449670443d5c739966c734522a62896b7f254c75d23c37.incomplete'
Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. Falling back to regular HTTP download. For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet`
README.md: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 320/320 [00:00<?, ?B/s]
Download complete. Moving file to ViT-L-16-SigLIP2-384__webli\textual\rknpu\rk3568\model.rknn██████████████████████████████████▋                    | 965M/1.14G [12:27<01:59, 1.49MB/s]
text.token_embedding.weight: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.05G/1.05G [13:34<00:00, 1.29MB/s]
Download complete. Moving file to ViT-L-16-SigLIP2-384__webli\textual\text.token_embedding.weight████████████████████████████████████████▌         | 1.06G/1.14G [13:28<00:53, 1.54MB/s]
model.rknn: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 674M/674M [05:46<00:00, 1.94MB/s]
Download complete. Moving file to ViT-L-16-SigLIP2-384__webli\visual\rknpu\rk3576\model.rknn██████████████████████████████████████████████▊        | 1.07G/1.14G [13:35<00:46, 1.56MB/s]
model.rknn: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.14G/1.14G [14:24<00:00, 1.32MB/s]
Download complete. Moving file to ViT-L-16-SigLIP2-384__webli\textual\rknpu\rk3588\model.rknn██████████████████████████████████████████████████▌   | 1.11G/1.14G [14:03<00:19, 1.54MB/s]
model.onnx: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.27G/1.27G [12:56<00:00, 1.63MB/s]
Download complete. Moving file to ViT-L-16-SigLIP2-384__webli\visual\model.onnx████████████████████████████████████████████████████████████████████| 1.14G/1.14G [14:24<00:00, 1.52MB/s]
model.rknn: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 653M/653M [06:46<00:00, 1.60MB/s]
Download complete. Moving file to ViT-L-16-SigLIP2-384__webli\visual\rknpu\rk3588\model.rknn
Fetching 164 files: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 164/164 [19:21<00:00,  7.09s/it]
模型部署

下载完成后我们需要将模型放置到它该在的位置,以下目录为所有类型的模型存放位置

immich-machine-learning:
  volumes:
   - /app/immich/cache:/cache

但是需要注意一点,我们不同的模型放到不同的目录:

  • 人脸识别模型存放位置:/app/immich/cache/facial-recognition

  • 能搜索模型存放位置:/app/immich/cache/clip

拷贝完成后目录结构如下:

随后,重启immich-machine-learning服务。

模型配置

接下来我们要做的就是对immich服务中,对人脸识别以及智能搜索的模型配置了:

这里需要注意的一点就是,模型名称是与上面拷贝的模型目录名称是一致的,不要输入错误了。


Nginx服务

代理配置

nginx.conf:

events {}
​
http {
    resolver 223.5.5.5; 
    upstream immich_server {
        server immich_server:2283;
    }
​
    upstream portainer {
        server portainer:9443;
    }
​
    # yourdomain.com
    server {
        listen 80;
        server_name yourdomain.com;
        return 301 https://$host$request_uri;
    }
​
    server {
        listen 443 ssl;
        server_name leeleo.cc;
​
        ssl_certificate /etc/nginx/certs/yourdomain.com.pem;
        ssl_certificate_key /etc/nginx/certs/yourdomain.com.key;
​
        return 404;  # 或者重定向到其他页面
    }
​
    # immich.yourdomain.com:443
    server {
        listen 443 ssl;
        server_name immich.yourdomain.com;
​
        ssl_certificate /etc/nginx/certs/immich.yourdomain.com.pem;
        ssl_certificate_key /etc/nginx/certs/immich.yourdomain.com.key;
​
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5:!TLSv1.0:!TLSv1.1;
​
        location / {
            proxy_pass http://immich_server;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
​
    # portainer.yourdomain.com:443
    server {
        listen 443 ssl;
        server_name portainer.yourdomain.com;
​
        ssl_certificate /etc/nginx/certs/portainer.yourdomain.com.pem;
        ssl_certificate_key /etc/nginx/certs/portainer.yourdomain.com.key;
​
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5:!TLSv1.0:!TLSv1.1;
​
        location / {
            proxy_pass https://portainer;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

Docker配置

docker-compose.yml

services:
  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "80:80"
      - "443:443"
    networks:
      - immich_default
      - portainer_default
      - halo_halo_network
    dns:
      - 223.5.5.5
      - 223.6.6.6
      - 8.8.8.8
      - 8.8.4.4
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./certs:/etc/nginx/certs
    restart: unless-stopped
networks:
  immich_default:  # 声明 immich_default 网络为外部网络
    external: true
  portainer_default:  # 声明 portainer_default 网络为外部网络
    external: true
  halo_halo_network:  # 声明 halo_halo_network 网络为外部网络
    external: true

Certd证书服务

Docker配置

mkdir -p -m 777 /app/docker/certd

cd /app/docker/certd

nano docker-compose.yml 基本没做修改,只改了个版本号

version: '3.3' # 兼容旧版docker-compose
services:
  certd:
    # 镜像                                                  #  ↓↓↓↓↓ ---- 镜像版本号,建议改成固定版本号,例如:certd:1.29.0
    image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:1.34.1
    container_name: certd # 容器名
    restart: unless-stopped # 自动重启
    volumes:
      #   ↓↓↓↓↓ -------------------------------------------------------- 数据库以及证书存储路径,默认存在宿主机的/data/certd/目录下,【您需要定时备份此目录,以保障数据容灾】
      #                                                                  只要修改冒号前面的,冒号后面的/app/data不要动
      - /data/certd:/app/data
    ports: # 端口映射
      #  ↓↓↓↓ ---------------------------------------------------------- 如果端口有冲突,可以修改第一个7001为其他不冲突的端口号,第二个7001不要动
      - "7001:7001"
      #  ↓↓↓↓ ---------------------------------------------------------- https端口,可以根据实际情况,是否暴露该端口
      - "7002:7002"
    #↓↓↓↓ -------------------------------------------------------------- 如果出现getaddrinfo ENOTFOUND错误,可以尝试设置dns
#    dns:
#      - 223.5.5.5      # 阿里云公共dns
#      - 223.6.6.6
#       # ↓↓↓↓ --------------------------------------------------------- 如果你服务器在腾讯云,可以用这个替换上面阿里云的公共dns
#      - 119.29.29.29  # 腾讯云公共dns
#      - 182.254.116.116
#       # ↓↓↓↓ --------------------------------------------------------- 如果你服务器部署在国外,可以用这个替换上面阿里云的公共dns
#      - 8.8.8.8       # 谷歌公共dns
#      - 8.8.4.4
#    extra_hosts:
#        # ↓↓↓↓ -------------------------------------------------------- 这里可以配置自定义hosts,外网域名可以指向本地局域网ip地址
#      - "localdomain.com:192.168.1.3"
#        #         ↓↓↓↓ ------------------------------------------------ 直接使用主机的网络,如果网络问题实在找不到原因,可以尝试打开此参数
#    network_mode: host
    labels:
      com.centurylinklabs.watchtower.enable: "true"
#    ↓↓↓↓ -------------------------------------------------------------- 启用ipv6网络,还需要把下面networks的注释放开
#    networks:
#      - ip6net
    environment:
#     设置环境变量即可自定义certd配置
#     配置项见: packages/ui/certd-server/src/config/config.default.ts
#     配置规则: certd_ + 配置项, 点号用_代替
#                                    #↓↓↓↓ ----------------------------- 如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false
      - certd_system_resetAdminPasswd=false
​
#     默认使用sqlite文件数据库,如果需要使用其他数据库,请设置以下环境变量
#     注意: 选定使用一种数据库之后,不支持更换数据库。
#     数据库迁移方法:1、使用新数据库重新部署一套,然后将旧数据同步过去,注意flyway_history表的数据不要同步
#                                    #↓↓↓↓ ----------------------------- 使用postgresql数据库,需要提前创建数据库
#      - certd_flyway_scriptDir=./db/migration-pg                        # 升级脚本目录
#      - certd_typeorm_dataSource_default_type=postgres                  # 数据库类型
#      - certd_typeorm_dataSource_default_host=localhost                 # 数据库地址
#      - certd_typeorm_dataSource_default_port=5433                      # 数据库端口
#      - certd_typeorm_dataSource_default_username=postgres              # 用户名
#      - certd_typeorm_dataSource_default_password=yourpasswd            # 密码
#      - certd_typeorm_dataSource_default_database=certd                 # 数据库名
​
#                                    #↓↓↓↓ ----------------------------- 使用mysql数据库,需要提前创建数据库 charset=utf8mb4, collation=utf8mb4_bin
#      - certd_flyway_scriptDir=./db/migration-mysql                     # 升级脚本目录
#      - certd_typeorm_dataSource_default_type=mysql                     # 数据库类型, 或者 mariadb
#      - certd_typeorm_dataSource_default_host=localhost                 # 数据库地址
#      - certd_typeorm_dataSource_default_port=3306                      # 数据库端口
#      - certd_typeorm_dataSource_default_username=root                  # 用户名
#      - certd_typeorm_dataSource_default_password=yourpasswd            # 密码
#      - certd_typeorm_dataSource_default_database=certd                 # 数据库名
​
#         ↓↓↓↓ ---------------------------------------------------------  自动升级,上面certd的版本号要保持为latest
#  certd-updater:  # 添加 Watchtower 服务
#    image: containrrr/watchtower:latest
#    container_name: certd-updater
#    restart: unless-stopped
#    volumes:
#      - /var/run/docker.sock:/var/run/docker.sock
#    # 配置 自动更新
#    environment:
#      - WATCHTOWER_CLEANUP=true            # 自动清理旧版本容器
#      - WATCHTOWER_INCLUDE_STOPPED=false   # 不更新已停止的容器
#      - WATCHTOWER_LABEL_ENABLE=true       # 根据容器标签进行更新
#      - WATCHTOWER_POLL_INTERVAL=600       # 每 10 分钟检查一次更新
​
​
#    ↓↓↓↓ -------------------------------------------------------------- 启用ipv6网络,还需要把上面networks的注释放开
#networks:
#  ip6net:
#    enable_ipv6: true
#    ipam:
#      config:
#        - subnet: 2001:db8::/64
​

docker compose up -d

HeadScale服务

官网:https://headscale.net/stable/

搭建HeadScale服务

  1. 先建三个文件夹

    mkdir -p ./headscale/{config,lib,run}
    cd ./headscale
  2. 下载配置文件,并扔到/config目录中,最终呈现:./headscale/config/config.yaml,对配置文件稍作修改,结果如下:

    server_url: https://headscale.leeleo.cc
    listen_addr: 0.0.0.0:443
    metrics_listen_addr: 0.0.0.0:9090
    grpc_listen_addr: 0.0.0.0:50443
    tls_letsencrypt_challenge_type: TLS-ALPN-01
    tls_letsencrypt_listen: ":http"
    tls_cert_path: "/var/certs/headscale.leeleo.cc.pem"
    tls_key_path: "/var/certs/headscale.leeleo.cc.key"
    dns:
      magic_dns: false
  1. 新建docker-compose.yaml文件到./headscale目录,内容如下:

    services:
      headscale:
        # 手动指定版本号为:0.26.1
        image: docker.io/headscale/headscale:0.26.1
        restart: unless-stopped
        container_name: headscale
        # 若想远程访问需使用0.0.0.0而不是127.0.0.1
        # 这里开放80端,不然Lets Encript证书检报错很烦
        ports:
          - "0.0.0.0:8080:8080"
          - "0.0.0.0:9090:9090"
          - "0.0.0.0:5280:80"
        volumes:
          # Please set <HEADSCALE_PATH> to the absolute path
          # of the previously created headscale directory.
          - ./config:/etc/headscale
          - ./lib:/var/lib/headscale
          - ./run:/var/run/headscale
          - /app/docker/nginx/certs:/var/certs
        command: serve
  2. 部署-验证

    # 部署
    docker compose up -d
    # 跟踪日志
    docker logs --follow headscale
    # 检查容器状态
    docker ps
    # 验证headscale是否可用:
    curl http://127.0.0.1:9090/metrics
  3. 部署完成后需要创建个账户给后续客户端使用

    docker exec -it headscale headscale users create admin

这里基本上就算是完成了,官网上还提供了其他的指令,内容比较多,基本用不上,到这就基本满足咱的使用了

安装TailScale客户端

官网:https://tailscale.com/download

可以理解为TailScale是客户端,而HeadScale是服务端

安装TailScale客户端:不同端的下载地址

不同端连接自建HeadScale服务的方式(参考:https://tailscale.com/kb/1507/custom-control-server?q=headscale&tab=windows

  • Win:tailscale login --login-server=https://headscale.leeleo.cc

  • Android:

    1. 点击Tailscale应用程序右上角的用户个人资料图标以打开设置菜单。

    2. 如果您尚未登录任何其他尾网,请点击登录。菜单项。否则,点按已登录的用户。

    3. 点击右上角的菜单,然后选择使用备用服务器

    4. 输入自定义控制服务器URL并点击登录

完事之后,最终都会弹出一个网页,提供一个命令行,让在咱的服务端执行,示例如下:

tips:如果上面图片中的网址并未弹出,那么就需要确认下当前客户端的DNS是否需要清理一下了,最简单的办法是断开网络重连一下,不行就手动设置静态IP地址,指定DNS服务,然后再切回DHCP自动分配。

然后,去服务端执行,出现Node *** registered字样就算是完成注册了

root@orangepi5-plus:/app/docker/headscale# docker exec -it headscale headscale nodes register --user admin --key z3lUqUEZ3ydDsm9xQu3mGNDf
Node pc0003 registered


MQTT和WS通讯协议服务

❓为什么选择Mosquitto

在家庭环境的NAS中部署Mosquitto(MQTT服务器)是一个相当实用的选择,主要基于以下几个核心需求和优势:

🏠 家庭物联网中枢的核心价值

1. 解决设备"孤岛"问题

  • 统一通信协议:不同品牌的智能设备(如小米传感器、飞利浦灯泡、ESP32开发板等)可以通过MQTT这个通用协议进行通信

  • 跨平台集成:作为Home Assistant、Node-RED等智能家居平台的消息总线,实现设备联动

2. 数据隐私与本地控制

  • 完全本地化:所有设备数据在家庭内部网络流转,不依赖任何云服务

  • 避免厂商锁定:即使设备厂商的云服务停止,本地自动化仍然正常工作

  • 自定义规则:基于本地消息的自由自动化,不受云服务功能限制

💡 具体应用场景

场景类型

具体应用

优势

传感器网络

温湿度传感器、门窗磁感应、运动检测

低功耗、实时数据传输

设备联动

有人移动→开灯;温度过高→开空调

本地执行、响应迅速

状态同步

多个终端显示相同设备状态

发布/订阅模式天然支持

远程控制

手机App控制家中设备

通过内网穿透实现安全远程访问

下面这个表格详细对比了几款常见的MQTT服务端,你可以快速了解它们的特点。

服务端

核心优势

明显短板

推荐适用场景

资源占用

Eclipse Mosquitto

部署简单,社区活跃,资源消耗极低

单线程架构,扩展性有限(约10万连接),不支持集群

家庭物联网、嵌入式设备、资源受限环境

非常低

NanoMQ

多线程架构,能利用多核CPU,性能优于Mosquitto,支持MQTT over QUIC

相对较新,社区和资料不如Mosquitto丰富,配置稍复杂

高性能边缘网关、需要多核性能或现代协议特性的场景

EMQX

高并发(支持数百万连接),功能丰富(规则引擎、多协议网关),支持集群

部署和管理相对复杂,资源消耗较高

大规模企业级应用、车联网、工业物联网

较高

VerneMQ

分布式架构,支持水平扩展

项目已不积极维护,社区活跃度低,企业功能有限

不推荐用于新项目

中等

对于在NAS的Docker环境中部署,Mosquitto因其轻量和简单,是目前最省心的选择。

🐳Docker配置

使用 Docker Compose 部署服务时,我们通常通过一个 docker-compose.yml 文件来定义服务。这里是一个基础且功能完整的配置示例,你可以直接使用:

version: '3.8'  # 建议使用 3.8 或更高版本
services:
  mosquitto:
    image: eclipse-mosquitto:2  # 使用 Mosquitto 2.x 版本
    container_name: mosquitto_server
    restart: unless-stopped  # 设置自动重启
    ports:
      - "1883:1883"   # MQTT 协议默认端口
      - "9001:9001"   # WebSocket 协议端口,适用于浏览器等客户端
    volumes:
      - ./mosquitto/config:/mosquitto/config   # 挂载配置文件目录
      - ./mosquitto/data:/mosquitto/data       # 挂载数据持久化目录
      - ./mosquitto/log:/mosquitto/log         # 挂载日志目录
    networks:
      - mosquitto_net  # 自定义网络,便于其他容器通信
​
networks:
  mosquitto_net:
    name: mosquitto_network
    driver: bridge
  • 镜像:我们使用了官方的 eclipse-mosquitto:2 镜像。

  • 端口映射1883 端口用于标准的 MQTT 通信,9001 端口则用于支持 WebSocket 连接。

  • 数据卷:通过 volumes 将容器内的配置、数据和日志目录挂载到宿主机,这样即使容器被删除,你的这些重要文件也不会丢失。

  • 网络:创建了一个自定义的桥接网络 mosquitto_net。如果 Home Assistant 也运行在 Docker 中,并接入同一个网络,它们之间就可以直接使用容器名 mosquitto 进行通信,无需通过宿主机的 IP 地址。

📁 创建目录和配置文件

  1. 创建目录结构

    在你存放 docker-compose.yml 文件的同级目录下,执行以下命令来创建所需的目录:

    mkdir -p mosquitto/config mosquitto/data mosquitto/log
  2. 创建基础配置文件

    mosquitto/config 目录中创建一个名为 mosquitto.conf 的文件,并填入以下基本配置:

    # 启用数据持久化
    persistence true
    # 设置持久化数据存储位置
    persistence_location /mosquitto/data/
    # 设置日志输出文件
    log_dest file /mosquitto/log/mosquitto.log
    ​
    # MQTT 协议监听器 - 1883 端口
    listener 1883 0.0.0.0
    ​
    # WebSocket 协议监听器 - 9001 端口
    listener 9001 0.0.0.0
    protocol websockets
    ​
    # 允许匿名连接(初期测试用,后期建议关闭)
    allow_anonymous false
    ​
    # 指定密码文件
    password_file /mosquitto/config/passwd

🚀 启动与验证

  1. 启动服务docker-compose.yml 文件所在目录下,执行以下命令来启动 Mosquitto 服务:

    docker compose up -d
  2. 检查服务状态 运行 docker compose ps 可以查看服务状态,确认 Mosquitto 容器是否正常启动。

  3. 测试连接 你可以使用 MQTTX-1、桌面版 MQTT Explorer 等客户端工具进行测试。连接时,使用你 Docker 宿主机的 IP 地址,端口为 1883。由于我们目前允许匿名连接,通常可以直接连上。

🔒 增强安全性(可选但重要)

设置用户名和密码

  • 修改配置文件:编辑 mosquitto/config/mosquitto.conf 文件,禁用匿名访问并指定密码文件。

    allow_anonymous false
    password_file /mosquitto/config/passwd
  • 创建用户和密码:进入容器内部创建密码文件并添加用户(这里以用户名 myuser,密码 mypassword 为例)。

    # 进入容器
    docker exec -it mosquitto sh
    # 在容器内创建密码文件并添加用户
    mosquitto_passwd -b -c /mosquitto/config/passwd admin 123456
    # 退出容器
    exit
  • 重启服务:修改配置后,重启 Mosquitto 容器使配置生效。

    docker compose restart

🔧 Nginx配置

nginx.conf配置

events {}
​
# TCP/UDP代理配置 (用于MQTT 1883端口)
stream {
    
    upstream mosquitto_mqtt_server {
        server mosquitto_server:1883; # 替换为您的Mosquitto容器名
    }
​
    # mosquitto.leeleo.cc:8883  - MQTT over SSL
    server {
        listen 8883 ssl;
        proxy_pass mosquitto_mqtt_server;
        
        ssl_certificate /etc/nginx/certs/mosquitto.leeleo.cc.pem;
        ssl_certificate_key /etc/nginx/certs/mosquitto.leeleo.cc.key;
        
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5:!TLSv1.0:!TLSv1.1;
        
        # TCP代理相关配置
        proxy_connect_timeout 1s;
        proxy_timeout 1h; # MQTT连接通常需要长时间保持
        proxy_buffer_size 4k;
    }
}
​
http {
    resolver 127.0.0.11 valid=10s; # 使用Docker内置DNS解析器
    
    upstream mosquitto_ws_server {
        server mosquitto_server:9001; # 替换为您的Mosquitto容器名
    }
​
    # mosquitto.leeleo.cc:443 -> 转发到Mosquitto的9001
    server {
        listen 443 ssl;  # Nginx在9001端口监听SSL
        server_name mosquitto.leeleo.cc;
​
        ssl_certificate /etc/nginx/certs/mosquitto.leeleo.cc.pem;
        ssl_certificate_key /etc/nginx/certs/mosquitto.leeleo.cc.key;
        ssl_protocols TLSv1.2 TLSv1.3;
​
        location / {
            proxy_pass http://mosquitto_ws_server;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
​
}

docker-compose.yml配置

services:
  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "80:80"
      - "443:443"
      - "8883:8883"
    networks:
      - mosquitto_network
    dns:
      - 223.5.5.5
      - 223.6.6.6
      - 8.8.8.8
      - 8.8.4.4
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./certs:/etc/nginx/certs
    restart: unless-stopped
networks:
  mosquitto_network:  # 声明  mosquitto_network 网络为外部网络
    external: true

🔗 客户端连接方式

配置完成后,客户端应该这样连接:

  • MQTT客户端: mqtts://mosquitto.leeleo.cc:8883

  • WebSocket客户端: wss://mosquitto.leeleo.cc:443