在archlinux下使用万象拼音实现更智慧的中文输入法

小登其实还在考期,按说应该复习的,但是这个万象拼音对我打字体验的提升还是让我觉得有必要记录一下搓一篇文章。 经常用linux桌面系统的朋友都知道,现在linux桌面对于中文的支持已经比早几年要好很多了。但是日常使用会发现中文输入法不如Windows下好用,linux下没有搜狗输入法,微软拼音这样的老牌正规军,linux中文用户常使用的fcitx5与rime输入法虽自带了词库,但是用下来给人的感觉还是差强人意。本文介绍在archlinux上与fcitx5配合使用万象拼音的方案,可提升输入效率。 万象拼音是基于万象语法模型、万象向量词库这一中文词库与算法构建的拼音输入方案。致力于提供RIME最强基础底座,做最精准的读音标注、做最精准的词频统计、最恰当的分词词库以及基于现有条件打造了一个高命中率、精确的输入模型。顺便为pypinyin维护出一个高质量拼音标注元数据库。它的输入方案类大厂习惯,意味着你可以在让RIME和fcitx5搭载这个词库与模型,然后收获和搜狗等输入法近似的体验。 我使用archlinux以及fcitx5,因此以此为例进行展示。 安装好Fcitx5以及万象拼音所需的RIME 1 sudo pacman -S fcitx5-im fcitx5-pinyin-zhwiki librime fcitx5-rime 编辑环境变量 参考ArchWiki 对于X11环境与Wayland环境有不同的配置 X11: 编辑/etc/environment: 1 2 3 4 5 GTK_IM_MODULE=fcitx QT_IM_MODULE=fcitx XMODIFIERS=@im=fcitx SDL_IM_MODULE=fcitx GLFW_IM_MODULE=ibus 然后注销并且重新登录 Wayland 我使用KDE,使用Gnome的朋友请自行查看wiki 按照Wiki,不应该添加GTK_IM_MODULE与QT_IM_MODULE,但是我在日常使用中好像会因此遇到问题。我目前使用的/etc/environment是: 1 2 3 XMODIFIERS=@im=fcitx # X11或XWayland窗口需要 GTK_IM_MODULE=fcitx QT_IM_MODULE=fcitx 并且在使用QQ的时候需要命令行参数:--no-sandbox %U --enable-wayland-ime --wayland-text-input-version=3 --enable-features=WaylandWindowDecorations 以及为了在VS Code里输入中文,我在~/code-flags.conf里写入了 1 2 3 4 5 --enable-features=UseOzonePlatform --ozone-platform-hint=wayland --enable-wayland-ime --wayland-text-input-version=3 --enable-features=WaylandWindowDecorations 这不优雅,Fcitx5会在登录桌面的时候给你一个弹窗警告,但是能跑,所以我“不再提醒” 配置ArchlinuxCN源 基本上国内用Arch的都加了这个源吧() Arch Linux 中文社区仓库 是由 Arch Linux 中文社区驱动的非官方用户仓库。包含中文用户常用软件、工具、字体/美化包等。 使用方法:在 /etc/pacman.conf 文件末尾添加以下两行: 1 2 [archlinuxcn] Server = https://mirrors.cernet.edu.cn/archlinuxcn/$arch 之后通过以下命令安装 archlinuxcn-keyring 包导入 GPG key。 1 sudo pacman -Sy archlinuxcn-keyring 安装万象词库与模型 如果看官方指引,你可能回去github release下载词库与模型,这样不仅慢,而且不利于维护更新 幸运的是ArchlinuxCN源会拉取这些文件 使用yay rime-wanxiang或者pacman -Ss rime-wanxiang可以看到这些打包好的词库和模型,不要单独下载词库或者基础数据,应该选择 万象拼音标准版(全拼方案) 这样不带 词库/基础数据 的包 安装过程中会告诉你要修改~/.local/share/fcitx5/rime/default.custom.yaml,你可能会忽略或者没看到,但是缺少这一不可能导致无法使用万象拼音。 你需要编辑或新建~/.local/share/fcitx5/rime/default.custom.yaml ,写入: 1 2 3 4 patch: # 这里的 wanxiang_suggestion 为万象方案的默认预设 # 辅码版为 wanxiang_pro_suggestion __include: wanxiang_suggestion:/ 然后在KDE设置里将原来的拼音输入法删掉,换成中州韵。这个时候在文本框中输入中文,你应该就能看到这样流畅的输入候选词了。 可以看到,在使用万象拼音之前我的候选词是类似于第二个的那种,简直牛头不对马嘴。这是因为默认的输入方式不带模型,只用拼音比对词频词库,而万象拼音引入了n-gram模型,于是可以获知上下文信息,自然输出更加流畅(像人话)。 没有生效? 可能你发现只能打出来繁体字,而且效果也不好,因为这个时候你可能用上里RIME默认的朙月拼音。你需要在状态栏右键RIME的这个图标 找到 部署/同步 点击之后在朙月拼音的右侧切换万象拼音 感谢万象拼音的开发者! 💖 love from Archers! (滚去复习高代了)

2026/1/10
articleCard.readMore

有关Alist不当言论的公开致歉声明

<p><img src="https://img.pengs.top/i/2026/01/10/790946178-1.webp" class="lazyload" data-srcset="https://img.pengs.top/i/2026/01/10/790946178-1.webp" srcset="https://cdn.pengs.top/asset/loading.gif" alt="屏幕截图_20260110_192731"></p>

2025/12/30
articleCard.readMore

Traefik实现单Docker容器托管多个静态网站

在本站全部Docker化后,目前我使用Traefik对Docker容器的公网映射进行统一管理。其标签化配置,自动续签SSL证书,以及原生的QUIC支持都是很好的特性。 唯一的问题是我迁移的时候没有考虑到以后静态站点的增长需求。此前对于每一个子域名我都拉了一个基础的nginx容器,把www文件夹映射进去。这虽然提供了 不必的 安全性,但是增加了服务器负载。最主要的问题是,一旦我希望添加一个静态站点,哪怕只有一个index.html 都需要走以下流程: 在www文件夹下新建目录,放入静态资源 新建nginx的站点配置文件,基本是把之前的抄过来改一下host 在docker-compose.yml里新加一个服务,也是把以前的段落复制粘贴改名称 把以上文件移到服务器上 docker compose up -d 添加DNS记录 这无疑增加了创意落地为现实耗费的时间精力。 我仔细观察了一下,www的目录被我收拾得还不错,基本上子目录的名称就是子域名,于是就有了想法根据请求头自动切换资源目录的想法。并在AI的帮助下做成了。 申请通配符证书 为了尽可能减少每次新增站点所需的工作量,我配置Traefik为我自动申请*.pengs.top与pengs.top的通配符证书,这样一个证书就可以为所有子域名提供SSL支持,缺点是需要你的DNS解析商支持(应该基本上都支持吧) 这一部分可以参看:如何使用Traefik通过Cloudflare DNS验证申请泛域名证书 新建Docker Compose Service 在docker-compose.yml内新增服务: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static-sites: image: nginx:alpine container_name: static-sites restart: unless-stopped volumes: - "./base/nginx/nginx.conf:/etc/nginx/nginx.conf:ro" - "./base/nginx/sites-enabled/static-sites.conf:/etc/nginx/conf.d/default.conf:ro" - "./web:/var/www:ro" # networks: # - proxy labels: - "traefik.enable=true" - "traefik.docker.network=docker-services_proxy" # 通配符匹配所有 *.pengs.top 子域名 # 优先级设为较低值,让其他具体服务的路由优先匹配 - "traefik.http.routers.static-sites.rule=HostRegexp(`^[a-z0-9-]+\\.pengs\\.top$$`)" - "traefik.http.routers.static-sites.priority=1" - "traefik.http.routers.static-sites.entrypoints=websecure" - "traefik.http.services.static-sites.loadbalancer.server.port=80" - "traefik.http.services.static-sites.loadbalancer.server.scheme=http" 这里需要你自行修改域名。 新建nginx配置文件 上面的配置中,我们将static-sites.conf穿透进了Docker容器中,现在来创建它 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 server { listen 80 default_server; listen [::]:80; server_name ~^(?<subdomain>[^.]+)\.pengs\.top$; gzip on; gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_min_length 256; gzip_types application/atom+xml application/geo+json application/javascript application/x-javascript application/json application/ld+json application/manifest+json application/rdf+xml application/rss+xml application/xhtml+xml application/xml font/eot font/otf font/ttf image/svg+xml text/css text/javascript text/plain text/xml; # 动态根目录:子域名对应文件夹 root /var/www/$subdomain; index index.html index.htm; location / { try_files $uri $uri/ /index.html =404; add_header Cache-Control private; } # 静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|webp|mp4|mkv)$ { expires 30d; add_header Cache-Control "public, immutable"; } } 额,看起来这么长,其实主要就是用正则表达式匹配了subdomain然后访问对应目录。多出来的那部分内容,一方面是增加了gzip压缩,利用服务器的cpu资源换取更少的流量流出,如果不需要刻意注释掉。另外的就是增加了一些不会改变的资源的缓存。 拉起! ssh登陆上服务器使用docker compose up -d拉起服务,然后到你的www目录下新建一个目录,再去dns那里添加记录就能访问到对应资源了。 祝安好!

2025/12/30
articleCard.readMore

Pengs.top浴火重生!备案、服务器迁移与全站Docker化

这学期刚刚进入大学,着急忙慌的博客也没怎么更新。要不是有一天突然发现中国移动ban掉了pengs.top,可能也不会腾出手来折腾。但是我做就要做绝,这一把顺带着给域名做了备案、更换了服务器(其实是砍预算)、以及最主要的——全站Docker化。 诶?WC! 一天我像往常一样下课走去食堂,心血来潮想看一眼过去这么久了pengs.top的访客情况如何,可是当我往浏览器里输入umami服务的地址后,竟然看到了Connection was reset 的恐怖字样。我立刻去看主域pengs.top 发现也是如此。能正常打开其他网站,我也没把锅往广电还有移动头上扣。到了食堂,我连上了校园网,再测试又正常访问。校园网是移动联通电信鹏博士教育网混合出口,我于是开始怀疑起中国移动,叫了几个人帮我测试都是连接已重置,这几乎是实锤了。 随后我又更细致地测试了一下,问题似乎只在北京移动的网络环境下出现。考虑到北京有自己的城域网,加上之前的作业让网站的访问量骤升了数百,我觉得倒有些合理,但这不能洗脱中国移动的罪恶。经控制变量法测试,北京移动阻断了二元组(pengs.top,ip),意味着如果使用ip裸连或者用cloudflare小黄云进行代理就好了。但是我不愿意浪费我这么好的iij线路走cloudflare,也不想配置运营商分流,于是就忍心让北京移动用户无法访问pengs.top了。 解决问题 毕竟pengs.top上运行着很多我自己日常要用的服务,不能在手机流量下正常使用总归不舒服,于是我想尽办法去解决这个问题。 更新:2025年12月24日发现中国移动还是ban了,没招了,我还是继续扯皮吧 备案 我想就算要刚中国移动,我好歹自己得是合法的,像原来那样海外主机+cloudflare域名托管+无备案简直容易被倒打一耙变成非法网站。我都成年了,不能这样没名没分的 于是又一次踏上了艰难的备案流程,不过好在比较顺利,这一次以自己的身份办的,中间没有卡壳。这里要感谢BUAASubnet的摩尔福斯提供的备案授权码! 于是,在2025年12月9日,pengs.top第二次拿到了ICP备案,这一次是京ICP备2025154912号-1 ! 然后公安网备懒得做了额。 10086 打了好几次10086,态度很好,但是一点用都没有。 第一回打过去对面说登记一下,让技术人员联系我。 然后等了一两个礼拜杳无音讯。 中间我发现了互联网信息服务投诉平台,抱着试一试的心态我就给中国移动投诉了。某天上午9点,接到了回电。可是糟糕的是我是南京的手机号,导致工单被派发给了南京移动,10086告诉我查询没有异常。我告诉客服我在北京,她让我加区号010再打一下10086, 结果接线的还是南京的,客服尝试给我转接到北京移动,可是失败了。后来又尝试了一次,依旧如此,无奈之下我只能放弃。 壮士断腕,直接换云 几经周折我也是没辙了 这域名不能就这么废了啊,我还要作传家宝呢。看了眼原先vmiss服务器的到期时间,26年2月就到期了,我寻思着干脆换国内服务器得了,反正备案也已经有了,但是又被高昂的价格,小到离谱的带宽劝退了。其实也有很多新客福利,但是都只能优惠一两年,像我这种懒人,不想频繁重装整个一套服务 所以最终还是打消了这个念头。我又想直接续费vmiss了,但是某天突然想起来: 我是尊贵的大学生啊! 于是Github Azure的学生权益薅起来,这里有点很烦的是你航被美10043法案制裁,导致我到现在github的payment information还是被锁(如下图) 我真担心哪天把我大号给扬了,但发了工单也无人问津,唉。 不管怎么说,教育优惠拿到了,至少Github Copilot在手。这玩意儿是真好用啊,后面还会再讲到。 接着开Azure的学生也全是糟点。我自己的个人账号和原来薅E5订阅的管理员账号绑定了,E5订阅被吊销后我的个人账号就有了一些奇怪的租户问题,一度非常无解,而且要开工单需要登陆,但是我TM压根无法登陆。 于是后来我又专门注册了一个outlook账号和我的Github账号关联起来。但是验证学生资质又卡住了,我真的无语。Azure没有给我的edu邮箱发激活邮件,起初我以为是学校的邮件系统给我拦了,问了才知道也没拦截。所以我又开了个工单。 客服让我通过这个链接🔗进行验证,又要了我的学信网报告,折腾了半天总算学生订阅也激活了。 我以为可以咔咔开干了,结果发现我开不了机器,或者准确来说,开不到我想要的。 网上关于Azure VPS的测评不多。ping0.cc有一个VPS延迟的24小时监控 是我参考的主要依据,搜索azure结果大致如图: 综合来看,新加坡(Southeast Asia)的表现最好,其次是Japan West、Japan East、East Asia(香港)。 此处还有Azure官方的测试页面 可以测试延迟和速度。我使用的网络下,依然是新加坡表现最好,延迟不到100ms。测试下载速度却差距悬殊。新加坡跑满了20MB/s的带宽,其他的均在2MB/s以下。上传差距不大,均为10MB/s.不过我无法确定分别是通过什么运营商的网络连接的,学校网络出口有负载均衡。 所以比较一圈下来,发现新加坡的机子比较香。我就通过创建免费虚拟机的链接试图去创建,这个链接进去会自动应用适合免费范围的策略,且可选地区是齐全的。但是,就在要确定创建的时候,又报错了 选的是East Asia而不是Southeast Asia其实是因为破防了,想着香港也行吧,结果发现新加坡,香港,日本都是清一色的这个报错。 一怒之下又开了工单,把材料交上去。就在对面要我继续补充细节的时候,我突然发现又可以开了,就稀里糊涂开了。估计免费机是有配额的。 看看新家园 配置与成本 SKU: Standard_B2ats_v2 CPU: EPYC™ 7763v 2核 内存: 1GB 硬盘: 64GB 网络: 有静态ipv4*1 无ipv6 每月免费流量为出站单向计算15GB 带宽未知,目前来看够用。 费用: 实际消耗0元。 Azure学生认证每一年有100刀的额度。其实感觉上还是有点紧,因为从9月开始Azure已经取消提供免费的动态ipv4地址了,使用ddns的路子行不通了,只能消耗100刀的额度租静态ipv4地址了。 静态ipv4地址的价格是$0.0036/小时,一年约32$,假设我每个月再有5$消耗在流量上,那么根据 带宽-定价 最高收费档(因为实际上我只有免费的15GB流量,而非前100GB免费)$0.12/GB 那么我每个月只能超出15GB再用40GB左右,这是相当少的。后续我可能通过观察流量消耗情况套个CDN啥的。 注:关于如何查看路由首选项,请看Microsoft的这篇教程,如果你是照着我说的做的,那么应该得到是通过Microsoft网络。 总结来看,除了流量减少了以外,其他方面属于是升配降费(降为0) 旧机子怎么办? 其实一开始想搭建一个节点上网的,可是目前手上还不缺梯子。而且对于一台陪伴pengs.top走过了三年的机子,终归有点舍不得最终将它作为节点,把这个ip糟蹋了。毕竟我一直以6.6折的价格用了这么久,还找老板免费加了10GB硬盘……可能就静静地等到它过期被释放掉吧。 建设新服 升级系统 Azure在免费区域里提供的系统映像最新好像只有Debian 11,对于我这种archlinux用户来说还是太古早了。通过将apt源依次换成Debian 12与Debian 13的同时执行apt update与apt upgrade可以顺利地完成升级。 启动bbr与性能优化 毕竟是生产环境,不太敢用网上那种魔改版BBR/锐速的一键脚本,linux内核早就内置bbr了,不过启用前需要先启用tcp_bbr内核模块。 使用以下命令可以立刻启用tcp_bbr模块并在下次开机时也自动激活: 1 2 modprobe tcp_bbr echo "tcp_bbr" > /etc/modules-load.d/tcp-bbr.conf 注意,到这里为止,我们只是加载了内核模块,并没有真正改变拥塞控制算法 我把以下文件写入了 /etc/sysctl.d/99-network-optim.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 net.ipv4.ip_local_port_range = 30000 65535 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fastopen = 3 net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_max_tw_buckets = 20000 net.ipv4.tcp_max_syn_backlog = 2048 net.core.netdev_max_backlog = 1000 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syn_retries = 2 net.ipv4.tcp_synack_retries = 2 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_ignore_bogus_error_responses = 1 net.ipv4.tcp_slow_start_after_idle = 0 net.ipv4.tcp_mtu_probing = 1 net.ipv4.tcp_sack = 1 # 设置TCP拥塞控制为BBR net.ipv4.tcp_congestion_control = bbr # BBR依赖fq队列调度器(必须配置) net.core.default_qdisc = fq 这里面参数的大小有待考量,不一定科学,我查看了ArchWiki对于sysctl配置的建议,结合我小内存的现实情况给出了这些参数。 此外还有一些系统优化的配置在/etc/sysctl.d/99-system-optim.conf,同样不保证科学 1 2 3 4 5 6 7 8 9 10 11 vm.dirty_ratio = 20 vm.dirty_background_ratio = 5 vm.dirty_writeback_centisecs = 1000 vm.swappiness = 20 vm.vfs_cache_pressure = 60 vm.min_free_kbytes = 65536 vm.oom_kill_allocating_task = 1 vm.panic_on_oom = 0 fs.file-max = 500000 fs.noatime = 1 kernel.sched_autogroup_enabled = 0 文件写入完成后可以通过sysctl --system 加载这些配置使之生效。 服务统计 我需要知道哪些服务需要迁移。这其实又是一个浩大的探勘工作,毕竟vmiss的服务器已经年久失修了,基础设施像是一个神话,数据库的账号密码我也不记得了,可能硬编码在某处,反正能跑() 我运行了以下命令查看了端口开放情况: 1 ss -tulnp 接着又看了一下 已经以docker形式运行的服务 1 docker ps 接着还对照了DNS解析列表以及/etc/nginx/sites-enabled 终于梳理出了十余个站点/服务,清理了若干已经废弃的dns记录。 因为怕服务器遭到攻击,这些服务的细节不能公开。 Dockerize! 这里的Dockerize指将原先基于源码/二进制可执行文件/系统级软件包运行服务转变为统一由一个Docker Compose进行编排的过程,与Github上的Dockerize项目无关 为什么要这么做? 光是把杂乱的各项服务梳理出来已经很麻烦了,为什么还要费劲全部Docker化呢?其实是出于安全性,可迁移性与易管理性的考虑做出的大胆的决定。 安全性 已经有很多人听说了Next.js的CVE-2025-55182这个漏洞了吧。CVSS 10.0 满分意味着 攻击者只要可以使用网络访问受害者,无需任何权限,无需用户交互,即可自动化地完成攻击并完全控制系统 很不幸原来的服务器也中招了,因为umami访客统计使用了next.js. 幸运的是umami被我部署在了docker中,环境不完整,攻击者释放的木马未能成功执行。发现这个问题也是因为docker ps看到umami一直在restart. 通过重新拉取umami的docker映像,木马很容易就被解决了,同时更新了版本。这让我对Docker的安全性大加赞赏。 可迁移性 大白话是我可以随时拎包跑路,更方便地在多家服务商之间切换。蹭新客福利,虽然只有几年,到期再换就是了 这是因为利用docker的目录映射,我把所有的配置文件,数据库等等统一映射到了一个目录下,如果需要迁移,只要用rsync就能把数据与配置一股脑传走 ,在新机子上使用docker compose up就把服务都拉起来了。 事实上,在从vmiss迁移到azure的过程中,我就是现在本地docker环境中一遍遍测试,确保没有问题之后才把整个目录rsync到服务器上的,整个过程都很顺利,只要在hosts里把所有pengs.top的条目指向本地就好了。 所有文件都在一个目录下也让我备份的时候不再需要备份整个系统,而只要像这样拉取一个目录就好了,检修的时候信息密度也更高: 1 sudo rsync --partial -avz --delete --info=progress2 root@pengs.top:<服务器上的目录> <本地位置> 易管理性 通过docker ps我可以看到各服务是否在线,资源占用如何。我可以更方便地升级映像使服务版本更新。 通过把服务全部写入docker-compose.yml,我可以清楚地看到我到底跑了多少服务(没错,因为之前看到有好玩的东西就喜欢拿过来跑,结果过一段时间我自己都忘了),它们的配置文件在哪里,端口映射关系如何。 执行 对于没有多少云原生技术基础的我而言,让我从0开始编排服务难如登天,好在有Github Copilot了, 真是帮了我大忙。我主要的任务是清楚地描述我需要什么,当它限于某一处问题时从宏观的角度定位问题的根源。因为不便透露服务细节,我就记录一些踩过的坑还有学到的要点吧。 Docker开机自启动服务 可以使用以下systemd服务单元 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [Unit] Description=Custom Docker Compose Services Requires=docker.service After=docker.service network.target network-online.target [Service] Type=simple User=root WorkingDirectory=/opt/docker-services ExecStart=/usr/bin/docker compose -f <docker-compose.yml位置> up ExecStop=/usr/bin/docker compose -f <docker-compose.yml位置> down Restart=always RestartSec=5 TimeoutStartSec=600 [Install] WantedBy=multi-user.target Docker对于端口以及路径的映射 <宿主机路径/端口>:<容器内路径/端口> 如果要用rsync拉取或推整个docker目录,先docker compose down,要不然很容易导致postgresql等数据库数据出错 Docker中使用Traefik报错 client version 1.24 is too old. Minimum supported API version is 1.44 解决方案: 编辑/usr/lib/systemd/system/docker.service 在[Service]下增加一行 1 Environment=DOCKER_MIN_API_VERSION=1.24 如何使用Traefik通过Cloudflare DNS验证申请泛域名证书并dump出证书pem? 参考我的Traefik配置: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 traefik: image: traefik:v3.0 container_name: traefik restart: unless-stopped env_file: .env command: - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" # Cloudflare DNS 验证 (用于 Traefik 自身申请证书) - "--certificatesresolvers.cf.acme.dnschallenge=true" - "--certificatesresolvers.cf.acme.dnschallenge.provider=cloudflare" - "--certificatesresolvers.cf.acme.email=${TRAEFIK_ACME_EMAIL}" - "--certificatesresolvers.cf.acme.storage=/letsencrypt/acme.json" - "--certificatesresolvers.cf.acme.dnschallenge.resolvers=1.1.1.1:53" - "--entrypoints.websecure.http.tls.certresolver=cf" - "--entrypoints.websecure.http.tls.domains[0].main=${TRAEFIK_TLS_DOMAIN_MAIN}" - "--entrypoints.websecure.http.tls.domains[0].sans=${TRAEFIK_TLS_DOMAIN_SANS}" # 允许不安全的后端证书 (因为 Nginx 使用自签名或旧证书) - "--serversTransport.insecureSkipVerify=true" ports: - "${TRAEFIK_HTTP_PORT}:80" - "${TRAEFIK_HTTPS_PORT}:443" environment: - "CLOUDFLARE_DNS_API_TOKEN=${CF_DNS_API_TOKEN}" - DOCKER_API_VERSION=${DOCKER_API_VERSION} volumes: - "./traefik/letsencrypt:/letsencrypt" - "/var/run/docker.sock:/var/run/docker.sock:ro" networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`<traefik面板地址>`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=${TRAEFIK_DASHBOARD_USER}:${TRAEFIK_DASHBOARD_PASSWORD}" 这会把acme返回的结果放在./traefik/letsencrypt下,随后使用ldez/traefik-certs-dumper 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 cert_dumper: image: ldez/traefik-certs-dumper:v2.8.3 container_name: cert_dumper restart: unless-stopped entrypoint: - sh - -c - | apk add jq while ! [ -e /letsencrypt/acme.json ] || ! [ -s /letsencrypt/acme.json ]; do sleep 1 done traefik-certs-dumper file --version v2 --watch --source /letsencrypt/acme.json --dest /letsencrypt/live --domain-subdir --crt-name "fullchain" --crt-ext ".pem" --key-name "privkey" --key-ext ".pem" volumes: - "./traefik/letsencrypt:/letsencrypt" networks: - proxy 然后你就会在./traefik/letsencrypt/live下得到熟悉的fullchain.pem和privkey.pem. 原谅我已经记不得太多排障的细节了,先写到这里吧。 新服务推出 本次服务器迁移带来了一些新的服务,简单介绍一下: list.pengs.top : 原先alist的翻版,但是改用openlist了 存储后端从最早的E5订阅的Onedrive for Business换到了阿里云盘,在阿里云盘限制了第三方API后,现在转向了E3订阅的Onedrive for Business,不用担心容量不够。 paste.pengs.top : 我托管的开源的pastebin,可以上传一些小文件,支持阅后即焚,加密选项使用AES-256在浏览器加解密,我无法获知内容 nezha.pengs.top : 服务监控,服务器掉线了来戳我。 祝大家圣诞节快乐 2025年12月25日 {·B·}

2025/12/23
articleCard.readMore

严谨与温度并存:北航宋友老师程设课的学习感悟

宋老师镇楼 还是这个吧() 个人主页 初识 教编程,我们团队是专业的 我匆匆忙忙在主南的教室里占据了一个有插座的有利地形。坐定以后抬头一看,发现PPT已经翻到了这一页: 看起来颇为唬人。我想我有一点C语言基础,学习起来应该不会太费劲吧。 后来事实证明,这门课的压力并不小。2025.09.16 到 2025.11.11这64天时间里,我们看过了 800页PPT,200多页题解,打了7场上机赛,每次都 酣畅淋漓 累到不行。我感受到了挑战,也确实相信了这个团队的专业程度。 如果说以前我自学编程是小打小闹的野路子土匪的话,现在能不能算正规军了呢? 课堂 宋友老师的课堂总是让人很有想听下去的欲望。老师授课内容清晰,风格是幽默里透露着严谨,宋老师总是穿着一身西装微笑着讲课,大有儒雅之风(可惜没有偷拍过),PPT也是精心准备的,相比于自编的教材(那本绿书,抱歉我好像是上到第三堂课了才发现是宋老师主编哈),PPT上的内容是经过提纯萃取的,更利于没有接触过编程的同学吸收,而课本本身又能作为很好的补充。 由于我上数分高代经常上课摸鱼划水(嘘🤫),宋老师的C语言程序设计课程是我学习吸收效率最高的一门课了。我会被宋老师接二连三抛出的一个又一个思考的问题所吸引。有的时候提问,会给同学发鼠标垫。因为感觉宋老师的课实在不可多得,每次上课,第一排靠左中间那个座位基本上总是让我给占了,近水楼台先得月,一学期下来,我也积攒了一沓鼠标垫。等到哪天有鼠标了再用吧😁 这是部分 表情包具象化了 表情包在这一刻具象化了。 关于WA 这不是WA 这才是: OJ是我挥之不去的阴影 好吧,虽然我曾经有过一点编程的基础,但是算法并非我是我熟悉的领域,果不其然,上机总是会被OIer爆杀。说实话,一开始确实是有点失落。我曾有点怀疑自我,我想为什么在我自以为会有点优势的领域,我的表现也没有那么出色? 那时候我从豪情满志到有一点心灰意冷。然而,冷静下来重新想想在CS这个辽阔的领域,没有人能够成为六边形战士,或许有人的算法比我强,但工程方面可能不如我。我想对于计算机领域的广度的认识是我的独特优势,这一点,是我在课下与同学交流的时候发现的。不过若是没有这样的OJ,我可能会沉浸于迷之自信中吧。 其实平心而论,大部分OJ的题目,其难度都设定在了努力想想可以完成的位置。由此带来的成就感是极大的,这也不难解释为什么有的时候写OJ会有一点上瘾(真的不是我有自虐倾向,我观察过室友同学,都有类似的现象)。有的时候,看见ACcoding题目条上一道题由红转绿,我会高兴得手舞足蹈。但有的时候一个问题无论如何也解决不了,这时候我可能放着数分高代的作业没写,钻研程序几个小时。 一点心路历程 刚才说到钻研题目很久,那怎么会没有一点想法呢?我总不能憋着,于是我的git日志就成了默默的承受者。我从10月2号开始启用git进行版本管理。至今已有48次提交。每一条commit信息,都是真情实感。 这里面既有aha-moment的一点收获启迪: 我学到的 学到了 也有难绷时刻: 难绷 当然,还有那些让我感觉很行的瞬间: 屏幕截图_20251124_122047 屏幕截图_20251124_122322 总而言之,这段学习历程苦乐交织,每一次成功都让我感觉那些被抽走的力量正在一点点回到我的体内。严谨的思维正一点点地在我脑海里成型。宋老师不语,只是微笑。 Don’t compare. 这些记录,是我一次次与自我相伴,而非内耗,比较的时光在缓缓积淀,像钟乳石一般。 Fun Facts 经统计,时至今日我的仓库里一共有6609行纯代码( (Markdown那些是一些snippet,还有“血泪教训”,也许有天可以放出来) 如果按照宋老师所说的1行19元 进行计算,那么现在我已经收获了125571元。。。 我后来才知道,宋老师同时还是北航实验学校的校长 看起来真的致力于教育教学了 结语 看着课程表上空缺的周二,我感觉大学生活真的好快,在知识的急速灌注中就忙忙碌碌了大半学期。此刻我才刚刚步入计算机的殿堂,这一领域充满着激情与热爱,但我不会忘记大树的根基: 主南201 星期二第3,4,5节 衣带渐宽终不悔,为伊消得人憔悴 P.s. 我本来想写个程序整点花活的,然而自觉水平不高,待来日学成,拿出更有价值的成果产出来替代吧!

2025/11/23
articleCard.readMore

Android Studio全流程换源指南

Android的东家Google在中国大陆受到大规模封锁,Gradle的官方服务器,受限于我国匮乏的国际出口带宽,下载速度也不理想。这给作为开发者的我们带来了诸多不便,这一不便又被Android Studio与Gradle包管理的复杂放大了,不能像linux包管理器或者pip那样一行命令搞定。想要在Android Studio开发全过程中尽可能多用上国内镜像站并不容易。本文大致记录一下。 因为我这里腾讯云与阿里云的镜像最快,所以我配置成了这两家,可酌情修改。 Android Studio SDK Update 这部分内容应该首先配置,因为第一次启动Android Studio时会有向导指引你安装SDK,此时如果不加以配置,会从默认的dl.google.com下载,虽然没有被封锁,但是速度终归有点慢。 配置的方式是按cancel按键退出向导,点击左下角齿轮打开设置,然后导航到这个位置: (我已经添加过了) 点击加号,名称随意,添加以下两个条目: 1 https://mirrors.aliyun.com/android.googlesource.com 与 1 https://mirrors.cloud.tencent.com/AndroidSDK/ 这会对速度有一定提升。 全局Gradle配置 在linux与Mac上位于~/.gradle/gradle.properties 添加以下内容: 1 maven.repo.remote=https\://maven.aliyun.com/repository/google,https\://maven.aliyun.com/repository/jcenter,https\://maven.aliyun.com/repository/public Gradle程序下载 在Android Studio自动生成的项目结构下,配置文件应该位于 gradle/wrapper/gradle-wrapper.properties 在我这里,生成的版本如下:(版本号不同很正常) 1 2 3 4 5 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists 网上的教程大多告诉你把链接换成腾讯镜像的,可是实际操作中会发现还是要连接services.gradle.org导致sync过程卡死,因为这里只提供了bin二进制包,我们还同时需要src源码(虽然我还不清楚为什么) 正确的修改应该如下:(版本号需要依据实际情况修改) 1 2 3 4 5 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-8.13-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists all包是我们需要的,它相当于bin加上src Gradle项目配置 位于项目根目录下的settings.gradle.kts 一般而言,只需要修改以下内容 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 pluginManagement { repositories { // 改为阿里云的镜像地址 maven { setUrl("https://maven.aliyun.com/repository/central") } maven { setUrl("https://maven.aliyun.com/repository/jcenter") } maven { setUrl("https://maven.aliyun.com/repository/google") } maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") } maven { setUrl("https://maven.aliyun.com/repository/public") } maven { setUrl("https://jitpack.io") } maven { setUrl("https://maven.aliyun.com/nexus/content/groups/public/") } maven { setUrl("https://maven.aliyun.com/nexus/content/repositories/jcenter") } gradlePluginPortal() google() mavenCentral() } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { // 改为阿里云的镜像地址 maven { setUrl("https://maven.aliyun.com/repository/central") } maven { setUrl("https://maven.aliyun.com/repository/jcenter") } maven { setUrl("https://maven.aliyun.com/repository/google") } maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") } maven { setUrl("https://maven.aliyun.com/repository/public") } maven { setUrl("https://jitpack.io") } google() mavenCentral() } } 总结 国内复杂的网络环境确实给开发者带来了很多不必要的麻烦…

2025/8/20
articleCard.readMore

解决linux系统下pipewire作为音频服务器持续播放声音中断问题

本文接上篇在ThinkBook 16+ 2025上安装archlinux驯服记录【基本信息与触摸板修复】。按理说,本文标题本应是《在ThinkBook 16+ 2025上安装archlinux驯服记录【音频修复】》的,考虑到此问题可能影响到较多机型,故修改为更通用的标题。 闲话少说,开始解决问题。 问题背景 我有时候会用电脑播放音乐,这些音乐都是无损flac格式的盗版音乐。在我的上一台电脑上,一切正常。在这台新款的ThinkBook 16+ 2025上,问题表现为: 播放音乐的时候,能放一会儿(约30秒),然后就没有声音了,插电也是这样 声音中断后KDE设置显示“已失去与声音服务器的连接”,VLC启动时加载时间比正常情况久很多,音量被自动设置到0,且进度条不开始。 这种情况令我糟心,为了立刻重新听上音乐,我通过systemctl重启了pipewire与wireplumber服务,重新打开vlc,播放了2~3分钟后,同样的声音中断发生了。 作为archlinux用户,我的软件包都是滚动更新的最新版本,所以显然上游还没有修复这个问题,只能自己动手了。 调试过程 我查看了与声卡有关的日志,如下: 从日志上看,驱动能够正常识别与处理设备,而在播放过程中,pipewire或其下的某个组件崩溃了,造成了broken pipe 考虑到linux音频系统的混乱与复杂(如下图),我没有能力深度调试,决定先进行“猜测”。 我首先怀疑是省电配置导致的,因为我希望延长续航时间,所以安装了tlp并且手动配置了许多省电选项。 所以我直接修改了/etc/tlp.conf,找到了与声卡节能有关的配置并修改为以下内容: 1 2 SOUND_POWER_SAVE_ON_BAT=0 SOUND_POWER_SAVE_ON_AC=0 这意味着在交流供电与电源供电时都不会尝试让声卡通过挂起等方式节能。根据我的经验与直觉,linux下硬件不能正常工作,常常是和suspend(挂起)与recover(恢复)有关的。所以我满心期待以为问题解决了。 然后我跟着音乐哼着哼着,音乐停了。 我寻思是不是有内核参数在作祟,于是又折腾了好久。可是并没有用。 就在这个时候我注意到一个此前忽略的细节:虽然连续播放的音乐会中断,但是如果不播放音乐,系统的提示音效在开机后多久,甚至睡眠又唤醒后都是正常的。 也就是说长音频不行而短音频没有影响。 诡异吧? 缓冲区玄学 这个玄学问题,最终还要归结于“缓冲区”。 什么是缓冲区? 想象一下你在搬砖,有一个小推车(缓冲区)。CPU负责往小推车里放砖(音频数据),声卡负责从车里取砖去砌墙(播放声音)。为了让声卡能源源不断地拿到砖,小推车里必须一直有存货。 什么是欠载? 如果CPU因为某些原因(比如在忙别的事情)没来得及往车里放砖,导致小推车空了,声卡过来取砖时发现没东西可取,这就叫“欠载”。 欠载后会发生什么? 通常情况下,ALSA驱动会检测到这个问题,并尝试快速“恢复”现场,比如重置指针、清空缓冲区等,这可能会导致你听到一声非常短暂的“咔哒”声,但播放会继续。 实际情况(猜测) 我的硬件驱动/固件(SOF)非常新,它的“欠载恢复”机制可能有Bug。当欠载发生时,驱动尝试恢复,但操作失败了,把自己搞“死机”了。这就解释了最初日志里的那句 snd_pcm_avail after recover: 断开的管道 (Broken pipe) —— “恢复后管道断开”,意思就是恢复失败了! 刑,既然咱猜是缓存区害得,那把缓存区调大不就好了! 问题解决 我们即将创建一个配置文件覆盖原有默认设置: 1 2 sudo mkdir -p /etc/pipewire/pipewire.conf.d/ sudo nano /etc/pipewire/pipewire.conf.d/99-custom-buffer.conf 数字-XXX是linux下约定俗成的配置文件(主要是在XXconf..d下的)的命名方式,前面的数字表示加载的先后顺序,数字越大越晚被加载,而后加载的配置会覆盖先加载的,所以99(几乎肯定)能覆盖默认配置。 写入以下内容: 1 2 3 4 context.properties = { default.clock.quantum = 2048, default.clock.min-quantum = 2048 } 这是把缓冲区大小设置为了2048,对于咱们32GB RAM的高端机器来说不值得一提😎 但是如果你想显得自己很阔气把这个值调的极大呢? 哈哈,我已经帮你试过了。 不会再有什么正面影响了,同时,音频的延迟性会上升,打游戏估计不爽,但对我没影响。实际播放其实影响也不大,因为pipewire似乎会选择一个较为合适的quantum. 更新:与sof-firmware交流,有以下新消息: 在#5284中有人提出了类似的问题,他们修改了一个与alsa有关的参数,经过我的测试,可以奏效,方法如下: 新建文件~/.config/wireplumber/wireplumber.conf.d/50-alsa-config.conf,内容如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 monitor.alsa.rules = [ { # Matches all SOF alsa sinks matches = [ { api.alsa.card.name = "~sof-*" }, { node.name = "~alsa_output.*" } ] actions = { update-props = { api.alsa.headroom = 1024 } } } ] 关于为什么要这么修改,我咨询了开发人员,感谢@kv2019i的耐心解答。 原文: In short, headroom controls how close to the hardware read pointer Pipewire stays. In systems without audio DSPs, the data is consumed at a steady pace, so Pipewire can keep only very little data in the buffer (to minimize latency). When you have a DSP, power can be saved by not transferring data all the time, but moving data in bigger chunks. What happens in your case, that Pipewire keeps too little data in the audio buffer and a single DSP transfer (from main memory to DSP memory) can dry out the buffer and cause an xrun (there is nothing to play). We are not talking about large buffers here. With regular PCMs, typical DSP configuration will be a 4ms buffer, so small addition to headroom will be enough to avoid xruns. Pipewire is doing this to minimize latency, but in this case, it is too aggressive by default and ends up causing continuous xruns. We do have a separate question how to solve this better in the longer term, but currently we don’t have means in ALSA interface to describe (to apps like Pipewire) what is the maximum DMA burst size. 中文: 简而言之,headroom 控制着 Pipewire 与硬件读取指针的距离。在没有音频 DSP 的系统中,数据以稳定的速度被消耗,因此 Pipewire 只需在缓冲区中保留极少的数据(以最小化延迟)。当系统配备 DSP 时,可以通过不持续传输数据,而是以更大的块为单位传输数据来节省电量。在你的情况下,问题在于 Pipewire 在音频缓冲区中保留的数据太少,一次 DSP 传输(从主内存到 DSP 内存)就可能耗尽缓冲区,从而导致 xrun(没有可播放的内容)。 这里我们说的并不是大型缓冲区。对于常规的 PCM,典型的 DSP 配置会采用 4 毫秒的缓冲区,因此稍微增加一点 headroom 就足以避免 xrun。 Pipewire 这样做是为了最小化延迟,但在这种情况下,其默认设置过于激进,最终导致了持续的 xrun。 我们另外有一个问题,即如何在长期内更好地解决这个问题,但目前我们在 ALSA 接口中还没有办法向 Pipewire 这类应用程序描述最大 DMA 突发大小。 也就是说问题是出在alsa与pipewire的协商。而sof-firmware本身并没有问题。让我们等待上游修复吧 最后重启电脑,或者重启服务都可以 1 systemctl --user restart pipewire.service 长远考虑 以上内容算是一个对我可用的workaround,我不知道别人有没有遇到过这样的问题,也不知道这样能不能奏效。 如果你也遇到了这样的问题,希望你在评论区告诉我这样的方案能不能奏效。 同时为了帮助到更多人,我在sof的github仓库上打开了一个issue,不知道上游会怎么说。 就到这里吧。

2025/8/18
articleCard.readMore

在ThinkBook 16+ 2025上安装archlinux驯服记录【基本信息与触摸板修复】

(网图,侵删) 高考结束啦,我如愿以偿地录取到了计算与智能科学专业,当然要奖励自己一台称心的电脑啦! 选电脑是一门学问(咳咳)目前来看,市面上的笔记本电脑主要有以下几类: 轻薄本:质量轻、便携是最大优势,续航一般也不错,但处理性能羸弱、接口少。主要就上网冲浪、编辑文字,不考虑。 全能本:性能较强,性能较好,质量稍大,接口丰富,外观低调,但容易溢价。续航稍微弱一点,差不多8小时。 移动工作站:性能超强,续航一般,重量很重,价格很贵 游戏本:性能Max,屏幕Max,重量Max,价格High,续航差。 Mac:贵,屏幕好,续航长,审美不错,*nix系统,程序员易上手。生态已经较为完善了,但还可以进步。 鸿蒙笔记本:不可用。(本科四年只用这个我敬你是条汉子) 结合价格、配置、品牌等多方面因素,我最终购买了ThinkBook 16+ 2025 Ultra9 285H 核显版,属于高性能全能本了,价格国补完7000元左右,可以接受。质量2kg左右,对于我一个年轻小伙来说不算事,只是单手拿久了会累。 主要配置信息 处理器:英特尔酷睿Ultra 9 285H,16核心/16线程,最高睿频5.4GHz 内存:三星 2*16GB DDR5 5600MT/s 硬盘:忆联AM541,1TB M.2 2242 PCIe Gen4固态硬盘 显卡:英特尔Arc 140T核显 屏幕:联想16英寸IPS屏,3200×2000分辨率,165Hz刷新率,100%DCI-P3色域 网卡:Intel BE201,支持802.11 a/b/g/n/ac/ax/be(WiFi7) 电池:85Wh 第一次live CD 其实用的不是官方启动映像,之前在一个比较小的移动固态硬盘上安装了archlinux,打造了一个Linux To Go. 经过测试,默认情况下,除了触摸板、指纹识别器、静音指示灯无法工作以外,其他硬件似乎都正常。最大的问题在于续航,那个安装里没有安装TLP,也没有开启什么节能选项。查看powertop发现功耗达到了惊人的17W. 调校目标 体验了一小会儿之后,我确定了如下努力方向: 修复触摸板问题,因为绝大多数时候,我都不会使用鼠标。 音频播放有问题:系统音效正常,但连续播放一会儿音频后,声音中断,此后就没有声音了,我有时候需要用电脑放音乐,因此这一点难以接受。 尽量压低功耗。在Windows上通过AID64查看闲置功率约7W,希望在archlinux上实现接近水平(不打算单独写文章了,降低屏幕亮度,安装tlp并配置得当,把i915驱动替换为xe就够了) 实现Windows下同款的OEM功能:联想Fn+Q切换性能模式通过逆向ACPI我已经实现了,然后发现感知不到差异(没有卵用) 这款笔记本键盘上有一个目前派不上任何用处的Copilot按键,但是竟然连PrtSc/SysRq键都没有,我希望通过按键映射配置Copilot按键为PrtSc/SysRq.(参考了这个帖子已经解决,值得注意的是,如果想要像我一样把copilot键映射为PrtSc截图键,实际上在keyd配置文件中要写sysrq) 现在,开始侦查 (这是和Gemini Vibe Coding的时候要Gemini给我修复一个它自己引入Bug,然后它自信满满满地要搞定这个Bug,但是失败了) 由于触摸板是我使用频率最高的输入方式,所以我首先展开了对触摸板的修复。 通过在互联网上的检索,我得知问题的源头在于这款笔记本电脑使用的触摸板为Goodix GXTP5100 方案压力感应板 (Force Pad) Force Pad没有按键,而是在整个触控区域感知压力的变化,发出信号,从而实现点击等功能。这导致它的驱动工作方式有别于一般的触摸板,而linux桌面环境下处理触摸板的libinput没能很好地处理这一点,致使其失灵。 解决 升级至最新内核 不用说,有的时候其实上游已经解决了这个问题。像本文提到的这个问题,其实社区已经注意到了,有望在未来修复。 创建libinput配置文件 因为libinput不能正确处理GXTP5100这块触摸板,我们需要手动告知其处理方式: 首先创建文件/usr/share/libinput/60-custom-thinkbookg7p2025iah.quirks 然后写入: 1 2 3 4 5 [Lenovo ThinkBook 16 G7+ IAH touchpad] MatchName=*GXTP5100* MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkBook16G7+IAH*:* MatchUdevType=touchpad ModelPressurePad=1 重启,问题修复。 致谢 感谢尼特子很辛苦哟的文章,这算是社区中较早摸清问题脉络,给出解决方案的人了。很佩服,希望以后我能像他一样! 这篇文章有点水,下一篇讲我怎么修复linux播放一段时间音乐之后声音消失的问题的。我一开始怀疑是tlp的节能设置,后来怀疑是wireplumber的bug,最后发现是pipewire的默认值不太适合我的设备。 欢迎阅读解决linux系统下pipewire作为音频服务器持续播放声音中断问题

2025/8/17
articleCard.readMore

「行云流水」在挂载移动硬盘时自动启动Syncthing开始同步的丝滑体验

Syncthing是一款持续文件同步程序。它能实时在两台或多台计算机之间同步文件,安全防范窥探。您的数据仅属于您自己,您理应选择数据的存储位置、是否与第三方共享,以及数据如何在互联网上传输。 很多人称Syncthing为一个网盘,实际上Syncthing本身不提供文件存储的服务。它只是一个工具,让你的数据可以在你的多个设备之间点对点增量传输,如果你有一台自己的NAS,那么你确实可以收获一个速度秒杀绝大部分网盘的“网盘” Syncthing的安装并不难,网上有很多教程,我就不重复造轮子了。 Syncthing的分布式存储理念很棒,但是在我的使用中,还是有点痛点。 痛点 我的上一台电脑只有256GB的存储空间,分给linux的只有60GB,在这样的空间上,我想要备份手机相册就捉襟见肘了。所以我一向把相册、音乐等等存储到一张1TB大小的机械硬盘上(1TB在机械盘中算小了,但是暂时够用)。 So,在设置Syncthing的时候我选择将Syncthing备份数据的位置放在机械硬盘上。为了防止Syncthing在我不需要的时候常驻后台,我并没有设置开机自启。于是在每次需要同步数据的时候,都需要把机械硬盘插上电脑,挂载打开,手动启动电脑和手机上的Syncthing,虽然只是一行命令的事,但是作为对系统要求到近乎苛刻的我,这一不流畅的工作流实在不够优雅。我希望实现类似于传统网盘客户端那样的“无感”体验。 你永远可以相信你对linux的自定义程度 想到要做这个事啊,我就想到了systemd 这个linux上几乎已成标准的服务管理程序。 要实现这个需求,我们希望有一个trigger触发器,在我的移动硬盘挂载的时候触发,激活我们编写的service,然后启动Syncthing 思路还挺清晰的。接下来找这个trigger 还是要吐槽一下linux,虽然可自定义性挺高,提供的接口也很多,这赋予了系统强大的能力,但是这些接口的文档太多太杂,且分散在各处。对于新手、老手都是个头疼的问题,好在现在AI吸收了天地之精华,问一下,很快就找出来了,在这一点上,AI真是提高了我的效率。 正如服务有对应的单元文件一样,设备挂载时也会产生固定的单位(但是并不存在实际文件)可以使用systemctl查看: 1 systemctl list-units --type=mount --user 我这里的输出如下: 第一列为我们需要的systemd挂载名称,最后一列为挂载路径。如果你参考持续化设置一节配置过/etc/fstab,则挂载名称会短一些。 参考ArchWiki我编写了如下的service: 1 2 3 4 5 6 7 8 9 [Unit] Description=Syncthing BindsTo=mnt-btrfs.mount [Service] ExecStart=/usr/bin/syncthing [Install] WantedBy=mnt-btrfs.mount 保存至~/.config/systemd/user/syncthing.service 创建后还需要运行: 1 systemctl enable syncthing --user 该服务才会生效,不用担心额外的资源占用,因为这个enable不会导致Syncthing在系统启动时开始运行。在设备卸载后,Syncthing也会随之停止运行 效果 Your browser does not support the video tag. 服务启动时,也会弹出浏览器中的WebUI,还挺好 Zcc见过很惊讶。

2025/8/9
articleCard.readMore

自建图床和PicGo闹不愉快?干脆自己写个脚本,深度整合到KDE右键菜单!

本站一直使用着自建EasyImages图床,提供了上传图片的API接口。在此基础上,我结合插件,一直使用饱受赞誉的PicGo作为写作时上传图片的工具。 但是,在我的Wayland桌面上,这个软件总是存在着一些小问题。首先是图片的WebP压缩支持似乎并不良好,需要使用插件,倒是有多个开发者维护的不同版本的插件,但它们质量差异大,效果也不太符合我的标准,同时也无法自定义压缩质量参数。其次PicGo的插件安装本应是很便捷的搜素-安装的,可是在我的电脑上,即使挂着梯子也无法直接在应用内搜索安装,只能上网搜索,在Github上找到后下载、解压、安装,再就是图片上传后不能自动复制链接,作为Electron软件,它在后台的资源占用也很大。 我本来一直忍受着,可是在换了新设备后,终于,在我的新电脑上,这一套行不通了。于是我干脆自己动手,丰衣足食,抛开PicGo,在KDE右键菜单中实现如图的一键上传功能。 这就是最终的效果: 简而言之,目前的版本实现了如下效果,完美符合我的需求: 上传图片前使用ImageMagick压缩为WebP(可自定义压缩参数) 压缩后图片本地留档 可以在KDE右键菜单一键上传,与系统深度整合 图片上传后自动复制Markdown格式链接 呈现系统通知,包含原始图片链接,压缩前后的大小 支持从CLI和GUI两种界面上传图片 无后台守护进程,上传图片时才调用,无前端,资源占用小 具体脚本: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 #!/bin/bash # --- 配置区 --- API_URL="请替换成你自己的图床地址" TOKEN="请通过后台获取" COMPRESSED_DIR="/home/micraow/Pictures/compressed" # 压缩后的图片将在此保存 MAX_DIMENSION="2400" # 图片最大尺寸 (已更新) WEBP_QUALITY="80" # WebP 压缩质量 # --- 配置区结束 --- format_size() { local bytes=$1 if (( bytes < 1024 )); then echo "${bytes}B" elif (( bytes < 1048576 )); then # 1024*1024 printf "%.1fK\n" $(echo "scale=1; $bytes/1024" | bc) else printf "%.1fM\n" $(echo "scale=1; $bytes/1048576" | bc) fi } # 检查必要命令 for cmd in magick curl jq bc notify-send; do if ! command -v $cmd &> /dev/null; then echo "错误: 命令 '$cmd' 未找到。请先安装。" exit 1 fi done # 检查剪贴板工具 (Wayland环境优先) if ! command -v wl-copy &> /dev/null && ! command -v xclip &> /dev/null; then echo "错误: 未找到剪贴板工具。请安装 'wl-clipboard' (推荐) 或 'xclip'。" exit 1 fi # 检查输入 if [ -z "$1" ]; then echo "用法: $0 <图片路径>" exit 1 fi INPUT_IMAGE="$1" if [ ! -f "$INPUT_IMAGE" ]; then echo "错误: 文件 '$INPUT_IMAGE' 不存在。" notify-send "上传失败" "文件 '$INPUT_IMAGE' 不存在" -i dialog-error exit 1 fi # 准备路径和文件名 mkdir -p "$COMPRESSED_DIR" FILENAME=$(basename -- "$INPUT_IMAGE") BASENAME="${FILENAME%.*}" OUTPUT_WEBP="$COMPRESSED_DIR/${BASENAME}.webp" echo "--- 开始处理图片 ---" ORIGINAL_SIZE=$(stat -c%s "$INPUT_IMAGE") ORIGINAL_SIZE_HR=$(format_size $ORIGINAL_SIZE) echo "原始文件: $INPUT_IMAGE ($ORIGINAL_SIZE_HR)" # 使用 magick 进行转换和压缩 echo "正在转换并压缩..." magick "$INPUT_IMAGE" -resize "${MAX_DIMENSION}x${MAX_DIMENSION}>" -quality "$WEBP_QUALITY" "$OUTPUT_WEBP" if [ $? -ne 0 ]; then echo "错误: 图片处理失败。" notify-send "上传失败" "使用ImageMagick处理图片时出错" -i dialog-error exit 1 fi COMPRESSED_SIZE=$(stat -c%s "$OUTPUT_WEBP") COMPRESSED_SIZE_HR=$(format_size $COMPRESSED_SIZE) PERCENTAGE=$(echo "scale=2; ($COMPRESSED_SIZE * 100) / $ORIGINAL_SIZE" | bc) printf "压缩后大小: %s (原始的 %.2f%%)\n" "$COMPRESSED_SIZE_HR" "$PERCENTAGE" echo "--- 开始上传图片 ---" RESPONSE=$(curl -s -X POST "$API_URL" -F "image=@$OUTPUT_WEBP" -F "token=$TOKEN") # 图片上传核心步骤,如果不使用EasyImages,请参考文档修改 # 处理上传结果,同样是适用于EasyImages的,其他图床自行修改 if echo "$RESPONSE" | jq -e '.result == "success"' > /dev/null; then UPLOADED_URL=$(echo "$RESPONSE" | jq -r '.url') MARKDOWN_LINK="![$BASENAME]($UPLOADED_URL)" # 复制到剪贴板 (Wayland环境使用 wl-copy) if command -v wl-copy &>/dev/null && [ -n "$WAYLAND_DISPLAY" ]; then echo -n "$MARKDOWN_LINK" | wl-copy elif command -v xclip &>/dev/null; then echo -n "$MARKDOWN_LINK" | xclip -selection clipboard fi # 输出到终端 echo "" echo "✅ 上传成功!" echo "----------------------------------------" echo "图片链接: $UPLOADED_URL" echo "Markdown: $MARKDOWN_LINK" echo "----------------------------------------" echo "Markdown 链接已复制到剪贴板!" NOTIFY_BODY="大小: $ORIGINAL_SIZE_HR → $COMPRESSED_SIZE_HR\n链接: $UPLOADED_URL\n\n(Markdown已复制)" notify-send "图片上传成功" "$NOTIFY_BODY" -i "network-transmit-receive" else ERROR_MSG=$(echo "$RESPONSE" | jq -r '.result // "未知错误"') echo "❌ 上传失败。" echo "服务器返回信息: $RESPONSE" notify-send "图片上传失败" "服务器返回: $ERROR_MSG" -i "dialog-error" exit 1 fi (没错,这么复杂的shell脚本又是Gemini帮我写的) 这个脚本实现了图片上传与反馈的主要逻辑,将其保存至/usr/local/bin/upload,然后就可以在终端以upload <文件路径>的命令上传图片了,效果如下: 其实现在已经很方便了,因为直接把文件拖入终端就会输入文件位置,就像PicGo的图片拽到窗口上传。 桌面集成(仅KDE Plasma适用) 程序员遇到重复三次以上的事情,就应该考虑用脚本自动化 作为CS新人,咱们也要学会这种懒高效率的工作方式。其实我觉得最自然的调用方式是应该像题图一样,选中图片,右键上传: 所以现在要考虑如何向我的KDE Plasma桌面注册“我可以操作图片”的信息,这样在Dolphin里才能直接上传图片。 双子星,闪耀! 1 2 3 4 5 6 7 8 9 10 11 12 [Desktop Entry] Type=Service ServiceTypes=KonqPopupMenu/Plugin MimeType=image/jpeg;image/png;image/gif;image/bmp;image/webp;image/x-icon;image/jfif;image/tiff;image/tga;video/mp4;video/x-matroska; Actions=uploadImage [Desktop Action uploadImage] Name[zh_CN]=上传到我的图床 Name=上传到我的图床 Icon=network-transmit-receive Exec=/bin/bash /usr/local/bin/upload %f 请保存至~/.local/share/kio/servicemenus/upload-action.desktop随后运行: 1 kbuildsycoca6 --noincremental 再打开一个Dolphin窗口,你会发现,有了! 🫠 这下写作的工作流更顺畅了,也更愿意在文章里配图了() 不得不说linux在自定义、功能编排这一块还是很出色的,同样的功能想要在Windows上实现至少要新建个软件项目,在linux上却可以通过连接各种cli工具实现,这一优势在AI的加持下愈发明显。普通人只需要描述想法,AI就能给出还算可靠的脚本。安装几个必须的包就能把很多事情自动化。

2025/8/8
articleCard.readMore

btrfs各压缩等级速率测试脚本,选择最适合你的压缩级别

btrfs透明压缩值得尝试 之前我们写过btrfs快照的使用,不得不说,btrfs是一个非常先进的文件系统(至少在设计理念上是的)。 除了快照,btrfs的另外一个高级特性是透明压缩,强调透明是由于压缩的过程由文件系统完成,而用户以及应用无感。这就是接口抽象的意义。 透明压缩有诸多好处,引用Arch wiki: Btrfs 支持透明自动压缩,这不仅能缩减文件体积,还能通过减弱写入放大效应显著延长闪存介质的使用寿命。 在某些情况下(例如单线程繁重文件 I/O 时),压缩可以提升性能,但在其他场景中(如多线程或高 CPU 占用并涉及大量文件读写的任务),性能则会明显下降。 通常采用压缩算法越快(zstd 和 lzo)性能越好,一些基准测试提供了详细的性能对比数据。 简而言之,优点是省地方,对SSD友好,缺点是会降低一定的吞吐量,以及会占用CPU资源,可是在SSD速度已经很充足,CPU性能总是过剩的现在,这点缺点算不了什么。 所以很值得尝试。 确实很值得“尝试” btrfs给用户提供了zlib(类似zip),lzo,zstd三个可选算法。 对于压缩级别,zlib:1~9;zstd:-15~-1、1~15,需为整数。 所以理论上有25种尝试组合(忽略zstd的负值,lzo无法设置等级) 手动尝试耗时耗力还不准确,所以我万能的Gemini又下场了: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 #!/bin/zsh set -e trap 'umount -q /mnt; rmmod brd' INT TERM # 依赖检查 check_dependency() { if ! command -v $1 &> /dev/null; then echo "错误: 未找到必需的工具 $1,请先安装" exit 1 fi } check_dependency zsh check_dependency hyperfine check_dependency compsize check_dependency jq check_dependency bc check_dependency mkfs.btrfs check_dependency mkfs.ext4 # 基准测试数据目录 BENCHMARK_DIR="/tmp/silesia/" # 检查基准目录是否存在且非空 if [ ! -d "$BENCHMARK_DIR" ] || [ -z "$(ls -A "$BENCHMARK_DIR" 2>/dev/null)" ]; then echo "错误: 基准目录 $BENCHMARK_DIR 不存在或为空" echo "请下载Silesia测试集: wget http://mattmahoney.net/dc/silesia.zip && unzip silesia.zip -d /tmp/silesia/" exit 1 fi DIR_SIZE=$(du -bs "$BENCHMARK_DIR" | cut -f1) if [ "$DIR_SIZE" -eq 0 ]; then echo "错误: 基准目录大小为零" exit 1 fi OUTPUT_ROW="%-15s %-10s %-10s %20s %25s\n" # 通用基准测试函数,增加文件系统参数 bench(){ local fs_type=$1 local mount_opts=$2 local label=$3 # 根据文件系统类型选择格式化命令 if [ "$fs_type" = "btrfs" ]; then mkfs_cmd="mkfs.btrfs -O block-group-tree /dev/ram0 -f" elif [ "$fs_type" = "ext4" ]; then mkfs_cmd="mkfs.ext4 -F /dev/ram0" else echo "错误: 不支持的文件系统类型 $fs_type" return 1 fi # 测量压缩时间 (对于ext4和无压缩Btrfs,这实际是纯复制时间) comp_time=$( hyperfine \ --prepare "umount -q /mnt; $mkfs_cmd; mount -o $mount_opts /dev/ram0 /mnt; sync; echo 3 > /proc/sys/vm/drop_caches" \ --style=none --export-json - --runs 20 \ "cp -r $BENCHMARK_DIR/* /mnt; sync" | jq -r '.results[].mean' ) # 测量解压缩/读取时间 decomp_time=$( hyperfine \ --prepare "umount -q /mnt; mount -o $mount_opts /dev/ram0 /mnt; sync; echo 3 > /proc/sys/vm/drop_caches" \ --style=none --export-json - --runs 20 \ "tar -c /mnt 2>/dev/null| cat > /dev/null" | jq -r '.results[].mean' ) # 检查是否成功获取时间数据 if ! [[ "$comp_time" =~ ^[0-9.]+$ ]] || ! [[ "$decomp_time" =~ ^[0-9.]+$ ]]; then echo "错误: 无法获取有效的时间数据 for $label" return 1 fi # 获取大小信息 (ext4不支持compsize,使用du替代) if [ "$fs_type" = "btrfs" ]; then usage=$(compsize /mnt | awk '/TOTAL/ {print $2, $3}') else # 对于ext4,Ratio设为1.0,压缩后大小等于原始大小 compressed_size=$(du -bs /mnt | cut -f1) ratio=$(echo "scale=2; $compressed_size / $DIR_SIZE" | bc) usage="$ratio $compressed_size" fi # 计算速度 (MiB/s) comp_speed=$(echo "scale=6; ($DIR_SIZE / 1024 / 1024) / $comp_time" | bc) decomp_speed=$(echo "scale=6; ($DIR_SIZE / 1024 / 1024) / $decomp_time" | bc) # 格式化输出 speed=$(printf "%.3f MiB/s | %.3f MiB/s" $comp_speed $decomp_speed) printf $OUTPUT_ROW "$label" ${=usage} "$speed" umount -q /mnt } # 输出表头 printf $OUTPUT_ROW "文件系统/算法" "压缩比" "压缩后大小" "压缩速度" "解压缩速度" # 加载ramdisk模块 (2GB大小以确保能容纳测试数据) modprobe brd rd_size=$((1*1024**2)) max_part=1 rd_nr=1 # 测试ext4 bench ext4 "defaults" "ext4" echo # 测试无压缩Btrfs bench btrfs "compress=none" "btrfs (无压缩)" echo # 测试LZO压缩Btrfs bench btrfs "compress=lzo" "btrfs (lzo)" echo # 测试不同级别zstd压缩Btrfs for i in {1..6}; do bench btrfs "compress=zstd:$i" "btrfs (zstd:$i)" done echo # 测试不同级别强制zstd压缩Btrfs for i in {1..6}; do bench btrfs "compress-force=zstd:$i" "btrfs (zstd-force:$i)" done echo # 清理 rmmod brd echo "测试完成" 前决条件 运行此脚本前,你需要安装以下包: zsh btrfs-progs hyperfine compsize jq bc 你还需要下载silesia测试集,并将其解压至/tmp/silesia/下。 silesia数据集是一个专门用来测试压缩算法的数据集,包含了各种格式与编码的内容,可以模拟日常使用中用户可能使用的各类文件,确保压缩算法的鲁棒性、通用性。 你最好不要在/mnt上挂载设备,因为这个脚本即将在/mnt上创建临时文件系统。 为了确保结果准确,测试过程中不要使用电脑。 结果展示 实际上图片中我没有测试完就结束运行了,因为上次测试发现,zstd压缩级别大于5时压缩后大小几乎不下降而读写速率持续下降。 从结果来看,无压缩的btrfs已经在读写速率上存在小幅下降,lzo压缩算法取得了还算不错的压缩率,而读写速率也有所下降。 可是我最看好的是压缩级别为1的zstd压缩。此时压缩率较lzo压缩有较大增长,而读写速率也有小幅下降,大于一的时候,读写速率持续下降,但是压缩率似乎已经达到极限了。 基于此,我最终选择了zstd压缩,压缩级别为1. 持久化设置 我们通过一个使用脚本完成了对压缩算法与级别的选择。可是如果想要应用压缩,需要在每次mount挂载时手动输入参数,否则就不会应用压缩。这对我来说是不可接受的,因为我已经习惯了在dolphin(文件管理器)里点击设备,自动挂载访问了。 那么有没有办法自动化应用挂载参数呢? 有! 答案在于/etc/fstab,linux已经提供了这样一种设置方式。 这个文件记录了某一个特定设备在挂载时应该挂载于什么目录,是什么文件系统,需要使用怎么样的参数。 这个文件非常重要,如果损毁将无法开机。在修改前建议先备份。 你应该会发现该文件每一行格式都如下: 1 <file system><dir><type><options><dump><pass> <file system>可以用/dev/sda1这样的设备名确定,但我更喜欢使用UUID,这样不容易出错。可以用sudo lsblk -f查看: UUID那一栏的内容,复制下来。 <dir>指定了该文件系统应该挂载于什么目录,它必须存在,否则会挂载失败。需要提前创建好。 <type> 写明文件系统。 <options>是这里的主角。如果你的fstab里已经有条目了,只需要增加compress=zstd:1就好了。 顺便推荐另外几个用于SSD上的btrfs参数:ssd,discard=async,space_cache=v2 <dump> 指定dump工具是否要备份此文件系统,一般我们都不用,置零即可。 <pass>指定需要检查的文件系统的检查顺序。允许的数字是0, 1, 和2。 根目录应当获得最高的优先权 1, 其它所有需要被检查的设备设置为 2. 0 表示设备不会被 fsck 所检查。 btrfs文件系统建议全部设置为0,因为btrfs的fsck是不起作用的。 btrfs支持在线检查,请在启动后使用btrfs scrub检查文件系统。 保存之后,重启生效。 压缩效果 你可以用之前安装的compsize检查压缩效果: 命令为: 1 compsize -x <路径> -x表示不跨越文件系统,不加上可能会报错: /boot/EFI/Microsoft/Boot/bg-BG/bootmgfw.efi.mui: Not btrfs (or SEARCH_V2 unsupported). 因为EFI分区使用了fat32文件系统。 从数据可以看出,在我的系统上,btrfs节省了6GB空间,可是要知道目前我整个系统,带上我一些文件一共只使用了19GB左右。(点名Windows) 总体来说,还是很满意的,吞吐量的减少对我的影响也不大。 你学会了吗?快利用酷酷的btrfs特性吧!

2025/8/8
articleCard.readMore

别当冤大头,Adobe全家桶破解源头方案:修图剪辑不求人,盗版网站也得从你这儿进货!

本站不提供盗版软件下载服务,本文仅供学习交流,严禁用于商业用途,请于24小时内删除。请支持正版! Adobe公司开发了一整套适用于艺术与创意工作者的重磅软件。Acrobat(那个PDF查看与编辑器),Ps, Pr,Ae,Lr等应用,你可能没用过,但是你一定听过。 (像元素周期表一样) 这些软件已成事实行业标准。虽然有开源替代方案,终究有一定距离。而正版虽好,价格太贵,穷学生也想用的话就要上网找破解版了。 可是在国内互联网环境下,上网一搜,不是老旧版本,就是要付费下载(积分,关注公众号,解压密码,这些坑都踩过吗),或者有肉眼可见的捆绑恶意软件。 不知道你有没有想过,何不直接从货源拿货,这些破解软件产自哪里,我们就从哪里下载! 这一把厂家直销,拿到的版本应该就比较可靠了,而且还是最新的。 美好的过去 其实在2023年8月11日前,只要在国内互联网上摸索会儿,你就会看到@vposy的鼎鼎大名,这是国内的原创adobe破解软件作者,历史背景很复杂,不展开了。 但是美好的故事结束了: 8 月 11 号的时候,国内嬴政天下 Adobe 全家桶系列的作者 Vposy 宣布因「工作调动」暂停更新。 这可是国内不少盗版软件站点的上游啊,这一出,国内一堆破解站就在2025年的今天,拿着2022、2023年的旧版本招摇撞骗。 论破解,还是得看俄罗斯黑客 众所周知,俄罗斯的黑客水平一流,不少破解软件就是那里流出的🤣 经过我的探索,我顺藤摸瓜地找到了各个破解版本之母:GenP GenP是一个补丁程序,也就是说它并不直接提供破解版本软件,需要你自己从Adobe网站下载官方安装包,再运行GenP对其进行修改,达到无限期试用的效果。 其wiki在:https://wiki.dbzer0.com/genp-guides/ wiki中提供了完整安装过程,但是是英语。 下面,我将为你翻译并整理 GenP 官方 Wiki 的核心安装指南,让你能“厂家直销”,安全、顺利地完成操作。 安装前:必读的核心信息 在开始之前,请务必阅读以下几点,这能帮你避免90%的问题。 🔴 重要警告:只从官方Wiki下载! GenP 是完全免费的,并且将永远免费。官方不会以任何形式要求或接受捐赠。如果你下载 GenP 的地方需要你付费、等待、完成任务、关注公众号,或者点击一堆广告链接,那100%是假的! 这些第三方网站经常捆绑广告、弹窗甚至恶意软件。请务必从官方渠道获取,保证安全和纯净。 🔴 系统要求:仅限 Windows,不支持 ARM 操作系统:GenP 只支持 x64 架构的 Windows 10 或 11 系统。 不支持 ARM:如果你的电脑使用高通骁龙处理器(比如 Surface Pro 11 或其他 “Copilot+ PC”),那么它是 ARM 架构,无法运行 GenP。 不支持的平台:macOS, Linux, 以及任何修改版或精简版 Windows (如 LTSC, Tiny11, GhostSpectre) 都不在支持范围内。 🔴 功能限制:生成式填充 (Generative Fill) 等 AI 功能不可用 像 Photoshop 里的生成式填充、Firefly AI 等功能是基于 Adobe 服务器的,需要有效的正版订阅才能联网使用。使用 GenP 后,这些联网 AI 功能将无法使用。请不要反复尝试或提问。 第一步:准备工作 (将 GenP 添加到杀毒软件白名单) 由于 GenP 的工作原理是修改文件,几乎所有杀毒软件(包括 Windows Defender)都会误报它为病毒。因此,在下载和解压前,你需要将存放 GenP 的文件夹添加到白名单(排除项)。 以 Windows Defender 为例: 打开 设置 > 隐私和安全性 > Windows 安全中心。 进入 病毒和威胁防护 > “病毒和威胁防护”设置 > 管理设置。 滚动到最下方,找到 排除项,点击 “添加或删除排除项”。 点击 “添加排除项” > “文件夹”,然后选择你计划用来存放 GenP 的文件夹。 如果你使用其他杀毒软件(如 Avast, Bitdefender, Kaspersky 等),请自行搜索如何添加排除项。 第二步:正式安装 (CC + GenP 方案) 这是官方最推荐的方案,通过官方 Creative Cloud 安装应用,再用 GenP 进行激活。 所需工具: Creative Cloud (CC) 安装程序:从 Adobe 官网下载。 最新版 GenP:从官方 Wiki 的下载目录获取(通常选择 Latest Updated Version)。 详细步骤: 安装 Creative Cloud (CC) 运行下载好的 CC 安装程序。 你需要登录一个 Adobe 账户。强烈建议注册一个新账户,不要使用你之前有订阅或试用记录的老账户,以免出现问题。(可以使用临时邮箱注册) 安装完成后,打开 CC,进入 菜单 > 文件 > 首选项,在“常规”选项卡中,关闭以下三个选项: 登录时启动 Creative Cloud 关闭后在后台运行 Creative Cloud 自动保持 Creative Cloud 为最新状态 完成设置后,点击 菜单 > 文件 > 退出 Creative Cloud,确保其完全关闭。 2. 下载并解压 GenP 从官方 Wiki 下载最新版的 GenP 压缩包。 解压到一个你已经添加了白名单的文件夹里。如果解压后 .exe 文件消失了,说明被杀毒软件隔离了,请检查你的白名单设置。 3. 激活 Creative Cloud 以 管理员身份运行 GenP.exe。 点击 “Search” 按钮,GenP 会自动搜索已安装的 Adobe 程序。 等待搜索结果出来后,只勾选 列表顶部的三个关于 Creative Cloud 的文件。 点击 “Patch” 按钮,等待它完成。当界面自动切换到 “Log” 选项卡时,就表示完成了。 4. 从 CC 中安装你需要的 Adobe 应用 打开 Creative Cloud。现在你应该能看到所有应用的旁边都有一个“安装”按钮,而不是“试用”或“购买”。 点击安装你想要的任何应用(如 Photoshop, Premiere Pro 等)。 全部安装完成后,先不要打开任何应用。再次退出 Creative Cloud。 5. 激活你安装的 Adobe 应用 再次以 管理员身份运行 GenP.exe。 点击 “Search”,GenP 会找到你刚刚安装的所有应用。 默认情况下所有找到的应用都会被勾选。确认无误后,点击 “Patch”。 等待过程结束。 6. 完成! 现在,你可以从开始菜单、桌面快捷方式或程序文件夹中直接打开你安装的 Adobe 应用了。切记:不要通过 Creative Cloud 界面里的“打开”按钮来启动应用,因为 CC 会联网验证,可能导致激活失效。 关于更新: 更新应用:可以在 CC 中直接更新应用,但更新后必须重复第 5 步,再次运行 GenP 对更新后的应用进行激活。 更新 CC:如果 CC 本身需要更新,更新后也必须重复第 3 步,再次激活 CC。 如果搞砸了怎么办:终极清理方案 如果你在安装过程中遇到问题,或者想彻底卸载重来,可以采用官方的完全清理方法,确保不留任何残余。 运行 Adobe 官方清理工具:下载并运行 Adobe Creative Cloud Cleaner Tool,选择清理所有(Clean All)。 手动删除文件夹:在文件管理器中,手动检查并删除以下路径中的所有 Adobe 相关文件夹(如果存在): 1 2 3 4 5 6 C:\Program Files\Adobe C:\Program Files\Common Files\Adobe C:\Program Files (x86)\Adobe C:\Program Files (x86)\Common Files\Adobe %appdata% (会定位到 C:\Users\你的用户名\AppData\Roaming) %localappdata% (会定位到 C:\Users\你的用户名\AppData\Local) 清理注册表: 按下 Win + R,输入 regedit 打开注册表编辑器。 分别在 HKEY_CURRENT_USER\Software 和 HKEY_LOCAL_MACHINE\Software 路径下,找到并删除 Adobe 项。 重启电脑:重启后,你的电脑就恢复了“纯净”状态,可以重新按照指南从头开始了。 希望这份“厂家直销”的指南能帮到你。请务必谨慎操作,并始终从官方渠道获取信息,享受你的创作之旅吧! 但是,如果你像我一样懒 其实上面的指南已经很详细了,但是如果你和我一样懒,希望直接安装使用,那么,你可以尝试官方Wiki里提到的monkrus版本 这个版本相当于预先用GenP破解过了,又精简修改了一下,版本同样很新。只是有些可选功能需要安装后额外下载。 同时,由于是“网络上的陌生人”构建的二进制版本版本,使用时,你需要自行承担风险! 警告完了,接下来是方法: 还是访问GenP的网站 你会在页面下方找到很多链接: 选择你需要的产品点进去。(可能需要自备科学上网工具) 对了,第一项qBittorent是一个BT下载工具,懂得应该都懂,如果你还没有一个BT下载器,可以看看本站的这篇文章:轻松配置aria2下载器,通过systemd设置开机自启并与浏览器集成,或者希望方便一点,就直接下载qBittorent吧,也是开源的 XD 这是monkrus的官方网站,这网站不做别的,就和Adobe叫板。 当然这界面也一股苏联老大哥味,反正我是看不懂,右上角有翻译按钮。 这里以Adobe Acrobat Pro为例。众所周知,我们每天使用的PDF格式是Adobe公司开发的,而Adobe Acrobat Pro是Adobe官方开发的PDF查看与编辑器,兼容性和功能都没的说。 现在电脑一般都是64位操作系统了,就别下x86的32位版本了。 详情页下方,有许多下载链接: 这里的链接,你可能打得开,也可能不行,看网络环境。 (我惊奇的发现还有个PB.WTF网站,有点想笑) (彭勃,What the Fuck!) 然后,你会得到…… 一个大小以KB计的种子 用你的BT下载器打开它,剩下来的就不用我说了吧? 创作愉快! (终于不用在鱼龙混杂的搜索引擎里蹚浑水了) (知道了资源,是不是马上能开盗版站了呢🤔) 免责声明 本站不提供盗版软件下载服务,本文仅供学习交流,严禁用于商业用途,请于24小时内删除。请支持正版!

2025/8/7
articleCard.readMore

轻松配置aria2下载器,通过systemd设置开机自启并与浏览器集成

高考完了,我买了新的笔记本电脑,是ThinkBook 16+ 2025 Ultra9 285H 32GB+1TB 核显版本,对于不怎么玩游戏的我来说,基本上够用了。高考前觉得闲下来之后会经常更新博客,但好像一直鸽着。。。 忙活了很多其他的事吧,在我看到我的好多同学学python、学C的最近,我倒没有把太多时间花在倒腾技术上。 不过出于对archlinux的热爱,我在WSL与双系统方案间犹豫了好久,还是决定在如此前沿的硬件上作死折腾archlinux 后续可能有系列文章吧。 言归正传,回到今天的主角,Aria2下载器 什么是aria2 官方github仓库 这是中国人开发的,但是README是英文,里面的介绍翻译过来是这样: Aria2是下载文件的实用程序。 支持的协议有:HTTP(S)、FTP、SFTP、BitTorrent和Metalink。 Aria2可以从多个源/协议下载文件,并尝试利用您的最大下载带宽。 它支持同时从HTTP(S)/FTP/SFTP和BitTorrent下载文件,同时将从HTTP(S)/FTP/SFTP下载的数据上传到BitTorrent群。使用Metalink的块校验和,aria2在下载像BitTorrent这样的文件时自动验证数据块。 听起来云里雾里的?正常。我总结一下,它是一个类似于IDM或者迅雷的多线程全能下载器 这意味着在服务器支持的情况下,下载文件不再是从头下到尾,而是将整个文件分成多个部分同时进行下载,得到可观的下载速度。 这个工具很强大,但是入手有一定门槛。需要自己编辑配置文件,虽然不难但是烦,重装系统的时候就知道了🥺 所以在此共享我的aria2.conf配置文件,希望能帮到你我。占位符用$$$括起来了,记得按照实际情况修改。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 ## 文件保存设置 ## # 下载目录。可使用绝对路径或相对路径, 默认: 当前启动位置 dir=$$$自己设置$$$ # 磁盘缓存, 0 为禁用缓存,默认:16M # 磁盘缓存的作用是把下载的数据块临时存储在内存中,然后集中写入硬盘,以减少磁盘 I/O ,提升读写性能,延长硬盘寿命。 # 建议在有足够的内存空闲情况下适当增加,但不要超过剩余可用内存空间大小。 # 此项值仅决定上限,实际对内存的占用取决于网速(带宽)和设备性能等其它因素。 disk-cache=128M # 文件预分配方式, 可选:none, prealloc, trunc, falloc, 默认:prealloc # 预分配对于机械硬盘可有效降低磁盘碎片、提升磁盘读写性能、延长磁盘寿命。 # 机械硬盘使用 ext4(具有扩展支持),btrfs,xfs 或 NTFS(仅 MinGW 编译版本)等文件系统建议设置为 falloc # 若无法下载,提示 fallocate failed.cause:Operation not supported 则说明不支持,请设置为 none # prealloc 分配速度慢, trunc 无实际作用,不推荐使用。 # 固态硬盘不需要预分配,只建议设置为 none ,否则可能会导致双倍文件大小的数据写入,从而影响寿命。 file-allocation=none # 文件预分配大小限制。小于此选项值大小的文件不预分配空间,单位 K 或 M,默认:5M no-file-allocation-limit=64M # 断点续传 continue=true # 始终尝试断点续传,无法断点续传则终止下载,默认:true always-resume=false # 不支持断点续传的 URI 数值,当 always-resume=false 时生效。 # 达到这个数值从将头开始下载,值为 0 时所有 URI 不支持断点续传时才从头开始下载。 max-resume-failure-tries=0 # 获取服务器文件时间,默认:false remote-time=true ## 进度保存设置 ## # 从会话文件中读取下载任务 input-file=$$$可修改,推荐~/.aria2/aria2.session$$$ # 会话文件保存路径 # Aria2 退出时或指定的时间间隔会保存`错误/未完成`的下载任务到会话文件 save-session=$$$可修改,推荐~/aria2/aria2.session$$$ # 任务状态改变后保存会话的间隔时间(秒), 0 为仅在进程正常退出时保存, 默认:0 # 为了及时保存任务状态、防止任务丢失,此项值只建议设置为 1 save-session-interval=1 # 自动保存任务进度到控制文件(*.aria2)的间隔时间(秒),0 为仅在进程正常退出时保存,默认:60 # 此项值也会间接影响从内存中把缓存的数据写入磁盘的频率 # 想降低磁盘 IOPS (每秒读写次数)则提高间隔时间 # 想在意外非正常退出时尽量保存更多的下载进度则降低间隔时间 # 非正常退出:进程崩溃、系统崩溃、SIGKILL 信号、设备断电等 auto-save-interval=30 # 强制保存,即使任务已完成也保存信息到会话文件, 默认:false # 开启后会在任务完成后保留 .aria2 文件,文件被移除且任务存在的情况下重启后会重新下载。 # 关闭后已完成的任务列表会在重启后清空。 force-save=false ## 下载连接设置 ## # 文件未找到重试次数,默认:0 (禁用) # 重试时同时会记录重试次数,所以也需要设置 max-tries 这个选项 max-file-not-found=10 # 最大尝试次数,0 表示无限,默认:5 max-tries=0 # 重试等待时间(秒), 默认:0 (禁用) retry-wait=10 # 连接超时时间(秒)。默认:60 connect-timeout=10 # 超时时间(秒)。默认:60 timeout=10 # 最大同时下载任务数, 运行时可修改, 默认:5 max-concurrent-downloads=10 # 单服务器最大连接线程数, 任务添加时可指定, 默认:1 # 最大值为 16 (增强版无限制), 且受限于单任务最大连接线程数(split)所设定的值。 max-connection-per-server=16 # 单任务最大连接线程数, 任务添加时可指定, 默认:5 split=64 # 文件最小分段大小, 添加时可指定, 取值范围 1M-1024M (增强版最小值为 1K), 默认:20M # 比如此项值为 10M, 当文件为 20MB 会分成两段并使用两个来源下载, 文件为 15MB 则只使用一个来源下载。 # 理论上值越小使用下载分段就越多,所能获得的实际线程数就越大,下载速度就越快,但受限于所下载文件服务器的策略。 min-split-size=4M # HTTP/FTP 下载分片大小,所有分割都必须是此项值的倍数,最小值为 1M (增强版为 1K),默认:1M piece-length=1M # 允许分片大小变化。默认:false # false:当分片大小与控制文件中的不同时将会中止下载 # true:丢失部分下载进度继续下载 allow-piece-length-change=true # 最低下载速度限制。当下载速度低于或等于此选项的值时关闭连接(增强版本为重连),此选项与 BT 下载无关。单位 K 或 M ,默认:0 (无限制) lowest-speed-limit=0 # 全局最大下载速度限制, 运行时可修改, 默认:0 (无限制) max-overall-download-limit=0 # 单任务下载速度限制, 默认:0 (无限制) max-download-limit=0 # 禁用 IPv6, 默认:false disable-ipv6=false # GZip 支持,默认:false http-accept-gzip=true # URI 复用,默认: true reuse-uri=true # 禁用 netrc 支持,默认:false no-netrc=true # 允许覆盖,当相关控制文件(.aria2)不存在时从头开始重新下载。默认:false allow-overwrite=false # 文件自动重命名,此选项仅在 HTTP(S)/FTP 下载中有效。新文件名在名称之后扩展名之前加上一个点和一个数字(1..9999)。默认:true auto-file-renaming=true # 使用 UTF-8 处理 Content-Disposition ,默认:false content-disposition-default-utf8=true # 最低 TLS 版本,可选:TLSv1.1、TLSv1.2、TLSv1.3 默认:TLSv1.2 #min-tls-version=TLSv1.2 ## BT/PT 下载设置 ## # BT 监听端口(TCP), 默认:6881-6999 # 直通外网的设备,比如 VPS ,务必配置防火墙和安全组策略允许此端口入站 # 内网环境的设备,比如 NAS ,除了防火墙设置,还需在路由器设置外网端口转发到此端口 listen-port=51413 # DHT 网络与 UDP tracker 监听端口(UDP), 默认:6881-6999 # 因协议不同,可以与 BT 监听端口使用相同的端口,方便配置防火墙和端口转发策略。 dht-listen-port=51413 # 启用 IPv4 DHT 功能, PT 下载(私有种子)会自动禁用, 默认:true enable-dht=true # 启用 IPv6 DHT 功能, PT 下载(私有种子)会自动禁用,默认:false # 在没有 IPv6 支持的环境开启可能会导致 DHT 功能异常 enable-dht6=false # 指定 BT 和 DHT 网络中的 IP 地址 # 使用场景:在家庭宽带没有公网 IP 的情况下可以把 BT 和 DHT 监听端口转发至具有公网 IP 的服务器,在此填写服务器的 IP ,可以提升 BT 下载速率。 #bt-external-ip= # IPv4 DHT 文件路径,默认:$HOME/.aria2/dht.dat dht-file-path=$$$可修改$$$ # IPv6 DHT 文件路径,默认:$HOME/.aria2/dht6.dat dht-file-path6=$$$可修改$$$ # IPv4 DHT 网络引导节点 dht-entry-point=dht.transmissionbt.com:6881 # IPv6 DHT 网络引导节点 dht-entry-point6=dht.transmissionbt.com:6881 # 本地节点发现, PT 下载(私有种子)会自动禁用 默认:false bt-enable-lpd=true # 指定用于本地节点发现的接口,可能的值:接口,IP地址 # 如果未指定此选项,则选择默认接口。 #bt-lpd-interface= # 启用节点交换, PT 下载(私有种子)会自动禁用, 默认:true enable-peer-exchange=true # BT 下载最大连接数(单任务),运行时可修改。0 为不限制,默认:55 # 理想情况下连接数越多下载越快,但在实际情况是只有少部分连接到的做种者上传速度快,其余的上传慢或者不上传。 # 如果不限制,当下载非常热门的种子或任务数非常多时可能会因连接数过多导致进程崩溃或网络阻塞。 # 进程崩溃:如果设备 CPU 性能一般,连接数过多导致 CPU 占用过高,因资源不足 Aria2 进程会强制被终结。 # 网络阻塞:在内网环境下,即使下载没有占满带宽也会导致其它设备无法正常上网。因远古低性能路由器的转发性能瓶颈导致。 bt-max-peers=128 # BT 下载期望速度值(单任务),运行时可修改。单位 K 或 M 。默认:50K # BT 下载速度低于此选项值时会临时提高连接数来获得更快的下载速度,不过前提是有更多的做种者可供连接。 # 实测临时提高连接数没有上限,但不会像不做限制一样无限增加,会根据算法进行合理的动态调节。 bt-request-peer-speed-limit=10M # 全局最大上传速度限制, 运行时可修改, 默认:0 (无限制) # 设置过低可能影响 BT 下载速度 max-overall-upload-limit=2M # 单任务上传速度限制, 默认:0 (无限制) max-upload-limit=0 # 最小分享率。当种子的分享率达到此选项设置的值时停止做种, 0 为一直做种, 默认:1.0 # 强烈建议您将此选项设置为大于等于 1.0 seed-ratio=1.0 # 最小做种时间(分钟)。设置为 0 时将在 BT 任务下载完成后停止做种。 seed-time=0 # 做种前检查文件哈希, 默认:true bt-hash-check-seed=true # 继续之前的BT任务时, 无需再次校验, 默认:false bt-seed-unverified=false # BT tracker 服务器连接超时时间(秒)。默认:60 # 建立连接后,此选项无效,将使用 bt-tracker-timeout 选项的值 bt-tracker-connect-timeout=10 # BT tracker 服务器超时时间(秒)。默认:60 bt-tracker-timeout=10 # BT 服务器连接间隔时间(秒)。默认:0 (自动) #bt-tracker-interval=0 # BT 下载优先下载文件开头或结尾 bt-prioritize-piece=head=32M,tail=32M # 保存通过 WebUI(RPC) 上传的种子文件(.torrent),默认:true # 所有涉及种子文件保存的选项都建议开启,不保存种子文件有任务丢失的风险。 # 通过 RPC 自定义临时下载目录可能不会保存种子文件。 rpc-save-upload-metadata=true # 下载种子文件(.torrent)自动开始下载, 默认:true,可选:false|mem # true:保存种子文件 # false:仅下载种子文件 # mem:将种子保存在内存中 follow-torrent=true # 种子文件下载完后暂停任务,默认:false # 在开启 follow-torrent 选项后下载种子文件或磁力会自动开始下载任务进行下载,而同时开启当此选项后会建立相关任务并暂停。 pause-metadata=false # 保存磁力链接元数据为种子文件(.torrent), 默认:false bt-save-metadata=true # 加载已保存的元数据文件(.torrent),默认:false bt-load-saved-metadata=true # 删除 BT 下载任务中未选择文件,默认:false bt-remove-unselected-file=true # BT强制加密, 默认: false # 启用后将拒绝旧的 BT 握手协议并仅使用混淆握手及加密。可以解决部分运营商对 BT 下载的封锁,且有一定的防版权投诉与迅雷吸血效果。 # 此选项相当于后面两个选项(bt-require-crypto=true, bt-min-crypto-level=arc4)的快捷开启方式,但不会修改这两个选项的值。 bt-force-encryption=true # BT加密需求,默认:false # 启用后拒绝与旧的 BitTorrent 握手协议(\19BitTorrent protocol)建立连接,始终使用混淆处理握手。 #bt-require-crypto=true # BT最低加密等级,可选:plain(明文),arc4(加密),默认:plain #bt-min-crypto-level=arc4 # 分离仅做种任务,默认:false # 从正在下载的任务中排除已经下载完成且正在做种的任务,并开始等待列表中的下一个任务。 bt-detach-seed-only=true ## 客户端伪装 ## # 自定义 User Agent user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.47 # BT 客户端伪装 # PT 下载需要保持 user-agent 和 peer-agent 两个参数一致 # 部分 PT 站对 Aria2 有特殊封禁机制,客户端伪装不一定有效,且有封禁账号的风险。 #user-agent=Deluge 1.3.15 peer-agent=Deluge 1.3.15 peer-id-prefix=-DE13F0- ## 执行额外命令 ## # 下载停止后执行的命令 # 从 正在下载 到 删除、错误、完成 时触发。暂停被标记为未开始下载,故与此项无关。 # on-download-stop=/root/.aria2/delete.sh # 下载完成后执行的命令 # 此项未定义则执行 下载停止后执行的命令 (on-download-stop) # on-download-complete=/root/.aria2/clean.sh # 下载错误后执行的命令 # 此项未定义则执行 下载停止后执行的命令 (on-download-stop) #on-download-error= # 下载暂停后执行的命令 #on-download-pause= # 下载开始后执行的命令 #on-download-start= # BT 下载完成后执行的命令 #on-bt-download-complete= ## RPC 设置 ## # 启用 JSON-RPC/XML-RPC 服务器, 默认:false enable-rpc=true # 接受所有远程请求, 默认:false rpc-allow-origin-all=true # 允许外部访问, 默认:false rpc-listen-all=true # RPC 监听端口, 默认:6800 rpc-listen-port=6800 # RPC 密钥 rpc-secret=$$$设置成你自己的$$$ # RPC 最大请求大小 rpc-max-request-size=10M # RPC 服务 SSL/TLS 加密, 默认:false # 启用加密后必须使用 https 或者 wss 协议连接 # 不推荐开启,建议使用 web server 反向代理,比如 Nginx、Caddy ,灵活性更强。 #rpc-secure=false # 在 RPC 服务中启用 SSL/TLS 加密时的证书文件(.pem/.crt) #rpc-certificate=/root/.aria2/xxx.pem # 在 RPC 服务中启用 SSL/TLS 加密时的私钥文件(.key) #rpc-private-key=/root/.aria2/xxx.key # 事件轮询方式, 可选:epoll, kqueue, port, poll, select, 不同系统默认值不同 #event-poll=select ## 高级选项 ## # 启用异步 DNS 功能。默认:true async-dns=true # 指定异步 DNS 服务器列表,未指定则从 /etc/resolv.conf 中读取。 async-dns-server=119.29.29.29,114.114.114.114,8.8.8.8,1.1.1.1 # 指定单个网络接口,可能的值:接口,IP地址,主机名 # 如果接口具有多个 IP 地址,则建议指定 IP 地址。 # 已知指定网络接口会影响依赖本地 RPC 的连接的功能场景,即通过 localhost 和 127.0.0.1 无法与 Aria2 服务端进行讯通。 #interface= # 指定多个网络接口,多个值之间使用逗号(,)分隔。 # 使用 interface 选项时会忽略此项。 #multiple-interface= ## 日志设置 ## # 日志文件保存路径,忽略或设置为空为不保存,默认:不保存 #log= # 日志级别,可选 debug, info, notice, warn, error 。默认:debug #log-level=warn # 控制台日志级别,可选 debug, info, notice, warn, error ,默认:notice console-log-level=notice # 安静模式,禁止在控制台输出日志,默认:false quiet=false # 下载进度摘要输出间隔时间(秒),0 为禁止输出。默认:60 summary-interval=0 # 关闭控制台进度条输出,避免日志里面打印大量空行 show-console-readout=false 请根据实际内容修改 推荐把修改后的文件保存到~/.aria2/aria2.conf 配置aria2开机自启(仅适用于linux) 按照上面说的做了以后其实只要在终端运行aria2c --conf-path=~/.aria2/aria2.conf就启动后端程序了。 但是我觉得在每次下载前都要这么跑一下把它打开太多余了,寻思着让它开机自启 在网上搜索了一圈,发现推荐的方案是编写systemd用户服务单元。 然后发现不会写。🥲 没关系,我们有Gemini !🤑 我的双子座助手如是说: 1 2 3 4 5 6 7 8 9 [Unit] Description=aria2 Daemon [Service] Type=simple ExecStart=/usr/bin/aria2c --conf-path=$$$修改成你的aria2.conf位置$$$ [Install] WantedBy=default.target 保存成为~/.config/systemd/user/aria2cd.service就ok了 为了让systemd知道这里配置文件更新了,你还需要运行 1 sudo systemctl daemon-reload 然后运行此命令启动: 1 systemctl enable aria2cd --now --user 注意这里不要加sudo,因为这里有--user flag,标识这是用户服务单元,而非root的。 该命令会使aria2cd立即启动,并在以后开机的时候启动。 这是资源占用情况,并不高,后台挂着就挂着吧 浏览器集成 Firefox: 我用的是这个,仅供参考 这个不包含前端,如果需要WebUI查看下载进度等,可以使用AriaNG官方实例 Chrome/Chromium/Edge: 可以用Aria2-Explorer,还蛮好用的,还内置WebUI,打开很方便。 安装地址: Chrome Web Store Microsoft Store 填写密码的时候,就是aria2.conf里配置的 ,端口默认。 进入WebUI可以更改更多设置。 效果 Your browser does not support the video tag. 你学会了吗? 快扔掉IDM吧!

2025/8/7
articleCard.readMore

Git Commit 规范指南

Git Commit 规范指南 用了那么久的git,输入git commit -m 之后是不是还是无从写起?大型项目的git提交记录看起来就很规范高大上。看看这篇短文,你也能写出高级感的git提交信息! 常用格式 1 2 3 4 5 <type>[scope]: <subject> [body] [footer] 各部分说明 1. <type> 提交类型 类型图标描述 feat✨新功能 fix🐛修复 bug docs📚仅修改文档 style💄不影响逻辑的代码格式(空格等) refactor♻️代码重构(非功能、非修复) perf⚡提升性能 test✅添加或修改测试代码 build🛠️构建系统或依赖的变更 ci👷CI配置相关(GitHub Actions) chore🧹杂务,如修改 .gitignore 等 revert⏪回滚提交 2. [scope] 影响范围(可选) 表示本次 commit 影响的模块或功能块,如: 1 2 feat(auth): 添加登录功能 fix(api): 修复用户接口错误处理 3. <subject> 简要说明 祈使语气,如:add, update, delete 不用句号 用英文的话小写即可 4. [body] 提交说明(可选) 说明为什么要做这个修改、修改的动机、解决的问题等,必要时写。建议 72 字换行。 5. [footer] 脚注(可选) 常用于关联 issue 或注明 breaking change: 1 2 3 BREAKING CHANGE: 用户数据结构已更改,不兼容旧版本 Closes #123 ✅ 示例 1 2 3 4 5 6 7 8 9 feat(user): 添加用户注册功能 新增用户注册页面,支持邮箱验证和密码强度检测。 fix(auth): 修复 JWT 校验失败的问题 原因是 token 过期未处理,已增加刷新机制。 Closes #45 小tips 在github还有gitee的网页版上,输入#加数字就能跳转到对应issue的页面。、 以上内容可以复制下来丢给人工智能,然后把git diff --cache | cat的内容附上,就能自动写出git提交信息啦! 实测:

2025/6/30
articleCard.readMore

【Q&A】 「学长说」我在金陵中学这三年啊,你还有什么想知道的?

我是南京市金陵中学2025届毕业生彭勃。 我在金中这三年,有时抱怨、经常吐槽,但总是感激热爱。 本文将从我的视角出发,回首我在金陵中学度过的这独特而不平凡的三年。基本上可以作为金陵中学典型学生的案例,这既是我自己的回忆,也可以让恰好读到本文的你,对我的过去、可能是你的未来有所了解。 欢迎学弟学妹报考金陵中学! 选择一种教育就是选择一种人生 索引 专门开个分类吧: 金陵中学 目录: 【开学前】「学长说」 我在金陵中学这三年啊,很青春,不后悔 【在学校】「学长说」我在金陵中学这三年啊,做了好多事情啊 【高考后】「学长说」 我在金陵中学这三年啊,轰轰烈烈的青春在平平常常中懵懵懂懂地结束 【Q&A】 「学长说」我在金陵中学这三年啊,你还有什么想知道的? Q&A 请在下方评论区提问,我会在看到后开始撰写回答。 支持我! 如果你感觉这些文章对你有所帮助,欢迎给我一点生活费,谢谢!

2025/6/11
articleCard.readMore

【开学前】「学长说」 我在金陵中学这三年啊,很青春,不后悔

我是南京市金陵中学2025届毕业生彭勃。 我在金中这三年,有时抱怨、经常吐槽,但总是感激热爱。 本文将从我的视角出发,回首我在金陵中学度过的这独特而不平凡的三年。基本上可以作为金陵中学典型学生的案例,这既是我自己的回忆,也可以让恰好读到本文的你,对我的过去、可能是你的未来有所了解。 欢迎学弟学妹报考金陵中学! 选择一种教育就是选择一种人生 索引 专门开个分类吧: 金陵中学 目录: 【开学前】「学长说」 我在金陵中学这三年啊,很青春,不后悔 【在学校】「学长说」我在金陵中学这三年啊,做了好多事情啊 【高考后】「学长说」 我在金陵中学这三年啊,轰轰烈烈的青春在平平常常中懵懵懂懂地结束 【Q&A】 「学长说」我在金陵中学这三年啊,你还有什么想知道的? 在初中 我的初中不太好,我那一届就有22个班,每个班50多人,现在大概突破30个了。公办的,鱼龙混杂,往年考上金中的就是个位数,所以一开始目标并非金中,只是本区一所不错的中学,后来我也有很多同学去了那里。 但我的成绩在初中算很好了,除了一次意外,一直在第一考场(应该是前50名)。所以确实有过一点野心去市区那些学校。 但说实话,如果你现在的成绩并不理想,不要气馁,逆袭的案例有很多,我们那一届来金中的大概有3个,刚好我们三个在一个班,就发现其实尽管大家的学习方式、成长路径不同,可还是可以殊途同归。 这是一点背景吧。这个时候我对于金陵中学的了解还是道听途说的一点排名、和我父母了解到的一点信息。 这里我要给予一条忠告了: 选择大于努力,认知信息的多少,决定了你的高度,比拥有信息更重要的是如何获取信息 这句话可能有的人懂了,有的人还没懂,但我不应该扯太远了。 值得一提的是,这个时候,我和我很好的一位朋友,也是我一直感激的一个人约定了 “要一起去金中”,但其实我心里是没底的。 中考前 化学公开课 与金中的相识,发生在中考之前。当时也不能算招生宣讲,金中搞了个公益性质的高中学科讲座,大概就是讲了各门学科到了高中会和初中有什么不同,并没有讲太多关于学校的事情,但是却给了我一个认识金中老师的机会。我听了江敏 老师一节课,课的内容已经记不得了。我只记得那节课挺轻松的,没有死气沉沉的感觉,她推荐了几本化学有关的读物给我们,不是教材更不是习题,只是一些科普类的读物。我后来没有读,但我当时就觉得,如果一个学校的老师,推荐学生做的事情不是简单的看教材、做习题,而是把眼光放得更长远一些,那么这所学校走出来的学生,大概也能在更长的人生中有着更多的选择。 那节课给我的感觉是:很特别,很不传统 现在江敏 老师已经退休了,但是我发现金中像这样“特别”的老师,遍地都是。 路过金中 有一次去市区玩,路过金中,我得以一睹金中的尊容。 我的感觉是“门好小” 好吧,如果说缺点的话,门小这条该加上。但黑色的大铁门,以及里面郁郁葱葱的树木,与土黄色的建筑还挺般配,有种悠闲的感觉。篮球场上有一大群人咚咚咚地打篮球,车道上有女生在打羽毛球,她们跑得很快,笑得很爽朗,我感觉到这是一座古老而年轻的学校。 特长生考试 我太菜了,金中不给我特长生考试资格,所以我甚至没有机会考试。如果有特长生录取同学看到了,欢迎联系我在这里添加你的感受 签协议 可能不少金中同学在入学前都到过学校北边一栋两层的小房子。学校的老师会根据中考前的模考排名给你一个协议,签了之后,满足一定条件,就能分班分到哪个班。 其实想谈的是关于班型。不同学校叫法不同,有什么星光班、东大班、南大班、南大A班等等,可能有不少同学把能不能进“好班”作为一个考量标准。 现在看起来,这大概除了满足个别学生和家长的一点虚荣心和安抚一下他们卷不到尽头的焦虑的一剂廉价安慰剂。 其实不同班型的差别,最主要的就在于你的同学的水平,然而客观事实表明,所谓“水平”浮动是会很大的,能进金中的同学,成绩也都不差。至于老师,则更不用担心了,金中的老师,绝大部分也是棒棒的,但如果在极少数情况下遇到了真的有点摆的老师,反馈也是有用的。 而且高二就分班了,全校打散重来。 所以这个协议最大的好处可能是让我知道能稳进“南大班”然后不用参加分班考了,我享受了一个完整的暑假。 中考后 焦急等待后,分数出来了,我比平时更略有进步,最后分数651分,南京市排名423名,那一年,金陵中学还没有江心洲校区,本部录取分数线是638分,南师附中是643分。 然而遗憾的是,我的那位朋友发挥失常,没能圆梦。 去哪? 看起来是一个甜蜜甚至有点凡尔赛的问题,南师附中和金陵中学,去哪个? 毕竟有约在先,我承认我会更偏爱金中。但去各个学校考察过后,选择就更坚定了。 我先到了中山路,门打开了随便进。学校其实并不大,但弯弯绕绕我还是差点迷路,绿化做得很漂亮。 我上楼去教室与负责各区片招生的老师交流。我觉得那些木头桌子看起来挺古朴的。对接江宁区考生的是马志钢 ,很巧的是他后来是我高一高二的数学老师。他同时也是后勤保障处主任,但是并没有行政的架子,对同学还挺好的。 我印象最深刻的是他把手放在我的肩上语重心长地说:“小伙子,你很有我们金中人的气质。” 短短的一句话,我被触动到了。 “诚真勤仁”四个字看上去不起眼,但不是所有人都能做到,我一直记得M@(马志刚自称)的那句话,从未敢忘记校训那四个字。 那天我还问了些可能都有点搞笑的问题“听我们校长说江宁的孩子很多到了市区都不适应,是这样的吗?”把M@还有体育组的刘挺 都问懵了,但还是笑着说:“因人而异吧,我们并没有看出来什么区别。” 到了察哈尔路,直接被铁围栏导流到体育馆,因此学校里面什么样没看到。人很多,几个老师只是介绍了一些政策和时间点,我们又看了看录取率,数据很漂亮,我们很快就走了。 三年下来,我感觉金中这群老师真的“很不一样”。他们不只是老师,更是你的益友,是对你有着深挚亲切的人文主义关怀的人,他们能与你共情,而非自上而下的指挥。他们是学生未来的奠基人,是要冲破无谓的内卷浪潮的素质教育破浪人。他们不止在教授,更在教育。 暑假 后来我把学校的指标生名额用了,早早地收到了录取通知书。那个暑假我加了金中表白墙和年级大群。表白墙上敢爱敢骂敢恨的消息,对于习惯了循规蹈矩,规规矩矩的严格校规下的我一点小小的震撼。我也与一些热心的学长交流了些。那个时候,我一直有种眼界被打开了的感觉,我终于不把视线囿于小小的一方书桌和自己的试卷,而是看看外面,看看远方,看看别人怎样。现在看来,我真的受益匪浅,这个后面还会谈到。 暑假作业 金中布置了一些预习的作业,不全是题目,还有一些自己可以做的实验,同时还推荐了一些课外书。这些作业开学之后收了,然后大概讲评了一下,也算让我接触了一点高中学习的内容。我在那个暑假没有上过一节课,但我现在想来并不后悔。我倒是自己买了些教材来看,而不是先行让无尽的题目与分数蚕食最原初的那份好奇与憧憬。嗯,我还是挺想把书本上的知识变成自己的智慧的。 pengs.top 也就是在这个时候,本站建立了,初中其实有另外一个免费域名和免费空间(好吧我承认我初中偷偷用了不少手机和电脑)。 在高中三年里,这一直是我的身份标识,但我一开始并没怎么宣传(感觉做得比较拉胯,现在的界面是后来我魔改过的),倒是被同学从qq介绍的peng@pengs.top这个邮箱扒出来了,我的同学们还挺仔细哈。 开学前教育 唉,我的肠胃太差了,一紧张就抽风。我记得到初中的第一天就窜了,到金中也是。大家别学我,请坐和放宽。 到底谁是12号? 我就说我第一次跨入高中校园紧张吧。去之前的晚上,我拿到分班结果12班21号,还蛮对称的。我记得可牢了,但还是抄了下来带着。 到学校了,我高一的班主任是一位年轻的数学老师,叫刘梦琰,后两个字音同“梦魇”,但名不副实,刘梦(我们一般这么称呼她)也是一位亲切和蔼的老师,有的时候会犯蠢,有的时候会和我们开玩笑。 到班坐定,班主任要认识学生,刘梦挨个报学号,让喊到的人举手。 前面一直很顺,直到…… 刘梦琰:12号 (我的大脑飞速运转,我是12,对,我记得清清楚楚1221是12号,赶紧举手) 两只手诡异地举起了。 刘梦琰(惊恐地):你们到底谁是12号? (沉默) 刘梦琰:你们两个叫什么名字? …… 刘梦琰:彭勃……(开始寻找)……21号 (羞红了脸) 唱校歌 接下来学校统一播放一段教育视频,除了基本情况介绍,还有循环了好几遍的校歌。我偏偏在这个时候肚子疼了,出去了少听了几遍校歌,回来不太会唱。但同学们又害羞不太敢唱,我想唱校歌是很正常的啊,就用平常唱歌的声音去唱。 结果这个时候刘梦经过,看我唱的挺认真,好奇地停了几秒,问:“你唱的不错啊,等下到上面领着大家唱。” 我大吃一惊:“啊,我五音不全啊。” 刘梦:“没事,你试试。” 于是我颤颤巍巍地走上讲台,那是我第一次从讲台的角度看底下那些不知道比我强了多少的同学,我腿软了,手扶着讲台边。 “大~~江滔滔~~东入海~~我~~” 我已经很确定不在调上了。 还得刘梦救场:“额,我承认我的判断有点失误。” 这事后来有点后续。 刘梦看我也是实在跑调得厉害,单独要求我唱好了发给她听。(顺便说一下,那时候我才知道,原来除了家长群以外还可以有个学生群,我竟然可以自己加老师好友而不用通过父母联系,这在我那个对于手机严防死守的初中是不能想的) 我回到租的房子,感觉不服啊,校歌怎么都能唱不好,果真听了好几遍音频,然后录了发给刘梦,竟然被打回来了,于是我又录啊,倒腾好几回。 后来分班时,刘梦提起过这事:“彭勃同学啊,很认真,我一开始以为他是装的,但是他真是这样。” 彭勃,我记住你了 “彭勃,我记住你了。” 那是开学第一天刘梦对我说的话,给我吓得不轻。不过也并没拿我怎么样。 军训 每年都在行知基地。总体上而言,强度是有的,但大部分人应该都可以坚持下来。 如果把军训看成一次体验,看作开学前同学情谊的Build Up的话,这会很值得回忆与纪念,并且那种感觉你以后再也不会有了。如果你真的把军训看作一种磨练的话,那这确实是让你嗓子嘶哑,皮肤疼痛,腰肢酸胀的吃不好(不是吃不饱)睡不好的经历。只能说把世界看成什么样,它便是什么样。金中有很多经历,教会我要“体验式地活着”,会有很多深刻而触动的情感的。我的人生观念也是去用心感受每一天,从早到晚,从小到大。 半夜的热水壶 金中要求军训的时候写一个实践记录,那时候觉得累啊,又没有桌子,在床铺上艰难地写着。可是现在收拾旧物时,它却被我视若珍宝了。那七扭八扭的字迹中,我还是读到了一些温馨的故事: 军训洗澡卡时间卡得近,第一天尤其严格,会要求在几分钟内洗完出来。为了省时间,大部分男生会在进澡堂前把衣服扣子解开一些,那时炎热的大夏天的晚上的户外,感觉应该没什么吧,结果晚上回到寝室胃就开始疼了。我疼得睡不下来,底下的所长(周昱岑)还有另一位同学见状,问我怎么了,我说“胃疼,一会儿就好了。”他们没有说话,但过了一小会儿我看他们推门出了寝室。又过了半天我还是因为胃疼躺不下来,坐在上铺又看到两个人蹑手蹑脚地把门推开一个小缝钻了进来。“校医说胃疼不能乱吃药,让你挨着。”,原来这俩人替我找校医问药去了,但碰壁了,可还不放弃,所长让我把水杯给他,很快他提过来一瓶热水,“你把这个抱着会好一点。”这个方法果然奏效了。 我至今一直很感谢所长和那位同学,也同时感谢在金中大家庭遇到其他所有人。他们可能学习成绩有高下,但是素质与品质大多都是毋庸置疑的。大家都是诚诚恳恳的,说一句是一句,我认为这一点难能可贵,尤其是在被我们的前辈教导过“世故”“圆滑”之后,我们依然能做到人与人的关系本来应该有的样子,而不是被一些世俗功利利己的观点蛊惑,歪曲本来正常的关系,同时还要污染下一代人的关系。很多时候,我们更应该听从内心的选择,做正确的事。 军体拳 军体拳应该是军训的标配吧,汇报表演都要做的。 奈何我四肢没有那么协调,笨手笨脚总学不会。 但好像不只是我这个样子,所以午休和晚上,男生宿舍都在各种练习军体拳,一时出现了各种辅助记忆的名称“喵喵拳”“铁山靠”…… 夏天中午那么热,我们男生宿舍大部分就赤膊在阳台上或者房间里面打拳。 到了夜晚,还是热。于是晚上11点,我和所长一个没穿上衣,一个没穿裤子,在厕所,在水房,在阳台,打拳。 我们做得很认真,仿佛我们生来便为了如此。 但是其实效果也没多好,有天晚上教官要求方阵练习打军体拳,我因为身高原因被排在最右侧一列,而那一列因为位置原因或其他原因,都学得不太好。打完一遍,教官让除了右边几列人以外的人坐下,又打了一遍,又坐了几列,到了我们最后一列,在全校人众目睽睽之下,我们扭曲地做了几遍才坐。 现在还是感觉尴尬。 告别 军训还是比较累的,可是,当谈及这段经历,我们绝大部分人的评价是怀念。 那个时候大家还没有接触那么多的考试与试题,我们感觉每一位都是有着完完全全无限可能的人,我们不带有任何先见地交往、畅谈,军训的卧谈会,多少人追溯锦年情事,多少人枕头大战,我们累,但是累完之后便不再挂念担心,日子很纯粹。那个时候我相信这样的纯粹会一直保持下去,后来也确实基本如此。 我们到达基地时,教官列队欢迎我们,我甚至都没有太多去注意他们。 几天训练之后,大巴车又开出了基地,教官们还整齐挺拔地站在那里,但是挥手时眼睛已经闪着泪花了。 到底我们舍不得什么?是什么在这短短几天的相处中被培养了起来? 战士只会怀念战友,不会怀念战场。 我觉得是这样的。 我们大概再也不会一同躺在闷热拥挤的上下铺寝室,头顶是吱呀的破旧风扇,空气中是浓重的汗臭味以及没有晾干的衣服叠起后的味道。有的时候哨声尖锐地响起来,我们所有人在寝室门口站好排队。 要开学了 从行知基地走出去,很快就真正成为金陵的学生,我很好奇我会做些什么,金中在正式开学前已经给了我这么多震撼,我想我会做一些以前不会做,没敢想的事情吧。 支持我! 如果你感觉这些文章对你有所帮助,欢迎给我一点生活费,谢谢!

2025/6/11
articleCard.readMore

【含复现方法】我对全球不到2%的IPv4网络设备进行了扫描,控制了几十个网络摄像头

互联网不完全扫描非正式监控摄像头安全报告 Peng’s Cybersecurity Lab 简介 在完成了累计24小时对全球1.2%的公开IPV4网络设备(NAT之后的以及路由器之后的设备未扫描)的每个主机的10个端口,针对 海康威视,大华以及雄迈摄像头,后台弱密码或漏洞的非常粗略的探测后,我发现了来自全球多个国家和地区的100多台摄像头主机存在弱密码或高危漏洞现象,可轻松进入后台。 整体情况 其中大华摄像头表现最为糟糕,很多设备可以通过cve-2021-33045和cve-2021-33044 绕过验证,进入后台,其余摄像头大多是因为弱密码。 海康威视部分是因为cve-2021-33044漏洞,部分是因为弱密码被我获取了后台权限。 雄迈摄像头扫描到了很多,但我我装不上一个插件,无法验证是否真的获取了控制权,先按下不表。 这些摄像头的账号和密码,很多堪称 弱智 ,如下图,是截取的一部分: 有相当一部分是默认密码,这种相当于敞开家门让路人看了。 资产呈现 目前实控50+台摄像头,它们分布在野外,院落,街道,酒店,光伏发电站,办公室,商店,工厂,仓库等等。体现了管理人员安全意识的缺失。 安徽某茶园,下雨了,玻璃栈道上有很多水 Your browser does not support the video tag. 中亚地区的某家中,看到有人,我接通语音: I: Hello, please change your password for the camera 图中女人:(吓了一跳)Who are you? I: Ethical hacker. Just a kind reminder. 今天早上已经失去了对该摄像头的控制,好事情。 18+商店?卖电子烟的罢了。 哞~ 我猜他在玩手机 Good morning! 东南亚工厂,晚上八点的夜班工人 还有一张也是工厂里的: 🎱 台球?喜欢! 好喜欢维也纳这个摄像头 这组照片是奥地利🇦🇹维也纳的一个摄像头拍的,位置角度都好极了,有那种胶片摄影风格。蓝天白云绿草,或者黎明破晓。 黎明 太阳升起不久 天还不是特别亮 已经很明媚了 好科幻的装修 开张前的打扫 杂项 以上只是部分,我已经尽可能地提醒了,仁至义尽。 复现方法 工具准备 我们将使用两款强大的扫描工具进行组合扫描: Masscan - 超高速端口扫描器,可在5分钟内扫描整个互联网(需要硬件足够好,我做不到,我的设备至多每秒30k个包,要一个多月才能扫完,所以我只扫描了2% Ingram - 专注于摄像头漏洞扫描的框架,支持海康、大华等主流品牌 安装步骤 建议使用linux或macos,安装简便一点,性能也更好,因为没有针对Windows优化,速度慢很多 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 安装Masscan git clone https://github.com/robertdavidgraham/masscan cd masscan make sudo make install 其实也可以从包管理器安装,如果你的发行版提供了 # 安装Ingram git clone https://github.com/jorhelp/Ingram.git cd Ingram python3 -m virtualenv venv source venv/bin/activate pip install -r requirements.txt 扫描策略设计 1. 目标范围选择 理想状态下,我们将扫描整个IPv4地址空间(IPv6这辈子算了),但排除以下私有地址段: 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 创建排除文件exclude.txt: 1 2 3 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 2. 端口选择 我为了省时间,只扫描了部分默认端口,还没扫全,ingram给出的规则里至少有这些: 1 'ports': [80, 81, 82, 83, 84, 85, 88, 8000, 8001, 8080, 8081, 8085, 8086, 8088, 8090, 8181, 2051, 9000, 37777, 49152, 55555], 但我其实只扫描了80,8000-8008 ,现在发现只扫80,8000就有不少,以后再尝试其他的吧。 分阶段扫描 第一阶段:Masscan快速端口扫描 1 2 3 4 5 masscan 0.0.0.0/0 -p80,81,8000-8010,554,37777 \ --excludefile exclude.txt \ --max-rate 100000 \ -oL masscan-results.txt \ --open-only 参数说明: --max-rate 100000:每秒10万包的速度,这个速度一般网络都ok的吧,你可以往上加。 -oL:输出纯文本格式结果 --open-only : 输出文件里只有开放端口,节省存储空间 第二阶段:结果整理 如果你只需要尝试一下的话,不需要扫太久,可以按Ctrl+C停止, 1 grep 'open' masscan-results.txt | awk '{printf"%s:%s\n", $4, $3}' > camera-targets.txt 第三阶段:Ingram深度扫描 这里解释一下,如果你不用masscan直接用ingram扫描0.0.0.0/0也是可以的,但是太慢了,所以不推荐。 1 python run_ingram.py -i camera-targets.txt -o scan-results -t 500 关键参数: -t 500:使用500线程并发扫描,这个速度会导致我家里其他设备上不了网,请求数可能太多了 -o scan-results:结果输出目录 结果分析 扫描完成后,重点关注以下文件: scan-results/results.csv:漏洞设备清单 scan-results/snapshots/:摄像头截图 典型结果格式: 1 192.168.1.100,80,Hikvision,admin,12345,CVE-2021-36260 法律声明 此方法仅限授权安全测试使用。未经授权扫描他人网络设备可能违反当地法律。实际操作前请确保已获得合法授权。 “With great power comes great responsibility.” Benjamin Parker 国内网段还是exclude掉吧,法律风险大,而且因为NAT,你扫不到什么。 一点感想 只能说,本来以为简单的测试,收获颇丰。同一时刻,世界上不同的角落,有的晴天,有的暴雨,有的白昼,有的深夜。你起床的时候,有的人刚结束一天的劳累。同在地球,不同国家,不同文化,不同职业,不同肤色的人以不一样的方式活着,在和我们一样或不一样的环境中活着,他们的住所、工作地点和我们不一样,但是他们开心了也会笑,工厂的工人劳累过后也会疲倦。看完感觉世界好大,脚步到不了的地方,网络可以,但我还是希望有一天我能用自己的眼睛去张望。 给惴惴不安的你 大家不用担心,国内互联网环境是全球最复杂的,有多层NAT,从外部很难扫到。因祸得福。 这些数据我也不会恶意利用或者泄露的,放心,我的人品还是靠得住的。不过看到这篇文章,还是建议你去提醒你的亲戚家人朋友,更新摄像头固件,用更复杂的密码,不要用默认的80或800X端口。我只是一个菜鸡,用着简陋的设备,尚能获得这么多信息,更不用说别有用心者了。 引用一句诗,写当今网络空间 溪云初起日沉阁,山雨欲来风满楼。 晚唐·许浑

2025/4/19
articleCard.readMore

Pengs.top灾后重建记

Major Outage Feb 11, 2025 南京 阴雨 2025年2月6日下午5:18分起,原先的pengs.top再也无法与互联网联通。位于日本大阪机房的服务器,RAID10两个镜像组各坏了一块硬盘,导致了无法恢复的故障。 所有云上数据丢失,呈现在我面前的一片荒芜。 最要紧的事情是先拿到一台服务器,才能谈得上恢复服务。好在vmiss那边服务态度挺好的,连开了几个工单: 最后谈下来结果是服务器补偿10天时长,剩余时长折算退款(折下来似乎还多退了几块钱),服务器价格照旧,是独享的2/3折,原价$50.00 CAD每年,折完$40.00 CAD每年,算是很便宜了。 既然服务器有了,那就着手恢复吧。 不幸的是服务器上炸的渣也不剩了,幸运的是: 这是我本地的备份,可以看到,要不是1月17日不知为何突然一时兴起备份了服务器,那么我只有将近半年前的备份了。 天助我也。 然后我发现天坑我也。 备份是用以下rsync命令做的: 1 2 3 4 5 6 7 sudo rsync -azr -e ssh root@pengs.top:/ /mnt/btrfs/backup/backserver --info=progress2 --partial --delete --exclude=/var/backups --exclude=/var/lock --exclude=/var/tmp  --exclude=/root/ .cache --exclude=/var/log --exclude=/var/cache --exclude=/proc --exclude=/var/swap --exclude=/lost+found  --exclude=/mnt --exclude=/sys --exclude=/run --exclude=/media --exclude=/dev --excl ude=/tmp --exclude=/boot --exclude=/root/swapfile sudo btrfs subvolume snapshot /mnt/btrfs/backup/backserver /mnt/btrfs/backup/snapshots/server/2025.2.12_qexo sudo btrfs property set -ts /mnt/btrfs/backup/snapshots/server/2025.2.12_qexo ro true 利用了rsync的增量备份和btrfs的快照功能 恢复用的是这个命令: 恢复的,唉,我就不贴了,误人子弟,因为,当我全量上传覆盖,又细心的修改了fstab后, 发现服务器 能开机,无法联网 重试了多次(一个上午)都一筹莫展,最后我走上一条艰难的道路:自下而上地重建pengs.top 结果呢,如你所见,忙活了一天,把过去几个月里干的事都干完了。其实还是要感谢有备份的,有些配置直接拷贝过来,不用手工配置了。 雄关漫道真如铁,而今迈步从头越 – 毛泽东《 忆秦娥 · 娄山关 》 因为过程太繁琐,pengs.top提供的服务还挺多的,包括但不限于 博客主站点,图床,Alist,网页邮箱,rustdesk中继,headscale控制器,在线会议,在线会议中继,qexo …… 这里不一一列举恢复方式了,只记录一些要点。 ssh免密登陆 在Debian服务器上实现SSH免密登录,可以通过以下步骤完成: 1. 生成SSH密钥对 在客户端机器上生成SSH密钥对(如果已有密钥对可跳过此步)。 1 ssh-keygen -t rsa -b 4096 按提示选择保存路径(默认~/.ssh/id_rsa)。 设置密码(可选,直接回车跳过)。 2. 将公钥上传到服务器 使用ssh-copy-id将公钥上传到服务器: 1 ssh-copy-id username@server_ip username:服务器用户名。 server_ip:服务器IP地址或域名。 系统会提示输入服务器密码,输入后公钥会自动添加到服务器的~/.ssh/authorized_keys文件中。 3. 手动上传公钥(可选) 如果没有ssh-copy-id,可以手动操作: 复制公钥内容: 1 cat ~/.ssh/id_rsa.pub 登录服务器,将公钥添加到~/.ssh/authorized_keys: 1 2 3 mkdir -p ~/.ssh echo "粘贴的公钥内容" >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys 4. 测试免密登录 尝试SSH登录服务器,应无需输入密码: 1 ssh username@server_ip 5. 禁用密码登录(可选) 为增强安全性,可禁用密码登录: 编辑SSH配置文件: 1 sudo nano /etc/ssh/sshd_config 修改以下配置: 1 PasswordAuthentication no 重启SSH服务: 1 sudo systemctl restart sshd 总结 通过以上步骤,你可以在Debian服务器上实现SSH免密登录。确保私钥安全,避免泄露。 rsync快速传输文件 要使用 rsync 将本地文件夹的内容覆盖到服务器上的某个文件夹,同时保留权限属性、压缩传输并支持续传,可以使用以下命令: 命令格式 1 rsync -avz --partial --progress /path/to/local/folder/ username@server_ip:/path/to/remote/folder/ 参数说明 -a:归档模式,保留文件权限、时间戳、符号链接等属性。 -v:详细输出,显示传输的文件信息。 -z:压缩传输,减少网络带宽占用。 --partial:支持断点续传,未完成的文件会保留部分传输的内容。 --progress:显示传输进度。 /path/to/local/folder/:本地文件夹路径,末尾的 / 表示同步文件夹内容,而不是文件夹本身。 username@server_ip:/path/to/remote/folder/:服务器上的目标文件夹路径。 示例 假设: 本地文件夹路径:/home/user/myfiles/ 服务器IP:192.168.1.100 服务器用户名:user 服务器目标文件夹路径:/var/www/html/ 命令如下: 1 rsync -avz --partial --progress /home/user/myfiles/ user@192.168.1.100:/var/www/html/ 注意事项 覆盖目标文件夹内容: 如果目标文件夹中有本地文件夹不存在的文件,这些文件会被保留。如果需要完全同步(删除目标文件夹中多余的文件),可以添加 --delete 参数: 1 rsync -avz --partial --progress --delete /home/user/myfiles/ user@192.168.1.100:/var/www/html/ SSH端口: 如果服务器的SSH端口不是默认的22,可以使用 -e 参数指定端口: 1 rsync -avz --partial --progress -e "ssh -p 2222" /home/user/myfiles/ user@192.168.1.100:/var/www/html/ 排除文件或目录: 如果需要排除某些文件或目录,可以使用 --exclude 参数: 1 rsync -avz --partial --progress --exclude 'temp/' --exclude '*.log' /home/user/myfiles/ user@192.168.1.100:/var/www/html/ 带宽限制: 如果需要限制传输带宽(例如限制为 1000 KB/s),可以使用 --bwlimit 参数: 1 rsync -avz --partial --progress --bwlimit=1000 /home/user/myfiles/ user@192.168.1.100:/var/www/html/ 总结 通过 rsync 的 -avz --partial --progress 参数组合,可以实现本地文件夹内容覆盖服务器文件夹内容,保留权限属性,压缩传输并支持续传。根据需求,可以灵活添加 --delete、--exclude 等参数以满足特定场景。 举例 1 sudo rsync -azrAX -e ssh --partial /mnt/local/2025.1.17_well_pruned/var/www/ root@pengs.top:/var/www/ --progress 配置php 1 apt install php php-fpm 查看/etc/php/8.2/fpm/pool.d/www.conf得 1 listen = /run/php/php8.2-fpm.sock 优化 PHP-FPM 性能和提高最大文件上传限制可以通过以下步骤实现: 1. 优化 PHP-FPM 性能 1.1 调整 PHP-FPM 配置 编辑 php-fpm.conf 或 www.conf 文件(通常位于 /etc/php/7.x/fpm/ 或 /etc/php-fpm.d/),调整以下参数: pm.max_children: 设置最大子进程数,根据服务器内存和负载调整。 pm.start_servers: 启动时的子进程数。 pm.min_spare_servers: 最小空闲子进程数。 pm.max_spare_servers: 最大空闲子进程数。 pm.max_requests: 每个子进程处理的最大请求数,避免内存泄漏。 示例配置: 1 2 3 4 5 6 pm = dynamic pm.max_children = 50 pm.start_servers = 10 pm.min_spare_servers = 5 pm.max_spare_servers = 20 pm.max_requests = 500 1.2 启用 OpCache 启用 OpCache 可以提升 PHP 性能。编辑 php.ini 文件,添加或修改以下配置: 1 2 3 4 5 zend_extension=opcache.so opcache.enable=1 opcache.memory_consumption=128 opcache.max_accelerated_files=4000 opcache.revalidate_freq=60 1.3 调整 PHP 内存限制 根据应用需求调整 memory_limit: 1 memory_limit = 256M 1.4 使用 FastCGI 缓存 启用 FastCGI 缓存(如 Nginx 的 fastcgi_cache)可以减少 PHP-FPM 的负载。 2. 提高最大文件上传限制 2.1 修改 php.ini 编辑 php.ini 文件,调整以下参数: 1 2 upload_max_filesize = 64M post_max_size = 64M 2.2 修改 PHP-FPM 配置 确保 PHP-FPM 配置与 php.ini 一致,通常不需要额外调整。 2.3 修改 Web 服务器配置 如果使用 Nginx,确保 client_max_body_size 足够大: 1 client_max_body_size 64M; 如果使用 Apache,确保 LimitRequestBody 足够大: 1 LimitRequestBody 67108864 2.4 重启服务 修改后重启 PHP-FPM 和 Web 服务器: 1 2 sudo systemctl restart php7.x-fpm sudo systemctl restart nginx # 或 apache2 3. 其他优化建议 数据库优化: 优化查询和索引。 使用缓存: 如 Redis 或 Memcached。 压缩输出: 启用 Gzip 压缩。 减少外部请求: 减少对外部 API 的依赖。 通过这些步骤,可以有效提升 PHP-FPM 性能并提高文件上传限制。 网络优化 在/etc/sysctl.conf: 1 2 3 4 5 6 7 8 9 10 11 net.ipv4.tcp_window_scaling = 1 # 增大 TCP 最大连接队列长度 net.ipv4.tcp_max_syn_backlog = 8192 # 减少 TIME-WAIT 状态连接的等待时间 net.ipv4.tcp_fin_timeout = 15 net.ipv4.tcp_fastopen = 3 net.ipv4.tcp_mtu_probing = 1 net.ipv4.tcp_timestamps = 0 net.core.default_qdisc=fq net.ipv4.tcp_congestion_control=bbr 然后运行 sysctl --system 使修改生效 安装 pm2 在 POSIX 系统上 1 curl -fsSL https://get.pnpm.io/install.sh | sh - 如果你没有安装 curl,也可以使用 wget: 1 wget -qO- https://get.pnpm.io/install.sh | sh - 提示 你可以使用 pnpm env 命令来安装 Node.js。 使用示例: 1 2 3 4 5 6 7 8 # Start the server $ pm2 start app/src/server.js # Takes a snapshot $ pm2 save # Add it on startup $ pm2 startup certbot与cloudflare结合使用 众所周知,想在国内的 VPS 上不备案开 80 端口是几乎不可能的事情。在 Let’s Encrypt 移除基于 TLS-SNI-01 的域名验证 后,想不使用 http-01 challenge 在 Let’s Encrypt 完成域名验证并获得证书只有 dns-01 challenge 一种方法了。 步骤 我使用的是 certbot-dns-cloudflare。该 certbot 插件的文档在 这里 可以阅读。 准备 假设你已经安装了 certbot。 安装插件和依赖 插件 1 sudo apt-get install python3-certbot-dns-cloudflare 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ➜ ~ sudo apt-get install python3-certbot-dns-cloudflare Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: python3-cloudflare python3-yaml The following NEW packages will be installed: python3-certbot-dns-cloudflare python3-cloudflare python3-yaml 0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded. Need to get 157 kB of archives. After this operation, 713 kB of additional disk space will be used. Do you want to continue? [Y/n] Get:1 https://mirrors.tuna.tsinghua.edu.cn/debian buster/main amd64 python3-yaml amd64 3.13-2 [121 kB] Get:2 https://mirrors.tuna.tsinghua.edu.cn/debian buster/main amd64 python3-cloudflare all 2.1.0-1 [27.8 kB] Get:3 https://mirrors.tuna.tsinghua.edu.cn/debian buster/main amd64 python3-certbot-dns-cloudflare all 0.23.0-2 [7,812 B] Fetched 157 kB in 4s (36.7 kB/s) Selecting previously unselected package python3-yaml. (Reading database ... 135351 files and directories currently installed.) Preparing to unpack .../python3-yaml_3.13-2_amd64.deb ... Unpacking python3-yaml (3.13-2) ... Selecting previously unselected package python3-cloudflare. Preparing to unpack .../python3-cloudflare_2.1.0-1_all.deb ... Unpacking python3-cloudflare (2.1.0-1) ... Selecting previously unselected package python3-certbot-dns-cloudflare. Preparing to unpack .../python3-certbot-dns-cloudflare_0.23.0-2_all.deb ... Unpacking python3-certbot-dns-cloudflare (0.23.0-2) ... Setting up python3-yaml (3.13-2) ... Setting up python3-cloudflare (2.1.0-1) ... Setting up python3-certbot-dns-cloudflare (0.23.0-2) ... 依赖 cloudflare >= 2.3.1 1 2 3 Using Cloudflare Tokens also requires at least version 2.3.1 of the cloudflare python module. If the version that automatically installed with this plugin is older than that, and you can’t upgrade it on your system, you’ll have to stick to the Global key. 但是: 1 2 3 4 5 6 7 ➜ ~ sudo apt install python3-cloudflare Reading package lists... Done Building dependency tree Reading state information... Done python3-cloudflare is already the newest version (2.1.0-1). python3-cloudflare set to manually installed. 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. 所以我们不得不使用 Global API Key。 获取 Global API Key 使用你的帐号登录 Cloudflare。 点击右上角的头像,在弹出的下拉栏中选择 My Profile。 切换到 API Tokens Tab。 在下方的 API Keys 中,查看你的 Global API Key。 将你的 Cloudflare 登陆邮箱和 Global API Key 按以下格式保存到一个文件中: 1 2 3 # Cloudflare API credentials used by Certbot dns_cloudflare_email = example@example.com dns_cloudflare_api_key = example_i_know_no_one_would_see_this 这里我将其保存到 ~/.secrets/certbot/cloudflare.ini 下。 记得将这个文件 chmod 600: 1 ➜ ~ chmod 600 ~/.secrets/certbot/cloudflare.ini 进行验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ➜ ~ sudo certbot certonly \ > --dns-cloudflare \ > --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \ > -d <redacted>.anzupop.com Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator dns-cloudflare, Installer None Obtaining a new certificate Performing the following challenges: dns-01 challenge for <redacted>.anzupop.com Waiting 10 seconds for DNS changes to propagate Waiting for verification... Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/<redacted>.anzupop.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/<redacted>.anzupop.com/privkey.pem Your cert will expire on <redacted>. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le 注意,该证书一周之内只能申请5次,请确保命令正确 查看各目录大小 1 du -h --max-depth=1 | sort -hr | head -n 5 -h:该参数的作用是以人类可读的格式显示磁盘使用量。在计算机中,磁盘空间通常以字节为单位进行计量,但对于我们人类来说,直接查看字节数并不直观。使用-h参数后,系统会自动将字节转换为 KB、MB、GB 等更易于理解的单位。 --max-depth=1:此参数用于指定递归的最大深度为 1。也就是说,命令只会显示当前目录下一级子文件夹的大小,而不会深入到这些子文件夹的更内层子文件夹中去。 sort -hr:-h选项用于以人类可读的格式进行排序,这与du命令中的-h参数作用相对应,确保在排序时能正确处理以 KB、MB 等单位表示的大小。-r选项则用于反转排序顺序,默认情况下sort是按从小到大排序,加上-r后就变成了从大到小排序。 head -n 5:该命令的作用是只显示输出的前 5 行。通过将du、sort和head命令组合使用,我们可以快速筛选出占用磁盘空间最大的几个文件夹。 清理缓存 pnpm 1 pnpm store prune apt 1 apt clean 监控 为了便于监控服务状态,我设置了uptime robot,取代了之前的netdata,地址依然如下: https://monitor.pengs.top 真觉得uptime robot的样式挺好看的。 结语 目前,网站已经重建完成了。希望高考前不要再出大问题…… 网站重建真是一种神奇的感觉: 最初建立pengs.top时,我像哥伦布刚刚发现美洲,他眼前是一片旷野,他辛勤地开垦 故障发生后,我像地震发生后无家可归的难民,他眼前是一片荒芜,他在砖石瓦砾上叹息 当我下定决心自下而上重建pengs.top而非继续和备份纠缠时,像是开着推土机,将从前的羁绊铲平 在重又空阔无所依的白花花大地上,我持着折皱的高楼大厦的旧照片,感到沉重 然而当我看到一个个Operational的绿灯亮起,我仿佛又回到了刚来到这里的时候 还是一样的新鲜,同时苛求每一份完美,这时候我发现原先的遗憾也能重圆。 走下去,pengs.top还会坚守初心,为改善所有人的数字生活而奋斗,用科技温暖人心,让人文的赤诚在每一次报错的Error中流露!(不是 2025年2月12日,正月十五,服务恢复 元宵节快乐!

2025/2/12
articleCard.readMore

忆故乡山西的春节

今年过年放假短,作业重,回不了老家了。思乡之情涌上心头,难以遏制,在此记录印象中山西老家的春节,以解乡愁。 我老家不是南京的,而是山西的。在我的认知里,过年应该是寒冷的清晨,前一天晚上忙完祭拜祖先和放鞭炮烟花忙得很累,但还是被爷爷奶奶叫醒,炕上暖和不愿意出被窝,好不容易起来了,出了门,一阵冷风袭来,冻得打个喷嚏,穿过院子去看爸爸妈妈,然后去西屋暖壶里倒出白花花的热水拿来洗漱。等我们家、我二叔家、我姑姑家都起床了,又聚到西屋,吃点油炸糕、包了硬币的羊肉饺子一类,而无论吃什么,每顿饭照例是要喝粥的,白的还是红的都无所谓。早饭后,裹得严严实实,踩着冻得嘎嘣脆的路面(有冰)(还会有一颗颗羊屎蛋,被踩扁了粘在路上),到七大姑八大姨家拜年,挨家挨户磕头,上香,每家客厅或者什么房间里一定墙上贴着一块板子,写着“某家多少代世孙”,下面摆着些正襟危坐或者面容和蔼的照片,玻璃相框映出了旁边摆的像金字塔的麻花,炭一样黑的柿饼,以及每家都常备的橘子花生瓜子一类。香炉里面填了黄沙,但不知道烧断过多少柱香,只能看到横竖的一段段香灰了。拜完年我们就能领压岁钱,然后放放炮仗,吃吃喝喝,有的人家里烧火做饭的,空气里就一股燃烧的味道。有时候我们遇到村里有人办喜事,宴席的桌子从家里支到巷子里,后厨的大锅敞开着,雾气腾腾,已经看不清里面是鱼,还是肘子一类的。过了一会儿就能看到敲锣打鼓的民乐队来了,绕着村子巡演一圈,敲的吹的每次都一样,但每次都不愿意错过。回到家里时,一天就到了晚上。院子里我和我的堂弟堂妹又或者表弟表妹玩,玩累了就回到屋里,听大人讲一年里的事,有时候大家都低下头一言不发思考,有时候又一起在笑,笑得爽朗大声。而我们晚辈聊自己的,玩自己的,最后爷爷奶奶和我们又躺到暖和、高大宽敞、硬邦邦的炕上了,但还不想睡,用手指抠着窗玻璃上坚硬的霜花,听爷爷奶奶关切问候我们的话,又到半夜才睡。过年还要在5、6米高的门楼顶上挂红灯笼,在大铁门上踩梯子贴春联。每年都要带着丝绒的大红灯笼到后山的庙上,大红灯笼上写着我的曾用名,那是我出生在老家时大人称呼我的名字,又有些祝福我的话,最后把一大堆纸钱烧成龙卷风一样的灰飞上天,我们又下山忙别的了,大红灯笼还无言凝视着山冈。从南京出发回老家是三四点,天正黑到极点,我兴奋地在车上坐过去一天,晚上到家了,离开的时候也是三四点走,走的时候爷爷奶奶总硬要塞给我们鸡蛋、饼子、暄子等等,车慢慢开下颠簸狭小的乡路,我总是带着眼泪看到爷爷奶奶,还有我们家的灯,那是村口或者可能整个村子唯一亮着的灯,就渐渐和后面高大威严的吕梁山融成一片夜幕了。也许有的时候很巧能碰到从地下上到村子里的车,那肯定是住在村中不知道哪栋屋子里的,但不需要知道是谁了,他们操着我们的方言,是和我们一样性格热烈直爽的可亲的乡亲。看到清早出发的车,他们不会不知道我们此行的目的,都会把本来就已经够亮的车灯闪了又闪,算是致意,然后默默把车往两边一望无际的,现在只长着矮小的冬小麦的黄土田里一开,一直快撞到高高的田垄上,给我们让出一条要非常小心才能不擦到人家的道路。经过的时候,车上的雷达总是滴滴地短促地响着,是像黑锅盖扣在我们头上的星空下唯一的声音了。夜很浓密,它们像水涌入洞里一样,从车窗玻璃涌到我的身边。再往前走,天空有一边显出圆弧状渐变的,看上去很羞涩的白的时候,我们已经快上高速了,我也知道,今年回了一趟老家,又离开了,又是一年开始了。等离开了河南,便再听不到那爽耳的,响亮的,猛烈的土话了,路两边看到的,也是千篇一律的平原地带的树,或有点绿的原野,不太像冬天,我觉得无聊,会在车后面睡上一觉。 我不知道还有多少人,还像我一样珍视这些气味、质感、温度。村中许多空洞坍塌的房屋,它们好像在告示我,会有一天,这里的一切都会被遗忘。但是我希望在我能看见的时候,还能紧紧抱住这个小村子。大山下的小村子,许多人走了出去,走出去了就没有回来。虽然似乎也有一些留在村中的年轻人,但是我担心村医可能都已经忘了怎么接生了。我的父辈早早离开了这里,他们还在向我的祖辈求教如何演习那些传统,希望他们能尽可能多的保留住一些。到了我这里,竟然连最基本的乡音都保持不住了,我还能听得懂土话,但是不会说了,偶尔记得的几个词,连缀起来也生硬得像在说外文。我担心以后可能就听不到那样粗犷的带着黄沙和狂风的方言了。村中的那些年轻人可能是接续这个村子脉搏的主要力量,作为同乡,我一方面希望他们也能像我们一样走出去,过上更舒适的生活,另一方面,又自私地不愿意他们走。也许等我也垂垂暮老时,我还会回来,把老屋子修缮一下,然后住定下来。到那个时候我希望,如果村子还在的话,它不要太繁华,让我认不出来,也不要太死寂,让这片土地心寒。等到我挥手告别人间的时候,我希望能回到北面岿然不动的灰绿色山峦上,那里住着我的祖祖辈辈,他们可能会怜爱地看我走完这曲折的一生,最终又回到了原点。我希望我能面向南面埋葬,这样我就能看见一排排灰色的平房屋顶,也可能是蓝色的铁皮,远处还有一望无际的原野。我希望我能像我的祖祖辈辈一样,守望着这片土地,祝佑从这里走出去的所有人,永远可以回到他们熟悉的地方,回到安宁祥和的村落。我的故事会成为后人称道的历史的厚重感的一部分,而我的名字也应当像吕梁山从不离弃这片土地一样,和故乡紧紧地联系在一起。 玩烟花 院子里的烟花,这张照片当过我的头像 登上山拍的,天气不好 后面的山就是吕梁山,比南京任何一座山都高 亲戚家里,堆满了收获的玉米 夜晚一片漆黑,天边有远处的灯亮 屋檐下的灯笼 木框窗子 家里的灶台 雪覆盖的原野 巷子

2025/1/16
articleCard.readMore

在命令行中使用自签名证书对PDF进行签名

!! 本文代码已上传Github 使用GPL-3.0协议开源 !! 有天我打开网上的PDF文件时,看到这样一行提示: 此文档已经过数字签名 我大惊,我平时会用GPG对文件进行签名,但得到的也只是一个单独的签名文件。难道,GPG创建的签名可以嵌入PDF?我想起以前在Windows上用PDF Reader时见过“签名”菜单,但是那看起来只是手绘了个图形贴上去,看上去好像也不高级,背后好像也没有特别的算法撑腰。这个“数字签名”却有证书,有颁发日期,到期时间,SHA-256指纹,和签名算法,看起来很专业,就像访问HTTPS站点时的SSL证书。 我决定要给自己的PDF也加上这样的数字签名,最好能有个很有信服力的图章,上面写着“signed by Pengbo”。 我在网上展开搜索,却发现linux下,好像少有这样的进行签名的工具,KDE的PDF查看器Okular有这个功能,但它找不到我的证书(恼 那就只能另寻办法啦。 我在网上搜查到的信息告诉我PDF签名需要S/MIME证书,一般由权威CA颁发,价格在…… 等等!我签名自己的文件还要付钱?不可能! CA创建S/MIME证书总要用一些工具吧,我能不能用这样的工具创建自签名证书? 这一工具就是openssl,自己建过网站的人应该对它不陌生,处理HTTPS时多少会碰到。OpenSSL 是一个用于实现安全通信的软件包,它由一组密码学函数库组成。它的主要目标是通过使用公开的密码学算法来保护数据的机密性、完整性和身份验证。它支持对称加密、非对称加密、数字签名、证书管理等功能。 背景知识了解的差不多了,动手吧! 生成 如果你没有openssl这个软件包,请安装它。 首先生成自己的私钥(不知道什么意思的话可以查查非对称加密) 1 openssl genrsa -aes128 -out myself.key 2048 -aes128 表示用AES128算法加密私钥,可选的还有-aes192,-aes256,2048表示私钥长度,越长越安全,但也越慢,我一般用4096位的。 1 openssl req -new -days 365 -key myself.key -out myself.csr 这个命令创建证书请求,正常情况下,你应该把这个证书请求发送给CA的工作人员,但今天我们要自己签发,这个待会儿再说。 -days 表示证书有效期,我太懒了,这辈子都不想换,疯狂加0,现在过期时间在34世纪。(这辈子用不完了 别学我,这样不太“正规”,我给你的示例,有效期是1年。 你可能会问:有效期只有一年,那一年以后数字签名是不是就不能验证了呢?别怕,后面我们利用时间戳解决这个问题。 1 openssl x509 -in myself.csr -out myself.crt -req -signkey myself.key -days 365 这一步本该由CA做的,可是贫穷提高了我们的计算机水平,我们现在要自己签发。signkey后面就是我们自己的私钥,如果你像让证书看起来更逼真,可以先自建CA,再用自建CA的私钥签发自己的私钥创建的证书请求,你可以在网上找到教程。 -days参数依然是有效期。 这一步后,你得到了一个x509证书,你可以用它来加密,签名,但是,我们用于PDF签名的证书需要是 PKCS#12 格式的,所以再转下格式。 1 openssl pkcs12 -export -out myself.pfx -inkey myself.key -in myself.crt 没什么特别的。 至此,myself.pfx已经可以用于PDF签名了,你可以将这一pfx证书导入Kleopatra(需另外安装),然后打开Okular,在设置>配置后端程序>PDF>签名后端程序选中GnuPG,然后就可以用工具>数字签名了。(当然这是我后来才发现的) 签名 经过艰苦的搜查,我尝试了pdftk,pdfsig等工具,都不太行。 最后我找到了pyhanko,一个专门用于签章pdf的python包,先安装它。 可以用pip安装: 1 pip install pyhanko[opentype] [opentype]表示安装opentype可选项,因为我们要生成可见签章,需要处理字体问题。 然后,上大招: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 import os from pyhanko import stamp from pyhanko.pdf_utils import text from pyhanko.pdf_utils.font import opentype from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter from pyhanko.sign import fields, signers from pyhanko.sign import timestamps from pyhanko.sign.fields import SigSeedSubFilter import uuid pfx = '/home/micraow/sec/cert.pfx' # 证书位置 passwd = b'填到这里' # 密码 output_dir = '/home/micraow/Documents/signed/' # 签名后的存放处,确保存在! signer_name = 'Pengbo' # 签章人姓名 url = 'https://pengs.top' # 主页地址 email = 'peng@pengs.top' # 邮箱地址 extra_info = 'GPG fingerprint: \n6B5314F24B17198DD24B\n5B47062C2BFFBDCBB303\n' # 另外的想打印的信息 signer = signers.SimpleSigner.load_pkcs12( pfx_file=pfx, passphrase=passwd ) timestamper = timestamps.HTTPTimeStamper( url='https://freetsa.org/tsr' ) in_file = input("Location of input pdf: ").strip() target = input('Who is this document given to? (Myself by default) ').strip() if target == '': target = 'Myself' purpose = input( 'The reason why you want to sign the document?(Not Specified by default) ').strip() if purpose == '': purpose = 'Not Specified' desc = input('Any other information you want to give? If not, hit Enter.').strip() filename = os.path.basename(in_file) with open(in_file, 'rb') as inf: w = IncrementalPdfFileWriter(inf, strict=False) fields.append_signature_field( w, sig_field_spec=fields.SigFieldSpec( # x1,y1,x2,y2 left to right, bottom to top 'Signature', box=(395, 750, 580, 830) ) ) meta = signers.PdfSignatureMetadata(field_name='Signature', md_algorithm='sha256', subfilter=SigSeedSubFilter.PADES, embed_validation_info=False, use_pades_lta=True,) pdf_signer = signers.PdfSigner( meta, timestamper=timestamper, signer=signer, stamp_style=stamp.QRStampStyle( # Let's include the URL in the stamp text as well stamp_text='Signed by: %(signer)s\nEmail: %(email)s\nTime: %(ts)s\nURL: '+ url + \ '\nUUID: \n%(uuid)s\n' + extra_info, text_box_style=text.TextBoxStyle( font=opentype.GlyphAccumulatorFactory( '/home/micraow/.local/Rajdhani-Medium.ttf') # 字体位置 ), ), ) id = uuid.uuid1() info = "如果你看到这段文字,它意味着这个文件经过了数字签名。\nIf you see this text, it means the document has been digitally signed.\n" + \ "签名人 The signer: " + signer_name + '\n'+'原始文件名 Original filename: ' + \ filename+'\n'+'文档接收方 Target: ' + target + \ '\n'+'文档签名原因 Reason: ' + purpose + '\n' if desc != '': info = info + '更多信息 More information: ' + desc+'\n' info = info + '这个文档使用了由Pengbo提供的工具进行签名,有关该签名的细节你可以在https://pengs.top/pdf-sign/ 看到。\n This document is signed using the tools provided by Pengbo, details of which can be found at https://pengs.top/pdf-sign/.' with open(output_dir+"signed_"+filename, 'wb') as outf: # with QR stamps, the 'url' text parameter is special-cased and mandatory, even if it # doesn't occur in the stamp text: this is because the value of the 'url' parameter is # also used to render the QR code. pdf_signer.sign_pdf( w, output=outf, appearance_text_params={ 'signer': signer_name, 'email': email, 'url': info, 'uuid': str(id)} ) print("File at: "+output_dir+"signed_"+filename) 有一些需要注意的: import下面一堆信息根据自己实际情况改 如果附加信息太多,二维码可能不好扫。 运行前确保output_dir存在,不存在请新建文件夹, Windows上路径需要转义,你需要在路径中每个反斜杠后再加一个反斜杠。 路径可用相对路径或绝对路径, linux上,可以将文件拖到终端窗口中快捷输入路径。 对了,关于上面提到的的时间戳 时间戳通常包含以下几个关键要素: 具体的时间信息:精确到秒甚至更高精度的时间点,明确标识了签名动作发生的时刻。 例如,时间戳可能记录为“2024 年 7 月 3 日 15 时 30 分 25 秒”。 数字签名:用于证明时间信息的完整性和准确性,防止被篡改。 这确保了记录的时间是真实和可信的。 权威认证:时间戳通常由可信赖的第三方时间戳服务器生成和提供。 这个服务器具有高度准确的时钟和安全机制,以确保其提供的时间信息是准确和不可伪造的。 举例来说,当对一份 PDF 文档进行签名时,时间戳就像一个公证员在旁边记录下您签名的精确时间,并给这个时间记录加上了一个无法篡改的印章,以证明这个时间的真实性和有效性。 在法律和合规性方面,时间戳可以作为重要的证据,证明签名操作在特定时间完成,具有不可否认性和权威性。 以上代码中,使用https://freetsa.org/tsr ,你可以用别的时间戳服务器。 效果 去繁就简,我觉得挺好看的,很有正式文件的感觉。 另外写到这儿我突然想到之前流浪地球里出现的字体,挺酷的,我把链接贴这儿,你可以下下来用,签名效果如下: 比较有科幻感。 Alist链接 扫描后结果: 总结 自己动手,丰衣足食。 另外,这是我第一次尝试将人工智能真正用于问题解决,由于pdf签名这一块,网上的信息很少,很杂,大多数是广告或windows上的软件,因此我使用了豆包这个免费的人工智能模型,速度和逻辑性都不错,可联网搜索,只是有的时候就在编造了。它给我的pdfsig的命令参数都是它自己编的,害我困惑了好久,后来还是我自己找到解决方案的。

2024/7/3
articleCard.readMore