步骤/目录： 1.背景介绍 2.拉取nextcloud镜像 3.nextcloud的基本配置 4.其它问题 （1）外部存储写入权限本文首发于个人博客https://lisper517.top/index.php/archives/1848/，转载请注明出处。本文的目的是使用nextcloud搭建私人网盘，类似一个私人的百度云盘。本文写作日期为2024年8月17日，在Ubuntu 22.04LTS系统演示。1.背景介绍目前市面上主流的网盘有百度、阿里、夸克、天翼、115等，但是最大的问题是基本都要买VIP才能有较快的下载速度，而且一些私有的敏感文件也不宜放在公共网盘上，比如你的公司和百度在同一个项目中竞标，那总不能把标书放在百度网盘里，万一泄露了。本文将使用nextcloud搭建私有网盘。除了nextcloud，还可选择owncloud、sealife等。2.拉取nextcloud镜像在2024年6月左右，docker官方对中国ip采取了封禁的措施（据说是由于中华有为。诶，美团实在是太坏了），所以目前大陆无法安装docker、docker-compose，也无法从docker官方仓库拉取镜像。解决方法见 这篇文章 ，这里摘取重要的说。（1）安装dockercurl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg #添加阿里云的Docker GPG密钥 echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null #配置阿里云的Docker APT源 apt-get update apt-get install docker-ce docker-ce-cli containerd.io docker -v docker-compose -v（2）更换docker源或者翻越目前无法从docker官方仓库拉取镜像（据说是由于华晨宇，详情见 github项目 ，华晨宇手机可能无法打开），所以只能换为国内docker镜像仓库，或者翻越，笔者建议直接翻越，更简单一些（见 Docker实践——如何查阅wiki百科及V2Ray 。但是这篇文章中使用的v2rayA也是docker，所以还是要先改docker源）。更换docker源的操作具体如下：vim /etc/docker/daemon.json写入：{ "registry-mirrors": [ "https://hub-mirror.c.163.com", "https://mirror.baidubce.com", "https://registry.docker-cn.com", "https://dockerhub.azk8s.cn", "https://mirror.ccs.tencentyun.com", "https://registry.cn-hangzhou.aliyuncs.com", "https://docker.mirrors.ustc.edu.cn", "https://docker.m.daocloud.io", "https://noohub.ru", "https://huecker.io", "https://dockerhub.timeweb.cloud", "https://dockerhub.icu", "https://docker.anyhub.us.kg", "https://docker.1panel.live" ], "features": {"containerd-snapshotter": true}, "log-driver": "json-file", "log-opts": { "max-size": "20m", "max-file": "3" } } }registry-mirrors 里列举了一些国内能连的镜像，但是最近也被封禁的厉害，说不定什么时候就连不上了（所以尽量翻越，更省事）。"features": {"containerd-snapshotter": true} 则是开启容器快照功能，目的是使得拉取镜像时能断点续传（参考 github问题 ），但是这个选项需要更换docker引擎，之前的镜像都要重下，所以最好是一开始就使用这个设置。最后的log则是设置了一下log文件的大小，防止docker的log塞满硬盘。最后更新设置，重启docker：systemctl daemon-reload systemctl restart docker docker info #输出结果 ...... ...... Registry Mirrors: https://hub-mirror.c.163.com/ https://mirror.baidubce.com/（3）拉取nextclouddocker pull nextcloud2.nextcloud的安装参考 nextcloud的官方镜像网址 。mkdir -p /docker/nextcloud/data/nextcloud mkdir -p /docker/nextcloud/data/mysql cd /docker/nextcloud vim docker-compose.yml写入如下内容：services: nextcloud_mysql: image: "mysql" container_name: "nextcloud_mysql" command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW volumes: - ./data/mysql:/var/lib/mysql environment: - MYSQL_ROOT_PASSWORD=mysql的root密码 - MYSQL_USER=mysql用户名 - MYSQL_PASSWORD=mysql用户的密码 - MYSQL_DATABASE=nextcloud restart: always nextcloud: image: "nextcloud" container_name: "nextcloud" ports: - 80:80 environment: MYSQL_USER: mysql用户 MYSQL_PASSWORD: mysql用户的密码 MYSQL_DATABASE: nextcloud MYSQL_HOST: nextcloud_mysql NEXTCLOUD_ADMIN_USER: NC管理员用户名 NEXTCLOUD_ADMIN_PASSWORD: NC管理员密码 NEXTCLOUD_TRUSTED_DOMAINS: 你为nextcloud准备的域名 volumes: - "你为nextcloud准备的路径:/var/www/html" depends_on: - nextcloud_mysql restart: always实际存储的网盘文件在 /var/www/html/data 下，最好为nextcloud准备一个大一点的硬盘。如果想简单一点，可以只写：services: nextcloud: image: "nextcloud" container_name: "nextcloud" ports: - 80:80 volumes: - "./data/nextcloud:/var/www/html" restart: always但是后面就要登录后手动设置。最后运行即可：cd /docker/nextcloud docker-compose config docker-compose up3.nextcloud的基本配置nextcloud的镜像分为fpm版和apache版，apache版就是自带了网页服务（无HTTPS加密，需要套一层反代），和typecho一样。 docker pull nextcloud 默认下载apache版，然后自己配置一下反代（笔者使用IPv6+DDNS，用NPM管理，见 IPv6与DDNS 和 可视化管理Nginx-Nginx Proxy Manager ）。如果刚才你使用了最简yml，这里就需要登录网页端，设置管理员及密码，使用的数据库（默认sqlite不用其它配置，但提醒sqlite勿用于生产环境），使用的域名。除了网页客户端，nextcloud还有PC、MAC、安卓端（谷歌商店）、iOS端，可自行下载。4.其它问题（1）外部存储写入权限nextcloud默认把文件存储到宿主机上，但有时宿主机空间不够。笔者的解决方法是宿主机连接局域网内的Samba，并把宿主机上的smb文件夹映射到docker-nextcloud（但是最后碰到了无解的目录权限问题）。在nextcloud容器的yml文件中增加一行映射：volumes: - "你为nextcloud准备的路径:/var/www/html" - "你为nextcloud准备的扩展存储:/external_storage"网页登录nextcloud，左键单击右上角头像，选择 应用 - 您的应用 ，下拉找到 External storage support ，把它启用。然后在头像处选择 管理设置 - 外部存储 ， 目录名称 是该连接的名称（可以随便写）， 增加存储 选择本地， 地点 填 /external_storage 即可， 可用于 选择 All people ，或者你也可以指定一个用户组。此时nextcloud已经可以读取外部存储目录内的文件，但没有写入权限。进行如下操作：docker exec -it nextcloud bash cd /external_storage ls -al显示：total 4 drwxr-xr-x 2 root root 0 Aug 28 03:07 . drwxr-xr-x 1 root root 4096 Aug 28 02:56 ..docker挂载卷是挂到root名下的，但nextcloud是执行在www-data用户下的（宿主机ubuntu为www-data，宿主机centos则是apache）。所以需要把目录权限改一下，可以进入容器改，也可以在yml中改（参考 stackoverflow问题 。）：command: > bash -c 'chown -R www-data:www-data /external_storage && /entrypoint.sh apache2-foreground'如果你的外接存储是在宿主机上，到这一步应该就可以了。但是笔者的外接存储是局域网内的smb分享给宿主机，宿主机又映射到docker-nextcloud，所以这个目录无法更改所属的用户及用户组，又没办法将www-data添加到root组里，因此这个问题目前应该是无解的。你可以在把 /external_storage 这个外部存储改成只读（因为它事实上就是只读）。如果有需要上传的文件，可以通过nextcloud网页暂时上传到宿主机，在宿主机上运行一个脚本，比如每天凌晨4点将宿主机上的部分文件复制到samba中：crontab -e 0 4 * * * /usr/bin/cp /docker/nextcloud/data/nextcloud/data/nextcloud用户名/files/smb_sync/* 你为nextcloud准备的扩展存储然后通过nextcloud网页将宿主机上的文件手动删除。唯一的缺点是网页无法删除扩展存储中的文件。如果你不想用脚本，恐怕只能用nextcloud而非docker-nextcloud。安装nextcloud后配置samba见 官方文档 。
步骤/目录： 0.raid介绍 1.背景介绍 2.r730xd的详细参数与扩展 3.esxi系统的安装 4.esxi虚拟机安装TrueNAS 5.esxi虚拟机安装Win10 6.esxi虚拟机安装Ubuntu 7.其它本文首发于个人博客https://lisper517.top/index.php/archives/1562/，转载请注明出处。本文的目的是使用r730xd组建NAS。本文写作日期为2024年7月14日，参考文章将会在正文中列出。0.raid介绍raid技术可以将多块物理硬盘合并成一个存储单位使用，比如说在电脑上显示为1个盘符。raid最大的作用是提升安全性或者读写性能。常用的raid如下（来自于 这篇文章 ）：RAID 0：条带化（数据分块）但没有冗余，提供较高的读写性能。 RAID 1：镜像，数据完全复制到另一个驱动器，提供容错能力。 RAID 5：条带化加分布式奇偶校验，提供数据冗余和读取性能。 RAID 6：类似于RAID 5，但提供更高级别的容错能力。 RAID 10：RAID 1+0，将RAID 1镜像组合成RAID 0条带化，提供较高的容错能力和读写性能。 RAID 50：RAID 5组合成RAID 0，提供较高的性能和容错能力。 RAID 60：RAID 6组合成RAID 0，提供更高级别的性能和容错能力。总的来说，追求简单就raid1（至少2块硬盘），追求速度就raid10（至少4块硬盘），raid1与raid10都只能使用一半的硬盘空间。想提高读取性能、空间利用率、容错率就raid50、raid60。另外需要注意的是，大量数据时，raid5硬盘恢复的失败率会上升。软硬raid的区别：（1）软raid不需要专门的硬件设备，可以在不同的操作系统中读写数据；缺点是消耗CPU、内存，高负载时性能不如硬raid。（2）硬raid需要专门的阵列卡，读写性能高；缺点是必须特定的硬件才能读写数据。另外一个重要的区别是，用软raid时硬盘无法作为系统盘，只有硬raid才能把系统盘也组raid。IT（initiator target）即直通模式，阵列卡只作为总线适配器，把硬盘直接交给操作系统处理，方便做软raid。一般是便宜的阵列卡支持IT模式。1.背景介绍在笔者之前的文章中，曾经用 Ubuntu + samba 的方式组建NAS，使用的硬件为 2盘位硬盘座 + 树莓派 + UPS （见 树莓派+Samba+frp搭建NAS（网络云存储） ），后来将树莓派改成了旧笔记本。这套配置的主要问题有：（1）树莓派的CPU不够强，旧笔记本的CPU可以、但散热不行，所以都无法运行一些其它占资源的东西，比如模拟器多开。（2）扩展性的限制，硬盘座需要通过USB3.0接到树莓派或者笔记本上，想再加硬盘就要再买硬盘座，但USB接口是比较少的。如果换大型硬盘柜则USB接口又容易发热。（3）达不到AIO的要求。AIO即all in one，用一台主机实现NAS、远程云游戏主机、网页服务器等多种功能，树莓派性能孱弱，旧笔记本又没有雷电接口（不能外接显卡）。综合下来，最好的选择是换一台淘汰的存储服务器，能插显卡的。买旧服务器唯二的缺点是：风扇噪音大（一般在60-100dB），耗电高。经过一系列比对，笔者最终在黄鱼上自提购买了Dell的r730xd，原因如下：（0）github上有针对Dell服务器的风扇调节工具，可以把风扇噪音降低到40dB，放在卧室也不影响入睡。作为对比，耳语大概在30-35dB。（1）耗电量，与卖家当面沟通，双CPU（2630L）、12硬盘，正常跑一些服务的情况下，功率为200W，不关机的话每月144度电，可以接受（按0.5计算，约72元/月，和便宜的云服务器差不多）。（2）保有量大，相关资料多，问题好解决，而且Dell的手册也比较详细。（3）工业设计成熟，看起来有一种信息技术革命的美感，赏心悦目。r730xd在2023年左右经过了一些炒作，价格略上涨，涨价前准系统据说只要￥650。笔者购买时￥1550，胜在卖家已经调好了，包括2颗2630L的CPU，4根2133频率的16GB、ECC内存，1张双千兆电口+双万兆光口的网卡（intel X520/I350），H330 mini阵列卡，1个750W电源，3张PCIe扩展卡，iDrac已授权，另外￥400收了卖家的单风扇1050ti。如果不是自提，最好在发货前让卖家拍照，因为对于准系统的定义不太一样。另外自购了2690v4的CPU（￥330），两个千兆光转电模块（￥150），750W电源1个（￥62），额外一张H330 mini卡备用（￥50，后来发现自带的H330 mini已经刷了直通模式，就买了个没刷直通的），硬盘用东芝的N300-16T（618活动￥1889）。2.r730xd的详细参数与扩展关于r730xd的详细介绍，见 参考文章一 和 参考文章二 ，实物介绍见 b站视频 ，官方手册见 r730xd官方手册 。笔者挑一些重点说：（1）存储，r730xd有几个版本，前面板可以放12个3.5英寸硬盘或者24个2.5寸，后面板有2个2.5寸盘位。内部可以扩展出2或4或6个3.5寸盘位（也可能是2.5寸？），但是散热不佳、需要风扇拉满。所以家用一般就是12个3.5寸盘位+后面板2个2.5寸。笔者本打算2个2.5寸用SSD，组RAID1装ESXI和其它系统镜像，但是发现阵列卡只连到了前面板，那么就需要1个能接PCIe的阵列卡 + mini SAS 8643连接线，再分线到后面板，比较麻烦（见 b站视频 ）；剩下的所有3.5寸组RAID1装一般文件，因为对读取速率要求不高，搞RAID10之类的太复杂了（单纯组raid1，一块硬盘坏了，把好的硬盘拿下来就能读，不需要花时间恢复数据，还可能恢复失败）。（2）内存，24条内存插槽，最高支持2400频率的DDR4，3072GB内存容量（24*128GB）。但是注意V4的CPU才能支持2400，V3的CPU最高只有2133。E5的CPU都很便宜，完全没必要省这个钱。另外，插内存时有讲究，单CPU与双CPU也有区别，详见 这篇文章 。简要来说，用同规格的内存，大小可以不同。如果单CPU，就按A1、A2、A3……顺序插；如果双CPU，就按A1、B1、A2、B2……插（标号在内存插槽旁边）。（3）CPU，首选E5-2640 V4，追求更高的就上E5-2690 V4。（4）阵列卡，可用H330 MINI、H730 MINI、H730P MINI，或者通过提升卡的PCIe装其它支持PCIe的阵列卡。数字越大越贵，只有H330是没有电池、缓存的，但是H330支持直通模式（需要自己刷固件，见 b站视频 ）。阵列卡的作用是组raid。（5）网卡，可用博通BCM5720（四口千兆）、Intel 99GTM（双千兆I350电口+双万兆X520电口）、Intel C63DV（双千兆I350电口+双万兆X520光口），其它还有很多。（6）idrac，即Dell的ipmi。ipmi是服务器的一种功能，通电后ipmi就会打开，然后可以通过ipmi远程开关机或管理服务器。大部分r730xd的idrac都是已注册的enterprise版，如果未注册就去tb花80激活一下。（7）提升卡，可插3张raiser提升卡进行扩展，提供额外的x8、x16的PCIe槽，可装显卡、网卡等。（8）显卡，装在提升卡上（官方论坛说不支持显卡，其实是可以装的）。如果买r730，能装2块大显卡，最大可以 32*4*12cm（最多同时装4个单宽显卡或2个双宽显卡）；r730xd则稍逊一筹，最多3个单宽显卡或1个双宽显卡。另外需要注意显卡是否需要额外供电，提升卡2、3都可以为显卡供电，最大可支持2张300W显卡（用Tesla显卡还要用第三方转接线，因为线序不同）。安装显卡可参考 b站视频 。（9）电源，有495W、750W、1100W三种规格。可以装1或2个电源，双电源会稍微增加功率，但1个电源坏了可迅速切换到另一个电源（需要设置电源设备冗余，2个电源必须相同）。电源的风扇偶尔会突然开启3秒左右，这是怕服务器的风扇不足以给电源散热而设置的策略，是正常的。（10）风扇，共有6个，适配的比较多。（11）vFlash，r730xd的在后面板的2.5寸盘位上方。作用是插入SD卡，在系统挂了等极端情况下从SD卡引导启动。这个对于普通家用的意义不大。3.esxi系统的安装参考了 b站视频 。（1）准备工作1）在第一次安装系统前，如果你不知道服务器idrac的ip地址，则需要配一台VGA接口的显示器（或者VGA转HDMI线。但是VGA转HDMI线有时候用不了，建议直接买一台小的VGA接口显示器和VGA线），然后先设置后面的静态ip，再从网页访问idrac进行剩余的设置。2）下载驱动等文件，到 Dell官网 下载针对r730xd的一些驱动文件，包括idrac（文章写作时最新是2.86.86.86），ESXI（7.0 U3，注意选择下载iso格式），BIOS（2.19.0）。其实只下idrac和ESXI就行了，其它东西可以在后面一键更新。3）登录idrac（注意是 https://idrac的IP ），默认账号密码为root:calvin，或者问卖家。在 idrac设置 - 网络 里，将IPv4、v6打开，都启用DHCP，然后在路由器里设置静态ipv4地址。你也可以在idrac里设置静态ip，但笔者觉得在路由器里统一管理更方便。4）更新idrac，在 idrac设置 - 更新与回滚 里，使用刚才下载的最新版idrac更新（需要注意的是，如果你的idrac版本过旧，则可能需要逐个版本更新idrac）。5）降低风扇噪音，到 github 下载最新版的DellEmcFansController。目前是1.0.2，甚至可以对每个风扇分别调速。一般设置到25%就比较合适。6）idrac的其它设置，见原视频。主要是 idrac设置 - 网络 里的几项：启用NIC-勾选 NIC选择-专用 自动协商-打开 启用 LAN 上的 IPMI-勾选 信道权限级别限制-管理员 启用 VLAN ID-不勾选 在 idrac设置 - 用户验证 里，更改root密码 在 服务器 - 虚拟控制台 里，把 插件类型 选择为 HTML57）一键更新固件。在idrac的 服务器 里，启动虚拟控制台（服务器的远程桌面），并打开电源（打开/关闭电源），启动过程比较慢，不停按F10以进入Lifecycle Controller。选择 获取最新固件 - 网络共享(CIFS、NFS、HTTP或HTTPS服务器) - HTTPS 。笔者尝试时显示 “IP地址或共享名称无效” ，应该是被墙了，换个时间或者fq。8）格式化硬盘。将准备使用的硬盘用diskgenius等软件格式化为ext4文件系统，装到r730xd上。（2）安装esxi在虚拟控制台的右上角有 虚拟介质 ，把刚才下的ESXI的iso镜像映射为CD/DVD，然后重启服务器，再次进入Lifecycle Controller。选择 OS部署 - 部署OS ，不组RAID（如果后面板作为系统盘且也想组raid，则需要多加一块能接PCIe的阵列卡，专门分到后面板）， 引导模式 选 BIOS ，可用的操作系统 选 Any Other Operating System ， 手动安装 ，介质选映射的ESXI。等待一段时间后，显示蓝底白字的Boot菜单，不需要操作，自动从ESXI引导，再等待ESXI加载。完成后，根据提示分别按Enter、F11，选择安装盘，键盘选择 US Default ，设置root密码（需要设置的复杂一点），最后F11确认。等待安装完成后，重启。可以注意到重启界面提示esxi在60天后需要购买许可证，这将在后续进行处理。另外需要注意，esxi本身只有不到2GB，但是默认会占用系统盘的119GB作为虚拟闪存。如果你的系统盘比较小，在前文的b站视频中有介绍如何减少系统保留区。（3）esxi的初步设置服务器启动esxi系统后按F2，输入root密码进入设置，选择 Configure Management Network ，设置IPv4（用空格键选择），在这里设置静态IPv4（或者在路由器里设置静态IP也行），并打开IPv6、DHCPv6；在 Network Adapters 里选择管理esxi时用哪个网口。退出到设置页首，进入 Troubleshooting Options ，开启SSH功能。最后，通过此步设置的静态IPv4地址访问esxi网页端（同样是https）。在 主机 - 管理 - 许可 - 分配许可证 中解除esxi的60天试用限制，可以自行搜索，或尝试以下的许可证（建议就用vSphere ESXi 7.0 Enterprise Plus的4个许可证）：vSphere ESXi 7.0 Enterprise Plus ======================================= JJ2WR-25L9P-H71A8-6J20P-C0K3F HN2X0-0DH5M-M78Q1-780HH-CN214 JH09A-2YL84-M7EC8-FL0K2-3N2J2 JA0W8-AX216-08E19-A995H-1PHH2 ======================================= vCenter 7.0 Standard 104HH-D4343-07879-MV08K-2D2H2 410NA-DW28H-H74K1-ZK882-948L4 406DK-FWHEH-075K8-XAC06-0JH08 ======================================= VSAN 7.0 Enterprise Plus HN0D8-AAJ1Q-07D00-6U924-CX224 50008-221DH-M7E99-A9CKM-A1030 HN0NH-62051-H75E9-P38RM-0H870 ======================================= vSphere 7 Enterprise Plus with Add-on for Kubernetes J1608-4GJEQ-071L8-9VA0H-2MUK6 M10DH-8YL47-474L1-DV3U0-8H054 MM4MR-2G005-H7039-JVCAP-2RAL8 ======================================= VMware Horizon 7 Enterprise 100 CCU(s) 9H0AK-4Y192-H8JAR-0H7R0-1RZJM笔者提前将硬盘格式化为ext4格式，将r730xd关机，插上硬盘并开机。在esxi的 存储 里，点进该硬盘， 新建数据存储 ，为硬盘取名， 使用全部磁盘 、 VMFS6 。（4）VMware Workstation Pro可以从网页管理ESXI，也可以使用VWP、从桌面端管理ESXI。截至2024年04月27日，最新版本为17.5.2，官方下载地址为 VWP-17.5.2 。17大版本的激活码有：MC60H-DWHD5-H80U9-6V85M-8280D 4A4RR-813DK-M81A9-4U35H-06KND NZ4RR-FTK5H-H81C1-Q30QH-1V2LA JU090-6039P-08409-8J0QH-2YR7F 4Y09U-AJK97-089Z0-A3054-83KLA在网页端管理ESXI可能会有一些问题，笔者遇到的是无法给已经创建的虚拟机添加新标准硬盘（添加新标准硬盘后无法点击 保存 按钮）。网页端有问题的话可以改用桌面端试试。4.esxi虚拟机安装TrueNAS（1）TrueNAS的安装这里参考了 这篇文章 。首先到 TrueNAS官网 下载TrueNAS-core，这里选择最新的TrueNAS-13.0-U6.2。如果下的太慢也可以选择到 freenas镜像站 下载。如果都下的很慢就用IDM试试。下载完成后，到esxi网页端，点击 存储 - 数据存储浏览器 ，进入esxi的文件管理器，新建文件夹并把TrueNAS镜像放到esxi里。进入 虚拟机 - 创建/注册虚拟机 ，如下选择：创建新虚拟机 客户机操作系统系列 选择 其他 客户机操作系统版本 选择 FreeBSD 13或更高版本（64），因为用的TrueNAS 13 CPU选择6核，这个看自己 内存至少16GB 硬盘1设置50GB，这是装系统的 添加两块存储盘（ 添加硬盘 - 新标准硬盘 ） CD/DVD驱动器1 选择 数据存储ISO文件 ，选择TrueNAS镜像 在 虚拟机选项 里，确认 引导选项 - 固件 是 BIOS创建虚拟机后，在 虚拟机 里打开电源， Boot TrueNAS Installer ，选择 Install/Upgrade ，用空格键选择装系统的位置（50G硬盘），设置root密码， Boot via BIOS 。安装完成后选择 Reboot System ，在控制台界面会输出局域网ip，可浏览器访问、管理TrueNAS。记得在路由器里设置静态ip。（2）TrueNAS的基础设置在 System - General 里，把语言设置为 Simplified Chinese ，时区设置为 Asia/Shanghai 。在 服务 里，把SMB打开，并勾选 自动运行 （开机自启动）。在 系统 - 电子邮件 里，可以设置SMTP发送邮件。在 系统 - 更新 里，把自动更新关闭。在 存储 - 池 里，创建新池，可能会发现如下提示：Warning: There are 2 disks available that have non-unique serial numbers. Non-unique serial numbers can be caused by a cabling issue and adding such disks to a pool can result in lost data.这是因为笔者的H330Mini刷了直通模式（参考 proxmox论坛），但esxi没告诉TrueNAS硬盘的序列号。在esxi中如下操作（参考 truenas论坛 ）：关闭TrueNAS虚拟机，选择TrueNAS虚拟机，点击 编辑 - 虚拟机选项 - 高级 - 配置参数 的 编辑配置... ，添加一项键值对，即 disk.EnableUUID=true然后重启TrueNAS，在 存储 - 磁盘 中选择对应磁盘并 编辑磁盘 ，可以看到其序列号。另外需要提醒一下，如果阵列卡没刷直通模式，并且用阵列卡组raid，那么raid在阵列卡这一层就组好了（硬raid）。比如你组了硬raid1，TrueNAS就只能看到1个硬盘，只能用条带模式。如果没有非常非常高的硬盘吞吐量，建议还是在TrueNAS层面组软raid。继续创建池。选择对应的硬盘后， 数据VDev 下方为 镜像Mirror ，即raid1。 条带Stripe 是raid0，如果有3块以上硬盘还可能显示RAIDZ1（raid5，一重奇偶校验，至少三块硬盘）、RAIDZ2（raid6，双重奇偶校验，至少四块硬盘）、RAIDZ3（TrueNAS独特的三重奇偶校验，至少五块硬盘）。创建时也会删除硬盘上原有内容。在 池 中，选择刚才创建的池的右侧的附加菜单（竖着的3个点）， 添加数据集 （数据集相当于文件夹）。在 账户 - 用户 里新建一个用户及配套的用户组，把该用户的主用户组改成刚新建的用户组。对刚才创建的数据集编辑权限，把 所有者 中的用户和群组改成刚新建的，并且 Apply User 、 Apply Group ，其它选项如图：把everyone删掉。最后打开windows的SMB共享：即可在windows系统访问硬盘。（3）TrueNAS的使用问题①一次断电后重启，磁盘仍然能连接上，但存储池挂了。使用如下命令：zpool import -m -R /mnt/ "池名" 提示有I/O错误，可以恢复到之前一个时间点。按照提示使用：zpool import -F 池名存储池成功上线，然后再次重启。5.esxi虚拟机安装Win10到微软官网下载工具，用该工具可以下载Win10的iso镜像，然后安装。为了玩游戏，可以显卡直通，在esxi网页端， 管理 - 硬件 中筛选支持直通的设备，可以看到显卡，将其切换直通（勾选显卡会自动勾选Audio，应该是显卡带的声卡）。在Win10虚拟机创建时（或者创建后也可以修改），选择 添加其他设备 - PCI设备 ，把显卡和声卡都添加上；在内存中把划分给Win10的内存全部预留并锁定。编辑参数、添加键值对 hypervisor.cpuid.v0=FALSE ，作用是不让显卡知道是在虚拟环境中运行，一般用于独立显卡，否则用不了驱动。另外，可以开启一个网口直通给Win10使用，以使用IPv6。6.esxi虚拟机安装Ubuntu这里选择的是Ubuntu-22.04 LTS，和上面的步骤差不多（参考 这篇文章 ），如果想给Ubuntu直通显卡，可参考 这篇文章 ，笔者尝试后无法装驱动。安装完成后，Ubuntu会显示无法卸载 /cdrom 挂载点，直接关闭电源，重启Ubuntu前把 CD/DVD驱动器1 的连接断开。最后，目前docker对我国关闭了服务。如果需要安装docker，可以参考 这篇文章 ，或者翻越。7.其它到这里已经差不多了，truenas做NAS，win10做云游戏主机，ubuntu做网页服务。如果有需要还可以装OpenWRT做软路由，装CentOS玩，本文就不一一介绍了。
步骤/目录： 1.准备工作 （1）另一台路由器 （2）CR6609降版本 （3）下载文件 2.开启SSH 3.连接SSH 4.刷入pandora 5.刷入breed 6.刷入AX1800固件本文首发于个人博客https://lisper517.top/index.php/archives/554/，转载请注明出处。本文的目的是在小米CR6609路由器上开启SSH，刷入pandora、breed固件，最后刷Redmi AX1800的固件。本文使用的方法应该也适用于所有CR660X的路由器。本文写作日期为2024年2月8日，主要参考了 参考文章一 和 参考文章二 。1.准备工作（1）另一台路由器需要另一台刷好openwrt的路由器（最好reset一下）。也可以用虚拟机，但是后面的流程可能有一些不同，笔者没有试过。（2）CR6609降版本本文使用的开启SSH的方法适用于1.0.103及以下的版本，所以最好回退CR6609版本。笔者实验时不知道当前固件版本，也没找到旧版本固件，测试时CR6609后台显示版本号6.0.xxx，这个6开头的版本可能对应某个1.0.103以后的版本。（3）下载文件两位原贴主提供了网盘：百度网盘一 （提取码: love）百度网盘二 （提取码: pvg4）阿里云盘下载3个网盘中的所有东西。或者直接下载 笔者提供的压缩包 。2.开启SSH笔者在每一步操作后会加上自己的理解，不一定对。openwrt路由器通电并用LAN口连接电脑，用WinSCP将 xqsystem.lua 文件上传到 /usr/lib/lua/luci/controller/admin 下，注意用SCP协议。（上传脚本）网页登录openwrt后台，在 Network - Interfaces 中 Edit 第一个 LAN ，将 IPv4 address 改为 169.254.31.1 ；然后关闭DHCP功能，该 LAN 的 DHCP Server - General Setup 中，勾选 Ignore interface ，最后 Save & Apply 。这之后需要换到 169.254.31.1 以操控该路由器。（ 169.254.31.1 可能是小米路由器留下的后门）在win10电脑中， 设置 - 网络和Internet - 状态 - 更改适配器选项 中，选择连接到openwrt路由器的网卡，右键单击，选择 属性 - 网络 页，找到 Internet 协议版本 4 (TCP/IPv4) ，更改它的属性，从 自动获得IP地址 改为 使用下面的IP地址 ， IP地址 填 169.254.31.3 ， 子网掩码 为默认的 255.255.0.0 即可。（保证等一下CR6609获得相同的IP）在 Network - Wireless 中，更改默认的名为 OpenWrt 的Master网络，ESSID（wifi名）改为 abc ， wifi密码改为 12345678 ，最后 Save & Apply 。如果不只一个Master网络（比如一些路由器有2.4G、5G两个甚至更多wifi），都需要改一下，但是各个wifi不要重名。（CR6609需要连接到openwrt路由器的wifi。同时确保等下没有CR6609之外的其它设备连接openwrt路由器）浏览器访问 http://169.254.31.1/cgi-bin/luci/api/xqsystem/token ，返回如下：{"token":"; nvram set ssh_en=1; nvram commit; sed -i 's\/channel=.*\/channel=\"debug\"\/g' \/etc\/init.d\/dropbear; \/etc\/init.d\/dropbear start;","code":0}将电脑与openwrt的连接断开，电脑从 169.254.31.3 改回 自动获得IP地址 。openwrt路由器不要断电。（测试脚本。 ssh_en=1 表示ssh已经enable， "code":0 是成功的状态码）电脑与CR6609的LAN口连接，登录路由器后台。笔者的后台是 192.168.31.1 ，这里以及后续的后台IP请自行查看是否需要更改，比如其它的CR660X可能是 192.168.1.1 、 192.168.2.1 、 192.168.10.1 。浏览器的网址会变成：http://192.168.31.1/cgi-bin/luci/;stok=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/web/home#router这样的形式。记住这个32位的stok（该stok在每次登录CR6609后台时都会变化）。浏览器访问：http://192.168.31.1/cgi-bin/luci/;stok=（STOK）/api/misystem/extendwifi_connect?ssid=abc&password=12345678将网址中的 （STOK） 改为刚才的stok。等待一会儿后，显示：{"msg":"connect succces!","code":0}有可能显示其它的，比如：提示1646的，请检查下第一步的DHCP是否关闭提示1619的，请检查第一步IP是否设置正确，或者openwrt路由器下连接了其他设备提示1655的，请再来一次，因为这一步确实有小概率会失败。最后访问：http://192.168.31.1/cgi-bin/luci/;stok=（STOK）/api/xqsystem/oneclick_get_remote_token?username=xxx&password=xxx&nonce=xxx返回：{"token":"; nvram set ssh_en=1; nvram commit; sed -i 's/channel=.*/channel=\u0022debug\u0022/g' /etc/init.d/dropbear; /etc/init.d/dropbear start;","code":0}最后的 "code":0 说明CR6609的SSH开启成功。到这一步时，已经可以关闭openwrt路由器了。3.连接SSH通过PuTTY或者MobaXterm等SSH工具登录CR6609，但是还需要得到root密码。首先看CR6609背面的标签，使用管理密码登录。笔者就是通过管理密码成功登录root；如果不行，到 这个网址 ，通过CR6609背面的SN号，计算并得到root密码。如果访问不了，请用bing自行搜索 小米路由器 SN root 。4.刷入pandoraSSH连接到CR6609后，将压缩包内的 pb-boot.img 文件放到 /tmp 下，然后进行以下操作：mtd write /tmp/pb-boot.img Bootloader reboot这之后会断开连接。然后需要拔掉CR6609的电源，用牙签顶住reset键不放，接上电源8s后放开reset，浏览器登录 192.168.1.1 进入PandoraBox。5.刷入breed先刷上breed。breed又称不死鸟，给刷机后的路由器多一层保障。在潘多拉里 选择文件 来上传固件，上传 breed-mt7621-xiaomi-r3g.bin ，然后 恢复固件 即可。路由器会自动重启，等待一会儿后访问 192.168.1.1 可看到breed界面。6.刷入AX1800固件笔者需要小米路由器AP组网。原版的CR6609对mesh组网支持不好（官方固件没办法做子路由），最佳的选择是刷红米AX1800的固件。三家运营商送的CR660X路由器其实就是 Redmi AX1800 的改版，区别有：红米AX1800是白壳，CR660X是黑壳； 前者内存是128MB，后者是256MB（运营商送的路由器反倒升级了）；目前小米商城已下架红米AX1800，二手价格则是￥70左右。一般来说 小米路由器官网 上的 Redmi AX1800 ROM也适用于CR660X，如果用起来有问题（网口速度下降之类的），可以使用笔者包里的1.0.88旧版本（1.0.93则是本文写作时的最新版本固件）。总之，刷好潘多拉和不死鸟后，现在需要刷红米AX1800的系统。进入 192.168.1.1 的breed界面，先备份一下目前的系统（Bootloader、epprom）；然后选择 固件更新 - Bootloader ，选择包里的 Bootloader-CR6608.bin （这个应该对CR660X都通用），勾选 自动重启 ，点击 上传 ，这样就刷好CR6608的Bootloader。然后使用 小米路由器修复工具 （注意它会被杀毒软件报错），根据它的提示，按照如下步骤操作：运行MIWIFIRepairTool.x86.exe，选择固件（笔者使用文章写作时官网的最新1.0.93固件）； 路由器断电后按住reset，插电后橙灯闪烁时放开reset； 选择网卡（LAN口连接的网卡），下一步即可。等蓝灯闪烁时将路由器断电重启。如果一直停留在 以太网配置成功，可以开始刷机操作 ，是windows的防火墙原因（参考 这篇贴子 ）。可以在设置中关闭防火墙（ 控制面板\系统和安全\Windows Defender 防火墙 中， 启用或关闭Windows Defender防火墙 ，把两个防火墙都关闭）。刷完固件后再打开。
步骤/目录： 1.背景介绍 2.adguardhome （1）安装 （2）配置 3.pihole （1）安装 （2）配置 附录： （1）macvlan （2）macvlan下的网段 （3）macvlan的其它操作 （4）pihole配置详解本文首发于个人博客https://lisper517.top/index.php/archives/476/，转载请注明出处。本文的目的是介绍自建DNS、过滤广告的两款软件。本文写作日期为2024年1月29日，在Ubuntu 22.04LTS系统演示。1.背景介绍在用电脑、手机平板浏览网页时，经常能看到网页上各种广告。这些广告最常见的形式是一些图片或视频，而图片和视频资源一般是通过网址加载的。如果在路由器中屏蔽这些广告网址，就能实现去广告。路由器默认设置下，会自动选择本地运营商的DNS，而运营商有时候会劫持DNS，情节轻时在返回的内容中加上广告，严重时则返回错误的内容。在这种情况下也有必要自建DNS。2.adguardhomeadguardhome最初应该是国人做的一款去广告DNS。（1）安装根据其 docker网址 的引导，在Ubuntu上如下操作：mkdir -p /docker/adguardhome/data/adguardhome mkdir -p /docker/adguardhome/conf/adguardhome cd /docker/adguardhome vim docker-compose.yml写入如下内容：version: '3.8' services: adguardhome: image: 'adguard/adguardhome' container_name: adguardhome ports: - '53:53' #DNS端口 - '3000:3000' #网页UI，初始配置端口 - '8500:80' #网页UI，后续配置端口 volumes: - ./data/adguardhome:/opt/adguardhome/work - ./conf/adguardhome:/opt/adguardhome/conf restart: unless-stopped以上设置仅将adguardhome作为DNS服务器使用，其实它还可用用来做DHCP服务器（动态分配内网ip）、HTTPS/DNS-over-HTTPS服务器（DNS的过程用HTTPS加密）、DNS-over-TLS服务器（用TLS加密DNS）、DNS-over-QUIC服务器（QUIC加密DNS）、DNSCrypt服务器（不太清楚，应该也是加密），详见原文，需要注意的是HTTPS、TLS、QUIC好像都需要公网ip+域名+HTTPS证书（所以需要在云服务器部署adguardhome），而DNSCrypt虽不需要证书、却需要客户端（电脑，手机平板等使用adguardhome进行DNS的设备）配置软件。另外需要注意，3000端口是adguardhome初始配置的端口，后续WebUI则会在80端口，已被占用的话可以改到其它端口（此处改到8500端口）。最后打开端口，运行即可（其实docker会自动打开，笔者用ufw是为了方便查看）：ufw allow 53 comment "DNS-adguardhome" ufw allow 3000 comment "WebUI-adguardhome-initial" ufw allow 8500 comment "WebUI-adguardhome" docker-compose config docker-compose up如果提示53端口被占用，可以把53改到其它端口，前提是你的路由器支持DNS服务器使用非53端口；或者使用笔者更推荐的macvlan，见附录。（2）配置访问 本地ip:3000 端口，设置登录用户名密码，其它一路默认，完成初始化配置；然后到8500端口进行进一步配置。在adguardhome配置前，或者配置完成后，到你的路由器管理页面，将ipv4的DNS改到adguardhome的ipv4地址。以下配置参考了 这篇文章 。a.DNS服务器在 设置 - DNS设置 - 上游 DNS 服务器 中，填入cloudflare和google的DNS：1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001 8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844后备 DNS 服务器 使用adguardhome提供的DNS：94.140.14.14 94.140.15.15 2a10:50c0::ad1:ff 2a10:50c0::ad2:ff笔者实验时用不了ipv6的DNS，这是因为docker没有给adguardhome容器分配ipv6地址，自然也用不了ipv6。开启的方法见 参考文章一 （讲解较乱）或者 参考文章二 （使用macvlan，见附录）。b.DNS 黑名单在 过滤器 - DNS 黑名单 里，添加DNS过滤规则。有人整理出来某些广告域名，添加到黑名单后adguard就会拦截这些请求。可以添加自带的，也可以自己找一些黑名单，比如 配置参考文章 中提供的：halflife https://raw.githubusercontent.com/o0HalfLife0o/list/master/ad.txt anti-AD https://anti-ad.net/easylist.txt neoHosts https://cdn.jsdelivr.net/gh/neoFelhz/neohosts@gh-pages/full/hosts.txt 大圣净化 - 针对国内视频网站 https://raw.githubusercontent.com/jdlingyu/ad-wars/master/hosts adgk手机去广告规则 https://raw.githubusercontent.com/banbendalao/ADgk/master/ADgk.txt 广告终结者 http://sub.adtchrome.com/adt-chinalist-easylist.txt Adbyby https://raw.githubusercontent.com/adbyby/xwhyc-rules/master/lazy.txt EasyList China+EasyList https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt EasyPrivacy https://easylist-downloads.adblockplus.org/easyprivacy.txt不用太多，只添加一两个即可，太多了容易误杀，也拖慢DNS速度。c.DNS 白名单为了防止错杀，还可以添加白名单，白名单的优先级高于黑名单。比如google analytics就容易被错杀。anti-ad白名单 https://raw.githubusercontent.com/privacy-protection-tools/dead-horse/master/anti-ad-white-list.txt filter_whitelist https://raw.githubusercontent.com/hl2guide/Filterlist-for-AdGuard/master/filter_whitelist.txt LWJ's white list https://raw.githubusercontent.com/liwenjie119/adg-rules/master/white.txt DNS允许白名单 https://raw.githubusercontent.com/ChengJi-e/AFDNS/master/QD.txt白名单也不需要太多。如果正常的网页加载不出来，到adguardhome的后台查看是否误杀，手动加白名单。d.DNS 重写如果想通过域名访问一些局域网ip，可以在这里配置。一些路由器如AX9000也可以在路由器里配置（小米路由器需要在同名app配置，找到hosts设置）。e.自定义过滤规则一些网站的广告需要其它设置才能去除，比如油管的视频广告（笔者未验证）：/googleads.$~script,domain=~googleads.github.io /pagead/lvz? ||google.com/pagead/ ||static.doubleclick.net^$domain=youtube.com ||youtube.com/get_midroll_ ||safebrowsing.googleapis-cn.com ||doubleclick.net自定义规则需要有一定的网络基础才能玩的转，至少要会用chrome的开发者模式，或者也可以搜索别人的规则试试。3.piholepihole最初是给树莓派做的广告拦截，但是也能用于其它电脑。pihole没有中文界面，需要的可自行找汉化版，但是笔者还是更推荐英文原版。（1）安装根据 docker-pihole 的介绍，在 Ubuntu 22.04 LTS 上操作（同样使用macvlan的方法）。创建docker-net（之前创建过的话这里就不用建了）：docker network create -d macvlan \ --subnet=192.168.31.0/24 \ --gateway=192.168.31.1 \ --ipv6 \ --subnet=fe80:7eb5:2afd::/64 \ --gateway=fe80:7eb5:2afd::1 \ -o parent=eth0 \ macvlan_net然后是熟悉的步骤：mkdir -p /docker/pihole/etc-pihole mkdir -p /docker/pihole/etc-dnsmasq.d cd /docker/pihole vim docker-compose.yml写入如下内容：version: "3" services: pihole: container_name: pihole image: pihole/pihole:latest environment: TZ: 'Asia/Shanghai' WEBPASSWORD: '123456' #网页密码 volumes: - './etc-pihole:/etc/pihole' - './etc-dnsmasq.d:/etc/dnsmasq.d' restart: unless-stopped networks: macvlan_net: ipv4_address: 192.168.31.31 ipv6_address: fe80:7eb5:2afd::31 networks: macvlan_net: external: true运行：docker-compose config docker-compose up然后到 [fe80:7eb5:2afd::31]/admin 或者 192.168.31.31/admin 登录，密码为yml中设置的密码。后面如果把pihole作为DNS，则也能从 http://pi.hole/admin 登录。如果忘记或者想更改登录密码，可以 docker exec -it pihole pihole -a -p （或者进入宿主机后 pihole -a -p ）。（2）配置pihole没有中文界面，配置起来稍微难一点。pihole配置中的高级选项会在附录中解释。另外，目前的pihole管理白名单不是很方便，大概是21年某次更新之前的网页UI还有黑白名单的设计，现在则是用groups代替了。在 Adlists 里，可以添加别人的屏蔽列表。添加完后， docker exec -it pihole pihole -g 来更新列表；或者到 Tools - Update Gravity 里更新。黑名单在这里添加，白名单见后；在 Settings - DNS 里，把Google、OpenDNS、Cloudflare的IPv4、IPv6的DNS服务器都勾选上。旁边也可以自己填；下方有一个 Rate-limiting ，默认应该是某个客户端在60s内请求1000次DNS时就封禁该客户端。玩多线程爬虫的话会有影响；或者用路由器作为pihole的客户端也容易被封。都设置为0可关闭该功能。其它配置见附录。附录：（1）macvlanmacvlan是一种网络虚拟化技术，可以用同一张物理网卡获得不同的局域网ip。在docker中可以调用macvlan，将容器作为一个单独设备、分配局域网ip，使得局域网内的机器（除了宿主机）几乎都能通过局域网ip来访问容器。比如将adguardhome绑定到 192.168.1.30 ，那么 192.168.1.30:80 、 192.168.1.30:3000 就分别变成了adguardhome的配置页面、初次配置页面。由于还要使用ipv6访问adguardhome，也需要给它一个v6地址。回到adguardhome容器启动前，如下设置（参考之前提到的 参考文章二 和之前未提到的 参考文章三 ，后者讲的比较详细）：docker network create -d macvlan \ --subnet=192.168.1.0/24 \ --gateway=192.168.1.1 \ --ipv6 \ --subnet=fe80:7eb5:2afd::/64 \ --gateway=fe80:7eb5:2afd::1 \ -o parent=eth0 \ macvlan_net-d macvlan 即 --driver macvlan ，指定docker-net的驱动。最后的 macvlan_net 是docker-net名；ipv4网关为 192.168.1.1 ，网段为 192.168.1.0/24 。由于笔者使用小米路由器，网关和网段都要改到 192.168.31 下；ipv6网关为 fe80:7eb5:2afd::1 ， 网段为 fe80:7eb5:2afd::/64 。这个 fe80:7eb5:2afd 局域网v6地址可以按 fe80:xxxx:xxxx 的格式随便写；指定物理网卡为 eth0 对应的网卡。如果网卡不存在，在linux上用 ifconfig 查看物理网卡，局域网ip对应的那张，类似 enp2s0f1 、 en0 、 ovs_eth0 这种。另外需要注意，macvlan是独立于docker的，docker需要调用macvlan进行网络虚拟化，所以你需要先安装macvlan包。一般linux发行版是自带的，少数情况则需要手动下载，比如用 树莓派4B + Ubuntu21.10系统 时需要 apt install linux-modules-extra-raspi + reboot （见 reddit提问 ）；或者有些openwrt系统下，需要 opkg update && opkg install kmod-macvlan 。创建完docker-net后，将yml文件更改为：version: "3" services: adguardhome: image: adguard/adguardhome container_name: adguardhome volumes: - ./data/adguardhome:/opt/adguardhome/work - ./conf/adguardhome:/opt/adguardhome/conf restart: unless-stopped networks: macvlan_net: ipv4_address: 192.168.1.30 #用小米路由器则改成192.168.31.30 ipv6_address: fe80:7eb5:2afd::30 networks: macvlan_net: external: true这里没有端口映射的设置。通过以上步骤，已经给容器组中的adguardhome容器分配了v4、v6地址，访问 192.168.1.30 或者 [fe80:7eb5:2afd::30] 的3000、80端口都能设置adguardhome，也可以正常访问ipv6的DNS。设置完adguardhome后，在路由器管理页把v4和v6的DNS分别改到 192.168.1.30 和 [fe80:7eb5:2afd::30] 即可。必须尝试通过 [fe80:7eb5:2afd::30]:3000 或者 [fe80:7eb5:2afd::30]:80 访问adguardhome。如果不行，可以看下面的方法。（2）macvlan下的网段无法从路由器或者局域网的其它机器内访问 [fe80:7eb5:2afd::30] ，可能是因为网段不对。在windows的cmd中 ipconfig 看 默认网关 ，或者linux下 ip -6 route show 最后一行 default via ... 确认一下ipv6的网关。如果网关以其它开头，比如不是 fe80 而是 f123 ，那么就把上文教程中所有的 fe80 换成 f123 即可。当然，一般网关都是 fe80 开头的，因为 fe80 默认是内网v6，类似于 192.168 在v4中的地位。如果不能通过以上方法确认v6网关，你也可以进入容器：docker exec -it adguardhome sh ifconfig其部分输出内容为：eth0 Link encap:Ethernet HWaddr XX:XX:XX:XX:XX:XX inet addr:192.168.1.30 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::xx:xxxx:xxxx:xxxx/64 Scope:Link inet6 addr: fe80:7eb5:2afd::30/64 Scope:Global inet6 addr: 240e:xxx:xxx:xx:xx:xxxx:xxxx:xxxx/64 Scope:Global ...这里出现了3个v6地址，它们的顺序可能调换。第一个 fe80 开头的是随机分配的局域网v6，即使无法通过 fe80:7eb5:2afd::30 访问adguardhome，也一定能通过这个v6访问；第二个 fe80:7eb5:2afd::30 是yml中设置的，是静态公网v6（实际上是内网）；第三个 240e 开头的，是真正的公网v6地址，但是ping不到（应该是出于安全考虑）。如果你的头两个v6地址开头不同，比如说： inet6 addr: f123::xx:xxxx:xxxx:xxxx/64 Scope:Link inet6 addr: fe80:7eb5:2afd::30/64 Scope:Global同样把所有的 fe80 换成 f123 即可。在几乎所有其它的docker-macvlan教程中，创建的网段都非 fe80 开头，比如 fd0d:7eb5:2afd 。此时容器虽然能访问外部的v6地址，但v6网段不同，导致局域网的其它机器只能访问到容器的v4地址，却访问不到容器的v6地址。（3）macvlan的其它操作使用macvlan的容器，无法直接 docker restart ，会提示ip地址已被占用。你可以重启docker service docker restart 或者重启宿主机，以释放容器的ipv4、ipv6地址。192.168.1.0/24 下虽然有256个ip地址，但也有可能用完。好在macvlan还能对物理网卡进一步分层，见 参考文章四 。分层后需要注意不同macvlan网络之间的通信问题。最后，在参考文章四作者的下一篇文章中提到了overlay，也可以达到给容器以局域网ip的效果，见 参考文章五 。（4）pihole配置详解这里都是笔者个人的理解，部分参考了 pihole的官方文档 。由于文档都是英文的，笔者没时间细看，难免可能有疏漏错误，请参考原文。a.Groups与Clients从主页面左侧边栏的 Groups 可进入Groups management（屏蔽规则的分组）。根据 官方文档 ，组可用于管理域名黑名单、白名单、客户端。但是注意目前版本pihole的白名单域名管理起来不是很方便（网页中只能一个个显示，没有白名单列表）。可以对屏蔽规则分组，也可以对客户端分组（侧边栏的 Groups 下方的 Clients ）。比如 电脑1 需要访问所有网站， 电脑2 则需要屏蔽掉不健康的网站，就可以对此类网站拉一个组，在 电脑2（客户端2） 的屏蔽规则中单独加上该组，守护少年儿童的心理健康。每个新的屏蔽规则和客户端都会加到各自的0号组（default）中。要对客户端分组，首先需要有不同的客户端，这就要求不能在路由器里统一把DNS设置到pihole，但是给每台电子设备分别改DNS又太麻烦了。笔者建议成人用一个路由器，少年儿童用另一个路由器，这样简单一些。创建组名时如果有空格，则需要用英文双引号将组名括起来。组的操作：对某个客户端取消所有屏蔽： 在 Clients - Group assignment 里，把该客户端适用的所有组移除。 对屏蔽规则（黑名单）分组： 在 Groups 里创建屏蔽规则组后，在 Adlists - Group assignment 里，对屏蔽规则分组。新增的所有规则都会加到0组（default），可以手动调整。 添加单独的域名（黑名单或白名单）到组： 在 Domains 里新增一个域名（或者正则）规则，添加到屏蔽规则的组里。目前的pihole不能添加白名单的列表，只能在这里一个个添加，因此笔者建议这里只添加白名单域名。另外，pihole中白名单的优先级也高于黑名单（ 官方文档 ）。对客户端和屏蔽规则都分组后，就能很方便地管理。比如刚才的例子，有域名黑名单A，域名黑名单B（成人能访问，儿童不能访问），域名白名单C，成人客户端1，儿童客户端2，那么进行以下操作：在 Groups 里，添加 adult_rule 和 kid_rule 两个屏蔽规则组； 在 Clients 里，添加两个客户端，分别为成人和儿童使用的客户端，分别使用 adult_rule 和 kid_rule 两个屏蔽规则组（去掉default组）； 在 Domains 里，一个个添加白名单C中的域名，注意选择 Add to Whitelist，并把所有白名单域名的 Group assignment 中勾选两个屏蔽规则组（default组随便）； 在 Adlist 里，通过URL，添加黑名单A、B，将A添加到 adult_rule 和 kid_rule ，B则只添加到 kid_rule （default组随便）；b.Domains与Adlists在 Domains 里可以手动单独添加域名到白名单或黑名单，还能用正则表达式。正式用RE之前最好用pihole检查一下，见 官方文档 （需要进入容器操作）。在 Adlists 里可以用别人总结好的屏蔽列表（anti-ad之类的），用法同adguardhome。添加完屏蔽表后， docker exec -it pihole pihole -g 来更新列表；或者到 Tools - Update Gravity 里更新。c.Disable Blocking可以临时或者永久取消所有的屏蔽，用于测试。d.Local DNS自定义解析，一般用于把某个域名绑定到局域网ip上。e.名词解释笔者对于 Settings 里的一些高级功能进行解释，可能会有错误的地方。ECS (Extended Client Subnet) ：应该是DNS的弹性负载。Content Delivery Networks (CDNs) ：基于ip提供地理信息。Never forward non-FQDN A and AAAA queries ：如果不勾选的话，有时候Local DNS可能往上游服务器查找；如果开启下面的 Conditional Forwarding 又不勾选本功能，有时会导致DNS死循环。Never forward reverse lookups for private IP ranges ：本地ip如果没有对应的本地域名，不会向上游服务器查找。这两个 Never forward 选项也许能增加隐私性，但勾选时最好同时把pihole设为DHCP服务器。Use DNSSEC ：即Domain Name System Security Extensions，验证DNS解析是否正确。如果验证失败或者上游服务器不支持DNSSEC，可能会出问题。另外该选项会显著增加log文件大小。Rate-limiting ：默认情况下，一个客户端在60s内发出1000次DNS请求后就封禁该客户端。玩多线程爬虫可能有影响，把两个值都改成0可以关闭此功能。Conditional forwarding ：如果不把pihole作为DHCP服务器，则pihole无法决定局域网内的设备名（注意这个不同于Local DNS），开启这个功能后，填入局域网段、DHCP服务器（一般是路由器）、选填本地域名，pihole会向你的路由器查询局域网内的设备名。选填的本地域名，意思是对该域名的DNS不会离开本地，并且这个本地域名要和路由器的设置一致。开启 Conditional forwarding 同时关闭 Never forward non-FQDN A and AAAA queries ，那么即使是本地域名，pihole也会交给上游的路由器处理。（所以要想用pihole解析本地域名，要么就都不开，要么就把 Conditional forwarding 和 Never forward non-FQDN A and AAAA queries 都打开）
步骤/目录： 1.背景介绍 2.准备工作 3.安装与使用docker （1）portainer （2）busybox开启SSH （3）docker-compose （4）adguardhome 4.收尾及注意事项 （1）docker备份 （2）注意事项 附录： （1）AX9000上adguardhome开启v6失败本文首发于个人博客https://lisper517.top/index.php/archives/423/，转载请注明出处。本文的目的是在小米AX9000路由器上开启docker。本文写作日期为2024年1月18日，主要参考了 参考文章一 和 参考文章二 和 小米论坛 。1.背景介绍2021年小米出了一款 AX9000旗舰路由器 ，其主要参数如下：处理器：Qualcomm IPQ8072A 4核 A53 2.2GHz CPU ⽹络加速引擎：双核 1.7GHz NPU 内存：1GB 2.4G Wi-Fi：4×4（最高支持 IEEE 802.11ax协议，理论最高速率可达 1148Mbps） 5.2G Wi-Fi：4×4（最高支持 IEEE 802.11ax协议，理论最高速率可达 4804Mbps） 5.8G Wi-Fi：4×4（最高支持 IEEE 802.11ax协议，理论最高速率可达 2402Mbps） 产品天线：外置高增益天线 + 内置 AIoT天线 产品散热：主动散热 整机接口：1个10/100/1000/2500M 自适应 WAN/LAN口（Auto MDI/MDIX） 1个10/100/1000M 自适应 WAN/LAN口（Auto MDI/MDIX） 3个10/100/1000M 自适应 LAN口（Auto MDI/MDIX）它有2.4G、5.2G、5.8G三个频段的wifi，网口正常使用时1个2.5G入口，4个千兆出口。这款路由器刚出来时售价￥999，后来涨到￥1299，偶尔有折扣也会卖￥999。另外2023年又出了万兆路由器（￥1799，折扣时￥1599），外观和其它参数差不多，但是网口是2个万兆、4个2.5G。这款路由器是 4核2.2GHz的CPU + 1G内存 ，性能和可玩性比较强，刚好小米官方提供了能装docker的固件。接下来就展示使用官方固件使用docker、开启ssh。需要说明的是，AX9000有稳定版和开发版固件，其中只有开发版能装docker。目前小米的路由器应该只有AX9000的开发版固件，和万兆路由器的稳定版能装docker，其它厂商不知道有无官固docker。2.准备工作首先做一些准备。（1）小米路由器修复工具：到 小米官网 ，在下面有一个 小米路由器修复工具 。如果出了什么问题，可以尝试用这个工具拯救路由器，但它也不是万能的。另外该工具会报毒，需要允许运行。（2）开发版固件：点击旁边的ROM（即固件），下载小米路由器AX9000的开发版即可。目前该开发版固件最后一次更新是2021年11月12日，估计以后也不会再更新了。（3）路由器备份：在路由器后台， 常用设置-系统状态-备份与恢复 里，把当前的路由器的大部分设置备份一下，方便恢复。（4）U盘准备：准备一个至少64GB的U盘，在windows上用diskgenius（一个windows下管理存储器的强大软件， 官网 的免费版本就能格式化）格式化为ext4，或者在ubuntu下 unmount 并 mkfs.ext4 /dev/xxx 。由于路由器的存储空间、内存不够，所以docker需要装在该u盘中，并且该u盘可以划出虚拟内存（因此最好不要用机械硬盘）。也可以用固态硬盘，稍微有点奢侈，不过最近固态都比较便宜。这个u盘会被挂载到 /mnt/docker_disk 下（同时也在 /extdisks/分区一名称 下）。该u盘的所有要求如下：有32GB以上的空闲空间；如果有多个分区，需要保证第一个分区为ext4格式，不能用sd卡。3.安装与使用docker登录路由器后台，在 常用设置-系统状态-升级检测 里，选择 手动升级 ，使用刚才下载的开发版固件。升级过程中切勿断电、重启，可以用UPS保险。升级完成后登录路由器后台，初始设置一下，然后把备份好的设置恢复一下（有些设置无法备份，需要手动恢复）。设置完成后重启，等待重启时可以插上u盘。重启后到 存储状态 中可以看到u盘已被识别，在 高级设置 下找到Docker，安装并使用docker。值得注意的是 虚拟内存 选项，AX9000的内存为1GB，一般的u盘读取大概在百兆、写入可能在20-100MB/s。如果你要在路由器上运行很多容器的话可以划虚拟内存，但虚拟内存的读写速度比较慢，也可以把u盘换成读写更快的固态硬盘，但是笔者更建议尽量把docker容器放在电脑上。接下来笔者装一些容器以演示。也可以装其它的容器，只要镜像的tags支持 linux/arm64 即可（最好能支持 linux/aarch64 ）。（1）portainer一个管理docker容器的容器。只要在路由器后台打开 允许Docker ，并 安装第三方管理 即可。其端口映射为 8001:8000 和 9001:9000 ，HTTP网页管理端口在9001，默认用户名密码都是 admin 。（2）busybox开启SSHbusybox用于开启SSH。需要注意的是，重启路由器后SSH会关闭。这个容器需要在portainer中开启，但是却不需要挂载卷。再portainer网页上（ 192.168.31.1:9001 ）如下操作：a.选择 Home - Containers - +Add container ，容器名和镜像名都填 busybox ；b.下面的 Advanced container settings 中的 Command & logging 的 Console 里把 None 改成 Interactive & TTY (-i -t) ；c.换到 Volumes 页，添加挂载（ + map additional volume ），容器（container）旁边要选 Bind ，宿主机（host）应该是 Writable ，并把宿主机的 / 根目录挂载到容器的 /mnt 下。d.最后点上面的 Deploy the container 即可部署容器。busybox容器创建完成后，在 Home - Containers 中点击容器名、进入容器详情页，点击 Container status - Attach ，运行如下命令：chroot /mnt也可以用Console而非Attach，在Console中 Use custom command ，命令同样为 chroot /mnt 。不管Console还是Attach，这里其实已经可以用ash了，如果你只是想用ssh，可以就在portainer里用。如果需要刷其它系统或者备份docker，才有必要进行下面的步骤，以通过portainer以外的客户端连接ssh。cp /etc/init.d/dropbear /etc/init.d/dropbear_backup vi /etc/init.d/dropbear如果不会用vi，可自行查找教程（简单来说，vi中按 / 查找，按 i 更改，按esc并 wq 写入+保存）。总之，该文件有如下几行：start_service() { # .....................ssh...... flg_ssh=`nvram get ssh_en` channel=`/sbin/uci get /usr/share/xiaoqiang/xiaoqiang_version.version.CHANNEL` if [ "$flg_ssh" != "1" -o "$channel" = "release" ]; then return 0 fi [ -s /etc/dropbear/dropbear_rsa_host_key ] || keygen . /lib/functions.sh . /lib/functions/network.sh注释头几行，完成后如下：start_service() { # .....................ssh...... #flg_ssh=`nvram get ssh_en` #channel=`/sbin/uci get /usr/share/xiaoqiang/xiaoqiang_version.version.CHANNEL` #if [ "$flg_ssh" != "1" -o "$channel" = "release" ]; then # return 0 #fi [ -s /etc/dropbear/dropbear_rsa_host_key ] || keygen . /lib/functions.sh . /lib/functions/network.sh最后运行 /etc/init.d/dropbear start 即可开启SSH，root的密码可以到 这个网站 ，根据路由器底部的SN码计算得出，或者直接 passwd root 修改密码。打开SSH后，可以用docker-compose来管理容器，见下文。另外，这里的SSH并未固化，所以重启路由器后还需要手动开启SSH。因为路由器的SSH其实不是很常用，这应该不是什么问题，需要的时候打开就行了，如果怕安全性问题，可以 /etc/init.d/dropbear stop 关闭SSH（后面的备份docker则需要保证SSH常开）。笔者日常使用时，虽然并未固化SSH，但每次重启后还是能SSH登录，portainer后台看到busybox并没有启动，不知道怎么回事。（3）docker-compose用putty或者MobaXterm等软件，或者就在portainer里连接SSH，然后执行以下命令：docker -v curl -L https://github.com/docker/compose/releases/download/v2.24.1/docker-compose-`uname -s`-`uname -m` > /mnt/docker_disk/docker-compose chmod +x /mnt/docker_disk/docker-compose ln -s /mnt/docker_disk/docker-compose /usr/bin/docker-compose docker-compose -v笔者实验时AX9000用的是19.03.15版本docker。国内从github下载docker-compose有点慢，笔者更推荐手动下载，用MobaXterm或者WinSCP上传，网址为 https://github.com/docker/compose/releases/download/v2.24.1/docker-compose-Linux-aarch64 （可以到 https://github.com/docker/compose/releases 看docker-compose最新版本号）。如果用老版本，注意docker-compose从v2.0.1后才支持Linux-aarch64。（4）adguardhome一个拦截广告的软件。基本的安装过程与设置见 自建DNS与广告过滤-adguardhome与pihole ，这里提醒yml改成如下（只去掉了53端口映射）：version: '3.8' services: adguardhome: image: 'adguard/adguardhome' container_name: adguardhome ports: - '3000:3000' #网页UI，初始配置端口 - '8500:80' #网页UI，后续配置端口 volumes: - ./data/adguardhome:/opt/adguardhome/work - ./conf/adguardhome:/opt/adguardhome/conf restart: unless-stopped因为是AX9000上建DNS，自己找自己解析，所以可以不映射53。在portainer的容器管理页中找到adguardhome的 IP Address 这一列（172开头，可能是 172.18.0.2 之类的），到AX9000路由器管理页， 常用设置 - 上网设置 里，把ipv4的DNS1和DNS2都改成该172的ip即可（注意，光改DNS是无法保存的，需要改一下 自动配置 、 手动配置 之类其它的东西）。另外，AX9000上装的adguardhome不能过滤ipv6广告或做v6的DNS，笔者实践过程及参考资料见附录。4.收尾及注意事项（1）docker备份笔者的习惯是所有docker数据都放在 /mnt/docker_disk/docker 下，备份时只需要在crontab中添加。mkdir /mnt/docker_disk/backup /bin/tar -zcf /mnt/docker_disk/backup/docker.tar.gz /mnt/docker_disk/docker crontab -e备份的命令确认运行无误后，在crontab中添加一行：0 23 * * * /bin/tar -zcf /mnt/docker_disk/backup/docker.tar.gz /mnt/docker_disk/docker然后从你的其它机器上scp到AX9000（或者，由于AX9000可以开samba，你也可以把备份文件放到分享硬盘上，但是默认的SMB是无加密的，请谨慎），或者从AX9000主动scp到其它机器上，备份tar.gz文件。比如后者，那么就在AX9000的crontab中修改：0 23 * * * /bin/tar -zcf /mnt/docker_disk/backup/docker.tar.gz /mnt/docker_disk/docker && /usr/bin/scp -i 你的密钥 /mnt/docker_disk/backup/docker.tar.gz root@其它机器的ip:/backup/AX9000这里使用了密钥，要注意openssh的密钥对于dropbear来说太长了，要用dropbear生成的密钥（ 参考文章 ）放到其它机器上。如果你是用其它机器连到AX9000，可参考如下命令：/usr/bin/sshpass -p "AX9000的密码" /usr/bin/scp -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa root@192.168.31.1:/mnt/docker_disk/backup/docker.tar.gz /backup/AX9000（2）注意事项摘自前文提到的小米论坛。a.docker与防火墙：由于docker与防火墙有冲突（经典问题，因为docker和系统都是更改iptables，参考 这个问题 ），建议： 关闭docker -> 修改防火墙 -> 开启docker 。b.由于docker运行时关机或重启可能导致错误，建议重启前，或者更改一些配置需要重启前，先做好备份，再关闭docker，最后重启。c.官方建议容器勿超过3个，笔者建议根据内存使用情况来。d.开启docker时想拔下u盘，应先到 存储状态 页面安全移出硬盘。附录：（1）AX9000上adguardhome开启v6失败和 自建DNS与广告过滤-adguardhome与pihole 中一样，试图通过macvlan为adguardhome开通ipv6：docker network create -d macvlan \ --subnet=192.168.31.0/24 \ --gateway=192.168.31.1 \ --ipv6 \ --subnet=fe80:7eb5:2afd::/64 \ --gateway=fe80:7eb5:2afd::1 \ -o parent=br-lan \ macvlan_net在AX9000的SSH中 ifconfig 看到 192.168.31.1 绑定在 br-lan 网卡设备上，在上面的命令中也已进行了修改。yml为：version: "3" services: adguardhome: image: adguard/adguardhome container_name: adguardhome volumes: - ./data/adguardhome:/opt/adguardhome/work - ./conf/adguardhome:/opt/adguardhome/conf restart: unless-stopped networks: macvlan_net: ipv4_address: 192.168.31.50 ipv6_address: fe80:7eb5:2afd::50 networks: macvlan_net: external: truedocker-compose up 时输出：Error response from daemon: failed to create the macvlan port: operation not supported小米路由器的系统是openwrt改的，上面的报错说明没有装macvlan包。装macvlan：opkg install kmod-macvlan #输出 Unknown package 'kmod-macvlan'. ，说明找不到这个包 opkg update更新一下软件源，出来一堆错误：Downloading http://downloads.openwrt.org/releases/18.06-SNAPSHOT/targets/ipq/ipq807x_64/packages/Packages.gz wget: server returned error: HTTP/1.1 404 Not Found *** Failed to download the package list from http://downloads.openwrt.org/releases/18.06-SNAPSHOT/targets/ipq/ipq807x_64/packages/Packages.gz ...意思是没有这个网址。浏览器访问一下，果然 http://downloads.openwrt.org/releases/ 下没有 18.06-SNAPSHOT 这个版本。到国内的清华镜像源 https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/ 看，也没有这个版本。再次确认一下版本号：ubus call system board输出： "version": "18.06-SNAPSHOT",确实是这个版本。寻找补救方法：a.更换版本号： 提问一 和 提问二 中也是发现官方源没有 18.06-SNAPSHOT 的包，分别把源改到了 18.06.0 和 18.06.1 版本（ vi /etc/opkg/distfeeds.conf ）。或许能运行，但不能保证以后的稳定性。b.修补： 小米AX1800修复opkg404 中对系统进行修改，但AX1800的方法不一定适用于AX9000，芯片可能不一样。c.根据 恩山论坛 的说法，在2023-07之后，openwrt官方已删除 18.06-SNAPSHOT 的源，可以 vi /etc/opkg/distfeeds.conf 替换为如下源：src/gz openwrt_base http://downloads.openwrt.org/releases/packages-18.06/aarch64_cortex-a53/base src/gz openwrt_packages http://downloads.openwrt.org/releases/packages-18.06/aarch64_cortex-a53/packages/ src/gz openwrt_routing http://downloads.openwrt.org/releases/packages-18.06/aarch64_cortex-a53/routing可以正常 opkg update ，但是 opkg install kmod-macvlan 仍然显示 Unknown package 'kmod-macvlan'. ，笔者便没有进一步尝试。
步骤/目录： 1.背景介绍 2.使用LCM加速 3.文生图 （1）入门 （2）tag通用写法 （3）通用写法的画面调整 （4）tag进阶 a.强短句 b.循环绘制 c.分步渲染 d.表情符号 （5）反推tag（图生文） （6）SD大致原理 （7）tag示例 4.Control Net （1）CN的使用 （2）CN常用预处理器 5.模型下载及使用 （1）模型分类 （2）大模型 （3）LoRA （4）Embedding/Textual inversion （5）VAE （6）Hypernetwork （7）Dreambooth与Native Train （8）DreamArtist 6.SD结构及进阶 7.图生图 （1）图生图 （2）局部重绘 （3）涂鸦重绘 （4）其它 （5）图生图的理论与技巧 （6）修手 （7）添加元素 （8）差分图 （9）LoRA协同 （10）草图生图 8.训练LoAR 9.使用技巧 （1）复制参数 （2）保存预设 （3）更换整合包时迁移数据 10.大模型简介 11.小模型推荐 12.保护画师作品本文首发于个人博客https://lisper517.top/index.php/archives/287/，转载请注明出处。本文的目的是讲解stable diffusion的初步使用。本文写作日期为2024年1月5日。系统为 Ubuntu 22.04 LTS ，显卡为 GTX 1050Ti mobile，4G显存。主要参考了 秋葉aaaki 等大佬制作的文档 ，以及其它各种分享。由于笔者也不是AI从业人员，本文难免出现各种错误，请在评论区指出。1.背景介绍在上一篇文章中，在Ubuntu下安装了Stable Diffusion（ 秋葉aaaki 整合包），这篇文章通过各路资料，初步讲解SD的使用。在开始之前需要强调：（1）目前为止，AI绘画的知识完全可以免费获取；（2）尽可能用safetensors后缀的模型，少用、不用pt、ckpt后缀的模型，以防电脑被注入病毒；（3）能够翻越的，优先在hugging face、civitai、github获取第一手信息，看不懂英文可用GPT翻译。2.使用LCM加速在开始介绍之前，建议安装LCM Lora以大大减少缩短出图时间，步骤如下：（1）关闭SD，在 webui-user.sh 中的 export COMMANDLINE_ARGS 加入 --enable-insecure-extension-access flag，保证从非本机访问SD时（ip不是127.0.0.1）也能安装插件；出于安全原因，不加这个flag就只能从本机装插件，装完插件后这个flag可以去掉，或者笔者建议用NPM给SD加密码（见 可视化管理Nginx-Nginx Proxy Manager ）。另一种方法是建立SSH隧道（或者用frp等工具），比如在本机（跑SD的机器）运行 ssh -L 127.0.0.1:7860:127.0.0.1:7860 ... ，参考 github问题 ；（2）通过 夸克网盘 或者到 huggingface 下载 LCM-LoRA_sd15.safetensors ，放到 models/Lora 下。从名字上也可以看出它适用于SD 1.5，但是SD 1.6也可以；（3）启动SD，在 扩展-从网址安装 下，在 扩展的git仓库网址 内粘贴 https://github.com/mcmonkeyprojects/sd-dynamic-thresholding （动态CFG插件，有助于LCM表现），点击 安装 ，到 扩展-已安装 下点 应用更改并重启 以重启SD；（4）操作方面，正常填提示词，在 Lora 里选择LCM的Lora， 迭代步数 (Steps) 调到7（生成步数，和耗时有很大关系）， 采样方法 (Sampler) 选择 Euler 或者 Euler a 采样器， 提示词引导系数 (CFG Scale) 调到最常用的7，下面还有个 Dynamic Thresholding (CFG Scale Fix) （刚才装的动态CFG插件），把 Mimic CFG Scale 调到1，该插件的高级选项中 CFG Scale Scheduler 选择 Half Cosine Up （也可选其它的）， Minimum value of the CFG Scale Scheduler 和 Minimum value of the Mimic Scale Scheduler 都调1，即可出图；（5）笔者实验时，512*512正常48s，用LCM仅9s。想要快速出大图，可以在 高分辨率修复 (Hires. fix) （用于放大小图）中放大算法选择 R-ESRGAN 4x+ Anime6B （这个应该是用于动漫，也可以其它的）， 高分迭代步数 、 重绘幅度 分别为5和0.5（这两个也可自调），笔者9s出小图、54s放大（正常放大的时间可能是10min左右）。原理方面，LCM Lora类似于先画线稿再上色，和普通出图对比，图片大致内容差不多，线条更清晰、出图非常快，但是有时候背景虚化、上色模糊。另一种用法是正常出图，仅在高分辨率修复时使用LCM（以笔者为例，用时就是48s+54s；不用LCM是54s+10min，都用LCM是9s+54s），参考 秋葉aaaki 。3.文生图（1）入门参考 秋葉aaaki ，这张图稍微有些过时了。上文安装了LCM，所以采样步数7即可（不用的话20-30），采样器选择Euler、Euler a。常用的正面提示词tags（注意所有符号都必须是英文符号）：masterpiece, best quality, 常用的反面提示词：（现在反面提示词可以Embedding，见 使用技巧 ）lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, 也可以在 标签超市 找灵感，根据个人要求选择；或者和GPT对话，也能帮你得到tag。 秋葉aaaki 的1.6.0整合包现在还带提示词翻译功能，非常方便。权重：默认权重是1； (lowres:1.5) 指定权重为1.5，一般在0-2之间； (lowres) 为增加1.1倍权重，和 (lowres:1.1) 一样； [lowres] 为1/1.1权重，等于 (lowres:0.909) ，但是用的少，一般都是指定权重； {} 也是增加权重，但在WebUI中不生效； (((lowres))) 括号可以叠加，此处等于 1.1^3 即 1.331 权重，但是不如直接指定； (a girl stands with (flowers:1.5) and dog:1.2) 写一个长句作为提示词，可以对其中某些词调整权重； (girl:1.5, stand, tree) 可以对几个tag一起调整，但是不要嵌套的太复杂，容易权重混乱。（2）tag通用写法参考 qq文档 。描述的顺序是 整幅画面 -> 主要目标 -> 次要目标 -> 更次要的目标 -> ... -> 背景 ，每个部分的写法包括目标，定义，细节。比如想画一个女孩坐在森林中，首先描述整幅画面的品质及内容：masterpiece, best quality, best 8k wallpaper, realistic oil painting, 1girl sitting inside forest, 对主要目标（女孩）描述（目标，定义，细节）：1 gorgeous dressed magic girl, solo, upper body, the girl (sit down) near a river in the forest, The girl has a beautiful face, attractive red lips and beautiful big shining eyes, blonde long curly hair with a high ponytail, blue Headdress, star earrings, the girl were gorgeous white dress, gold patterns and lace, (thigh:1.2),对森林和其它部分、背景的描述（同样是目标，定义，细节）：flowers and trees in the forest, Flowery meadow, colorful (wildflowers) bloom beside the girl, sunlight, bright spots, shine, glow, Tyndall effect,由于SD的机制，前面的tag比后面的tag权重稍大，所以先描述画面整体，再描述各个部分。对 整幅画面 和 主要目标 的描述中都出现了girl，这会加强girl的权重。长句或者强短句（强短句见后）的单词之间联系更紧密，描述整体关系时比零散的tag更好。默认的tags有75个，可以超量，但超量时最好按照75个tags、75个tags、75个tags来分类，比如前75个词描述 整体+主要目标1 ，中间75个词描述 次要目标1+次要目标2 ，最后75个词描述 次要目标3+... 。如果把 主要目标1 的描述放在前75个词和中间75个词、被分开，有可能造成 主要目标1 的权重降低，并且污染中间75个词描述的 次要目标1+次要目标2 。在一些模型中，每个目标之间可以用占位词分开以避免污染，比如 ai is sb 。（3）通用写法的画面调整首先写出所有提示词，跑几次，对一些没有出现的tag加权重。权重不能太大，否则tag会出现在图中不该出现的地方，称为权重溢出。权重溢出也可以合理利用，达到梦幻的效果。复杂的tags需要图片足够大，以囊括所有tags内容；但是图片过大会触发xformers分块画图，导致图片细节降低，所以需要先画小图再扩大，要注意放大倍数太大时也会超出显存。（4）tag进阶a.强短句(red eyes) AND (long hair) 用大写的AND来连接，可以增强短句tag之间的联系。b.循环绘制cat | dog 在两个或多个关键词间加|表示循环绘制，可以理解为先画一笔cat再画一笔dog，可以起到混合图形的作用，比如 cat:1|dog:2 ，最终绘制出来的cat和dog可能会混合 1/3猫 + 2/3狗 的特征。c.分步渲染仅限2023-10-20后的SDW版本。[A:B:步数占比] 在到达迭代步数前画A，该步数之后画B。A、B中有一个可以为空； 如 a girl with [white idol dress:red hanfu:0.2] ，在前20%次迭代被理解为 a girl with white idol dress ，在后80%的步数被视为 a girl with red hanfu ； 分布渲染适用于添加细节，比如A是衣服，B描述衣服上的花纹。注意步数占比，保证在该步时A已经画完。d.表情符号在tag中可以使用各种emoji。可以把这些emoji理解为权重很高的tag，常用的比如🤚作为反面提示词以防止手指异常。其它更多的emoji可在 EMOJI中文网 查找。（5）反推tag（图生文）AI生成的原图自带tag，在 PNG图片信息 中上传图片、获得tags，发送到文生图即可；对于非AI图或者没有tag信息的图， 秋葉aaaki 整合包内安装了WD 1.4标签器，可以一定程度上代替人工反推tag。（6）SD大致原理文生图时SD可以分为自然语言处理器和图像生成器，2个部分。默认的tags有75个，更多的tags会有150、225、300个上限，笔者猜测不足上限的应该都用0填充了，这也是常用的方法。总之，文生图时，自然语言处理器将每个tag编码，计算得到最接近的token（可能像计算hash值一样？），所有tag的token形成 token数组0 ，加入随机数生成的 噪音图像0 （加入随机性），输入到图像生成器，得到 token数组1 + 图像1 （第1次迭代），然后把 数组1 + 图像1 再输入图像生产器得到 数组2 + 图像2 （第2次迭代），直到完成指定的迭代步数。最后，图像生成器的结果通过图像解码器翻译，形成人类能看懂的图片。潜空间Latent space：图片分为电脑能理解的、人能理解的。人能理解的图片需要经过VAE处理、得到潜空间下的图片，电脑才能理解并处理；最后输出图片前，再用VAE解码得到人能看懂的图片。（7）tag示例集合了一些tag示例（需要注意选择模型）：元素法典 2元素法典 2.54.Control Net2023年初Control Net推出后，立刻受到广泛应用，可以说玩SD必用CN。如果你的SDW没有装CN，参考 秋葉aaaki 或者自行从 抱脸 下载。（1）CN的使用在文生图下面可找到ControlNet插件。其它不变，只需要调整CN插件，勾选 启用 ，如果 显存≤8G 则勾选旁边的 低显存模式 。如果要控制人物姿势， 预处理器 和 模型 都选择 openpose 系列的（这两个需要一一对应。 秋葉aaaki 整合包不仅有每个CN功能的中文翻译，还有二者自动对应）。 控制权重 默认为1，可自调。插件的最上面可以上传一张图像（最好是真人，openpose最初是用来识别真人图像的，但是动漫也可以），点击生成，就能完美复刻图片的动作。如果用ps生成骨骼图，也可以直接使用，此时 预处理器 选择 none ，模型还是 openpose 。如果感觉用CN后分辨率有问题，可以把 低显存模式 旁边的 完美像素模式 勾上。CN的原理，图片经过CN的预处理器，得到生成条件图（对于openpose就是骨骼图），然后使用生成条件图指导图片生成。（2）CN常用预处理器OpenPose：姿态检测，指定人物动作； Canny：线条/硬边缘检测，达到重新上色的效果； Depth：景深检测，指定画面结构； SoftEdge：以前叫HED，软边缘。相比于Canny，边缘识别更模糊，AI发挥空间更大； MLSD：线段图，类似Canny+Depth； Lineart：线稿，可以根据简单的手绘轮廓或者复杂的线稿进行上色； InstructP2P：按照tag，局部修改图片，比如从白天改为黑夜（make it night，增加夜晚的tag）。这个预处理器只适用于部分模型； Tile/Blur：Tile可以增加画面细节，Blur则是减少细节。Tile可以配合图片放大，或者PS上一个物品，Tile帮你把该物品融入图片； Shuffle：特征提取（画风迁移），比如按梵高的画风修改图片；CN还可以用于生成人设三视图（见 秋葉aaaki ）5.模型下载及使用以下内容主要来源于 参考文章一 、 参考文章二 、 参考文章三 。首先需要提醒，使用画师的作品训练模型并私自盈利是很不道德的行为。做不到给原作者分钱，至少应该做到免费开放。最正牌的资源站是 HF抱脸站 ，需要翻越，下载可能比较慢；最常用的是 C站 ，需要翻越，有各位网友分享样图；国内有 吐司 ，它也是整合包部分模型的来源。需要手机注册（笔者被限速过）；其它还有一些 镜像站 。笔者的建议是，浏览C站时翻越，下载时不翻越，因为C站模型好像是放在cloudflare上的（站点不能访问，但是下载链接可以访问）；或者去镜像站，一些镜像站使用的也是C站的下载链接（当然，镜像站更新不如原站快）。不要轻易使用非safetensors格式的模型，因为有一定风险。最后，笔者单独推荐一下 pixiv ，有世界各地的画师分享作品。该网站也需要翻越，但有些校园网可以访问。（1）模型分类从大小和用途，模型可分为基础的大模型和微调大模型的小模型。训练/微调大模型耗时长、对专业性和显卡要求高，业余玩家更常用的做法是训练小模型。常见的小模型包括LoRA、Textual inversion（即Embedding）、VAE、Hypernetwork。从后缀名上各种模型容易搞混，可以通过大小来区分，或者通过 秋葉aaaki的网站 识别。通常来说，模型的后缀名是ckpt、pt、pth、safetensors（可以互相转换），SDW还可以通过PNG、WEBP等图片格式保存模型。前三者都是通过python的Pickle模块直接导出的，使用起来可能会有一些风险（Pickle反序列化攻击）；safetensors则没有这样的安全问题。（2）大模型这里指标准的 latent-diffusion 模型。拥有完整的 U-Net、TextEncoder、VAE。大模型一般大小为2G、4G、7G，后缀为ckpt、safetensors等。对于出图来说，2G的大模型就是全部的有效数据，U-Net(EMA)是完全可以裁剪掉的。EMA即Exponential Moving Average指数滑动平均，可理解为训练时把最后一些步数的结果做平均，并单独存下来（笔者猜测可以减少迭代最后几层的时间），但是SDW中不使用EMA，而且一些人喜欢模型融合，但模型A带EMA、模型B不带EMA，AB融合后的EMA是完全没有用的（EMA是模型专用的）。在 秋葉aaaki整合包 的SDW中集成了裁剪EMA的功能，在 文生图 这一列找到 模型转换 ，按照如下的设置：选定待裁剪的模型； 精度 为 fp16 。这也是SDW默认的精度； 模型修剪 为 删除EMA权重 ； Force CLIP position_id to int64 before convert 勾选上。即可裁剪。另外，一些大模型的VAE不行，表现为画面发灰，需要更换VAE补救，通常在C站模型下载页作者会告诉你用哪个VAE。详见下面VAE的介绍。模型的精度：SDW之能使用fp16的精度（笔者猜测是float precision），其它比如fp32的精度也会转换为fp16来使用。大模型需要放在 models/Stable-diffusion 下。（3）LoRA后缀为pt、ckpt等，大小为8-144MB。LoRA的使用方法有两种，一是以插件形式调用，目前已废弃；另一种方法是SD 1.0以后，在下方调整生成图片大小的那一行，有LoRA页面，点击以后在提示词中出现 <lora:模型名:权重> 。LoRA需要放在 models\Lora 下。SDW中调整生成图片大小那一行可以找到。训练Lora需要显存8G，训练难度低、耗时短，十分推荐，教程见 秋葉aaaki 视频一 、 秋葉aaaki 视频二 、 blender王子 视频一 。（4）Embedding/Textual inversion一般是pt或者图片格式（PNG、webp等），大小在KB级别。是一种特殊的提示词，使用该提示词可以使AI明白你需要的一系列风格。Embedding需要放在 embeddings 下（最外层，不在 models 里），使用时将其文件名作为提示词即可。SDW中调整生成图片大小那一行可以找到。训练方面，Embedding要求显存6G，可学习画风、人物，局限性大但也可以用，教程见 秋葉aaaki 。（5）VAE一般是pt格式。Variational autoencoder变分自编码器，负责将潜空间的数据转换为正常图像。VAE类似于滤镜（实际上是一个翻译器），正常的大模型自带VAE，但是有些融合模型的VAE无法正常工作，表现为跑出来的画面发灰，需要更换VAE来拯救（这种大模型很多，但常用的VAE只有那几个，也就是说大模型和VAE经常是多对一的关系，最常用的是 vae-ft-mse-840000-ema-pruned.safetensors 这个VAE，整合包内已安装）。在WebUI中，左上角选大模型的下拉菜单，其右边可以选择VAE，SDW会转而使用该VAE。VAE需要放在 models/VAE 目录下。（6）Hypernetwork几乎没人用。一般是pt，大小数十、数百MB或者数GB。需要放在 models/hypernetworks 下。SDW中调整生成图片大小那一行可以找到。训练超网络要求显存6G，其性能强大但训练难度高，不推荐训练。（7）Dreambooth与Native TrainLoRA其实是Dreambooth的一种。LoRA对模型的修改范围小（更改输出，不对模型本身更改），训练起来比Dreambooth方便，但LoRA局限性也更大。训练上要求显存12G，训练比较灵活。建议Dreambooth用于人物，Native Train用于画风。教程见 秋葉aaaki 。（8）DreamArtist也是一种Embedding，相比比Textual inversion，DreamArtist还能训练负面提示词。笔者猜测是快速反面tag（EasyNegative等）的来源。6.SD结构及进阶理解SD结构需要深度学习基础或者训练过一段时间的模型，见 秋葉aaaki 。7.图生图参考 重绘学派法术绪论1.1 。图生图比较适合对图片进行精修，可以分为基础的图生图，进阶的局部重绘。（1）图生图界面和文生图差不多，可以对整幅图进行调整大小、重绘等操作，核心参数是重绘幅度。重绘幅度大致以0.5为分界线，这个值越大、重绘后和原图的差距越大。基本操作和文生图类似，多了一个调整重绘幅度的步骤。另外，文生图的 高分辨率修复 （图片放大）也有重绘幅度，其实这个图片放大也是图生图。基础的图生图用于对原图大幅在创作，修瑕疵、改大小，转换风格等。（2）局部重绘和图生图、文生图的区别在于上传图片后，鼠标左键点击图片可以涂白（画笔大小可在图片右上角调整），可以对涂白区域（称为蒙版，笔者猜测就是mask）或涂白以外的区域重新绘制。参数包括：蒙版边缘模糊度 ，重绘区域和原图的融合度，太高会使重绘区域过于接近原图，太低会使二者边界生硬； 蒙版模式 ，可以选择重绘涂白区还是涂白以外的区域； 蒙版区域内容处理 ，重绘区域可以选择填充纯色、不处理、填充噪音、留空白； 重绘区域 ，参考整张图重绘，还是只参考蒙版周边进行重绘； 仅蒙版区域下边缘预留像素 ，如果只参考蒙版周边进行重绘，在这里选择参考到周边的第几个像素为止。一般情况下重绘部分和不重绘部分不需要太精确，把不需要重绘的部分囊括进蒙版，有助于AI对全图的理解，使重绘区域更好地融入整体。局部重绘用于修改细节。（3）涂鸦重绘也称 有色蒙版重绘 。相比于局部重绘，多了调整蒙版透明度的选项，当透明度100时即蒙版区域为原图，0时蒙版区域为纯色（AI会偏向于你指定的颜色）。涂鸦重绘用于大幅重绘，指定颜色、形状。（4）其它包括：涂鸦 ，在原图基础上涂纯色块（同样是告诉AI该区域应该用该颜色），再进行基础图生图。由于网页的局限，不如用PS涂色；上传蒙版 ，上传一张精确的蒙版，而非在网页中手画。可用PS制作，白色为蒙版区域，黑色为非蒙版。（5）图生图的理论与技巧画面占比大的事物，AI画起来简单，像手这类小东西AI容易崩，通过局部重绘，将局部放大后交给AI画，能得到很好的效果。另外还有以下注意：图生图的提示词，要描述你希望AI如何更改内容，并且提示词被其它参数分走了权重，必要时请适当加权； 图生图占用显存略大于文生图，但是局部重绘、仅参考局部时显存占用不大； 可以选择其它模型，但是要与原模型画风一致； 途中生成了一些有进步的图，可以替换原图，在有进步的基础上继续出图； 多次画蒙版时可能发现蒙版的范围有问题，这是SDW的bug，需要重新打开SDW并上传图片。（6）修手某张图的手部崩了，进行如下操作：a.把图片粘贴到图生图的 局部重绘 。也可以选择 发送到图生图 ，但是目前该功能bug较多；b.将手部涂上蒙版；c.正面提示词只需填写 hand 、 spread fingers 等手部相关的，反面提示词用 bandhandv4 （一个Embedding，见后）即可；d.重绘幅度默认0.75，调整这个值，直到手部合适，途中可以用修出来有改进的图替换原图。如果想加一根手指，可以吸手指色，在PS中涂到大概的位置，在 涂鸦重绘 中操作，注意提示词换成finger，详见原文。（7）添加元素用PS把素材/纯色块添加到需要的位置即可。（8）差分图差分图指画面的大部分元素不变，只改变某些元素（如人物的表情，天气）。图生图可以制作差分图，详见原文。（9）LoRA协同LoRA过拟合，或者两种不同画风的LoRA融合进同一张图。详见原文。（10）草图生图除了之前介绍的Control Net的LineArt，也可以用图生图，把简单的草图转换为复杂的图片。区别在于LineArt更适用于线条草图，图生图更多用于色块草图。8.训练LoAR9.使用技巧（1）复制参数从C站复制的参数都是一坨，包括正面、负面、步数、采样器等。把所有参数复制到正面tag里，在 生成 下面有个 从提示词或上次生成的图片中读取生成参数 ，就能把一坨参数改为SD能用的形式。（2）保存预设在 生成 下面的 编辑预设样式 ，可以把当前的生成样式保存为模板。（3）更换整合包时迁移数据参考 秋葉aaaki 。注意这里的 .cache 目录，Windows下正常是放在 C:\Users\用户名\.cache 下， 秋葉aaaki 整合包考虑到打包方便，一并放在这里。笔者猜测，Windows下可以在webui-user.bat里设置 XDG_CACHE_HOME 更改该文件位置；在linux下可能不需要？以上文件都需要转移。10.大模型推荐一些大模型的简单介绍，使用的注意事项，笔者主要是翻译一下模型的简介。排名按照目前（2024-1月）的下载量。这里能介绍的有限，笔者建议下载量超过100K的都可以下载试试，正式出图的时候把其中几个模型用好了就行，不需要太杂。由于模型更新的很快，这些内容在你读到的时候可能有较大出入。（1）Realistic Vision V6.0 B1Realistic Vision V6.0 B1 ，真实风对比度太强时，可以用 Detail Tweaker LoRA (细节调整LoRA) 减小对比度。建议的正面提示词：RAW photo, subject, 8k uhd, dslr, soft lighting, high quality, film grain, Fujifilm XT3其它建议的参数：Euler A or DPM++ SDE Karras CFG Scale 3.5 - 7 Hires. fix with 4x-UltraSharp upscaler Denoising strength 0.25-0.45 Upscale by 1.1-2.0 Clip Skip 1-2 ENSD 31337（2）ChilloutMixChilloutMix 真实+梦幻，偏真实比较适用于画亚洲人、big tits。（3）DreamShaperDreamShaper 真实+梦幻作者希望该模型能胜任所有图片生成。目前更新到了8，还有LCM版本（目前只能用LCM采样器）。建议设置：- I had CLIP skip 2 on some pics, the model works with that too. - I have ENSD set to 31337, in case you need to reproduce some results, but it doesn't guarantee it. - All of them had highres.fix or img2img at higher resolution. Some even have ADetailer. Careful with that tho, as it tends to make all faces look the same. - I don't use "restore faces".（4）majicMIX realistic 麦橘写实majicMIX realistic 麦橘写实 真实，亚洲，中国模型推荐参数：Sampler: Euler a, Euler, restart Steps: 20~40 Hires upscaler: ESRGAN 4x or 4x-UltraSharp or 8x_NMKD-Superscale_150000_G Hires upscale: 2+ Hires steps: 15+ Hires denoising strength: 0.05~0.5 clip skip 2 我习惯开启Dynamic Thresholding来更好控制cfg值，1~20都可以尝试一下。 如果要添加滤镜效果、噪点，请使用BMAB - https://github.com/portu-sim/sd-webui-bmab（5）Uber Realistic Porn Merge (URPM) [LEGACY Version]Uber Realistic Porn Merge (URPM) [LEGACY Version] 真实，欧洲，P站建议设置：Xformers: Off ETA Seed Noise Delta: 0 ClipSkip: 1为了避免出现各种年龄的人，正面提示词不要用 girl 、 boy ，而应用 woman 、 man 。除非指定人数时，可以用 1girl 、 2girl 。如果感觉效果不如预期，可以把反面提示词调轻，如：((blurry)), animated, cartoon, duplicate, child, childish（6）epiCRealismepiCRealism 真实建议参数：Prompt: simple explanation of the image (try first without extra keywords) Negative: "cartoon, painting, illustration, (worst quality, low quality, normal quality:2)" Steps: >20 (if image has errors or artefacts use higher Steps) CFG Scale: 5 (higher config scale can lose realism, depends on prompt, sampler and Steps) Sampler: Any Sampler (SDE, DPM-Sampler will result in more realism) Size: 512x768 or 768x512 Hires upscaler: 4x_NMKD-Superscale-SP_178000_G (Denoising: 0.35, Upscale: 2x)使用建议：use simple prompts no need to use keywords like "masterpiece, best quality, 8k, intricate, high detail" or "(extremely detailed face), (extremely detailed hands), (extremely detailed hair)" since it doesn't produce appreciable change use simple negatives or small negative embeddings. gives most realistic look (check samples to get an idea of negatives i used) add "asian, chinese" to negative if you're looking for ethnicities other than Asian Light, shadows, and details are excellent without extra keywords If you're looking for a natural effect, avoid "cinematic" avoid using "1girl" since it pushes things to render/anime style to much description of the face will turn out bad mostly for a more fantasy like output use 2M Karras Sampler no extra noise-offset needed, but u can if you like to （8）ReV AnimatedReV Animated 介于真实+梦幻建议图片规格：512x512、512x768、768x512提示词建议：Order matters - words near the front of your prompt are weighted more heavily than the things in the back of your prompt. Prompt order - content type > description > style > composition This model likes: ((best quality)), ((masterpiece)), (detailed) in beginning of prompt if you want anime-2.5D type This model does great on PORTRAITS（8）Perfect World 完美世界Perfect World 完美世界 介于真实+梦幻，中国模型，P站（9）MeinaMixMeinaMix 动漫使用建议：Enable Quantization in K samplers. Hires.fix is needed for prompts where the character is far away in order to make decent images, it drastically improve the quality of face and eyes!参数建议：Sampler: DPM++ SDE Karras: 20 to 30 steps. Sampler: DPM++ 2M Karras: 20 to 60 steps. Sampler: Euler a: 40 to 60 steps. CFG Scale: 4 to 11. Resolutions: 512x768, 512x1024 for Portrait! Resolutions: 768x512, 1024x512, 1536x512 for Landscape! Hires.fix: R-ESRGAN 4x+Anime6b, with 10 steps at 0.3 up to 0.6 denoising. Clip Skip: 2. Negatives: ' (worst quality, low quality:1.4), (zombie, sketch, interlocked fingers, comic) ' Negatives if you can't use Hires.fix: '(worst quality:1.6, low quality:1.6), (zombie, sketch, interlocked fingers, comic)'（10）Beautiful Realistic AsiansBeautiful Realistic Asians 真实，亚洲（11）CyberRealisticCyberRealistic 真实，相片推荐VAE： sd-vae-ft-mse-original ，就是840000那个。（12）Counterfeit-V3.0Counterfeit-V3.0 动漫11.小模型推荐由于模型更新的很快，这些内容在你读到的时候可能有较大出入。（1）快速出图使用LCM插件，具体见上文。建议在调整tag、参数时使用LCM，因为LCM和最终出图大体差不多，但是细节稍微差一些；然后在正式出图时关闭LCM。LCM也可以在生成视频时使用。另外，有些模型现在也有LCM版本，但是必须使用LCM采样器（而非DPM、Euler等），比如DreamShaper-8就有LCM后缀的模型。（2）快速反面tag秋葉aaaki 整合包中， embeddings 下自带了反面tag的Embedding，使用时只需要在反面提示词里加上这些文件名即可。分别是：EasyNegative 最初用于Counterfeit-V3大模型。Deep Negative V1.x ，它有几个版本，最易上手的是75T，见下：75T: The most “easy to use” embedding, which is trained from its accurate dataset created in a special way with almost no side effects. And it contains enough information to cover various usage scenarios. But for some "good-trained-model" may hard to effect. And, change about may be subtle and not drastic enough. 最易上手。 64T: It works for all models, but has side effect. so, some tuning is required to find the best weight. recommend: [( NG_DeepNegative_V1_64T :0.9) :0.1] 太强了，可能需要减轻权重。 32T: Useful, but too more 同样太多了。 16T: Reduces the chance of drawing bad anatomy, but may draw ugly faces. Suitable for raising architecture level. 改进肢体，但是可能脸画崩。 4T: Reduces the chance of drawing bad anatomy, but has a little effect on light and shadow 可能光影画崩。 2T: “easy to use like T75”, but just a little effect 太弱了。badhandv4 - AnimeIllustDiffusion ，针对手部。其它的还有：Fast Negative Embedding (+ FastNegativeV2) ，V1版本太强了建议权重0.9，V2版本不需要。negative_hand Negative Embedding ，针对手部，对原画风改动较小。（3）添加/减少细节Detail Tweaker LoRA (细节调整LoRA) ，建议取值2到-2之间，正数为添加画面细节、负数减少细节。（4）梦幻/现实BadDream + UnrealisticDream (Negative Embeddings) ，BadDream适用于营造梦幻感，UnrealisticDream用于真实感，可正面可负面。（5）水墨风墨心 MoXin 水墨风分为 墨心 和 疏可走马 ，使用后者时会生成大面积留白。注意事项：1.）CFG范围将会改变风格 1~3 : 大小写意 3~7 : 逐渐工笔 2.）推荐基础模型为ChilloutMix、国风3.2等 3.）《墨心》的推荐Lora权重为0.85以下 4.）《疏可走马》推荐Lora权重为0.7~112.保护画师作品通过给图片加上一些抗AI的水印（包括Mist、Glaze等），防止画师的作品被用于AI训练。当然，也有去除这些水印的方法，见 秋葉aaaki 。
Python，爬虫与深度学习（18）——Ubuntu下安装stable diffusion
步骤/目录： 1.背景介绍 2.安装CUDA （0）卸载之前的CUDA、驱动 （1）安装依赖项 （2）检查PyTorch兼容的CUDA （3）安装CUDA （4）将CUDA添加到PATH （5）安装PyTorch （6）初运行Stable Diffusion WebUI 3.SDW的更新 4.安装问题 （1）无法连接到github （2）运行webui.sh时提示没有pip3模块 （3）运行webui.sh时提示TCMalloc （4）SafetensorError （5）其它模块 附录-显卡厂商的区别本文首发于个人博客https://lisper517.top/index.php/archives/278/，转载请注明出处。本文的目的是在ubuntu机器上安装stable diffusion。本文写作日期为2024年1月5日。系统为 Ubuntu 22.04 LTS ，显卡为 GTX 1050Ti mobile，4G显存。主要参考了 文章一 。1.背景介绍2020年笔者读到了一本深度学习的书：《深度学习入门：基于 Python 的理论与实现》，作者是斋藤康毅，书上介绍的东西简单易懂（比如深度学习界的Hello World-识别手写数字），比较适合入门。后来从一些量化交易的论坛获得了中国股市过去30年每天的开盘、收盘、最高、最低价数据，试图用机器学习找出其中的规律，最后得出结论：股市的数据是完全随机的、或者有其它的隐变量，不适用于机器学习。之前笔者还写过系列文章：《Python，爬虫与深度学习》，但是只介绍完了爬虫，还没有涉及深度学习。2022-2023年stable diffusion、chatgpt如火如荼，今天便重拾这个系列。Stable Diffusion刚出来时笔者也在windows上进行了尝试，当时用的 AMD RX 5500 XT 大概30s一张图。如果想浅尝，笔者建议用Nvidia的p104显卡（8G显存魔改版），闲鱼只要￥120左右（显卡扩展坞都值4张p104），跑512*512的图大约10s（但是装驱动有点麻烦）；目前商用跑图性价比最高的应该是￥3500的 4060Ti 16G ，但是这个价格还是太高了。只生成图片，至少需要4G显存，推荐8G；要训练自己的模型，推荐12G；内存推荐16G；固态硬盘。如果要买新显卡，关于各种显卡厂商的区别，可参考 知乎回答 ，或 附录。接下来笔者将在Ubuntu上安装SD。如果想在Windows上体验，可以下各位大佬的安装包，见 秋葉aaaki ，网盘为 夸克 ；Win + AMD ，则用 这个整合包 ，使用说明见 b站 （A卡跑图性能大概是同价位N卡的一半）。2.安装CUDA以下的操作需要切换到有sudo权限的非root用户进行。创建该用户的操作如下（参考 提升树莓派安全性 ）：mkdir /home/SD useradd -d /home/SD SD -m #SD也将装在该家目录下，建议至少有100GB空间 chown -R SD:SD /home/SD passwd SD usermod -aG sudo SD vim /etc/sudoers.d/SD加一行：SD ALL=(ALL) NOPASSWD: NOPASSWD: ALL（0）卸载之前的CUDA、驱动如果之前装过CUDA，或者在本次流程装CUDA时出现了意外，可以卸载后重装。参考 Nvidia官方文档 ，执行以下命令：sudo apt-get --purge remove "*cuda*" "*cublas*" "*cufft*" "*cufile*" "*curand*" \ "*cusolver*" "*cusparse*" "*gds-tools*" "*npp*" "*nvjpeg*" "nsight*" "*nvvm*" sudo apt-get --purge remove "*nvidia*" "libxnvctrl*" sudo apt-get autoremove（1）安装依赖项安装一些依赖项：python3 -V #如果没有显示python3版本，就apt install python3，或者参考后文 sudo apt install wget git python3-venv安装python的版本需要注意，由于后文 --xformers 选项，笔者安装的是python-3.10.11。（2）检查PyTorch兼容的CUDA到 PyTorch官网 ，找到下面的 INSTALL PYTORCH 。需要选择以下几项：PyTorch Build 选 Stable Your OS 选 Linux Package 选 Pip Language 选Python下面的 Compute Platform 看一下CUDA版本号。本文写作时支持的CUDA为11.8、12.1，选择11.8进行安装（因为后面的 --xformers 选项仅支持CUDA 11.8）。这个网站暂时不要关闭。（3）安装CUDA到 CUDA各版本归档 找对应的版本，小版本号可能无所谓，本文选择11.8.0。修改以下网址https://developer.nvidia.com/cuda-11-8-0-download-archive?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=22.04&target_type=deb_local中的版本号（ cuda-11-8-0 ）并访问该网址，有需要的可以自行选择其它参数，值得注意的是这里选择的是下载包到本地安装。最后下面会生成安装需要的命令，本文写作时生成了如下命令：wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-ubuntu2204.pin sudo mv cuda-ubuntu2204.pin /etc/apt/preferences.d/cuda-repository-pin-600 wget https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda-repo-ubuntu2204-11-8-local_11.8.0-520.61.05-1_amd64.deb sudo dpkg -i cuda-repo-ubuntu2204-11-8-local_11.8.0-520.61.05-1_amd64.deb sudo cp /var/cuda-repo-ubuntu2204-11-8-local/cuda-*-keyring.gpg /usr/share/keyrings/ sudo apt-get update sudo apt-get -y install cuda-11-8需要注意的是最后一条命令原本是 apt-get -y install cuda ，必须加上版本号，否则会下载最新的CUDA。如果有小版本号，应该也是要加上的。SD能成功运行后， cuda-repo-ubuntu2204-11-8-local_11.8.0-520.61.05-1_amd64.deb 这个包可以删掉。（4）将CUDA添加到PATH安装好CUDA后，检查一下：/usr/local/cuda-11.8/bin/nvcc --version然后把CUDA加入路径：vim ~/.bashrc添加：export PATH="/usr/local/cuda-11.8/bin:$PATH" export LD_LIBRARY_PATH="/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATH"然后打开新的终端，用 which nvcc 检查一下，能找到正确的nvcc。（5）安装PyTorch刚才打开的 PyTorch官网 ，复制下面的命令以安装PyTorch：pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118需要注意的是，该命令有可能不指定CUDA版本：pip3 install torch torchvision torchaudio为了避免装错，应该指定一下：pip3 install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu118这里可以先装好PyTorch，节省时间；如果不想打乱本机的python库，这里也可以不装。最后重启一下，显卡驱动才能被正确调用。（6）初运行Stable Diffusion WebUIgit clone --branch v1.7.0 https://github.com/AUTOMATIC1111/stable-diffusion-webui目前最新的版本就是1.7.0，也可以选择1.2.1等老版本。笔者经过与SD的一番搏斗，最终选择了上文提到的 秋葉aaaki整合包 （用前需要 sed -i 's/\r$//' ./*.sh ，因为Windows下的换行符 '/r' 在linux下是多余的），该整合包是1.6.0的，在Ubuntu上安装前先在Windows下解压、打开其中的启动器，通过启动器进行更新，把更新好的整合包复制到Ubuntu。考虑到更新的便捷性，笔者建议通过Samba将SDW安装文件夹在Windows和Ubuntu之间共享，在Windows上通过启动器管理更新，在Ubuntu上运行。Samba见笔者以前的文章： 树莓派+Samba+frp搭建NAS（网络云存储） 。其中的 webui-user.sh 可以修改一些配置：export COMMANDLINE_ARGS="--xformers --medvram --listen" export TORCH_COMMAND="pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118" #安装PyTorch的命令。如果用pip3，会提示没有pip3模块默认 install_dir="/home/$(whoami)" 安装在家目录下（但是笔者实测默认安装在本目录下），可修改安装目录。建议安装硬盘至少100GB空间，且最好是SSD硬盘（否则每次启动都要等5min）。参数方面， --xformers 可略微加快出图速度；由于笔者的显存为4G，所以加上了 --medvram ； --listen 允许本机外的电脑访问。其它参数见 SDW选项 ，比较有用的是 --autolaunch ，开机后自动运行SD（如果装模型等原因需要重启SD时，在网页的 扩展 中可以重启）。用 nvidia-smi 可以查看你的显存，同时也检查显卡驱动是否正确。如果没有正确显示，先重启一下以保证驱动应用。为了避免出现红字 Cannot locate TCMalloc (improves CPU memory usage) ，使用：sudo apt-get install libgoogle-perftools4 libtcmalloc-minimal4 -y最后开始初运行。请确保这一步之前、装驱动之后至少重启过一次电脑，并且这里最好全程翻越，否则容易出现各种连接不上：sudo ufw allow 7860 comment "SD WebUI" chmod 755 webui-user.sh bash ./webui-user.sh bash ./webui.shwebui.sh 第一次运行时会安装一些依赖项，用时可能数小时，用整合包的话快一点。最后，到7860端口访问即可。画512*512图测试，使用 watch -d -n 1 nvidia-smi 观察显卡状态，显存占用保持在 3228/4096MiB ，出一张图50s左右。时间可以接受，笔者主要为了给显卡找点事情干。下一篇文章将讲解SD的使用。3.SDW的更新SD内各种插件有时需要更新，在WebUI虽然也能更新，但访问外网太慢了，更建议通过Samba将SDW在Windows和Ubuntu间共享，在Windows上通过整合包的启动器（A绘世启动器.exe）更新（参考 秋葉aaaki ），一定要注意在更新前首先关闭SDW。对于1.6.0版本启动器，在 版本管理 页中可以找到内核（SDW版本）、扩展，右上角有一键更新。另外，每次更新后都要重新修改 webui-user.sh ，笔者常用：export COMMANDLINE_ARGS="--xformers --medvram --listen --enable-insecure-extension-access" export TORCH_COMMAND="pip install torch==2.0.1+cu118 torchvision==0.15.2+cu118 torchaudio==2.0.2 torchtext==0.15.2+cpu torchdata==0.6.1 --index-url https://download.pytorch.org/whl/cu118"并且 sed -i 's/\r$//' ./*.sh 一下。4.安装问题（1）无法连接到github因为美国不允许我们使用github，所以需要翻越。实际上最好在安装中全程翻越，否则总是遇到奇怪的问题。（2）运行webui.sh时提示没有pip3模块No module named pip3 ，因为 webui-user.sh 里， export TORCH_COMMAND="pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118" 的pip写成了pip3。venv里的pip和pip3没有软链。如果在Win，参考 这个问题 ，把venv文件里的内容删掉以重新创建venv，或者用 python3 -m ensurepip 。（3）运行webui.sh时提示TCMalloc出现红字 Cannot locate TCMalloc (improves CPU memory usage) 。参考 这个问题 ，使用 sudo apt-get install libgoogle-perftools4 libtcmalloc-minimal4 -y ；或者，如果是你的SD找不到TCMalloc，在 webui-user.sh 中加上 PATH=$PATH:/usr/sbin 。OpenSUSE请参考原回答。笔者的电脑内存为32GB，感觉这个问题不大，但还是装上好一点。（4）SafetensorError运行webui.sh时提示：Loading weights [7912d8218e] from /xxx/stable-diffusion-webui/models/Stable-diffusion/v1-5-pruned-emaonly.safetensors loading stable diffusion model: SafetensorError Traceback (most recent call last): ··· ··· ··· safetensors_rust.SafetensorError: Error while deserializing header: MetadataIncompleteBuffer根据 这篇文章 ，到 这个网址 手动下载模型 v1-5-pruned-emaonly.safetensors （如果报错是ckpt，则下载ckpt），然后放到 models\Stable-diffusion 下。用整合包时 models\Stable-diffusion 下是其它文件，但是没有这个问题。（5）xformers显示如下：WARNING:xformers:WARNING[XFORMERS]: xFormers can't load C++/CUDA extensions. xFormers was built for: PyTorch 2.0.1+cu118 with CUDA 1108 (you have 2.1.2+cu118) Python 3.10.11 (you have 3.10.12) Please reinstall xformers (see https://github.com/facebookresearch/xformers#installing-xformers) Memory-efficient attention, SwiGLU, sparse and more won't be available. Set XFORMERS_MORE_DETAILS=1 for more details后面虽然说 Applying attention optimization: xformers... done. ，但是 xformers 可能还是没有生效，需要下载2.0.1的PyTorch、使用3.10.11的python。根据 这个回答 ，首先删除venv：rm -r venv/*然后手动创建一下venv环境。由于python3-venv无法创建系统上没有的python版本，所以安装python 3.10.11（这会删除之前的3.10.12）：cd /tmp wget https://www.python.org/ftp/python/3.10.11/Python-3.10.11.tgz sudo apt install libssl-dev libncurses5-dev libsqlite3-dev libreadline-dev libtk8.6 libgdm-dev libdb4o-cil-dev libpcap-dev #解决pip的TLS/SSL问题 sudo apt-get install libbz2-dev #解决_bz2模块的问题 sudo apt-get install liblzma-dev #_lzma模块 tar -zxvf Python-3.10.11.tgz cd Python-3.10.11 ./configure --enable-optimizations make && make test sudo make install cd .. pip install lmdb #lmdb库能够运行SD后，可以删掉python安装包和目录（也可以不删）。如果你有多个python3，可以设置一下优先级，本文并不需要：update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10.11 1 update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10.12 10 update-alternatives --config python3 python3 -V数值越大越优先。在 webui-user.sh 中，把安装PyTorch的命令修改如下（如果报错显示非PyTorch2.0.1，可能不适用）：pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 改为 pip install torch==2.0.1+cu118 torchvision==0.15.2+cu118 torchaudio==2.0.2 torchtext==0.15.2+cpu torchdata==0.6.1 --index-url https://download.pytorch.org/whl/cu118重新运行。（5）其它模块安装模块后，重装python3，然后重新运行 webui.sh 。_bz2：sudo apt-get install libbz2-dev_lzma：sudo apt-get install liblzma-dev附录-显卡厂商的区别作者：申宏宇链接：https://www.zhihu.com/question/652729281/answer/3473132108来源：知乎著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。显卡品牌大概可以分为一二三线，就是按照产品力、品牌影响力和售后几大方面打分，如果三项得分全都名列前茅，可以称之为一线品牌，如果只有两项突出，可以被评为二线品牌；如果只有一项可以，就被称为三线。（评价区建议插一句，为什么显卡有那么多的品牌，还有各品牌与英伟达的关系。）英伟达为华硕提供GPU，而华硕或其他品牌则生产实际的显卡产品。英伟达负责设计显卡芯片，并将其交给如台积电这样的芯片代工厂生产。随后华硕等AIC厂商（即英伟达的亲密合作伙伴）会向英伟达购买芯片，并为这些芯片设计专属的PCB电路、散热器， 最终组装成我们看到的显卡。我说的显卡做工以及用料等级，指的便是显卡的外观、散热、PCB电路板这些外部因素，而非型号区别。显卡的做工和用料按等级划分可以分为旗舰卡、次旗舰、中端、入门、低端几个档次。从高到低来，先说一线。1.一线厂商一般约定俗成的一线厂商有：华硕、微星、技嘉、七彩虹，这四家里华硕算老大，微星万年老二，技嘉和七彩虹争夺老三的位置。（1）华硕华硕算是认可度最高的了，毫无争议的第一，售后很好，支持三年个人送保，牌子也大，你要送礼可以首选华硕。华硕从高端到低端的系列有：ROG猛禽、TUF电竞特工、雪豹和巨齿鲨。ROG猛禽无疑的当代卡皇，猛禽又分为OC版和普通版，OC就是厂商预超频版的意思，你可以简单理解为性能更强了。一般情况下OC版的芯片体质更好，极限频率比普通版高，单纯从外观来说OC和普通猛禽没区别。TUF电竞特工是次旗舰级别的卡，用料不错，外观没有猛禽好看，并且没有败家之眼的信仰加成。华硕的信仰加成全在这个眼睛图标上了，没这个图标B格砍一半，不差钱还是建议直接ROG。再往下的雪豹和巨齿鲨是入门级的卡，产品用料对比旗舰卡缩水不少，但是胜在售后可以，并非不能选。（2）微星微星和华硕主要差在品牌影响力上，其他方面并不差，基本可以做到保二争一，所以万年老二。微星显卡从高端到低端的有：超龙、魔龙、万图师。超龙是对标ROG猛禽系列的卡，做工用料和华硕不相上下。魔龙是次旗舰的卡，4090魔龙表现一般，但是我感觉魔龙的外观比TUF电竞特工好看，你想送微星的卡可以选这个。万图师是纯纯低端卡，用料极其缩水，等级要略低于华硕的雪豹。（3）技嘉技嘉显卡也就那么回事，这牌子素有拒保嘉的称号，因为他家的售后电商渠道不保，其他渠道三年个人送保，还经常拒绝保修，单纯从售后层面就差了一层。技嘉从高端到低端分别是：雕系列、魔鹰、猎鹰。雕系列是旗舰卡，对标猛禽和超龙的，但是产品力在三家里面垫底。魔鹰是次旗舰卡，跟魔龙和华硕TUF平替，三个系列平起平坐。猎鹰是中端卡，做工和散热要高于雪豹和万图师，但是猎鹰价格也不便宜，算是三个系列中最贵的。技嘉我不推荐你买，因为这个品牌很垃圾，号称御三家之耻。（4）七彩虹七彩虹是一个专注做显卡的厂商，除了显卡都不行，他家的显卡在众多品牌中能站稳一线，在国内销量很高，比华硕卖的显卡还多。而且七彩虹的售后也不错，支持三年个人送保，服务点也多，我感觉从售后方面七彩虹要强过微星一些。七彩虹显卡从高端到低端分别是：火神、Advance、ultra、战斧系列。火神是旗舰卡，对标其他三家的旗舰卡，火神的外观有些特色，带一个可以反转的LED屏幕，基本可以平替ROG猛禽和微星超龙。Advance是次旗舰，比较舍得用料，属于接近旗舰级的次旗舰卡，还是很有水平的。ultra是中端卡，对标技嘉猎鹰；战斧豪华版是入门卡，对标华硕雪豹；战斧是低端卡，对标微星万图师。七彩虹是一挑三，产品线分的很细，对每家都有针对的卡。2.二线厂商一线基本说完了，说说二线。二线目前就是索泰、影驰、耕升、映众、铭瑄、盈通。（1）索泰索泰号称堆料泰，意思就是舍得下料，就好像同样是做珍珠奶茶的店，索泰家做的奶茶珍珠多放一点，但是实际喝起来没啥差别。索泰从高端到低端分别是：AMP、天启、X-Gaming、毁灭者。AMP是旗舰卡，天启是次旗舰卡，但是天启的纸面规格接近AMP，性价比更高。所以选天启的人多一点。X-Gaming是入门卡，比中端略差。毁灭者是低端卡，和万图师差不多。送礼想选索泰，看看天启系列就差不多了。（2）影驰影驰从高端到低端分别为：名人堂、星耀、金属大师、将系列。名人堂是对标微星超龙和ROG猛禽的系列，属于旗舰卡，但是因为是二线品牌，终归差了一点意思。星耀是次旗舰，几乎和七彩虹Advance平齐，素质还不错。金属大师是中端卡。将系列是低端卡。影驰和耕升算是兄弟关系，所以他俩很多显卡都是互相换皮，影驰显卡的外形和宣传比耕升强一些，于是慢慢超过耕升了，本质上他俩还是差不多的品牌。（3）耕升耕升算是老牌厂商，挺有实力的，就是名字起的不咋地，感觉听着像杂牌。做工和用料跟影驰差不多，因为他俩都是一家代工厂生产的，不过个人觉得外形方面影驰更好看。耕升从高到低分别是：炫光、星极、追风。耕升的星极和影驰的星耀基本就是换皮，他俩的PCB板基本都差不多，只是外观和散热略有不同。追风和金属大师也是如此。因为散热和外观差别，耕升的显卡比影驰的低半级。（4）映众映众和索泰是一个厂家生产的，但是用料没有索泰豪华，甚至近几年越来越寒酸了。映众从高端到低端分别是：冰龙、电竞判客。冰龙属于次旗舰级别的卡，距离旗舰卡还有一定的距离。电竞判客属于入门级别，比微星万图师略强。（5）铭瑄铭瑄号称丐帮帮主，是二线里面价格比较实惠的品牌，主打二次元外观。铭瑄从高端到低端分别是：电竞之心、瑷珈、终结者。电竞之心和瑷珈用料几乎差不多，瑷珈走的是二次元风格，电竞之心就是传统造型的，喜欢萌妹风格的可以看看瑷珈。电竞之心属于中端卡，大概相当于影驰的金属大师级别，但是却有着近乎低端卡的售价，因为性价比极高，也被大家戏称丐帮帮主。终结者就是低端卡，不过价格卖的也很低，质量也还行，算是比较良心的品牌。（6）盈通盈通也是主打二次元的品牌，基本和铭瑄瑷珈一个路子。盈通从高端到低端分别是：樱瞳花嫁、六道兵甲、大地之神。樱瞳花嫁属于中端卡，六道兵甲属于入门卡，大地之神属于低端卡。盈通整体实力不如铭瑄，如果让我从铭瑄和盈通里面选一个，我可能会选铭瑄。不过盈通显卡的背板还不错，很好看。
步骤/目录： 1.背景介绍 2.测试IPv6 3.购买域名，DNS解析 4.安装ddns-go 5.端口被封禁的解决方法 6.安全措施 7.进阶搭配使用本文首发于个人博客https://lisper517.top/index.php/archives/246/，转载请注明出处。本文的目的是使用 IPv6 + DDNS 以访问内网ubuntu机器。本文写作日期为2024年1月4日，主要参考了 这篇文章 。1.背景介绍在以前的文章中，笔者介绍过frp，也介绍过DDNS。通过frp，购买一台有公网IPv4地址的云服务器，可以将内网机器开放到公网，还可以搭配NPM给内网机器分配不同的子域名。缺点有：（1）服务器成本；（2）如果被封禁80、443端口，需要换ip，但除了vultr等少数厂商外，很多厂商都不能免费换ip；（3）受服务器网速限制，家里的上传带宽一般都不能跑满。优点则是：（1）内网机器不直接暴露端口，获得了一层额外的保护。DDNS（动态DNS），如果你有幸获得了公网IPv4地址（前几年的电信据说比较容易获得），一般是一个动态的公网v4，每次拨号都会变化。通过DDNS，一个固定域名可以与你每次都不同的v4地址绑定，从而方便使用。参考 路由器与DDNS 。随着IPv6的普及，现在基本上一半的网址都能通过v6访问（手机基本上都支持v6）。由于v6能提供的地址太多，协议也比较新鲜，美国暂时没有管制v6发放，现在使用v6的机器都能分配到公网v6地址。但是v6地址太长且经常变化，使用不方便，所以需要搭配DDNS（动态DNS）使用。最后需要提醒，v6 + DDNS 的方案会将内网机器直接暴露到公网，所以一定要设置好防火墙。对于linux系统，这里推荐ufw防火墙（见 ufw简介与树莓派安装ufw ）和fail2ban端口封禁（见 Fail2ban提升服务器安全性 ）。2.测试IPv6第一步确认自己的路由器、光猫能否访问IPv6。先到光猫、路由器后台找到v6相关设置，把v6打开，如果路由器自带v6防火墙可以暂时先打开。然后访问 IPv6 连接测试 和 ddnspod提供的v6检测 （如果有代理，此时需要关闭代理），正常情况下会显示电脑的v6地址，并且结果相同。接下来最好把光猫改桥接，因为光猫的性能较差，而且光猫的防火墙喜欢拦截入站的v6请求。直接打电话给运营商转人工服务，要求光猫改桥接，几分钟就好了。如果不知道自己的宽带账号密码，可以顺便问一下。接着到主路由管理页面，上网方式从DHCP（或者静态IP）改到PPPoE，输入宽带拨号的账号密码即可。另外，ipv6、ipv4的DNS也可以手动改一下，以缓解DNS污染，这里提供cloudflare和google的：cloudflare: 1.1.1.1；1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001 google: 8.8.8.8；8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844路由器PPPoE能成功上网后，查看路由器的v6地址，复制到 IP查询 ，看一下路由器是否公网v6，也可以在cmd中 ping -6 你的v6地址 能否ping通，不是的话可以先关闭路由器防火墙，还是不行的话问一下运营商。最后，在浏览器访问路由器的v6地址（注意网址栏的v6地址要用 [] 括起来），应该能看到路由器的登录界面。显示 ERR_CONNECTION_REFUSED ，那一般是防火墙的问题。这里如果看不到也没关系，后面的方案是把内网的其它机器开放而非路由器开放到公网。3.购买域名，DNS解析以下购买域名的厂商称为域名厂商，提供DNS的厂商称为DNS厂商。购买一个自己的专属域名，最便宜的依然推荐 namesilo ，因为没什么套路，域名续费也很便宜。如果不会用namesilo，也可以在cloudflare、阿里云、腾讯云等购买，当然可能会稍微贵一点。普通的top域名一般一年在￥9.9-99比较合理。如果在namesilo购买域名，还要设置一下DNS解析，因为namesilo的DNS不是很给力。把DNS服务器修改到DNS厂商，笔者最推荐cloudflare。然后转到DNS厂商，把域名解析到路由器的v6地址进行测试（cloudflare），等几分钟（解析记录需要几分钟扩散），浏览器访问该域名，也许能看到路由器的登录页面（看不到也没关系）。最后，登录到你的DNS厂商，获得一个token令牌。以阿里云为例，在头像处的下拉菜单中找到AccessKey，创建一个，保存好（忘记保存就再创建一个），AccessKey ID相当于用户名，AccessKey Secret相当于密码。各家DNS厂商可能有一些细小的区别，其它厂商可能叫token令牌、API之类的。总之它会给你一串只出现一次，但可以重复创建的字符作为令牌，用令牌可以对接认证到该厂商进行一些服务。权限最高的称为全局令牌，只拥有某些权限的是局部令牌或者子令牌，一般来说尽量用局部令牌，并且令牌要严防泄露，如果不小心泄露了要及时重新创建。4.安装ddns-go路由器每次重启获得的v6地址都会变化，即动态ip地址，家庭内的其它电脑也一样。现在需要的最后一步就是让电脑每次开机时，通过token对接到DNS厂商，更改DNS解析，将你的域名解析到新的v6地址。好在这一步有现成的工具，即 ddns-go 。接下来就演示在linux下，通过docker安装ddns-go。另外提醒一下，群晖、win、mac也是可以用ddns-go的。需要说明的是，一些路由器也可以进行类似的操作，把路由器暴露到公网。笔者不推荐这样做，因为一般都需要刷固件、新手容易刷坏，而且路由器设置防火墙也稍微要复杂一点。如果想折腾，可以到 恩山论坛 看看有没有自己路由器对应的教程。安装好docker、docker-compose后（参考 Docker入门（一） 和 Docker入门（二） ），在linux上如下操作：mkdir -p /docker/ddns-go/conf/ddns-go cd /docker/ddns-go vim docker-compose.yml写入以下内容：version: '3.8' services: ddns-go: image: 'jeessy/ddns-go:latest' container_name: ddns-go network_mode: host volumes: - /docker/ddns-go/conf/ddns-go:/root restart: always用ufw打开ddns-go使用的9876端口，并运行ddns-go：ufw allow 9876 comment "ddns-go" ufw status docker-compose config docker-compose pull docker-compose up然后网页访问 linux机器ip:9876 ，配置一下。ddns-go的配置比较简单，选一个DNS厂商（也可以多个DNS厂商配置都针对一条解析，能提高解析传播速度。目前支持 Cloudflare、阿里云Alidns、腾讯云Dnspod、华为云、Callback、百度云、Porkbun、GoDaddy、Google Domain），填入该厂商的token，关闭v4，开启v6即可。等待几分钟到半个小时后，通过公网访问该linux机器的网页服务或者SSH测试，记得打开端口。5.端口被封禁的解决方法笔者发现IPv6的80和443被封禁了，但其它端口还能访问。具体表现为内网能通过域名访问，外网不行（但外网ping又能获得正确的IPv6地址），如果把网页服务改到其它端口则外网能访问。解决方法见 可视化管理Nginx-Nginx Proxy Manager 。6.安全措施最后提醒，v6 + DDNS 会将内网机器端口直接暴露到公网。笔者建议的安全措施如下：（1）设置复杂密码。担心记不住密码，浏览器可以记忆，或者用vaultwarden等密码管理工具（参考 VaultWarden ）。（2）SSH设置仅密钥登录，并且密钥设置密码。（3）su用户和sudo用户分开。su指切换用户的权限，sudo指执行命令权限，这样的话即使密钥泄露，登录以后还是要通过密码切换到sudo用户才能执行其它命令。（4）用好ufw（见 ufw简介与树莓派安装ufw ，推荐用 ufw allow from 192.168.1.0/24 to any port 22 这样指定来源ip的形式），fail2ban（见 Fail2ban提升服务器安全性 ）。同时也要理解frp这类穿透能无视ufw。（5）用好docker，做好备份。（6）设置非常规端口，或者更进一步用NPM等反代工具（只需要暴露80、443，扫端口的一般不会去猜子域名）。当然，v6因为地址太多了，其实被扫IP的风险相比v4已经大大降低。7.进阶搭配使用（1）NPM，方便管理各种子域名，见 可视化管理Nginx-Nginx Proxy Manager 。（2）如果要将内网的其它机器也通过该linux机器开放到公网，可以使用 NPM + frp ，也就是开放的机器作frps，其它内网机器为frpc。
步骤/目录： 1.背景介绍 2.Matrix与element的安装 3.Matrix的设置与使用 （1）初始化 （2）注册管理员账号 （3）关闭注册功能 （4）其它本文首发于个人博客https://lisper517.top/index.php/archives/225/，转载请注明出处。本文的目的是介绍一款去中心化的私密聊天软件-Matrix。本文写作日期为2024年1月1日。主要受up主 我不是咕咕鸽 的启发。他还分享了很多其它有趣的内容，讲解也很详细、基础，很适合小白学习。1.背景介绍在日常管理服务器的过程中，一些工具能大大减轻工作量。前几天在up主 我不是咕咕鸽 的空间看到了很多有趣的分享，也尝试自己搭建一下。Matrix是一款支持端到端加密、去中心化的聊天服务器软件，比较适合小公司或者需要保护公司秘密、个人隐私时。你可以搭建自己的Matrix服务器，借助一些Matrix的客户端，在自己的服务器内，或者与其它的Matrix服务器通信。2.Matrix与element的安装在服务器上如下操作：mkdir -p /docker/matrix/data/matrix mkdir -p /docker/matrix/conf/element接下来需要运行一次Matrix，生成默认的配置等文件（把域名改成自己为Matrix准备的域名）：sudo docker run -it --rm \ -v /docker/matrix/data/matrix:/data \ -e SYNAPSE_SERVER_NAME=matrix域名 \ -e SYNAPSE_REPORT_STATS=yes \ matrixdotorg/synapse:latest generate修改一下homeserver.yaml，允许注册、允许无验证注册：vim /docker/matrix/data/matrix/homeserver.yaml在末尾加入以下两行（也可以不加，因为能通过其它方式创建用户）：enable_registration: true enable_registration_without_verification: true修改后该文件内容如下：# Configuration file for Synapse. # # This is a YAML file: see [1] for a quick introduction. Note in particular # that *indentation is important*: all the elements of a list or dictionary # should have the same indentation. # # [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html # # For more information on how to configure Synapse, including a complete accounting of # each option, go to docs/usage/configuration/config_documentation.md or # https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html server_name: "你的matrix域名" pid_file: /data/homeserver.pid listeners: - port: 8008 tls: false type: http x_forwarded: true resources: - names: [client, federation] compress: false database: name: sqlite3 args: database: /data/homeserver.db log_config: "/data/你的matrix域名.log.config" media_store_path: /data/media_store registration_shared_secret: "一串密码" report_stats: true macaroon_secret_key: "一串密码" form_secret: "一串密码" signing_key_path: "/data/你的matrix域名.signing.key" trusted_key_servers: - server_name: "matrix.org" enable_registration: true enable_registration_without_verification: true # vim:ft=yaml最后创建一下yml：cd /docker/matrix vim docker-compose.yml写入以下内容：version: "3.3" services: synapse: image: "matrixdotorg/synapse:latest" container_name: "matrix" ports: - 8008:8008 volumes: - "./data/matrix:/data" environment: VIRTUAL_HOST: "你的matrix域名" VIRTUAL_PORT: 8008 LETSENCRYPT_HOST: "你的matrix域名" SYNAPSE_SERVER_NAME: "你的matrix域名" SYNAPSE_REPORT_STATS: "yes" restart: unless-stopped element-web: image: vectorim/element-web ports: - '80:80' #用好了element默认设置后，可以挂自己的设置 #volumes: #- "./conf/element/config.json:/app/config.json" restart: unless-stoppedElement是Matrix应用较广的一个客户端，有web、PC、手机端（国内无法用到），这里顺便把element网页端也搭建了。两个分别用80、8008，有冲突的话改一下。最后运行：docker-compose config docker-compose up如果有NPM的话，可以给2个子域名，详见 可视化管理Nginx-Nginx Proxy Manager 。总之通过各种方式，使得两个域名都通过https访问。3.Matrix的设置与使用（1）初始化访问你的matrix域名，能看到matrix界面。访问你的element域名，可以切换，以你的matrix域名作为服务器，注册一个账号。但是现在先不要注册，因为还需要创建一个管理员。（2）注册管理员账号根据 官方文档 ，Matrix可以通过修改数据库来将已有的用户改为管理员，或者用 register_new_matrix_user 在新建用户时顺便赋予管理员权限。笔者用第二种方式演示：docker exec -it matrix bash #进入matrix容器 register_new_matrix_user --help register_new_matrix_user -u 用户名 -p 密码 --admin -c "/data/homeserver.yaml"换成自己需要的即可。如果要注册成普通用户，把 --admin 换成 --no-admin 即可。根据help信息的提示，usertypes一共有admin、guest、none三种，普通用户是none。（3）关闭注册功能把 /docker/matrix/data/matrix/homeserver.yaml 中的：enable_registration: true enable_registration_without_verification: true注释掉，重新创建容器。（4）其它matrix更多的配置在 配置文档 。几个比较重要的有：a.SMTP，邮件（见 此处）。不会用SMTP的可参考 这篇文章 介绍CommentNotifier一节。由于用户填写个人邮箱时要发确认邮件，SMTP还是有可能用到的；b.电话服务，见 此处 。类似邮件，用户填个人电话时也要验证码；c.通过token控制注册人数（控制时间、个数等），Registration Tokens；不过这个好像已经被废弃了，见 此处 。
步骤/目录： 1.背景介绍 2.Ward 3.ServerStatus （1）服务器端 （2）客户端 （3）SS的使用本文首发于个人博客https://lisper517.top/index.php/archives/202/，转载请注明出处。本文的目的是介绍一些监控linux状态的工具，类似windows的任务管理器。本文写作日期为2023年12月30日。主要受up主 我不是咕咕鸽 的启发。他还分享了很多其它有趣的内容，讲解也很详细、基础，很适合小白学习。1.背景介绍在日常管理服务器的过程中，一些工具能大大减轻工作量。前几天在up主 我不是咕咕鸽 的空间看到了很多有趣的分享，也尝试自己搭建一下。windows上有任务管理器，可以方便地查看电脑的CPU及内存使用量，网速，硬盘状态等。linux也有类似的工具。2.Ward之前笔者介绍过 Pi Dashboard ，一个可以在网页监控树莓派状态的项目。Ward比较类似Pi Dashboard，也能通过网页监控linux电脑的状态。根据 github-ward 的说明，在linux中如下操作：mkdir -p /docker/ward cd /docker/ward vim docker-compose.yml内容为：version: "3.9" services: ward: image: antonyleons/ward ports: - "4000:4000" environment: - WARD_PORT=4000 privileged: true restart: unless-stopped打开4000端口，运行ward：ufw allow 4000 comment "ward" docker-compose config docker-compose up浏览器访问 ip:4000 即可，非常简单。3.ServerStatusWard适用于单个linux机器的监控。如果有多个linux机器，可以使用ServerStatus。设置一台SS的服务器端，在SS的客户端运行客户端代码，SS客户端就能将运行状态数据提交到SS服务器端，此时访问该服务器端网页就能看到所有客户端机器的状态。（1）服务器端mkdir -p /docker/server_status/month_traffic mkdir -p /docker/server_status/conf/server_status cd /docker/server_status wget --no-check-certificate -qO /docker/server_status/conf/server_status/config.json https://raw.githubusercontent.com/cppla/ServerStatus/master/server/config.json vim docker-compose.yml内容为：version: "3.9" services: server_status: image: cppla/serverstatus:latest container_name: server_status ports: - "80:80" - "35601:35601" volumes: - /docker/server_status/conf/server_status/config.json:/ServerStatus/server/config.json - /docker/server_status/month_traffic:/usr/share/nginx/html/json restart: always80是网页访问，35601是接收客户端数据，记得打开（如果用NPM，把80注释掉，配置反代）。最后运行：docker-compose config docker-compose up此时在网页访问80就能看到了。config.json里自带了几个示例服务器，现在的状态都显示为关闭。（2）客户端客户端不需要有公网ip，所以家庭内的服务器也可。首先确认客户端已安装了python：python3 -V一般云服务器都是装了的，没有装的参考 runoob 。SS客户端只需运行几行命令：mkdir -p /docker/SS_client wget --no-check-certificate -qO /docker/SS_client/client-linux.py 'https://raw.githubusercontent.com/cppla/ServerStatus/master/clients/client-linux.py' chmod +x /docker/SS_client/client-linux.py该py脚本内容为：#!/usr/bin/env python3 # coding: utf-8 # Update by : https://github.com/cppla/ServerStatus, Update date: 20220530 # 版本：1.0.3, 支持Python版本：2.7 to 3.10 # 支持操作系统： Linux, OSX, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures # 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义，例如：CU = "www.facebook.com"。 SERVER = "127.0.0.1" USER = "s01" PASSWORD = "USER_DEFAULT_PASSWORD" PORT = 35601 CU = "cu.tz.cloudcpp.com" CT = "ct.tz.cloudcpp.com" CM = "cm.tz.cloudcpp.com" PROBEPORT = 80 PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6 PING_PACKET_HISTORY_LEN = 100 INTERVAL = 1 import socket import time import timeit import re import os import sys import json import errno import subprocess import threading try: from queue import Queue # python3 except ImportError: from Queue import Queue # python2 def get_uptime(): with open('/proc/uptime', 'r') as f: uptime = f.readline().split('.', 2) return int(uptime[0]) def get_memory(): re_parser = re.compile(r'^(?P<key>\S*):\s*(?P<value>\d*)\s*kB') result = dict() for line in open('/proc/meminfo'): match = re_parser.match(line) if not match: continue key, value = match.groups(['key', 'value']) result[key] = int(value) MemTotal = float(result['MemTotal']) MemUsed = MemTotal-float(result['MemFree'])-float(result['Buffers'])-float(result['Cached'])-float(result['SReclaimable']) SwapTotal = float(result['SwapTotal']) SwapFree = float(result['SwapFree']) return int(MemTotal), int(MemUsed), int(SwapTotal), int(SwapFree) def get_hdd(): p = subprocess.check_output(['df', '-Tlm', '--total', '-t', 'ext4', '-t', 'ext3', '-t', 'ext2', '-t', 'reiserfs', '-t', 'jfs', '-t', 'ntfs', '-t', 'fat32', '-t', 'btrfs', '-t', 'fuseblk', '-t', 'zfs', '-t', 'simfs', '-t', 'xfs']).decode("Utf-8") total = p.splitlines()[-1] used = total.split()[3] size = total.split()[2] return int(size), int(used) def get_time(): with open("/proc/stat", "r") as f: time_list = f.readline().split(' ')[2:6] for i in range(len(time_list)) : time_list[i] = int(time_list[i]) return time_list def delta_time(): x = get_time() time.sleep(INTERVAL) y = get_time() for i in range(len(x)): y[i]-=x[i] return y def get_cpu(): t = delta_time() st = sum(t) if st == 0: st = 1 result = 100-(t[len(t)-1]*100.00/st) return round(result, 1) def liuliang(): NET_IN = 0 NET_OUT = 0 with open('/proc/net/dev') as f: for line in f.readlines(): netinfo = re.findall('([^\s]+):[\s]{0,}(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)', line) if netinfo: if netinfo[0][0] == 'lo' or 'tun' in netinfo[0][0] \ or 'docker' in netinfo[0][0] or 'veth' in netinfo[0][0] \ or 'br-' in netinfo[0][0] or 'vmbr' in netinfo[0][0] \ or 'vnet' in netinfo[0][0] or 'kube' in netinfo[0][0] \ or netinfo[0][1]=='0' or netinfo[0][9]=='0': continue else: NET_IN += int(netinfo[0][1]) NET_OUT += int(netinfo[0][9]) return NET_IN, NET_OUT def tupd(): ''' tcp, udp, process, thread count: for view ddcc attack , then send warning :return: ''' s = subprocess.check_output("ss -t|wc -l", shell=True) t = int(s[:-1])-1 s = subprocess.check_output("ss -u|wc -l", shell=True) u = int(s[:-1])-1 s = subprocess.check_output("ps -ef|wc -l", shell=True) p = int(s[:-1])-2 s = subprocess.check_output("ps -eLf|wc -l", shell=True) d = int(s[:-1])-2 return t,u,p,d def get_network(ip_version): if(ip_version == 4): HOST = "ipv4.google.com" elif(ip_version == 6): HOST = "ipv6.google.com" try: socket.create_connection((HOST, 80), 2).close() return True except: return False lostRate = { '10010': 0.0, '189': 0.0, '10086': 0.0 } pingTime = { '10010': 0, '189': 0, '10086': 0 } netSpeed = { 'netrx': 0.0, 'nettx': 0.0, 'clock': 0.0, 'diff': 0.0, 'avgrx': 0, 'avgtx': 0 } diskIO = { 'read': 0, 'write': 0 } def _ping_thread(host, mark, port): lostPacket = 0 packet_queue = Queue(maxsize=PING_PACKET_HISTORY_LEN) while True: # flush dns , every time. IP = host if host.count(':') < 1: # if not plain ipv6 address, means ipv4 address or hostname try: if PROBE_PROTOCOL_PREFER == 'ipv4': IP = socket.getaddrinfo(host, None, socket.AF_INET)[0][4][0] else: IP = socket.getaddrinfo(host, None, socket.AF_INET6)[0][4][0] except Exception: pass if packet_queue.full(): if packet_queue.get() == 0: lostPacket -= 1 try: b = timeit.default_timer() socket.create_connection((IP, port), timeout=1).close() pingTime[mark] = int((timeit.default_timer() - b) * 1000) packet_queue.put(1) except socket.error as error: if error.errno == errno.ECONNREFUSED: pingTime[mark] = int((timeit.default_timer() - b) * 1000) packet_queue.put(1) #elif error.errno == errno.ETIMEDOUT: else: lostPacket += 1 packet_queue.put(0) if packet_queue.qsize() > 30: lostRate[mark] = float(lostPacket) / packet_queue.qsize() time.sleep(INTERVAL) def _net_speed(): while True: with open("/proc/net/dev", "r") as f: net_dev = f.readlines() avgrx = 0 avgtx = 0 for dev in net_dev[2:]: dev = dev.split(':') if "lo" in dev[0] or "tun" in dev[0] \ or "docker" in dev[0] or "veth" in dev[0] \ or "br-" in dev[0] or "vmbr" in dev[0] \ or "vnet" in dev[0] or "kube" in dev[0]: continue dev = dev[1].split() avgrx += int(dev[0]) avgtx += int(dev[8]) now_clock = time.time() netSpeed["diff"] = now_clock - netSpeed["clock"] netSpeed["clock"] = now_clock netSpeed["netrx"] = int((avgrx - netSpeed["avgrx"]) / netSpeed["diff"]) netSpeed["nettx"] = int((avgtx - netSpeed["avgtx"]) / netSpeed["diff"]) netSpeed["avgrx"] = avgrx netSpeed["avgtx"] = avgtx time.sleep(INTERVAL) def _disk_io(): ''' good luck for opensource! by: cpp.la 磁盘IO：因为IOPS原因，SSD和HDD、包括RAID卡，ZFS等阵列技术。IO对性能的影响还需要结合自身服务器情况来判断。 比如我这里是机械硬盘，大量做随机小文件读写，那么很低的读写也就能造成硬盘长时间的等待。 如果这里做连续性IO，那么普通机械硬盘写入到100Mb/s，那么也能造成硬盘长时间的等待。 磁盘读写有误差：4k，8k ，https://stackoverflow.com/questions/34413926/psutil-vs-dd-monitoring-disk-i-o :return: ''' while True: # pre pid snapshot snapshot_first = {} # next pid snapshot snapshot_second = {} # read count snapshot snapshot_read = 0 # write count snapshot snapshot_write = 0 # process snapshot pid_snapshot = [str(i) for i in os.listdir("/proc") if i.isdigit() is True] for pid in pid_snapshot: try: with open("/proc/{}/io".format(pid)) as f: pid_io = {} for line in f.readlines(): if "read_bytes" in line: pid_io["read"] = int(line.split("read_bytes:")[-1].strip()) elif "write_bytes" in line and "cancelled_write_bytes" not in line: pid_io["write"] = int(line.split("write_bytes:")[-1].strip()) pid_io["name"] = open("/proc/{}/comm".format(pid), "r").read().strip() snapshot_first[pid] = pid_io except: if pid in snapshot_first: snapshot_first.pop(pid) time.sleep(INTERVAL) for pid in pid_snapshot: try: with open("/proc/{}/io".format(pid)) as f: pid_io = {} for line in f.readlines(): if "read_bytes" in line: pid_io["read"] = int(line.split("read_bytes:")[-1].strip()) elif "write_bytes" in line and "cancelled_write_bytes" not in line: pid_io["write"] = int(line.split("write_bytes:")[-1].strip()) pid_io["name"] = open("/proc/{}/comm".format(pid), "r").read().strip() snapshot_second[pid] = pid_io except: if pid in snapshot_first: snapshot_first.pop(pid) if pid in snapshot_second: snapshot_second.pop(pid) for k, v in snapshot_first.items(): if snapshot_first[k]["name"] == snapshot_second[k]["name"] and snapshot_first[k]["name"] != "bash": snapshot_read += (snapshot_second[k]["read"] - snapshot_first[k]["read"]) snapshot_write += (snapshot_second[k]["write"] - snapshot_first[k]["write"]) diskIO["read"] = snapshot_read diskIO["write"] = snapshot_write def get_realtime_data(): ''' real time get system data :return: ''' t1 = threading.Thread( target=_ping_thread, kwargs={ 'host': CU, 'mark': '10010', 'port': PROBEPORT } ) t2 = threading.Thread( target=_ping_thread, kwargs={ 'host': CT, 'mark': '189', 'port': PROBEPORT } ) t3 = threading.Thread( target=_ping_thread, kwargs={ 'host': CM, 'mark': '10086', 'port': PROBEPORT } ) t4 = threading.Thread( target=_net_speed, ) t5 = threading.Thread( target=_disk_io, ) for ti in [t1, t2, t3, t4, t5]: ti.daemon = True ti.start() def byte_str(object): ''' bytes to str, str to bytes :param object: :return: ''' if isinstance(object, str): return object.encode(encoding="utf-8") elif isinstance(object, bytes): return bytes.decode(object) else: print(type(object)) if __name__ == '__main__': for argc in sys.argv: if 'SERVER' in argc: SERVER = argc.split('SERVER=')[-1] elif 'PORT' in argc: PORT = int(argc.split('PORT=')[-1]) elif 'USER' in argc: USER = argc.split('USER=')[-1] elif 'PASSWORD' in argc: PASSWORD = argc.split('PASSWORD=')[-1] elif 'INTERVAL' in argc: INTERVAL = int(argc.split('INTERVAL=')[-1]) socket.setdefaulttimeout(30) get_realtime_data() while True: try: print("Connecting...") s = socket.create_connection((SERVER, PORT)) data = byte_str(s.recv(1024)) if data.find("Authentication required") > -1: s.send(byte_str(USER + ':' + PASSWORD + '\n')) data = byte_str(s.recv(1024)) if data.find("Authentication successful") < 0: print(data) raise socket.error else: print(data) raise socket.error print(data) if data.find("You are connecting via") < 0: data = byte_str(s.recv(1024)) print(data) timer = 0 check_ip = 0 if data.find("IPv4") > -1: check_ip = 6 elif data.find("IPv6") > -1: check_ip = 4 else: print(data) raise socket.error while True: CPU = get_cpu() NET_IN, NET_OUT = liuliang() Uptime = get_uptime() Load_1, Load_5, Load_15 = os.getloadavg() MemoryTotal, MemoryUsed, SwapTotal, SwapFree = get_memory() HDDTotal, HDDUsed = get_hdd() array = {} if not timer: array['online' + str(check_ip)] = get_network(check_ip) timer = 10 else: timer -= 1*INTERVAL array['uptime'] = Uptime array['load_1'] = Load_1 array['load_5'] = Load_5 array['load_15'] = Load_15 array['memory_total'] = MemoryTotal array['memory_used'] = MemoryUsed array['swap_total'] = SwapTotal array['swap_used'] = SwapTotal - SwapFree array['hdd_total'] = HDDTotal array['hdd_used'] = HDDUsed array['cpu'] = CPU array['network_rx'] = netSpeed.get("netrx") array['network_tx'] = netSpeed.get("nettx") array['network_in'] = NET_IN array['network_out'] = NET_OUT # todo：兼容旧版本，下个版本删除ip_status array['ip_status'] = True array['ping_10010'] = lostRate.get('10010') * 100 array['ping_189'] = lostRate.get('189') * 100 array['ping_10086'] = lostRate.get('10086') * 100 array['time_10010'] = pingTime.get('10010') array['time_189'] = pingTime.get('189') array['time_10086'] = pingTime.get('10086') array['tcp'], array['udp'], array['process'], array['thread'] = tupd() array['io_read'] = diskIO.get("read") array['io_write'] = diskIO.get("write") s.send(byte_str("update " + json.dumps(array) + "\n")) except KeyboardInterrupt: raise except socket.error: print("Disconnected...") if 's' in locals().keys(): del s time.sleep(3) except Exception as e: print("Caught Exception:", e) if 's' in locals().keys(): del s time.sleep(3)最后以后台方式运行SS客户端脚本（但是更建议等下再运行）：nohup python3 /docker/SS_client/client-linux.py SERVER={$SERVER} USER={$USER} PASSWORD={$PASSWORD} >/dev/null 2>&1 &这里的 {$SERVER} 是SS客户端机器的公网ip； {$USER} 、 {$PASSWORD} 要和服务器端的config.json中能对上，这将在下文介绍。相比于手动运行，更建议把该py脚本加入开机自启，参考 笔者以前的文章 ：vim /etc/systemd/system/ss_client.service写入：[Unit] Description=ServerStatus-client Wants=network-online.target After=network.target network-online.target Requires=network-online.target [Service] ExecStart=/usr/bin/python3 /docker/SS_client/client-linux.py ExecStop=/bin/kill $MAINPID Restart=on-failure RestartSec=5 StartLimitInterval=0 [Install] WantedBy=multi-user.target在启动之前，修改一下 /docker/SS_client/client-linux.py ，填入自己修改的 {$SERVER} 、 {$USER} 、 {$PASSWORD} 。最后启动一下service：systemctl enable ss_client.service systemctl start ss_client.service systemctl status ss_client.service（3）SS的使用初始的/docker/server_status/conf/server_status/config.json内容为：{ "servers": [ { "username": "s01", "name": "node1", "type": "xen", "host": "host1", "location": "🇨🇳", "password": "USER_DEFAULT_PASSWORD", "monthstart": 1 }, { "username": "s02", "name": "node2", "type": "vmware", "host": "host2", "location": "🇯🇵", "password": "USER_DEFAULT_PASSWORD", "monthstart": 1 }, { "disabled": true, "username": "s03", "name": "node3", "type": "hyper", "host": "host3", "location": "🇫🇷", "password": "USER_DEFAULT_PASSWORD", "monthstart": 1 }, { "username": "s04", "name": "node4", "type": "kvm", "host": "host4", "location": "🇰🇷", "password": "USER_DEFAULT_PASSWORD", "monthstart": 1 } ], "watchdog": [ { "name": "cpu high warning,exclude username s01", "rule": "cpu>90&load_1>5&username!='s01'", "interval": 600, "callback": "https://yourSMSurl" }, { "name": "memory high warning, exclude less than 1GB vps", "rule": "(memory_used/memory_total)*100>90&memory_total>1048576", "interval": 300, "callback": "https://yourSMSurl" }, { "name": "offline warning,exclude name node1", "rule": "online4=0&online6=0&name!='node1'", "interval": 600, "callback": "https://yourSMSurl" }, { "name": "ddcc attack,limit type Oracle", "rule": "tcp_count>600&type='Oracle'", "interval": 300, "callback": "https://yourSMSurl" }, { "name": "month traffic warning", "rule": "(network_out-last_network_out)/1024/1024/1024>999", "interval": 3600, "callback": "https://yourSMSurl" }, { "name": "you can parse an expression combining any known field", "rule": "load_5>3", "interval": 900, "callback": "https://yourSMSurl" } ] }上面的servers字段是客户端设置，客户端的 {$USER} 、 {$PASSWORD} 分别和这里的 username 、 password 键对上即可；name是展示在SS服务端网页的名称，type是服务器的类型（参考 这篇文章 ），host可以填客户端服务器具体在哪座城市（但是这个默认不显示），location是国别， "monthstart": 1 的意思是每个月1号，流量计数会清零（这个也可以设置成累计、不清零）。下面的watchdog字段是一些警告设置，参考 github-SS 。其它的自己可以看情况改，改完后重启一下SS的服务器端。在SS服务端网页，最左边的协议是指这个服务器自己有无v4、v6地址，最右边的CU、CT、CM是联通、电信、移动网络的丢包率。每个服务器还能点开下拉菜单进一步查看。