躬行笔记 - Python
type: channel
link: https://www.fuzhoupyy.work/index.php/category/uncategorized/
items: 抓狂！明明开了系统代理，为啥CMD和PowerShell还是上不了网？深扒Windows代理机制的坑
items: Nginx 为啥这么牛？深入聊聊事件驱动和非阻塞 I/O，看完这篇你就懂了
items: 别再折腾 iptables 了！用 cproxy + wstunnel 轻松搞定 Linux 透明代理，内网穿透稳如老狗
items: 那个让Claude直接操控我电脑的MCP协议，到底是个什么鬼东西？
items: 如何在 Azure 中创建 Windows 10 虚拟机
items: 通过命令行界面（winget）在 Windows 上安装 Node.js
items: 这个开源知识库太香了！PandaWiki搭建全过程，踩坑经验全分享
items: Python sh库：让运维脚本告别subprocess的痛苦，一行代码搞定系统命令
items: CDN优化实战：从命中率30%到95%的血泪史，AWS CloudFront踩坑全记录
items: 博客更新！！！

抓狂！明明开了系统代理，为啥CMD和PowerShell还是上不了网？深扒Windows代理机制的坑
type: item
date: 2026-04-02T14:19:04+00:00
description: 昨晚本来打算早点睡的，结果刚躺下，手机就震动个不停。看了一眼，是咱们群里的小王发来的私信，一连串的表情包加感叹号，隔着屏幕都能感觉到他的崩溃。事情挺简单，也挺典型。这哥们最近在捣鼓那个啥“科学上网”工具，想在服务器上拉个Docker镜像，或者是用脚本去请求个外部API。他在Windows设置里把代理开得好好的，浏览器访问Google那是嗖嗖的快，一点毛病没有。可是一切换到CMD或者PowerShell里，立马就瞎火，curl 一下超时，wget 一下拒绝连接。他当时那个郁闷啊，跟我抱怨说：“这Windows是不是针对我？设置里都配好了，怎么到了命令行就成了聋子的耳朵——摆设？”其实吧，这事儿真不能怪Windows针对谁，这是很多刚入坑运维或者开发的小伙伴经常遇到的经典“玄学”问题。咱们平时在图形界面点点点，习惯了那种“所见即所得”的爽快，殊不知Windows底层的网络机制其实是个“双轨制”。今天咱们就趁着这个机会，好好扒一扒这里面的门道。别看这是个代理问题，里面涉及的底层逻辑，如果你没搞清楚，以后遇到更复杂的网络故障，一样得抓瞎。浏览器能通，为啥命令行不通？咱们得先把这个事儿理清楚。很多人有个误区，觉得我在“设置 -> 网络和 Internet -> 代理”里面填了个地址，这电脑上所有的流量就应该乖乖地走那个通道出去。其实不是的。Windows这系统，历史悠久，身上背着不少历史包袱。它的网络架构里，其实并存着两套主要的机制。一套是咱们老百姓常用的，叫 WinINET 代理设置；另一套，是更底层、更“极客”一点的 WinHTTP。你在Windows设置界面里配的那个代理，它实际上修改的是 WinINET 的配置。这玩意儿是给谁用的呢？主要是给浏览器用的，给那些跑在用户态的应用程序用的。比如你打开Edge、Chrome，或者是一些现代化的桌面软件，它们启动的时候，会自动去读WinINET的配置，“哦，原来用户设了代理，那我把请求发给代理服务器吧”。所以你的浏览器能通，是因为它听话，它主动去适配了这个配置。但是，问题来了。CMD和PowerShell，这俩货虽然长得黑乎乎的挺像黑客工具，但它们本质上只是命令行解释器。当你在这个黑框框里敲下 curl 或者 Invoke-WebRequest 的时候，它们默认是不会去读那个WinINET的配置的。这就好比你跟家里的管家（浏览器）说：“以后有人找我，先经过你筛选一下。” 管家听懂了，照做了。但是你忘了跟那个负责跑腿的快递员（CMD/PowerShell）说这事儿。快递员还是按照老规矩，直接去敲客户的门，结果客户（目标网站）在国外，他哪能敲得开？直接就被大防火墙给拦回来了。所以，CMD和PowerShell默认情况下，它是“直连”模式。它不知道你设了代理，它也不想管这闲事，它就觉得：“我有网关，我有DNS，我直接发请求不就完了吗？” 结果就是，请求发出去，石沉大海。那个让人误解的 curl 命令这里还得插一句，特别容易误导人的一个点。现在的Windows 10、Windows 11，居然自带 curl 命令了。以前咱们在Windows上用curl，那都是得自己去下载个exe，扔到System32里，或者配个环境变量。现在好了，微软良心发现，原生支持了。但是！这个坑就在于，PowerShell里有个别名机制。你在PowerShell里敲 curl，你以为你用的是那个大名鼎鼎的Linux下的curl工具吗？并不是。在PowerShell里，curl 其实是 Invoke-WebRequest 这个Cmdlet的别名。这就导致了一个很搞笑的现象：你在网上搜教程，人家Linux下是 curl -x socks5://...，你原封不动复制到PowerShell里跑，报错！参数不对！因为 Invoke-WebRequest 它是.NET Framework封装出来的东西，它的逻辑跟原生的curl.exe完全不是一码事。你要是真想在PowerShell里用原生的curl，得敲 curl.exe，或者把别名去掉。这一步搞不清楚，很多人配代理能配一天，最后把自己配懵了。我之前有个同事，就是死活搞不定这个，还在群里骂微软垃圾，说curl都不兼容。后来我让他敲个 Get-Alias curl 看一眼，他才恍然大悟，原来是“李鬼”遇上了“李逵”。既然默认不走，咱们怎么让它走？知道了原因，解决办法其实就呼之欲出了。既然CMD和PowerShell不会主动去读WinINET的配置，那咱们就得想办法把代理配置“喂”到它们嘴里。一般来说，有三种路子，咱们一种一种掰开了说。方法一：环境变量大法，简单粗暴这是最通用、最省事的办法。不管是CMD还是PowerShell，不管是curl还是git，绝大多数命令行工具，都会去读系…

Nginx 为啥这么牛？深入聊聊事件驱动和非阻塞 I/O，看完这篇你就懂了
type: item
date: 2026-03-26T14:21:30+00:00
description: 咱们干运维的，天天跟 Nginx 打交道，配置文件写得飞起，upstream、location 闭着眼睛都能配。但你要是问我，这玩意儿到底为啥能抗住几万甚至十几万的并发连接？以前我可能也就背背面试题：“哦，因为是异步非阻塞，基于事件驱动。”这话没毛病，但总觉得像隔靴搔痒，没说到点子上。今天咱们就撇开那些枯燥的教科书定义，用大白话，结合着咱们生产环境的实际情况，好好把这个事儿给唠透了。不然下次面试官问你“为什么 Nginx 不用多线程”，你总不能说“因为官方文档这么写的”吧。咱们先从“傻等”说起要搞懂 Nginx 的牛X之处，得先看看它的“前辈”或者说是反面教材是怎么干的。咱们以前用 Apache，或者自己写个简单的 Socket 服务器，最传统的模型是啥？就是 BIO（Blocking I/O），阻塞式 I/O。想象一下，你是个服务员（服务器进程），负责给客人点菜。传统的阻塞模式是这样的：你走到 1 号桌，拿着小本本准备点菜。1 号桌的大哥还在看菜单，没理你。这时候你干啥？你只能傻站在那儿等，手里的小本本也不能给别人用，整个人的状态就是“阻塞”了。这时候 2 号桌喊：“服务员，点菜！”你听到了吗？听到了，但你走不开啊，你被 1 号桌占用了。这就尴尬了。老板（系统管理者）一看这不行啊，一个服务员根本忙不过来，于是就开始招人。来一个客人，我就派一个专门的服务员盯着。这就是所谓的“多进程”或“多线程”模型。在早期的 Web 服务里，Apache 的 prefork 模式就是这么干的。来一个连接，fork 一个子进程。这招虽然解决了“一人一桌”的问题，但代价太大了。进程是啥？是资源的大户。每个进程都要占内存，都要占 CPU 时间片。你要是来个 1 万个并发，好家伙，1 万个进程在系统里跑，CPU 光忙着在这些进程之间切换上下文了，真正干活的时间没多少。这就好比饭店里挤满了服务员，客人没几个，服务员之间还互相撞来撞去，这生意还怎么做？这就是著名的 C10K 问题的根源。服务器资源是有限的，你用“人海战术”去堆连接，肯定得崩。换个思路：非阻塞 I/O既然“傻等”效率低，那咱们能不能不等？还是那个服务员的例子。这次你学聪明了，你走到 1 号桌，大哥还在看菜单。你这次不傻等了，你说：“大哥您先看，看好了喊我。”然后你立马转身去 2 号桌。这就是非阻塞 I/O。你尝试去读取数据（点菜），如果没有数据（客人没想好），你不阻塞在那儿，而是直接返回一个错误（EAGAIN/EWOULDBLOCK），告诉你“现在没数据，待会儿再来”。这听起来挺美好，但有个问题。你虽然不等了，可你不知道谁想好了啊。于是你只能像个没头苍蝇一样，一会儿跑去 1 号桌问“想好了吗？”，一会儿跑去 2 号桌问“想好了吗？”，一会儿跑去 3 号桌……如果你有 1 万桌客人，你光是跑路就把腿跑断了，CPU 也在不停地轮询，空转，这也是一种浪费。这叫非阻塞 I/O 的忙轮询。真正的大招：事件驱动机制这时候，如果有个大堂经理（操作系统内核），手里拿个大喇叭，这事儿就解决了。你不用一个个去问了。你就在那儿站着喝茶。哪桌客人想好了，经理就喊一声：“5 号桌要点菜！”这时候你过去处理一下。这就是事件驱动。在计算机的世界里，这个“大堂经理”就是操作系统内核提供的 I/O 多路复用机制。在 Linux 上，这玩意儿叫 epoll；在 BSD/Mac 上叫 kqueue；在老一点的系统上还有 select 和 poll。Nginx 之所以牛，核心就在这儿。它不搞人海战术，它搞的是“精英战术”。一个 worker 进程，就能处理成千上万个连接。咱们来拆解一下 Nginx 的工作流，看看它是怎么把这几个概念揉在一起的。1. Master 和 Worker 的分工Nginx 启动后，你会看到一个 master 进程和多个 worker 进程。Master 就像饭店老板，他负责管理 Worker，比如读取配置、绑定端口、平滑重启这些管理活儿，他不具体接客。真正干活的是 Worker 进程。重点来了，Worker 进程通常只有几个，一般咱们配置成跟 CPU 核心数一样多。为啥？因为少了浪费多核性能，多了反而增加上下文切换的开销。2. 抢占式处理Worker 进程是怎么工作的？它们都监听着同一个端口（比如 80 或 443）。当一个新连接来了，谁去接？这里有个细节，Nginx 利用了一把锁。当连接进来时，哪个 Worker 进程抢到了锁，哪个就去处理这个连接。一旦连接建立好了，这个连接后续的所有读写操作，都由这个 Worker 全权负责。这就避免了多个进程瞎抢一个连接导致的“惊群效应”。所谓惊群，就是一嗓子喊过来，所有 Worker 都醒过来抢，结果只有一个能抢到，其他的白醒了，这很伤性能。Nginx 处理得很…

别再折腾 iptables 了！用 cproxy + wstunnel 轻松搞定 Linux 透明代理，内网穿透稳如老狗
type: item
date: 2026-03-04T15:00:26+00:00
description: 最近有个朋友找我帮忙，说他们公司有个老旧的 Linux 服务器，跑着一堆内部服务，现在想让这些服务能通过公网访问，但又不能直接暴露端口，防火墙策略也卡得死死的。常规的反向代理方案搞不定，因为应用层根本没做任何代理适配，总不能一个个改代码吧？这时候我就想到了“透明代理”——对应用完全无感，流量在系统层面就被劫持转发，上层程序压根不知道自己走的是代理。听起来很玄乎？其实没那么复杂，关键就俩工具：cproxy 和 wstunnel。今天这篇，我就手把手带你把这套组合拳打出来，顺便聊聊我在生产环境里踩过的坑、调过的参，保证你照着做就能跑起来。先说说 cproxy 是啥cproxy 不是那种大厂开源的明星项目，它是个轻量级的透明代理工具，专门干一件事：把本地发出的 TCP 流量重定向到指定的 SOCKS5 或 HTTP 代理。它底层用的是 Linux 的 TPROXY 模块（不是 REDIRECT！），所以能保留原始目的地址，特别适合做透明代理。很多人一听到“透明代理”就想到 iptables + redsocks / proxychains，但那些方案要么配置复杂，要么兼容性差。cproxy 的优势在于：配置简单、性能不错、支持 UDP（虽然我们这次主要用 TCP），而且它能和 wstunnel 完美配合——后者能把任意 TCP 流量封装成 WebSocket，轻松绕过企业防火墙。场景还原：为什么需要这个组合？假设你有台内网机器 A（192.168.1.100），上面跑了个 Web 服务（比如 8080 端口）。现在你想让外网用户通过你的公网服务器 B（比如 example.com）访问这个服务，但：服务器 A 不能直接开公网 IP防火墙只允许出站 443（HTTPS）你不想改 Web 应用的代码或配置这时候，常规思路是用 frp/ngrok，但它们依赖中心节点，而且有些环境连 frp 的自定义端口都不让连。而 wstunnel 可以把流量伪装成正常的 WebSocket（走 443），再配合 cproxy 做透明劫持，整个链路就通了。实操开始：部署 wstunnel先在公网服务器 B 上起一个 wstunnel 服务端。wstunnel 的 GitHub 仓库是 https://github.com/erebe/wstunnel，安装很简单，直接下二进制就行：# 在服务器 B（公网）上执行 wget https://github.com/erebe/wstunnel/releases/latest/download/wstunnel-linux-amd64 -O /usr/local/bin/wstunnel chmod +x /usr/local/bin/wstunnel然后启动服务端，监听 443 端口（假装是 HTTPS）：wstunnel server --port 443 --restrictTo "127.0.0.1:8080" wss://example.com--restrictTo 是安全限制，只允许转发到本机的 8080 端口（后面我们会把内网流量打到这里）。注意：如果你已经有 Nginx 占用 443，可以用 --port 8443，然后用 Nginx 反代 /wstunnel 路径到 8443，这里为了简化先直接占 443。内网机器 A：部署 cproxy + wstunnel 客户端现在回到内网机器 A（192.168.1.100）。首先装 cproxy。它没有官方 release，但源码编译非常快：git clone https://github.com/txthinking/cproxy.git cd cproxy make sudo cp cproxy /usr/local/bin/接着，在 A 上启动 wstunnel 客户端，连接到公网服务器 B：wstunnel client wss://example.com --udp --tcp -L 127.0.0.1:1080这行命令的意思是：把本地 1080 端口作为 SOCKS5 代理，所有流量通过 wss://example.com 隧道转发。--udp --tcp 表示同时支持两种协议（虽然我们主要用 TCP）。现在，1080 端口就是一个“出口”，所有发往这里的流量都会被 wstunnel 打包成 WebSocket，从 443 出去。关键一步：用 cproxy 把流量劫持到 1080接下来就是透明代理的核心了。cproxy 的作用是：监听一个本地端口（比如 12345），把所有发往它的 TCP 连接，通过 SOCKS5 代理（127.0.0.1:1080）转发出去。启动 cproxy：cproxy -l 12345 -a 127.0.0.1…

那个让Claude直接操控我电脑的MCP协议，到底是个什么鬼东西？
type: item
date: 2025-12-30T15:03:29+00:00
description: 昨晚熬夜折腾了一宿，头发又掉了几十根，总算把Anthropic搞的那个MCP（Model Context Protocol）给摸透了。说实话，刚听到这个词的时候，我内心是拒绝的。这年头，概念造得比母猪下崽还快，今天Agent，明天RAG，后天又来个什么Chain。咱们干运维的，最怕这种听着高大上、落地一地鸡毛的玩意儿。但是！这次好像真不一样。当我第一次在Claude Desktop里，直接让它“读取我本地的Nginx日志并分析502错误原因”，然后它真的直接读了我硬盘里的文件并且给出分析结果时，我承认，我有点起鸡皮疙瘩了。这玩意儿不是单纯的插件，它更像是一个给大模型开的“USB接口”。以前我们怎么用AI？复制粘贴代码，或者把日志脱敏了再喂给它，要么就是费劲巴拉地写个脚本调用API。现在好了，MCP直接把这个过程标准化了。废话不多说，今天咱们就来扒一扒这个MCP到底是个啥，以及作为一个手痒的IT人，怎么自己动手撸一个MCP服务，让AI变成你的私人定制运维专家。啥是MCP？别给我整虚的官方文档写得那叫一个晦涩，什么“开放标准”、“上下文交互”，看着就困。其实你把它想象成电脑的USB协议就完事了。以前（没有MCP的时候），你想让ChatGPT连你的数据库，你得自己写个特殊的插件；你想让Claude连你的Jira，又得写另一套代码。这就好比以前的手机充电口，诺基亚是圆孔，三星是扁口，苹果是宽口，乱得一塌糊涂。MCP就是Type-C接口。只要你的数据源（比如你的运维平台、你的本地文件夹、你的Postgres数据库）实现了MCP协议，不管是Claude，还是最近很火的Cursor编辑器，亦或是Zed，都能直接插上用。这里面有两个核心角色：MCP Host（主机）：比如Claude Desktop客户端，或者Cursor编辑器。它是大脑，负责提问和处理。MCP Server（服务端）：这就是我们要开发的东西。它负责干活，比如去查数据库、去执行个ls -l、去读个文件。这一打通，事情就变得有意思了。你可以写个Server，专门查你们公司的服务器负载。然后你在Claude里问：“现在哪台机器CPU飙高了？”Claude就通过MCP协议，调你的Server查数据，然后告诉你结果。听起来是不是有点像API？是，也不是。它比API更“智能”，因为它把工具的定义、资源的模板都标准化了，AI一看就知道怎么用，不需要你写那种几百行的Prompt去教它。准备动手：环境这块得支棱起来咱们是搞技术的，光说不练假把式。只要你会点Python，这事儿就不难。虽说官方也支持TypeScript，但咱们运维圈子，Python才是亲爹。先把环境弄好。我假设你电脑上已经有Python 3.10以上了。没有的话自己去面壁。我最近特别喜欢用 uv 这个包管理工具，速度快得离谱，比pip那种老牛拉破车强多了。当然，你习惯用pip也行。先建个目录，假装我们要搞一个“运维百宝箱”：mkdir ops-mcp-server cd ops-mcp-server python -m venv .venv source .venv/bin/activate # Windows下是 .venv\Scripts\activate接下来安装核心库。Anthropic官方出了个SDK，叫 mcp。pip install mcp[cli]装完之后，咱们别急着写代码。很多教程一上来就让你写类、写继承，那太累了。咱们用个偷懒的方法——FastMCP。这玩意儿就像FastAPI一样，装饰器一挂，代码跑起来，贼爽。对了，还得装个 uvicorn 之类的吗？其实MCP通常是走标准输入输出（Stdio）通信的，特别是在本地跑的时候，这样最安全，不需要暴露端口。这也是我觉得它设计得精妙的地方——它默认不是为了做成HTTP微服务，而是做成一个本地的“插件进程”。第一个吃螃蟹：写个“查进程”的工具咱们的目标很简单：让Claude能查我电脑上运行的进程。新建个文件 server.py。代码大概长这样，逻辑我都写注释里了，仔细看：from mcp.server.fastmcp import FastMCP import psutil # 初始化一个Server，名字随便起，就叫 "OpsTools" mcp = FastMCP("OpsTools") @mcp.tool() def list_top_processes(limit: int = 5) -> str: """ 列出当前系统占用CPU最高的几个进程。 Args: limit: 要显示的进程数量，默认为5个 """ # 既然是实战，就得真去读系统信息 # psutil这库搞运维的应该都熟 procs = [] for proc in psutil.process…

如何在 Azure 中创建 Windows 10 虚拟机
type: item
date: 2025-11-12T15:07:00+00:00
description: 什么是虚拟机？虚拟机（VM）是由软件创建和运行的物理计算机的虚拟化版本。本质上，它就是一台“云端计算机”。创建步骤创建虚拟机：在 Azure 门户中搜索虚拟机。点击创建虚拟机，在下拉菜单中选择虚拟机。在“基本信息”选项卡上，选择现有资源组或为虚拟机创建一个新的资源组。为虚拟机创建一个实例名称。选择一个地区。如有必要，请选择可用区；否则，请选择“不需要基础架构冗余”。选择图像和兼容的安全类型“标准”。创建管理员帐户。选择用户名和密码。创建入站端口：HTTP (80) 和 RDP。确认资格。转到监控选项卡，禁用系统启动诊断。转到标签选项卡，为虚拟机创建一个标签。然后进行审核和创建。点击创建。部署完成后，转到资源，然后转到网络，增加虚拟机的屏幕使用时间。保存更改。进入虚拟机概览并连接虚拟机。请前往下载 RDP 文件。下载完成后，进入电脑的下载文件夹，通过远程桌面协议进行部署，然后输入你在管理员部分创建的密码。连接上创建的win10如果这篇文章对你有帮助，别忘了点赞转发支持一下！想了解更多运维实战经验和技术干货，记得关注微信公众号@运维躬行录，领取学习大礼包！！！我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习，共同进步！公众号：运维躬行录个人博客：躬行笔记

通过命令行界面（winget）在 Windows 上安装 Node.js
type: item
date: 2025-11-08T14:19:02+00:00
description: 最近有接触到nodejs，今天就来讲讲在 Windows 上安装 Node.js ，直接通过命令行安装不再需要点击安装程序——这要归功于微软官方的 Windows 程序包管理器 winget 。以下是如何在几秒钟（三秒真男人！！！）内完全通过终端使用 npm 安装 Node.js 的方法。1. 打开 PowerShell按 Win + X → 选择 Windows PowerShell（管理员） 或终端（管理员） 。2. 查找可用的 Node.js 版本首先，列出所有可用的 Node.js 软件包：winget search OpenJS.NodeJS你会看到类似这样的结果：名称 ID 版本 源 ----------------------------------------------- Node.js OpenJS.NodeJS 25.1.0 winget Node.js 14 OpenJS.NodeJS.14 14.21.3 winget Node.js 16 OpenJS.NodeJS.16 16.20.2 winget Node.js 18 OpenJS.NodeJS.18 18.20.8 winget Node.js 20 OpenJS.NodeJS.20 20.19.5 winget Node.js 21 OpenJS.NodeJS.21 21.7.2 winget Node.js 22 OpenJS.NodeJS.22 22.21.0 winget Node.js 23 OpenJS.NodeJS.23 23.11.0 winget Node.js (LTS) OpenJS.NodeJS.LTS 24.11.0 winget选择 LTS 版本（推荐）或最新版本并安装：winget install -e --id OpenJS.NodeJS.LTS或者安装最新版本：winget install -e --id OpenJS.NodeJS⚠️ 建议大多数用户使用 LTS（长期支持）版本——它更稳定，并且会获得更长时间的安全更新。3. 重新打开命令行界面（重要！）安装完成后， 关闭并重新打开 PowerShell 或终端 。这将刷新 PATH 环境变量，以便识别 node 和 npm 。然后验证安装情况：node --version npm --version你应该能看到 Node.js 和 npm 的版本号（npm 与 Node.js 捆绑在一起）。4. 故障排除：PowerShell 中无法识别 npm。如果看到类似 npm : File C:\Program Files\nodejs\npm.ps1 cannot be loaded because running scripts is disabled on this system 的错误，则表示 PowerShell 的执行策略阻止了 npm 脚本。以下三种方法可以解决这个问题：选项 A：更改执行策略（推荐）以管理员身份运行 PowerShell 并设置执行策略：Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser然后关闭并重新打开 PowerShell。这样既可以运行本地脚本（例如 npm），又能防止未经签名的远程脚本运行。选项 B：改用命令提示符如果您不想更改 PowerShell 设置，请改用命令提示符 (cmd) 或带有命令提示符配置文件的 Windows 终端 。npm 在 cmd 中无需任何策略更改即可正常工作。选项 C：绕过当前会话暂时绕过当前 PowerShell 会话的策略：Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process这只会影响当前会话，关闭 PowerShell 时会重置。5.（可选）升级 npm保持 npm 更新：npm install -g npm@latest为什么要使用 winget？✅ 官方（由微软和 OpenJS 基金会维护）✅ 自动将 Node.js 和 npm 添加到 PATH 环境变量中（只需重新打开终端即可生效）✅ 完全可脚本化（非常适合自动化和持续集成）✅ 适用于全新机器的可复现设置就这样——你只需一条命令就在 Windows 上安装了 Node.js 和 npm，重新打开终端后即可使用。如果这篇文章对你有帮助，别忘了点赞转发支持一下！想了解更多运维实战经验和技术干货，记得关注微信公众号@运维躬行录，领取学习大礼包！！！我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习，共同进步！公众号：运维躬行录个人博客：躬行笔记

这个开源知识库太香了！PandaWiki搭建全过程，踩坑经验全分享
type: item
date: 2025-10-23T14:40:42+00:00
description: 最近公司要搭建一个内部知识库，领导让我调研几个方案。说实话，市面上的知识库产品真的是五花八门，什么Confluence、Notion、语雀啥的，但要么收费贵得离谱，要么功能不够用。偶然间发现了PandaWiki这个开源项目，试用了一下发现还真不错。界面简洁，功能够用，关键是免费！今天就把我搭建的整个过程分享给大家，希望能帮到有需要的朋友。什么是PandaWiki项目地址：https://github.com/chaitin/PandaWiki演示体验demo：https://192.168.198.133:2443/doc/editor/019a131f-12df-759c-a1a9-194d3c5ae47cPandaWiki是一个基于Go语言（好多项目都是go开发的，看来确实得学go了！！！）开发的轻量级知识库系统，支持Markdown编辑，有着不错的用户体验。相比其他重量级的知识库系统，它的部署和维护都相对简单。我之前用过MediaWiki，那个配置起来真的是要命，光是数据库配置就能折腾半天。PandaWiki就不一样了，基本上几个命令就能跑起来。环境准备在开始之前，我们需要准备一台Linux服务器。我这里用的是Debian 13（老演员了！），配置是2核4G，对于小团队使用完全够了。首先更新一下系统：apt update && apt upgrade -y然后安装一些必要的工具：apt install -y wget curl git vim开始部署PandaWiki一条命令搞定安装！！舒服！bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)"选择安装还是升级！会让你确认安装目录，无脑回车就行，也是通过docker部署(最喜欢看这种安装界面了哈哈哈哈)还有交流群二维码！！哈哈哈初始化配置打开浏览器访问 http://你的服务器IP:8080，应该能看到PandaWiki的初始化页面。第一次访问会要求你创建管理员账户。我建议用户名不要用admin这种太常见的，密码也要设置复杂一点。初始化完成后，你就能看到一个干净的知识库界面了。界面还是挺清爽的，左侧是目录树，右侧是内容区域。让你配置大模型很丰富注册靠谱白嫖一个（不是广告！）基本使用新手文档：https://192.168.198.133:2443/doc/editor/019a131f-12da-76b3-bafe-3cfbe1069e69创建文档点击"新建文档"按钮，可以选择创建普通文档或者文件夹。PandaWiki支持Markdown语法，写起来还是很顺手的。我试着创建了几个测试文档，发现它的Markdown渲染效果还不错，代码高亮、表格、图片都支持得挺好。我这里直接通过rss来导入自己博客的文档！通过rss订阅可以直接拉取很多地方的操作文档！这是拉取到的博客文章：去发布导入本地文本这就是财富！！！发布！！！使用统计！常用配置使用体验用了一段时间下来，感觉PandaWiki还是挺不错的。界面简洁，功能够用，性能也还可以。我们团队大概20多个人在用，响应速度还是很快的。当然也有一些不足的地方，比如权限管理相对简单，插件生态也不够丰富。但对于大多数中小团队来说，这些功能已经够用了。最重要的是它是开源免费的，不用担心突然收费或者服务停止。而且代码托管在GitHub上，如果有需要还可以自己修改。我感觉很nice！！会给出具体的引用，我准备用这个来替代我的博客搜索了哈哈哈写在最后PandaWiki作为一个轻量级的知识库解决方案，确实有它的优势。部署简单，维护方便，功能够用，关键是免费开源。虽然在一些高级功能上可能不如商业产品，但对于大多数团队来说已经足够了。特别是对于预算有限的小团队，这绝对是个不错的选择。如果你也在寻找知识库解决方案，不妨试试PandaWiki。反正是免费的，试试又不会怀孕。部署过程中如果遇到问题，可以查看官方文档或者GitHub上的issue。社区虽然不大，但还是比较活跃的。好了，今天的分享就到这里。如果这篇文章对你有帮助，记得点个赞转发一下。有问题的话也可以在评论区留言，我看到会回复的。如果这篇文章对你有帮助，别忘了点赞转发支持一下！想了解更多运维实战经验和技术干货，记得关注微信公众号@运维躬行录，领取学习大礼包！！！我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习，共同进步！公众号：运维躬行录个人博客：躬行笔记

Python sh库：让运维脚本告别subprocess的痛苦，一行代码搞定系统命令
type: item
date: 2025-10-21T14:27:45+00:00
description: 最近在整理服务器监控脚本的时候，发现自己写的代码里到处都是subprocess.Popen()，看着就头疼。想起刚入行那会儿，为了执行个简单的ls命令，愣是写了十几行代码处理各种异常和输出，现在想想真是太蠢了。直到遇到了Python的sh库，我才发现原来执行系统命令可以这么优雅。今天就来聊聊这个让我爱不释手的库，相信看完之后你也会和我一样，再也不想碰subprocess了。为什么我会选择sh库说实话，Python标准库里的subprocess功能很强大，但用起来真的很繁琐。每次想执行个简单命令都要考虑一堆问题：怎么获取输出？怎么处理错误？怎么传参数？import subprocess # 传统的subprocess写法，光看着就累 result = subprocess.run(['ls', '-la'], capture_output=True, text=True, check=True) print(result.stdout)而用sh库呢？import sh print(sh.ls('-la'))就这么简单！一行代码搞定，看着就舒服多了。sh库的安装和基本使用安装很简单，pip一下就行：pip install sh基本使用更简单，直接把系统命令当成Python函数调用就可以了：import sh # 执行ls命令 print(sh.ls()) # 带参数的命令 print(sh.ls('-la', '/home')) # 管道操作也很简单 print(sh.grep(sh.ps('aux'), 'python'))我第一次看到这种写法的时候，真的被震撼到了。这不就是我一直想要的那种简洁的方式吗？实际项目中的应用场景在我日常运维中，sh库真的帮了大忙。比如说服务器健康检查脚本：import sh from datetime import datetime def check_server_status(): # 检查磁盘使用情况 disk_usage = sh.df('-h') print(f"磁盘使用情况：\n{disk_usage}") # 检查内存使用 memory_info = sh.free('-h') print(f"内存使用情况：\n{memory_info}") # 检查CPU负载 load_avg = sh.uptime() print(f"系统负载：{load_avg}") # 检查特定进程 try: nginx_processes = sh.pgrep('nginx') print(f"Nginx进程数：{len(nginx_processes.strip().split())}") except sh.ErrorReturnCode_1: print("警告：Nginx进程未运行！")这种写法比subprocess清爽太多了，而且代码可读性特别好。处理命令输出和错误sh库在处理命令输出方面也很贴心：import sh # 获取命令输出 output = sh.ls('/home') print(type(output)) # <class 'sh.RunningCommand'> print(str(output)) # 转换为字符串 # 实时处理输出 def process_line(line): print(f"处理行: {line.strip()}") sh.tail('-f', '/var/log/syslog', _out=process_line)错误处理也很直观：import sh try: # 执行可能失败的命令 result = sh.ls('/nonexistent') except sh.ErrorReturnCode_2 as e: print(f"命令执行失败: {e}") print(f"错误输出: {e.stderr}") print(f"标准输出: {e.stdout}") print(f"退出码: {e.exit_code}")高级功能：管道和重定向sh库对管道的支持让我印象深刻，写起来就像在shell里一样自然：import sh # 管道操作 result = sh.ps('aux') | sh.grep('python') | sh.wc('-l') print(f"Python进程数量: {result}") # 更复杂的管道 log_errors = sh.tail('-n', '1000', '/var/log/app.log') | sh.grep('ERROR') print(log_errors) # 重定向到文件 sh.dmesg(_out='/tmp/dmesg.log') # 从文件读取输入 sh.sort(_in='/tmp/unsort…

CDN优化实战：从命中率30%到95%的血泪史，AWS CloudFront踩坑全记录
type: item
date: 2025-10-16T14:14:55+00:00
description: 最近客户cdn命中率异常，让我优化下缓存策略。经过一番折腾，总算把命中率提上来了！！！今天就把这些年踩过的坑和一些实用的经验分享给大家。其实CDN优化这事儿，说简单也简单，说复杂也复杂。很多人以为接入个CDN就万事大吉了，结果发现命中率低得可怜，钱花了不少效果却不明显。我之前就遇到过这种情况，CDN命中率只有30%多，简直是在烧钱。先说说CDN的那些关键指标做CDN优化，你得先知道怎么看数据。就像开车要看仪表盘一样，不然怎么知道车子跑得怎么样？命中率（Hit Ratio）这个是最重要的指标，没有之一。命中率就是CDN直接返回缓存内容的请求占总请求的比例。一般来说，静态资源的命中率应该在90%以上，如果你的命中率只有50-60%，那肯定有问题。在AWS CloudFront里查看命中率很简单，进入CloudFront控制台，选择你的分发，然后点击"Monitoring"标签页。这里会显示Cache hit rate的图表，可以看到不同时间段的命中率变化。回源率（Origin Request Rate）这个和命中率是相对的，回源率高说明CDN经常要去源站拿数据，这样就失去了CDN的意义。正常情况下回源率应该控制在10%以下。响应时间包括CDN响应时间和回源响应时间。CDN响应时间一般应该在100ms以内，如果超过这个数值就要检查是不是节点选择有问题。我记得有次优化一个电商网站，发现图片加载特别慢。一查监控发现CDN响应时间居然有2秒多，后来才发现是缓存策略配置错误，每次都要回源验证。带宽使用情况这个主要是看成本，CDN的费用很大一部分就是带宽费用。通过监控带宽使用情况，可以了解流量分布，优化成本。在AWS CloudFront的监控面板里，你还能看到：Origin latency（回源延迟）Error rate（错误率）Requests（请求数）Bytes downloaded（下载字节数）这些数据都很有用，特别是错误率，如果突然飙升可能是源站出问题了。命中率低的常见原因和解决方案说到命中率低，我遇到过各种奇葩的情况。缓存策略配置不当这是最常见的问题。很多人图省事，直接用默认配置，结果发现很多本该缓存的内容都没有缓存。比如说，有些动态参数会导致URL不同，CDN就认为是不同的资源。像这种情况：https://example.com/image.jpg?timestamp=1234567890 https://example.com/image.jpg?timestamp=1234567891CDN会认为这是两个不同的文件，实际上内容是一样的。解决办法是在CloudFront的Behavior设置里配置Query String参数处理，可以选择忽略某些参数或者只转发特定参数。TTL设置太短Time To Live设置太短会导致缓存频繁过期。我见过有人把图片的TTL设置成5分钟，这不是瞎搞吗？静态资源的TTL至少要设置几个小时，甚至几天。在CloudFront里可以设置三种TTL：Minimum TTL：最小缓存时间Maximum TTL：最大缓存时间Default TTL：默认缓存时间一般我会这样设置：图片、CSS、JS等静态资源：24小时到7天HTML页面：1-6小时API接口：根据业务需求，可能几分钟到几小时源站响应头配置问题有时候源站返回了不合适的Cache-Control头，比如no-cache或者max-age=0，这会导致CDN不缓存内容。我之前遇到过一个案例，开发在Nginx配置里给所有静态资源都加了no-cache，结果CDN命中率惨不忍睹。后来改成这样：location ~* \.(jpg|jpeg|png|gif|css|js)$ { expires 7d; add_header Cache-Control "public, immutable"; }预热不充分新上线的CDN或者清除缓存后，需要一段时间来"预热"。这期间命中率会比较低，这是正常现象。但如果长时间命中率都上不去，就要检查其他配置了。CloudFront支持手动预热，可以通过Invalidation功能清除缓存，然后用脚本批量访问重要资源来预热缓存。CDN优化策略详解现在说说aws托管的缓存策略AWS CDN托管的缓存策略详细说明策略名称缓存内容不缓存内容使用场景Amplify缓存大多数静态资源和部分动态内容不缓存包含特定身份验证头的请求Amplify应用程序的通用缓存策略Amplify-Default缓存静态资源和基于常用头部的内容，保留某些Cookie不缓存带有特定认证头的请求，某些动态API响应Amplify应用的标准配置，平衡缓存与个性化Amplify-Default-V2与Amplify-Default类似，但有优化的TTL设置与Ampli…

博客更新！！！
type: item
date: 2025-09-21T14:15:20+00:00
description: 博客终于大更新啦！之前那个默认主题比较简单！除了博客文章不能给粉丝盆友带来什么价值。所以我在修改后的页面上加了一个导航页。希望能够激你大家收藏的欲望（大家有什么更好的建议也欢迎在评论区提哈，感谢支持！！！）主要变动：1、添加白天黑夜主题切换2、修改logo3、添加导航页，这个我会持续更新，欢迎大家收藏，有事没事来逛逛4、添加个人介绍页面5、优化页面样式，响应式布局采用DaisyUI + Tailwind CSS构建，提供简洁优雅的设计风格和丰富的功能特性。主题注重用户体验和响应式设计。DaisyUI官网地址：https://daisyui.com/Tailwind CSS官网地址：https://tailwindcss.com/