[{"data":1,"prerenderedAt":952},["ShallowReactive",2],{"search:index":3},{"blogPosts":4,"notes":119,"blogSections":135,"noteSections":917},[5,18,28,38,48,58,65,75,84,91,100,108],{"path":6,"title":7,"description":8,"date":9,"category":10,"tags":11,"featured":16,"readingTime":17},"\u002Fblog\u002Fgrok-auto-register-analysis","Grok 注册机","Grok Auto Register 项目的架构拆解、浏览器控制、临时邮箱集成、并发注册、token 入池。","2026-07-12","engineering",[12,13,14,15],"python","automation","grok","drissionpage",false,"7 min read",{"path":19,"title":20,"description":21,"date":22,"category":10,"tags":23,"featured":16,"readingTime":27},"\u002Fblog\u002Fchatgpt-k12-bug","ChatGpt K12 Bug - 已拉闸","ChatGPT K12 工作空间的越权邀请漏洞利用脚本。","2026-07-02",[24,25,26],"chatgpt","security","bug","12 min read",{"path":29,"title":30,"description":31,"date":32,"category":10,"tags":33,"featured":16,"readingTime":37},"\u002Fblog\u002Fai-relay-station-guide","AI 中转站","AI API 中转站的定价体系、模型倍率机制、隐蔽成本、避坑方法和选型框架。","2026-06-20",[34,35,36],"ai","api","pricing","8 min read",{"path":39,"title":40,"description":41,"date":42,"category":10,"tags":43,"featured":16,"readingTime":47},"\u002Fblog\u002Fpm2-process-manager-guide","PM2 Node.js 进程管理方案","从安装配置到生产部署，系统讲解 PM2 的进程管理、日志轮转、集群模式、优雅重启和监控告警。","2026-04-16",[44,45,46],"nodejs","pm2","devops","10 min read",{"path":49,"title":50,"description":51,"date":52,"category":10,"tags":53,"featured":16,"readingTime":57},"\u002Fblog\u002Fpostgresql-commands-guide","PostgreSQL 日常运维与查询实战","PostgreSQL 常用操作指南，涵盖数据库管理、表操作、索引优化、备份恢复、性能诊断和事务排查。","2025-07-24",[54,55,56,46],"postgresql","database","sql","14 min read",{"path":59,"title":60,"description":61,"date":62,"category":10,"tags":63,"featured":16,"readingTime":27},"\u002Fblog\u002Flinux-common-commands","Linux 常用命令速查与指南","Linux 常用命令分类整理，涵盖文件管理、文本处理、进程控制、网络诊断和系统信息查询。","2025-04-19",[64,46],"linux",{"path":66,"title":67,"description":68,"date":69,"category":70,"tags":71,"featured":16,"readingTime":74},"\u002Fblog\u002Fsteam-balance-guide","Steam 余额操作：倒余额与挂刀指南","Steam 社区市场的余额流转逻辑——饰品折价买入、卖出、选品方法和风险控制。","2025-04-12","gaming",[72,73],"steam","trading","6 min read",{"path":76,"title":77,"description":78,"date":79,"category":10,"tags":80,"featured":16,"readingTime":37},"\u002Fblog\u002Fmpv-config-guide","mpv.conf 配置与性能调优","mpv 播放器的配置文件详解——视频\u002F音频\u002F字幕选项、硬件解码、性能调优和场景配置模板。","2025-02-13",[81,82,83],"mpv","video","configuration",{"path":85,"title":86,"description":87,"date":88,"category":10,"tags":89,"featured":16,"readingTime":27},"\u002Fblog\u002Fnginx-config-guide","Nginx 配置实战：反向代理、静态服务与性能调优","从基础站点配置到生产环境调优，系统讲解 Nginx 作为反向代理、静态文件服务器、HTTPS 终结和负载均衡的典型用法。","2024-09-06",[90,46],"nginx",{"path":92,"title":93,"description":94,"date":95,"category":10,"tags":96,"featured":16,"readingTime":37},"\u002Fblog\u002Fcomfyui-deployment-guide","ComfyUI 部署与性能调优","ComfyUI 的部署方式、启动参数调优、显存优化、推理加速和生产配置。","2024-07-18",[97,98,99],"comfyui","stable-diffusion","deployment",{"path":101,"title":102,"description":103,"date":104,"category":10,"tags":105,"featured":16,"readingTime":37},"\u002Fblog\u002Fffmpeg-commands-guide","FFmpeg 命令实战：常用场景速查","按场景分类的 FFmpeg 命令——格式转换、裁剪、压缩、拼接、提取音频、截图、滤镜。","2024-06-06",[106,82,107],"ffmpeg","audio",{"path":109,"title":110,"description":111,"date":112,"category":10,"tags":113,"featured":16,"readingTime":47},"\u002Fblog\u002Fopenopenwf-analysis","OpenWF Enabler：C++ API Hook 实现游戏流量重定向","拆解 OpenWF Enabler 的技术实现——Win32 DLL 注入、MinHook API 拦截、SSL 证书绕过、内存签名扫描。","2021-10-15",[114,115,116,117,118],"cpp","reverse-engineering","windows","hook","warframe",[120,129],{"path":121,"title":122,"description":123,"date":124,"category":10,"tags":125,"featured":16,"readingTime":128},"\u002Fnotes\u002Fsite-roadmap-next-phase","官网后续开发规划","官网下一阶段的开发任务，按前端优化、后端工具和国际化扩展三个方向分类。","2026-07-10",[46,126,127],"nuxt","strapi","2 min read",{"path":130,"title":131,"description":132,"date":22,"category":10,"tags":133,"featured":16,"readingTime":128},"\u002Fnotes\u002Fquick-index","导览页","地址导航",[134],"map",[136,139,145,150,156,161,166,171,176,181,183,188,190,195,199,204,209,214,218,223,228,233,238,243,248,253,256,261,266,271,276,281,286,291,296,300,302,307,312,317,322,327,332,337,342,344,348,352,357,362,367,372,377,382,387,392,396,401,406,411,416,421,426,431,435,440,445,450,452,457,461,466,471,476,481,486,491,495,500,505,509,514,519,524,526,530,535,540,545,550,555,560,565,570,575,579,584,589,594,598,603,608,611,616,621,626,631,635,637,641,646,651,656,661,666,671,676,681,686,690,692,696,701,706,711,716,721,726,731,736,741,745,750,755,760,765,770,774,776,780,785,790,795,799,804,809,813,818,823,828,833,838,842,847,852,857,862,866,868,873,877,882,887,892,897,902,907,912],{"id":29,"title":30,"titles":137,"content":31,"level":138},[],1,{"id":140,"title":141,"titles":142,"content":143,"level":144},"\u002Fblog\u002Fai-relay-station-guide#背景","背景",[30],"OpenAI \u002F Anthropic \u002F Google 的大模型 API 在中国大陆无法直接访问。AI 中转站购买官方额度、架设反向代理，以统一接口转售给国内用户。问题在于价格极不透明——同样模型报价差 3-5 倍是常事。 中转站底层通常是 OneAPI 或 NewAPI，做三件事：协议转换（非 OpenAI 协议转兼容格式）、计费扣减（按倍率算额度）、路由分发（多后端负载均衡）。",2,{"id":146,"title":147,"titles":148,"content":149,"level":144},"\u002Fblog\u002Fai-relay-station-guide#模型倍率","模型倍率",[30],"倍率系统的来源：OneAPI 把所有模型价格与基准模型 davinci-002（$0.002\u002F1K tokens）对齐。但这个基准的绝对价格没意义，问题在于中转站可以任意调整倍率。 从官方定价到用户实际支付，每个环节都能掺水： 环节可操作空间模型倍率任意设定，与官方无关额度汇率1 元 = 5000~20000 不等最低消费每笔最低扣费四舍五入向上取整",{"id":151,"title":152,"titles":153,"content":154,"level":155},"\u002Fblog\u002Fai-relay-station-guide#算绝对倍率","算绝对倍率",[30,147],"def real_cost(cny_per_million, usd_per_million, rate=7.3):\n    \"\"\"绝对倍率 = 中转站价格 ÷ 官方价格\"\"\"\n    return cny_per_million \u002F (usd_per_million * rate) 例：某站 Claude Sonnet 4.6 输入收 8 元\u002FM token，官方 $3\u002FM × 7.3 = 21.9 元。绝对倍率 8\u002F21.9 = 0.37——官方价的 37%。",3,{"id":157,"title":158,"titles":159,"content":160,"level":144},"\u002Fblog\u002Fai-relay-station-guide#常见坑","常见坑",[30],"",{"id":162,"title":163,"titles":164,"content":165,"level":155},"\u002Fblog\u002Fai-relay-station-guide#_1-冒牌模型","1. 冒牌模型",[30,158],"中转站在 NewAPI 后台改个模型别名，就能用低成本模型冒充高价模型。检测方法： import openai\nclient = openai.OpenAI(api_key=\"key\", base_url=\"https:\u002F\u002F中转站\u002Fv1\")\nresp = client.chat.completions.create(\n    model=\"claude-sonnet-4.6\",\n    messages=[{\"role\": \"user\", \"content\": \"你是谁？\"}]\n)\nprint(resp.model)  # 看实际返回什么模型名",{"id":167,"title":168,"titles":169,"content":170,"level":155},"\u002Fblog\u002Fai-relay-station-guide#_2-隐蔽成本","2. 隐蔽成本",[30,158],"最低消费：每次请求最低扣 1000 额度，短请求实际翻倍额度双重汇率：充值和消耗用不同汇率预充值不退：一旦跑路钱打水漂（2026 年已有多起刑拘案例）",{"id":172,"title":173,"titles":174,"content":175,"level":144},"\u002Fblog\u002Fai-relay-station-guide#怎么选","怎么选",[30],"靠谱中转站的特征： 明码标价，公示每百万 token 价格主要渠道来自官方 API，不是多层嵌套代理有工单或用户群支持按量计费，不强制高额预付有公开接入文档 辅助工具： API Ranking — 实时比价 + 真假检测最全 API 导航 — 1000+ 中转站收录One Tracker — 价格追踪",{"id":177,"title":178,"titles":179,"content":180,"level":144},"\u002Fblog\u002Fai-relay-station-guide#自建中转","自建中转",[30],"services:\n  newapi:\n    image: calciumion\u002Fnew-api:latest\n    ports: [\"3000:3000\"]\n    volumes: [.\u002Fdata:\u002Fdata]\n    restart: always 自建完全掌控渠道，数据不经过第三方。需要一台境外服务器，仍需购买官方 API 额度。 先充 10-20 元试模型质量和余额消耗速度，满意再续。不要一次性大量充值。 参考：https:\u002F\u002Flinux.do\u002Ft\u002Ftopic\u002F2504277 html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s5NuB, html code.shiki .s5NuB{--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .s215V, html code.shiki .s215V{--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sYBhb, html code.shiki .sYBhb{--shiki-default:#CE9178;--shiki-dark:#CE9178}",{"id":19,"title":20,"titles":182,"content":21,"level":138},[],{"id":184,"title":185,"titles":186,"content":187,"level":144},"\u002Fblog\u002Fchatgpt-k12-bug#越权加入-k12-工作空间脚本","越权加入 K12 工作空间脚本",[20],"fetch(\"https:\u002F\u002Fchatgpt.com\u002Fapi\u002Fauth\u002Fsession\", {\n  method: \"GET\",\n  credentials: \"include\"\n})\n.then(response => response.json())\n.then(sessionData => {\n  const accessToken = sessionData.accessToken;\n  \n  if (!accessToken) {\n    throw new Error('未能获取到 accessToken');\n  }\n  \n  console.log('获取到 accessToken，正在发送邀请请求...');\n  \n  return fetch(\"https:\u002F\u002Fchatgpt.com\u002Fbackend-api\u002Faccounts\u002F\u003CACCOUNT_ID>\u002Finvites\u002Frequest\", {\n    \"headers\": {\n      \"accept\": \"*\u002F*\",\n      \"accept-language\": \"en-US,en;q=0.9\",\n      \"authorization\": `Bearer ${accessToken}`,\n      \"cache-control\": \"no-cache\",\n      \"oai-language\": \"en-US\",\n      \"pragma\": \"no-cache\",\n      \"sec-ch-ua-arch\": \"\\\"x86\\\"\",\n      \"sec-ch-ua-bitness\": \"\\\"64\\\"\",\n      \"sec-ch-ua-mobile\": \"?0\",\n      \"sec-ch-ua-model\": \"\\\"\\\"\",\n      \"sec-ch-ua-platform\": \"\\\"macOS\\\"\",\n      \"sec-ch-ua-platform-version\": \"\\\"13.5.1\\\"\",\n      \"sec-fetch-dest\": \"empty\",\n      \"sec-fetch-mode\": \"cors\",\n      \"sec-fetch-site\": \"same-origin\"\n    },\n    \"referrer\": \"https:\u002F\u002Fchatgpt.com\u002Fk12-verification\",\n    \"referrerPolicy\": \"strict-origin-when-cross-origin\",\n    \"body\": null,\n    \"method\": \"POST\",\n    \"mode\": \"cors\",\n    \"credentials\": \"include\"\n  });\n})\n.then(response => response.json())\n.then(result => {\n  console.log('邀请请求成功:', result);\n})\n.catch(error => {\n  console.error('请求失败:', error);\n}); html pre.shiki code .sW7EW, html code.shiki .sW7EW{--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .s215V, html code.shiki .s215V{--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sYBhb, html code.shiki .sYBhb{--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .skSZV, html code.shiki .skSZV{--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .s5NuB, html code.shiki .s5NuB{--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sG3YZ, html code.shiki .sG3YZ{--shiki-default:#4FC1FF;--shiki-dark:#4FC1FF}html pre.shiki code .sBpJa, html code.shiki .sBpJa{--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .sa4-K, html code.shiki .sa4-K{--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":92,"title":93,"titles":189,"content":94,"level":138},[],{"id":191,"title":192,"titles":193,"content":194,"level":144},"\u002Fblog\u002Fcomfyui-deployment-guide#硬件基线","硬件基线",[93],"显存SD1.5SDXLSD3\u002FFLUX视频模型4-6GB✅⚠️ lowvram❌❌8GB✅✅ 基础⚠️ FP8❌12-16GB✅✅✅ FP8⚠️ 基础24GB+✅✅✅✅",{"id":196,"title":197,"titles":198,"content":160,"level":144},"\u002Fblog\u002Fcomfyui-deployment-guide#安装","安装",[93],{"id":200,"title":201,"titles":202,"content":203,"level":155},"\u002Fblog\u002Fcomfyui-deployment-guide#便携包推荐","便携包（推荐）",[93,197],"下载 ComfyUI portable，解压双击 run_nvidia_gpu.bat。",{"id":205,"title":206,"titles":207,"content":208,"level":155},"\u002Fblog\u002Fcomfyui-deployment-guide#手动","手动",[93,197],"git clone https:\u002F\u002Fgithub.com\u002Fcomfyanonymous\u002FComfyUI.git\ncd ComfyUI\npython -m venv venv && source venv\u002Fbin\u002Factivate\npip install torch torchvision torchaudio --index-url https:\u002F\u002Fdownload.pytorch.org\u002Fwhl\u002Fcu124\npip install -r requirements.txt\npython main.py",{"id":210,"title":211,"titles":212,"content":213,"level":155},"\u002Fblog\u002Fcomfyui-deployment-guide#docker","Docker",[93,197],"services:\n  comfyui:\n    build: .\n    ports: [\"8188:8188\"]\n    volumes:\n      - .\u002Fmodels:\u002Fapp\u002Fmodels\n      - .\u002Foutput:\u002Fapp\u002Foutput\n    environment:\n      - PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True\n    deploy:\n      resources:\n        reservations:\n          devices: [{driver: nvidia, count: all, capabilities: [gpu]}]",{"id":215,"title":216,"titles":217,"content":160,"level":144},"\u002Fblog\u002Fcomfyui-deployment-guide#启动参数","启动参数",[93],{"id":219,"title":220,"titles":221,"content":222,"level":155},"\u002Fblog\u002Fcomfyui-deployment-guide#显存模式","显存模式",[93,216],"python main.py --lowvram      # 4-6GB，逐模型加载卸载\npython main.py --medvram      # 6-8GB，半卸载，推荐多数用户\npython main.py                 # 8GB+ 默认\npython main.py --highvram     # 24GB+ 全常驻，最快",{"id":224,"title":225,"titles":226,"content":227,"level":155},"\u002Fblog\u002Fcomfyui-deployment-guide#加速","加速",[93,216],"python main.py --medvram --xformers --force-fp16\npython main.py --use-sage-attention   # FLUX 专用，30-50% 加速 手段加速显存--xformers20-35%降 5-10%--force-fp1610-20%降 15-20%--use-sage-attention30-50%降 10-15% --xformers + --force-fp16 可能产生 NaN 输出，全黑图时关 --force-fp16 测试。",{"id":229,"title":230,"titles":231,"content":232,"level":155},"\u002Fblog\u002Fcomfyui-deployment-guide#网络与安全","网络与安全",[93,216],"python main.py --listen 0.0.0.0 --port 8188\npython main.py --enable-auth --auth-file auth.txt\npython main.py --fast     # 纯 API 模式，无 UI",{"id":234,"title":235,"titles":236,"content":237,"level":144},"\u002Fblog\u002Fcomfyui-deployment-guide#性能诊断","性能诊断",[93],"各阶段瓶颈： 阶段瓶颈改善Prompt 编码CLIP\u002FT5FP16 CLIP，减提示词长度SamplingUNetxformers、SageAttention、减步数VAE DecodeVAEtiny VAEControlNet多 CN 堆叠减少激活数量 watch -n 1 nvidia-smi        # 监控显存",{"id":239,"title":240,"titles":241,"content":242,"level":144},"\u002Fblog\u002Fcomfyui-deployment-guide#api-调用","API 调用",[93],"import requests\nSERVER = \"http:\u002F\u002F127.0.0.1:8188\"\n\ndef queue_prompt(workflow):\n    resp = requests.post(f\"{SERVER}\u002Fprompt\",\n        json={\"prompt\": workflow, \"client_id\": \"my-client\"})\n    return resp.json()[\"prompt_id\"]",{"id":244,"title":245,"titles":246,"content":247,"level":144},"\u002Fblog\u002Fcomfyui-deployment-guide#云端部署","云端部署",[93],"RunPod \u002F Vast.ai 选带 ComfyUI 的镜像，端口映射 8188。批量生图 4090(24GB) 性价比最高，FLUX 至少 24GB。",{"id":249,"title":250,"titles":251,"content":252,"level":144},"\u002Fblog\u002Fcomfyui-deployment-guide#模型目录","模型目录",[93],"models\u002F\n├── checkpoints\u002F     # 主模型 .safetensors\n├── clip\u002F\n├── controlnet\u002F\n├── loras\u002F\n├── vae\u002F\n├── upscale_models\u002F\n└── unet\u002F            # FLUX 拆分模型 html pre.shiki code .s5NuB, html code.shiki .s5NuB{--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .s215V, html code.shiki .s215V{--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sfmjH, html code.shiki .sfmjH{--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sYBhb, html code.shiki .sYBhb{--shiki-default:#CE9178;--shiki-dark:#CE9178}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sW7EW, html code.shiki .sW7EW{--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .skTid, html code.shiki .skTid{--shiki-default:#6A9955;--shiki-dark:#6A9955}",{"id":101,"title":102,"titles":254,"content":255,"level":138},[],"按场景分类的 FFmpeg 命令——格式转换、裁剪、压缩、拼接、提取音频、截图、滤镜。 FFmpeg 命令基本结构：ffmpeg [全局参数] -i [输入] [输出参数] [输出文件]。输出参数必须写在输出文件名之前。大部分参数可用 ffmpeg -h encoder=libx264 查文档。",{"id":257,"title":258,"titles":259,"content":260,"level":144},"\u002Fblog\u002Fffmpeg-commands-guide#格式转换","格式转换",[102],"# 容器转换（不重新编码）\nffmpeg -i input.mp4 -c copy output.mkv\nffmpeg -i input.mov -c copy output.mp4\n\n# 编码转换（H.264 + AAC，最兼容）\nffmpeg -i input.mkv -c:v libx264 -c:a aac output.mp4\n\n# HEVC（压缩率更高）\nffmpeg -i input.mp4 -c:v libx265 -c:a aac output_hevc.mp4\n\n# 批量 mp4 → mkv\nfor f in *.mp4; do ffmpeg -i \"$f\" -c copy \"${f%.mp4}.mkv\"; done",{"id":262,"title":263,"titles":264,"content":265,"level":144},"\u002Fblog\u002Fffmpeg-commands-guide#裁剪","裁剪",[102],"# 时间裁剪（关键帧快速定位）\nffmpeg -ss 00:00:30 -i input.mp4 -t 10 -c copy clip.mp4\n\n# 精确到帧（重新编码）\nffmpeg -i input.mp4 -ss 00:00:30 -t 10 -c:v libx264 -c:a aac clip.mp4 -ss 在 -i 之前用关键帧定位（快但不精确），之后逐帧解码（精确但慢）。 # 画面裁切 crop=宽:高:起始x:起始y\nffmpeg -i input.mp4 -vf \"crop=1280:720:200:100\" output.mp4\n\n# 缩放到 720p，保持宽高比\nffmpeg -i input.mp4 -vf \"scale=-1:720\" output_720p.mp4\n\n# 缩放到 50%\nffmpeg -i input.mp4 -vf \"scale=iw\u002F2:ih\u002F2\" output_half.mp4",{"id":267,"title":268,"titles":269,"content":270,"level":144},"\u002Fblog\u002Fffmpeg-commands-guide#音频提取与替换","音频提取与替换",[102],"# 提取 MP3\nffmpeg -i input.mp4 -vn -c:a libmp3lame -b:a 192k output.mp3\n\n# 提取 AAC\nffmpeg -i input.mp4 -vn -c:a aac -b:a 128k output.m4a\n\n# 提取 WAV\nffmpeg -i input.mp4 -vn -c:a pcm_s16le output.wav\n\n# 去掉音频\nffmpeg -i input.mp4 -an -c:v copy silent.mp4\n\n# 替换音频轨\nffmpeg -i input.mp4 -i audio.mp3 -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 -shortest output.mp4",{"id":272,"title":273,"titles":274,"content":275,"level":144},"\u002Fblog\u002Fffmpeg-commands-guide#压缩","压缩",[102],"# CRF 质量模式（0-51，越小越好，推荐 18-28）\nffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac output.mp4\nffmpeg -i input.mp4 -c:v libx265 -crf 28 -c:a aac output.mp4\n\n# 固定码率\nffmpeg -i input.mp4 -c:v libx264 -b:v 1M -c:a aac -b:a 128k output.mp4\n\n# 两遍编码（最大压缩率）\nffmpeg -i input.mp4 -c:v libx264 -b:v 1M -preset slow -pass 1 -an -f null \u002Fdev\u002Fnull\nffmpeg -i input.mp4 -c:v libx264 -b:v 1M -preset slow -pass 2 -c:a aac output.mp4 CRF 是首选，两遍编码只对固定码率有效。",{"id":277,"title":278,"titles":279,"content":280,"level":144},"\u002Fblog\u002Fffmpeg-commands-guide#拼接","拼接",[102],"同格式（编码参数一致）用 concat demuxer，无需重新编码： # filelist.txt:\n# file 'clip1.mp4'\n# file 'clip2.mp4'\n\nffmpeg -f concat -safe 0 -i filelist.txt -c copy merged.mp4 不同格式先统一转码再拼。",{"id":282,"title":283,"titles":284,"content":285,"level":144},"\u002Fblog\u002Fffmpeg-commands-guide#截图","截图",[102],"# 取单帧\nffmpeg -ss 00:01:00 -i input.mp4 -vframes 1 thumb.jpg\n\n# 每隔 30 秒一张\nffmpeg -i input.mp4 -vf \"fps=1\u002F30\" thumb_%03d.jpg\n\n# 3x3 缩略图平铺\nffmpeg -i input.mp4 -vf \"fps=1\u002F30,tile=3x3\" preview.jpg\n\n# 查看媒体信息\nffprobe -v quiet -print_format json -show_format -show_streams input.mp4",{"id":287,"title":288,"titles":289,"content":290,"level":144},"\u002Fblog\u002Fffmpeg-commands-guide#滤镜","滤镜",[102],"# 文字水印\nffmpeg -i input.mp4 -vf \"drawtext=text='DEMO':fontsize=36:fontcolor=red:x=w\u002F2-text_w\u002F2:y=h\u002F2\" output.mp4\n\n# 图片水印（右上角）\nffmpeg -i video.mp4 -i logo.png -filter_complex \\\n  \"[1:v]scale=iw*0.1:-1[logo];[0:v][logo]overlay=W-w-10:10\" -c:a copy output.mp4\n\n# 2 倍速\nffmpeg -i input.mp4 -filter_complex \"[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]\" -map \"[v]\" -map \"[a]\" output.mp4\n\n# 慢动作 0.5x\nffmpeg -i input.mp4 -filter_complex \"[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]\" -map \"[v]\" -map \"[a]\" output.mp4",{"id":292,"title":293,"titles":294,"content":295,"level":144},"\u002Fblog\u002Fffmpeg-commands-guide#gpu-加速","GPU 加速",[102],"# NVIDIA NVENC\nffmpeg -i input.mp4 -c:v h264_nvenc -preset p4 -b:v 5M output.mp4\n\n# 列出可用硬件编码器\nffmpeg -encoders | grep -E \"(nvenc|vaapi|qsv|videotoolbox)\" 硬件编码快但同码率下画质略低，适合批量转码和直播。",{"id":297,"title":158,"titles":298,"content":299,"level":144},"\u002Fblog\u002Fffmpeg-commands-guide#常见坑",[102],"参数顺序：输出参数（-b:v、-c:v）必须写在输出文件名之前音频不同步：-c copy 裁剪时，重新编码可解决覆盖确认：-y 自动覆盖，-n 跳过已有快速测试：-t 10 只处理前 10 秒 html pre.shiki code .skTid, html code.shiki .skTid{--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sW7EW, html code.shiki .sW7EW{--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .s5NuB, html code.shiki .s5NuB{--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sYBhb, html code.shiki .sYBhb{--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sBpJa, html code.shiki .sBpJa{--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .skSZV, html code.shiki .skSZV{--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .s215V, html code.shiki .s215V{--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sfmjH, html code.shiki .sfmjH{--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sa4-K, html code.shiki .sa4-K{--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}",{"id":6,"title":7,"titles":301,"content":8,"level":138},[],{"id":303,"title":304,"titles":305,"content":306,"level":144},"\u002Fblog\u002Fgrok-auto-register-analysis#核心架构","核心架构",[7],"项目分四层： CLI \u002F GUI 入口层\n   │\n   调度层（并发控制、重试、速度统计）\n   │\n   业务层（注册流程、CPA 导出）\n   │\n   基础设施层（浏览器管理、临时邮箱、HTTP 请求、token 入池） 主程序 grok_register_ttk.py（~160KB）同时承载 GUI（tkinter）和 CLI 入口。浏览器控制用 DrissionPage（DevTools Protocol），HTTP 请求用 curl_cffi。",{"id":308,"title":309,"titles":310,"content":311,"level":144},"\u002Fblog\u002Fgrok-auto-register-analysis#浏览器控制引擎","浏览器控制引擎",[7],"用 DrissionPage（v4.1.1.4）替代 Selenium，API 更轻量： from DrissionPage import Chromium, ChromiumOptions\n\ndef create_browser_options():\n    co = ChromiumOptions()\n    co.set_argument('--no-sandbox')\n    co.set_argument('--disable-gpu')\n    co.set_user_agent(user_agent)\n    return co 每个 worker 用独立的 Chromium 实例和 user-data 目录，单账号完成后完整重启浏览器，避免 session 残留。",{"id":313,"title":314,"titles":315,"content":316,"level":144},"\u002Fblog\u002Fgrok-auto-register-analysis#临时邮箱","临时邮箱",[7],"支持 DuckMail、YYDS、Cloudflare 三种。Cloudflare 最常用，基于 dreamhunter2333\u002Fcloudflare_temp_email： def cloudflare_create_temp_address(api_base):\n    resp = http_post(f\"{api_base}\u002Fapi\u002Fnew_address\")\n    data = resp.json()\n    return data['address'], data['jwt_token'] 两种鉴权模式： 模式创建 API鉴权适用none\u002Fapi\u002Fnew_address无默认x-admin-auth\u002Fadmin\u002Fnew_addressADMIN_PASSWORDTurnstile 保护时 验证码轮询 \u002Fapi\u002Fmails 接口，超时则换邮箱重试。",{"id":318,"title":319,"titles":320,"content":321,"level":144},"\u002Fblog\u002Fgrok-auto-register-analysis#并发注册","并发注册",[7],"concurrent_count 控制并行 worker 数，各自独立的浏览器实例： { \"register_count\": 20, \"concurrent_count\": 3 } RateMeter 每 60s 输出速率： class RateMeter:\n    def format_line(self, success, fail=0, force=False):\n        elapsed = time.time() - self.window_start\n        rate = success \u002F (elapsed \u002F 60) if elapsed > 0 else 0\n        return f\"{success}\u002F{fail}，{rate:.1f}\u002Fmin\"",{"id":323,"title":324,"titles":325,"content":326,"level":144},"\u002Fblog\u002Fgrok-auto-register-analysis#cpa-凭证导出与-token-入池","CPA 凭证导出与 Token 入池",[7],"注册后异步导出 CPA xAI OIDC 凭证（独立浏览器，不占用注册 tab）。SSO token 写入三个目标：本地 accounts 文件、本地 grok2api 池、远端 grok2api REST API。 def add_token_to_grok2api_remote_pool(raw_token, email=\"\", log_callback=None):\n    bases = get_grok2api_remote_api_bases(config.grok2api_remote_base)\n    for base in bases:\n        url = base.rstrip('\u002F') + '\u002Ftokens\u002Fadd'\n        resp = http_post(url, json={\n            'token': normalized_token, 'email': email,\n            'app_key': config.grok2api_remote_app_key,\n        })",{"id":328,"title":329,"titles":330,"content":331,"level":144},"\u002Fblog\u002Fgrok-auto-register-analysis#配置示例","配置示例",[7],"最小注册（Cloudflare 匿名邮箱）： {\n  \"email_provider\": \"cloudflare\",\n  \"cloudflare_api_base\": \"https:\u002F\u002F你的-worker域名\",\n  \"register_count\": 5,\n  \"concurrent_count\": 1\n} 批量 + 远程入池： {\n  \"register_count\": 50,\n  \"concurrent_count\": 5,\n  \"grok2api_auto_add_remote\": true,\n  \"grok2api_remote_base\": \"https:\u002F\u002F你的-grok2api-域名\",\n  \"grok2api_remote_app_key\": \"your_app_key\",\n  \"log_level\": \"info\"\n}",{"id":333,"title":334,"titles":335,"content":336,"level":144},"\u002Fblog\u002Fgrok-auto-register-analysis#稳定性设计","稳定性设计",[7],"每账号完整重启浏览器，独立 user-data 目录CF 拦截页检测与重试验证码超时自动换邮箱每 5 个账号调用 gc.collect()Ctrl+C 首次收尾，连按两次强制退出 def sleep_with_cancel(seconds, cancel_callback=None):\n    for _ in range(int(seconds)):\n        if cancel_callback and cancel_callback():\n            raise RegistrationCancelled()\n        time.sleep(1)",{"id":338,"title":339,"titles":340,"content":341,"level":144},"\u002Fblog\u002Fgrok-auto-register-analysis#注意事项","注意事项",[7],"自动化注册工具仅用于学习研究。使用前阅读目标网站服务条款。 Python 3.10+，创建虚拟环境运行所有操作依赖真实浏览器，CLI 模式同样会打开窗口需自行部署 Cloudflare Worker 临时邮箱服务concurrent_count 过高消耗大量系统资源 项目地址：github.com\u002Fmaxucheng0\u002Fgrok-auto-register html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s215V, html code.shiki .s215V{--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .skSZV, html code.shiki .skSZV{--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sfmjH, html code.shiki .sfmjH{--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sYBhb, html code.shiki .sYBhb{--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .s5NuB, html code.shiki .s5NuB{--shiki-default:#569CD6;--shiki-dark:#569CD6}",{"id":59,"title":60,"titles":343,"content":61,"level":138},[],{"id":345,"title":141,"titles":346,"content":347,"level":144},"\u002Fblog\u002Flinux-common-commands#背景",[60],"Linux 命令行是开发者的日常工具。无论本地开发、远程服务器维护还是 CI\u002FCD 流水线操作，掌握一批稳定、高效的命令能显著减少对搜索引擎的依赖。 本文面向有基础语法概念但希望系统化整理常用命令的开发者。按使用场景分类，每类给出最常用的命令和典型组合，最后补充容易忽略的注意事项。",{"id":349,"title":350,"titles":351,"content":160,"level":144},"\u002Fblog\u002Flinux-common-commands#文件与目录操作","文件与目录操作",[60],{"id":353,"title":354,"titles":355,"content":356,"level":155},"\u002Fblog\u002Flinux-common-commands#基础命令","基础命令",[60,350],"# 列出当前目录内容（隐藏文件、详细信息、按时间排序）\nls -laht\n\n# 递归创建目录\nmkdir -p project\u002F{src,docs,test}\n\n# 复制与移动\ncp -r source\u002F dest\u002F       # 递归复制\nrsync -avz --progress     # 增量同步，更适合大文件\nmv oldname newname        # 移动或重命名\n\n# 安全删除\nrm -rf dir\u002F               # 慎用，-rf 不确认直接删 rm -rf 不可逆，建议养成两个习惯：删除前先 ls 确认目标，或在 shell 配置中设置别名 alias rm='rm -i' 让每次删除都要求确认。",{"id":358,"title":359,"titles":360,"content":361,"level":155},"\u002Fblog\u002Flinux-common-commands#查找文件","查找文件",[60,350],"# find：按名称、类型、大小、时间过滤\nfind . -name \"*.log\" -mtime +7 -delete   # 删除 7 天前的 .log\nfind . -type f -size +100M               # 找超过 100MB 的文件\n\n# fd：更快的现代替代（需要安装）\nfd \"\\.py$\" -x wc -l                      # 找 .py 文件并统计行数\n\n# locate：依赖数据库，查找极快（需要 updatedb 更新索引）\nlocate nginx.conf",{"id":363,"title":364,"titles":365,"content":366,"level":144},"\u002Fblog\u002Flinux-common-commands#文本处理","文本处理",[60],"文本处理是命令行最强大的能力之一，适合在管道中组合使用。",{"id":368,"title":369,"titles":370,"content":371,"level":155},"\u002Fblog\u002Flinux-common-commands#查看文件","查看文件",[60,364],"cat file.txt          # 全文输出，适合小文件\nless file.txt         # 翻页查看，\u002F搜索，q 退出\nhead -n 20 file.txt   # 前 20 行\ntail -n 50 file.txt   # 后 50 行\ntail -f app.log       # 实时跟踪日志追加",{"id":373,"title":374,"titles":375,"content":376,"level":155},"\u002Fblog\u002Flinux-common-commands#grep文本搜索","grep：文本搜索",[60,364],"grep -rn \"error\" --include=\"*.log\" .\u002F\ngrep -i \"warning\" app.log                # 忽略大小写\ngrep -c \"timeout\" access.log             # 只计数\ngrep -v \"healthy\" check.log              # 排除匹配行\n\n# 上下文查看\ngrep -B 3 -A 5 \"Exception\" crash.log     # 前 3 行 + 后 5 行",{"id":378,"title":379,"titles":380,"content":381,"level":155},"\u002Fblog\u002Flinux-common-commands#sed流编辑","sed：流编辑",[60,364],"sed -i 's\u002Fold\u002Fnew\u002Fg' file.txt            # 原地替换全部匹配\nsed -n '10,20p' file.txt                 # 打印第 10 到 20 行\nsed '\u002F^#\u002Fd' config.conf                  # 删除注释行",{"id":383,"title":384,"titles":385,"content":386,"level":155},"\u002Fblog\u002Flinux-common-commands#awk结构化文本处理","awk：结构化文本处理",[60,364],"# 列提取与条件过滤\nawk '{print $1, $3}' access.log          # 打印第 1、3 列\nawk '$4 > 500 {print $1, $4}' stats.txt  # 输出第 4 列 > 500 的行\n\n# 内置变量\nawk 'NR%2==0' file.txt                   # 只打印偶数行\nawk '{sum+=$1} END{print sum}' nums.txt  # 累加第一列 awk 和 sed 的单引号在 shell 中保护 $ 符号，避免变量展开。如果需要在表达式中嵌入 shell 变量，可以用双引号包裹：awk \"{print \\$$var}\" 或通过 -v 传参：awk -v col=\"$var\" '{print $col}'。",{"id":388,"title":389,"titles":390,"content":391,"level":155},"\u002Fblog\u002Flinux-common-commands#排序与去重","排序与去重",[60,364],"sort -k2 -t, data.csv                    # 按第二列排序\nsort -u file.txt                         # 排序 + 去重\nuniq -c sorted.txt                       # 统计连续重复次数",{"id":393,"title":394,"titles":395,"content":160,"level":144},"\u002Fblog\u002Flinux-common-commands#进程与系统管理","进程与系统管理",[60],{"id":397,"title":398,"titles":399,"content":400,"level":155},"\u002Fblog\u002Flinux-common-commands#进程查看与控制","进程查看与控制",[60,394],"ps aux                                   # 所有进程快照\nps aux --sort=-%mem | head -5            # 内存 TOP 5\ntop -o %MEM                              # 交互式进程监视\n\n# 按名称查找 PID\npgrep -f \"node app.js\"\npidof nginx\n\n# 终止进程\nkill -15 \u003CPID>                           # 优雅退出（SIGTERM）\nkill -9 \u003CPID>                            # 强制杀死（SIGKILL）\npkill -f \"node app.js\"                   # 按名称匹配杀死 kill -9 (SIGKILL) 无法被进程捕获，进程没有机会做资源清理、写日志或释放连接。应优先使用 kill -15 (SIGTERM)，只有在 SIGTERM 无效时才使用 kill -9。",{"id":402,"title":403,"titles":404,"content":405,"level":155},"\u002Fblog\u002Flinux-common-commands#后台运行","后台运行",[60,394],"nohup python server.py > output.log 2>&1 &\n# 或者使用 systemd 管理长期服务\n# 或者用 tmux\u002Fscreen 保持终端会话\n\n# 查看后台进程\njobs -l\nbg\u002Ffg                                    # 前后台切换",{"id":407,"title":408,"titles":409,"content":410,"level":155},"\u002Fblog\u002Flinux-common-commands#系统资源","系统资源",[60,394],"df -h                                    # 磁盘分区使用率\ndu -sh * | sort -rh | head -10           # 当前目录 TOP 10 大占用\nfree -h                                  # 内存占用\nuptime                                   # 运行时长 + 负载均值\nlscpu                                    # CPU 架构信息",{"id":412,"title":413,"titles":414,"content":415,"level":144},"\u002Fblog\u002Flinux-common-commands#网络诊断","网络诊断",[60],"# HTTP 请求\ncurl -v https:\u002F\u002Fapi.example.com          # 带请求\u002F响应头详情\ncurl -o file.zip -L https:\u002F\u002Fexample.com\u002Ffile.zip   # 下载并跟随重定向\ncurl -X POST -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"key\":\"value\"}' https:\u002F\u002Fapi.example.com\u002Fendpoint\n\n# 连接诊断\nping -c 4 google.com                     # 连通性 + 延迟\nss -tlnp                                 # 查看监听端口（现代版 netstat）\nnetstat -tulpn                           # 传统版（需要安装）\ntelnet host 80                           # 手动测试 TCP 端口\nnc -zv host 22 80 443                    # 批量端口探测\n\n# DNS 查询\nnslookup example.com\ndig example.com +short",{"id":417,"title":418,"titles":419,"content":420,"level":144},"\u002Fblog\u002Flinux-common-commands#权限管理","权限管理",[60],"chmod 755 script.sh                      # rwxr-xr-x（所属者可写，其他只读执行）\nchmod +x script.sh                       # 添加可执行权限\nchown user:group file.txt                # 修改所属用户和组\nchattr +i config.yaml                    # 锁定文件禁止修改（root 才能解除）\n\n# 查看权限\nls -l                                    # 第一列即权限位\nstat file.txt                            # 更详细的元信息",{"id":422,"title":423,"titles":424,"content":425,"level":144},"\u002Fblog\u002Flinux-common-commands#压缩与归档","压缩与归档",[60],"# tar（最通用）\ntar -czf archive.tar.gz dir\u002F             # 创建 .tar.gz\ntar -xzf archive.tar.gz                  # 解压\ntar -tf archive.tar.gz                   # 查看内容\n\n# zip（跨平台交换）\nzip -r archive.zip dir\u002F\nunzip -l archive.zip                     # 查看内容而不解压\nunzip archive.zip -d dest\u002F\n\n# 快速压缩单个文件\ngzip -k file.txt                         # 保留原文件\ngzip -d file.txt.gz                      # 解压",{"id":427,"title":428,"titles":429,"content":430,"level":144},"\u002Fblog\u002Flinux-common-commands#组合实战日志排查场景","组合实战：日志排查场景",[60],"# 场景：500 错误已经出现，需要找出所有 5xx 响应并分析\nzgrep -h \"HTTP\u002F1.1\\\" 5[0-9][0-9]\" access.log.2.gz access.log.1.gz access.log \\\n  | awk '{print $1}' \\\n  | sort \\\n  | uniq -c \\\n  | sort -rn \\\n  | head -20 这个管道组合做了： zgrep 并行搜索多个 .gz 和当前日志，匹配 HTTP 5xx 状态码awk 提取第一列（通常是客户端 IP）sort | uniq -c 统计每个 IP 的请求次数再 sort -rn 按次数降序排列head -20 取 TOP 20",{"id":432,"title":433,"titles":434,"content":160,"level":144},"\u002Fblog\u002Flinux-common-commands#常见陷阱","常见陷阱",[60],{"id":436,"title":437,"titles":438,"content":439,"level":155},"\u002Fblog\u002Flinux-common-commands#容易被误解的命令","容易被误解的命令",[60,433],"# 1. chmod 644 与 755 的含义不要搞混\n#    644 = rw-r--r--（文件默认安全权限）\n#    755 = rwxr-xr-x（目录和可执行脚本）\n\n# 2. cp 与 mv 的区别\n#    cp 复制，源文件保留\n#    mv 移动或重命名，源文件消失\n\n# 3. rm -rf 的谨慎使用\n#    习惯用 rm -ri 或先 ls 确认再删\n#    设置别名：alias rm='rm -i'\n\n# 4. tar -czf 与 -xzf 的参数顺序\n#    -f 必须在紧跟的归档文件名之前\n#    正确：tar -czf archive.tar.gz dir\u002F\n#    错误：tar -cfz archive.tar.gz dir\u002F",{"id":441,"title":442,"titles":443,"content":444,"level":155},"\u002Fblog\u002Flinux-common-commands#管道中变量失效","管道中变量失效",[60,433],"# 错误的写法\ncat file.txt | while read line; do\n  count=$((count + 1))\ndone\necho $count   # 输出 0！子 shell 变量不传回\n\n# 正确的写法\ncount=0\nwhile read line; do\n  count=$((count + 1))\ndone \u003C file.txt\necho $count   # 正确",{"id":446,"title":447,"titles":448,"content":449,"level":144},"\u002Fblog\u002Flinux-common-commands#总结","总结",[60],"Linux 命令行的核心能力不是记忆每个参数，而是理解三类思维方式： 组合思维 — 管道 | 连接小命令完成复杂任务文本思维 — 一切皆文本流，用 grep\u002Fsed\u002Fawk 处理结构化输出可逆思维 — 写脚本前先用 echo 或 --dry-run 验证意图 建议在新服务器上先做三件事： # 1. 设置安全别名\nalias rm='rm -i'\nalias mv='mv -i'\nalias cp='cp -i'\n\n# 2. 启用历史时间戳\nexport HISTTIMEFORMAT=\"%F %T \"\n\n# 3. 安装 tldr（简化版 man，适合快速回忆）\nnpm install -g tldr\n# 或 pip install tldr\n\n# 用法：tldr tar \u002F tldr find 后续可以继续深入的方向：Shell 脚本最佳实践、Vim 高效编辑、tmux 终端复用、以及 systemd 服务管理。 html pre.shiki code .skTid, html code.shiki .skTid{--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sW7EW, html code.shiki .sW7EW{--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .s5NuB, html code.shiki .s5NuB{--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sYBhb, html code.shiki .sYBhb{--shiki-default:#CE9178;--shiki-dark:#CE9178}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sfmjH, html code.shiki .sfmjH{--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .s215V, html code.shiki .s215V{--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sa4-K, html code.shiki .sa4-K{--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}html pre.shiki code .sBpJa, html code.shiki .sBpJa{--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .skSZV, html code.shiki .skSZV{--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}",{"id":76,"title":77,"titles":451,"content":78,"level":138},[],{"id":453,"title":454,"titles":455,"content":456,"level":144},"\u002Fblog\u002Fmpv-config-guide#配置体系","配置体系",[77],"mpv 按以下顺序加载配置，后覆盖前： 系统路径Linux~\u002F.config\u002Fmpv\u002Fmpv.confWindows%APPDATA%\\mpv\\mpv.confmacOS~\u002F.config\u002Fmpv\u002Fmpv.conf 语法：option=value，# 注释，行末不要有空格。profile 块用 [name] 定义。 目录结构： ~\u002F.config\u002Fmpv\u002F\n├── mpv.conf          # 主配置\n├── input.conf        # 按键绑定\n├── script-opts\u002F      # 脚本参数\n└── scripts\u002F          # Lua\u002FJavaScript 脚本",{"id":458,"title":459,"titles":460,"content":160,"level":144},"\u002Fblog\u002Fmpv-config-guide#视频核心","视频核心",[77],{"id":462,"title":463,"titles":464,"content":465,"level":155},"\u002Fblog\u002Fmpv-config-guide#输出驱动","输出驱动",[77,459],"vo=gpu-next            # 推荐，支持 Vulkan\u002FOpenGL\ngpu-api=vulkan         # 性能最好，Linux\u002FWindows 优先",{"id":467,"title":468,"titles":469,"content":470,"level":155},"\u002Fblog\u002Fmpv-config-guide#硬件解码","硬件解码",[77,459],"hwdec=nvdec            # NVIDIA 纯解码（省电）\nhwdec=cuda             # NVIDIA 更广兼容\nhwdec=vaapi            # Intel\u002FAMD Linux\nhwdec=d3d11va          # Intel Windows\nhwdec=videotoolbox-copy # macOS 花屏或绿屏时 hwdec=no 回退软件解码。",{"id":472,"title":473,"titles":474,"content":475,"level":155},"\u002Fblog\u002Fmpv-config-guide#画质","画质",[77,459],"scale=ewa_lanczossharp      # 放大\ndscale=mitchell             # 缩小\ncscale=bilinear             # 色度缩放\nlinear-scaling=yes          # 线性光域缩放\nsigmoid-upscaling=yes       # S 形上采样\ncorrect-downscaling=yes     # 修正缩小混叠\nicc-profile-auto=yes        # 加载校色文件\ntone-mapping=hable          # HDR→SDR 映射",{"id":477,"title":478,"titles":479,"content":480,"level":155},"\u002Fblog\u002Fmpv-config-guide#帧率同步","帧率同步",[77,459],"video-sync=display-resample\ninterpolation=yes                    # 运动插值\ninterpolation-past-frames=8\ninterpolation-future-frames=8",{"id":482,"title":483,"titles":484,"content":485,"level":144},"\u002Fblog\u002Fmpv-config-guide#音频","音频",[77],"ao=wasapi                   # Windows\naudio-normalize-downmix=yes\naudio-format=float\naudio-channels=auto\nvolume-max=200",{"id":487,"title":488,"titles":489,"content":490,"level":144},"\u002Fblog\u002Fmpv-config-guide#字幕","字幕",[77],"sub-auto=fuzzy\nsub-font=\"Source Han Sans SC\"\nsub-font-size=48\nsub-border-size=2\nsub-ass-override=force      # 覆盖 ASS 样式\nsub-shadow-offset=1.5",{"id":492,"title":493,"titles":494,"content":160,"level":144},"\u002Fblog\u002Fmpv-config-guide#性能调优","性能调优",[77],{"id":496,"title":497,"titles":498,"content":499,"level":155},"\u002Fblog\u002Fmpv-config-guide#缓存","缓存",[77,493],"cache=yes\ncache-default=50000          # 50MB\ncache-secs=300               # 网络流最大缓冲秒数",{"id":501,"title":502,"titles":503,"content":504,"level":155},"\u002Fblog\u002Fmpv-config-guide#加速参数","加速参数",[77,493],"# 低显存（4-6GB）\n--lowvram\n\n# 推荐平衡（8-12GB）\n--medvram --xformers --force-fp16\n\n# 高显存（24GB+）\n--highvram --use-sage-attention 各加速手段效果： 手段加速显存影响--xformers20-35%降 5-10%--force-fp1610-20%降 15-20%--use-sage-attention30-50%降 10-15%（FLUX） --xformers + --force-fp16 可能让部分节点输出 NaN，全黑图时先关 --force-fp16。",{"id":506,"title":507,"titles":508,"content":160,"level":144},"\u002Fblog\u002Fmpv-config-guide#场景模板","场景模板",[77],{"id":510,"title":511,"titles":512,"content":513,"level":155},"\u002Fblog\u002Fmpv-config-guide#通用高质量","通用高质量",[77,507],"vo=gpu-next\nhwdec=nvdec\nscale=ewa_lanczossharp\nlinear-scaling=yes\nsigmoid-upscaling=yes\nvideo-sync=display-resample\ninterpolation=yes\nsub-auto=fuzzy\nsave-position-on-quit=yes",{"id":515,"title":516,"titles":517,"content":518,"level":155},"\u002Fblog\u002Fmpv-config-guide#笔记本节能","笔记本节能",[77,507],"vo=gpu\nhwdec=nvdec\nscale=spline36\nlinear-scaling=no\ninterpolation=no\nframedrop=vo",{"id":520,"title":521,"titles":522,"content":523,"level":155},"\u002Fblog\u002Fmpv-config-guide#网络流","网络流",[77,507],"cache=yes\ncache-default=100000\ncache-pause-initial=yes\nforce-seekable=yes\nytdl-format=bestvideo[height\u003C=?1080]+bestaudio\u002Fbest html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .skTid, html code.shiki .skTid{--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sW7EW, html code.shiki .sW7EW{--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .s5NuB, html code.shiki .s5NuB{--shiki-default:#569CD6;--shiki-dark:#569CD6}",{"id":85,"title":86,"titles":525,"content":87,"level":138},[],{"id":527,"title":141,"titles":528,"content":529,"level":144},"\u002Fblog\u002Fnginx-config-guide#背景",[86],"Nginx 是生产环境中最常见的反向代理和 Web 服务器。无论是给 Node.js 应用做流量入口、托管前端静态资源、还是做负载均衡和 SSL 终结，Nginx 几乎是一线部署的标配。 本文按使用场景分类，给出可复用的配置模板和参数说明。Nginx 配置的核心是理解指令的作用域——http、server、location 三个层级逐层继承和覆盖。",{"id":531,"title":532,"titles":533,"content":534,"level":144},"\u002Fblog\u002Fnginx-config-guide#安装与基础验证","安装与基础验证",[86],"# Ubuntu \u002F Debian\nsudo apt update && sudo apt install nginx\n\n# CentOS \u002F RHEL\nsudo yum install nginx\n\n# macOS\nbrew install nginx\n\n# 验证安装\nnginx -v\nnginx -t                   # 检查配置文件语法",{"id":536,"title":537,"titles":538,"content":539,"level":144},"\u002Fblog\u002Fnginx-config-guide#配置文件结构","配置文件结构",[86],"Nginx 的配置按功能拆分到 conf.d\u002F 或 sites-available\u002F，避免一个文件过长。 \u002Fetc\u002Fnginx\u002F\n├── nginx.conf             # 主配置\n├── conf.d\u002F\n│   └── default.conf       # 通用站点配置\n├── sites-available\u002F       # Debian 风格：站点配置存放\n│   └── example.com\n├── sites-enabled\u002F         # 启用站点的软链接\n│   └── example.com -> ..\u002Fsites-available\u002Fexample.com\n└── modules-enabled\u002F       # 模块启用",{"id":541,"title":542,"titles":543,"content":544,"level":155},"\u002Fblog\u002Fnginx-config-guide#最小可用配置","最小可用配置",[86,537],"events {\n    worker_connections 1024;\n}\n\nhttp {\n    include mime.types;\n    default_type application\u002Foctet-stream;\n    sendfile on;\n\n    server {\n        listen 80;\n        server_name example.com;\n\n        root \u002Fvar\u002Fwww\u002Fexample.com;\n        index index.html;\n\n        location \u002F {\n            try_files $uri $uri\u002F \u002Findex.html;\n        }\n    }\n}",{"id":546,"title":547,"titles":548,"content":549,"level":144},"\u002Fblog\u002Fnginx-config-guide#反向代理最常用场景","反向代理（最常用场景）",[86],"将请求转发到后端应用，是 Nginx 最核心的用途。 server {\n    listen 80;\n    server_name api.example.com;\n\n    # 请求体大小限制（默认 1MB，API 通常需要调大）\n    client_max_body_size 10m;\n\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n\n        # WebSocket 支持\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n\n        # 超时控制\n        proxy_connect_timeout 60s;\n        proxy_send_timeout 60s;\n        proxy_read_timeout 60s;\n    }\n}",{"id":551,"title":552,"titles":553,"content":554,"level":155},"\u002Fblog\u002Fnginx-config-guide#代理关键指令说明","代理关键指令说明",[86,547],"指令作用proxy_pass后端地址，注意不带 \u002F 和带 \u002F 路径拼接规则不同proxy_set_header Host $host传递原始 Host，后端才能知道客户端请求的域名proxy_set_header X-Real-IP $remote_addr传递客户端真实 IPproxy_set_header X-Forwarded-For传递整条代理链的 IP 列表proxy_set_header X-Forwarded-Proto传递请求协议（http\u002Fhttps） proxy_pass http:\u002F\u002Fbackend — 不传原始 URI 的匹配部分\nproxy_pass http:\u002F\u002Fbackend\u002F — 传原始 URI，会拼接替换细节：location \u002Fapi\u002F {\n    proxy_pass http:\u002F\u002Fbackend\u002F;\n    # 请求 \u002Fapi\u002Fusers → http:\u002F\u002Fbackend\u002Fusers\n}\nlocation \u002Fapi\u002F {\n    proxy_pass http:\u002F\u002Fbackend;\n    # 请求 \u002Fapi\u002Fusers → http:\u002F\u002Fbackend\u002Fapi\u002Fusers\n}",{"id":556,"title":557,"titles":558,"content":559,"level":144},"\u002Fblog\u002Fnginx-config-guide#静态文件服务","静态文件服务",[86],"前端 SPA 打包后的资源用 Nginx 直接托管，性能远优于通过 Node.js 静态中间件。 server {\n    listen 80;\n    server_name app.example.com;\n\n    root \u002Fvar\u002Fwww\u002Fapp\u002Fdist;\n    index index.html;\n\n    # 静态资源缓存（带 hash 的文件名可长期缓存）\n    location \u002Fassets\u002F {\n        expires 1y;\n        add_header Cache-Control \"public, immutable\";\n    }\n\n    # SPA 路由回退\n    location \u002F {\n        try_files $uri $uri\u002F \u002Findex.html;\n    }\n\n    # 拒绝访问隐藏文件\n    location ~ \u002F\\. {\n        deny all;\n    }\n}",{"id":561,"title":562,"titles":563,"content":564,"level":144},"\u002Fblog\u002Fnginx-config-guide#https-与-tls-配置","HTTPS 与 TLS 配置",[86],"Certbot 配合 Let's Encrypt 是目前最推荐的证书管理方式。 # 安装 Certbot 并申请证书\nsudo apt install certbot python3-certbot-nginx\nsudo certbot --nginx -d example.com -d www.example.com\n\n# 仅获取证书，手动配置\nsudo certbot certonly --nginx -d example.com\n\n# 证书自动续期（Certbot 默认已添加 systemd timer）\nsudo certbot renew --dry-run server {\n    listen 443 ssl http2;\n    server_name example.com;\n\n    ssl_certificate     \u002Fetc\u002Fletsencrypt\u002Flive\u002Fexample.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fexample.com\u002Fprivkey.pem;\n\n    # 现代安全配置（2025+）\n    ssl_protocols TLSv1.2 TLSv1.3;\n    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;\n    ssl_prefer_server_ciphers off;\n\n    # HSTS\n    add_header Strict-Transport-Security \"max-age=63072000\" always;\n\n    # 会话缓存\n    ssl_session_cache shared:SSL:10m;\n    ssl_session_timeout 10m;\n\n    # OCSP Stapling\n    ssl_stapling on;\n    ssl_stapling_verify on;\n    resolver 8.8.8.8 1.1.1.1 valid=300s;\n    resolver_timeout 5s;\n\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\n\n# HTTP → HTTPS 重定向\nserver {\n    listen 80;\n    server_name example.com;\n    return 301 https:\u002F\u002F$host$request_uri;\n}",{"id":566,"title":567,"titles":568,"content":569,"level":144},"\u002Fblog\u002Fnginx-config-guide#负载均衡","负载均衡",[86],"将流量分发到多个后端实例，支持多种策略。 upstream backend {\n    # 默认轮询\n    server 10.0.0.1:3000 weight=3;    # 权重 3，承担更多请求\n    server 10.0.0.2:3000 weight=1;\n    server 10.0.0.3:3000 backup;      # 备用节点，其余不可用时启用\n\n    # 健康检查（需要 nginx-plus 或 ngx_http_upstream_check_module）\n    # keepalive 连接池\n    keepalive 64;\n}\n\nserver {\n    listen 80;\n    server_name api.example.com;\n\n    location \u002F {\n        proxy_pass http:\u002F\u002Fbackend;\n        proxy_http_version 1.1;\n        proxy_set_header Connection \"\";\n    }\n}",{"id":571,"title":572,"titles":573,"content":574,"level":155},"\u002Fblog\u002Fnginx-config-guide#负载均衡策略","负载均衡策略",[86,567],"# 轮询（默认）— 按顺序分配\nupstream backend {\n    server 10.0.0.1:3000;\n    server 10.0.0.2:3000;\n}\n\n# 最少连接 — 分配给当前活跃连接最少的节点\nupstream backend {\n    least_conn;\n    server 10.0.0.1:3000;\n    server 10.0.0.2:3000;\n}\n\n# IP Hash — 同一 IP 始终分配同一节点（适合会话保持）\nupstream backend {\n    ip_hash;\n    server 10.0.0.1:3000;\n    server 10.0.0.2:3000;\n}",{"id":576,"title":577,"titles":578,"content":160,"level":144},"\u002Fblog\u002Fnginx-config-guide#常见场景组合","常见场景组合",[86],{"id":580,"title":581,"titles":582,"content":583,"level":155},"\u002Fblog\u002Fnginx-config-guide#前后端分离部署同域名按路径分流","前后端分离部署（同域名，按路径分流）",[86,577],"server {\n    listen 80;\n    server_name example.com;\n\n    root \u002Fvar\u002Fwww\u002Fapp\u002Fdist;\n\n    # 前端 SPA\n    location \u002F {\n        try_files $uri $uri\u002F \u002Findex.html;\n    }\n\n    # API 代理到后端\n    location \u002Fapi\u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3000\u002F;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n    }\n\n    # WebSocket\n    location \u002Fws\u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n    }\n}",{"id":585,"title":586,"titles":587,"content":588,"level":155},"\u002Fblog\u002Fnginx-config-guide#限制访问速率","限制访问速率",[86,577],"# 定义限速区域（共享内存，10MB 存储客户端状态）\nlimit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r\u002Fs;\n\nserver {\n    location \u002Fapi\u002F {\n        limit_req zone=api_limit burst=20 nodelay;\n        proxy_pass http:\u002F\u002Fbackend;\n    }\n} 参数说明rate=10r\u002Fs平均每秒最多 10 个请求burst=20允许瞬时突发 20 个请求排队nodelay突发请求不延迟处理，但超过 burst 的请求直接返回 503",{"id":590,"title":591,"titles":592,"content":593,"level":155},"\u002Fblog\u002Fnginx-config-guide#屏蔽爬虫或恶意-ip","屏蔽爬虫或恶意 IP",[86,577],"# 屏蔽特定 User-Agent\nif ($http_user_agent ~* (curl|wget|python-requests|Go-http-client)) {\n    return 403;\n}\n\n# 屏蔽 IP 段\nlocation \u002Fadmin\u002F {\n    allow 192.168.1.0\u002F24;\n    allow 10.0.0.0\u002F8;\n    deny all;\n    proxy_pass http:\u002F\u002Fbackend;\n}",{"id":595,"title":493,"titles":596,"content":597,"level":144},"\u002Fblog\u002Fnginx-config-guide#性能调优",[86],"# 工作进程数 = CPU 核心数\nworker_processes auto;\n\nevents {\n    # 每个 worker 的最大并发连接数\n    worker_connections 4096;\n    # 启用高效事件模型\n    use epoll;\n    # 一次接受多个新连接\n    multi_accept on;\n}\n\nhttp {\n    # 高效文件传输\n    sendfile on;\n    tcp_nopush on;\n    tcp_nodelay on;\n\n    # 连接复用\n    keepalive_timeout 65;\n    keepalive_requests 1000;\n\n    # 缓冲区调优\n    client_body_buffer_size 128k;\n    client_max_body_size 10m;\n    proxy_buffer_size 4k;\n    proxy_buffers 8 16k;\n    proxy_busy_buffers_size 32k;\n\n    # Gzip 压缩\n    gzip on;\n    gzip_vary on;\n    gzip_proxied any;\n    gzip_comp_level 5;\n    gzip_min_length 256;\n    gzip_types\n        text\u002Fplain\n        text\u002Fcss\n        text\u002Fjavascript\n        application\u002Fjavascript\n        application\u002Fjson\n        application\u002Fxml\n        image\u002Fsvg+xml;\n\n    # 静态文件缓存\n    open_file_cache max=2000 inactive=20s;\n    open_file_cache_valid 60s;\n    open_file_cache_min_uses 2;\n    open_file_cache_errors off;\n}",{"id":599,"title":600,"titles":601,"content":602,"level":144},"\u002Fblog\u002Fnginx-config-guide#日志与调试","日志与调试",[86],"# 自定义日志格式\nlog_format main '$remote_addr - $remote_user [$time_local] \"$request\" '\n                '$status $body_bytes_sent \"$http_referer\" '\n                '\"$http_user_agent\" \"$http_x_forwarded_for\" '\n                'rt=$request_time uct=$upstream_connect_time '\n                'uht=$upstream_header_time urt=$upstream_response_time';\n\naccess_log \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log main;\nerror_log \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log warn;\n\n# 调试单个 location 的请求\nserver {\n    location \u002Fapi\u002F {\n        access_log \u002Fvar\u002Flog\u002Fnginx\u002Fapi.log main;\n        proxy_pass http:\u002F\u002Fbackend;\n    }\n}",{"id":604,"title":605,"titles":606,"content":607,"level":155},"\u002Fblog\u002Fnginx-config-guide#快速排障","快速排障",[86,600],"# 检查配置语法\nnginx -t\n\n# 重新加载配置（不停机）\nnginx -s reload\n\n# 查看活跃连接\ncurl http:\u002F\u002F127.0.0.1\u002Fnginx_status\n\n# 查看访问日志中 5xx 响应\ntail -f \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log | grep 'HTTP\u002F1.1\" 5[0-9][0-9]'\n\n# 测试代理是否正常工作\ncurl -H \"Host: api.example.com\" http:\u002F\u002F127.0.0.1\u002Fapi\u002Fhealth",{"id":609,"title":433,"titles":610,"content":160,"level":144},"\u002Fblog\u002Fnginx-config-guide#常见陷阱",[86],{"id":612,"title":613,"titles":614,"content":615,"level":155},"\u002Fblog\u002Fnginx-config-guide#_1-location-匹配优先级","1. Location 匹配优先级",[86,433],"# 匹配顺序不是配置文件中的先后顺序，而是：\n# = 精确匹配 > ^~ 前缀匹配 > ~* 正则匹配 > 普通前缀匹配\n\nlocation = \u002Fexact { ... }        # 1. 完全匹配（最高优先级）\nlocation ^~ \u002Fstatic\u002F { ... }    # 2. 前缀匹配，不检查正则\nlocation ~ \\.(jpg|png)$ { ... } # 3. 正则匹配（大小写敏感）\nlocation ~* \\.(jpg|png)$ { ... }# 4. 正则匹配（忽略大小写）\nlocation \u002Fapi\u002F { ... }           # 5. 普通前缀匹配\nlocation \u002F { ... }               # 6. 兜底 容易踩的坑：正则 location (~) 写在普通 location 前面时，会截走本应落到普通 location 的请求。",{"id":617,"title":618,"titles":619,"content":620,"level":155},"\u002Fblog\u002Fnginx-config-guide#_2-代理后端返回-502","2. 代理后端返回 502",[86,433],"检查以下几个方向： # 后端进程是否运行\ncurl http:\u002F\u002F127.0.0.1:3000\u002Fhealth\n\n# nginx 能否连接到后端地址（不要只看 127.0.0.1 通不通）\nss -tlnp | grep 3000\n\n# 是否有 SELinux 拦截（CentOS\u002FRHEL 常见）\nsudo setenforce 0    # 临时关闭测试 setenforce 0 会临时关闭 SELinux，降低系统安全级别。仅用于临时测试定位问题。生产环境应通过 sudo setsebool -P httpd_can_network_connect 1 永久解决，而不是保持 SELinux 关闭。 # 永久解决：sudo setsebool -P httpd_can_network_connect 1\n\n# 检查 nginx error log\ntail -20 \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log",{"id":622,"title":623,"titles":624,"content":625,"level":155},"\u002Fblog\u002Fnginx-config-guide#_3-ssl-证书路径权限","3. SSL 证书路径权限",[86,433],"ssl_certificate_key 文件的权限不能太开放，否则 nginx 启动会报 permission denied： sudo chmod 400 \u002Fetc\u002Fletsencrypt\u002Flive\u002Fexample.com\u002Fprivkey.pem\nsudo chown root:root \u002Fetc\u002Fletsencrypt\u002Flive\u002Fexample.com\u002Fprivkey.pem",{"id":627,"title":628,"titles":629,"content":630,"level":155},"\u002Fblog\u002Fnginx-config-guide#_4-x-forwarded-for-未正确传递","4. X-Forwarded-For 未正确传递",[86,433],"如果后端获取不到真实客户端 IP，检查 proxy_set_header 是否齐全。后端框架通常还需要额外配置才能信任 Nginx 传递的头部： # Nginx 端\nproxy_set_header X-Real-IP $remote_addr;\nproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\n# 后端（以 Express 为例）\napp.set('trust proxy', true);\n# 或\napp.set('trust proxy', 'loopback, 10.0.0.0\u002F8');",{"id":632,"title":447,"titles":633,"content":634,"level":144},"\u002Fblog\u002Fnginx-config-guide#总结",[86],"Nginx 配置可以按四个层次记忆： 站点接入 — server 块定义域名、端口、SSL请求路由 — location 块按路径匹配分流到静态文件、代理或 API流量控制 — upstream 负载均衡 + limit_req 限流性能与安全 — Gzip、缓存、CORS、HSTS、SSL 配置 大多数生产项目只需要一个 HTTPS 反向代理配置 + 一个静态文件配置，直接复用本文中的模板替换域名和端口即可上线。如果需要调试某个请求，先打开对应 location 的独立 access log，配合 nginx -t + nginx -s reload 快速迭代验证。 html pre.shiki code .skTid, html code.shiki .skTid{--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sW7EW, html code.shiki .sW7EW{--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sYBhb, html code.shiki .sYBhb{--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .s215V, html code.shiki .s215V{--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .s5NuB, html code.shiki .s5NuB{--shiki-default:#569CD6;--shiki-dark:#569CD6}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sfmjH, html code.shiki .sfmjH{--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}",{"id":109,"title":110,"titles":636,"content":111,"level":138},[],{"id":638,"title":141,"titles":639,"content":640,"level":144},"\u002Fblog\u002Fopenopenwf-analysis#背景",[110],"OpenWF 是 Warframe 私服项目。原版启动器用 WinDivert 在网络驱动层拦截流量。OpenWF Enabler 是替代方案：用户态 DLL 注入 + API Hook，不依赖驱动。 项目三个组件： openopenlauncher.exe  ── Win32 GUI 启动器（选 Warframe 路径、语言、注入 DLL）\nopenopenwf.dll        ── 核心重定向模块（注入到 Warframe 进程）\nopenopenclr.dll (C#)  ── 可选调试检查器 注入流程：挂起创建 Warframe 进程 → VirtualAllocEx 写入 DLL 路径 → CreateRemoteThread 调 LoadLibraryW 加载 DLL → Hook 主线程入口点完成初始化。",{"id":642,"title":643,"titles":644,"content":645,"level":144},"\u002Fblog\u002Fopenopenwf-analysis#入口点-hook","入口点 Hook",[110],"DllMain 限制严格，不能做大部分初始化。项目在 DllMain 中劫持 PE 入口点，让初始化代码在主线程上下文中执行： static void HookEntryPoint()\n{\n    PIMAGE_DOS_HEADER hdr = (PIMAGE_DOS_HEADER)GetModuleHandleA(nullptr);\n    PIMAGE_NT_HEADERS64 nt = (PIMAGE_NT_HEADERS64)((char*)hdr + hdr->e_lfanew);\n    g_entryPointAddress = (char*)hdr + nt->OptionalHeader.AddressOfEntryPoint;\n    \u002F\u002F 覆盖入口点为 jmp → trampoline → HookedEntryPoint\n    memcpy(g_entryPointAddress, entryPointOverwriteBytes, sizeof(entryPointOverwriteBytes));\n} HookedEntryPoint 执行 LoadConfig → PlaceHooks → InitCLR，然后恢复原始入口点，让游戏继续启动。",{"id":647,"title":648,"titles":649,"content":650,"level":144},"\u002Fblog\u002Fopenopenwf-analysis#minhook-api-拦截","MinHook API 拦截",[110],"项目用 MinHook 在系统调用层拦截网络请求，重定向到本地 OpenWF 服务器。",{"id":652,"title":653,"titles":654,"content":655,"level":155},"\u002Fblog\u002Fopenopenwf-analysis#dns-劫持","DNS 劫持",[110,648],"static INT WSAAPI NEW_getaddrinfo(PCSTR pNodeName, ...)\n{\n    if (pNodeName) {\n        std::string url = pNodeName;\n        for (auto& c : url) c = std::tolower(c);\n        if (url.find(\"warframe\") != std::wstring::npos)\n            return OLD_getaddrinfo(g_Config.serverHost.c_str(), ...);\n    }\n    return OLD_getaddrinfo(pNodeName, ...);\n} getaddrinfo 和 GetAddrInfoExW 同时 Hook，域名含 \"warframe\" 时解析到 serverHost（默认 127.0.0.1）。",{"id":657,"title":658,"titles":659,"content":660,"level":155},"\u002Fblog\u002Fopenopenwf-analysis#ssl-绕过","SSL 绕过",[110,648],"static int NEW_X509_verify_cert(void* ctx) { return 1; }\nstatic int NEW_Curl_ossl_verifyhost(void* ctx) { return 0; }\nstatic int NEW_WorldStateVerify(void* a1, void* a2) { return 1; } 直接返回成功，跳过证书校验和世界状态签名验证。",{"id":662,"title":663,"titles":664,"content":665,"level":155},"\u002Fblog\u002Fopenopenwf-analysis#aes-密钥劫持","AES 密钥劫持",[110,648],"Warframe 部分请求用随机 AES-192 密钥加密，RSA 公钥加密传输。Hook RSA 函数，替换密钥为已知值： static int NEW_rsa_ossl_public_encrypt(int flen, unsigned char* from, ...)\n{\n    if (flen == 40 && padding == 4) { \u002F\u002F IV(16) + Key(24)\n        memset(from, 0x41, flen);    \u002F\u002F → AAAAAAAAAAAAAAAAAAAA...\n        memset(to, 0x41, 128);\n        return 128;\n    }\n    return OLD_rsa_ossl_public_encrypt(flen, from, to, rsa, padding);\n} OpenWF 服务器用已知密钥 AAAAAAAAAAAAAAAAAAAAAAAA（Key）+ AAAAAAAAAAAAAAAA（IV）解密。",{"id":667,"title":668,"titles":669,"content":670,"level":155},"\u002Fblog\u002Fopenopenwf-analysis#请求-url-修改","请求 URL 修改",[110,648],"拦截 SendPostRequest \u002F SendGetRequest，替换域名并附加 OpenWF 参数（buildLabel、clientMod）。",{"id":672,"title":673,"titles":674,"content":675,"level":144},"\u002Fblog\u002Fopenopenwf-analysis#内存签名扫描","内存签名扫描",[110],"Warframe 更新会改变函数地址。项目用特征码扫描在内存中定位目标函数： std::vector\u003Cunsigned char*> SignatureScan(const char* pattern, const char* mask,\n    unsigned char* data, size_t length)\n{\n    std::vector\u003Cunsigned char*> results;\n    for (size_t i = 0; i \u003C length - strlen(pattern); ++i) {\n        bool match = true;\n        for (size_t j = 0; j \u003C strlen(pattern); ++j)\n            if (mask[j] == 'x' && data[i+j] != (unsigned char)pattern[j])\n                { match = false; break; }\n        if (match) results.push_back(data + i);\n    }\n    return results;\n} PlaceHooks() 中进行近 20 次签名扫描。x 表示精确匹配，? 通配。",{"id":677,"title":678,"titles":679,"content":680,"level":144},"\u002Fblog\u002Fopenopenwf-analysis#clr-inspector","CLR Inspector",[110],"C++ 进程内宿主 .NET 运行时，运行 C# 检查器，通过原生事件队列通信。可查看 Warframe 对象类型列表、类型属性、继承关系。",{"id":682,"title":683,"titles":684,"content":685,"level":144},"\u002Fblog\u002Fopenopenwf-analysis#稳定性","稳定性",[110],"启动时验证进程名是否为 Warframe.x64.exe签名扫描失败时 FATAL_EXIT 明确报错函数地址对齐到 0x...0 边界防止 Hook 越界 #define FATAL_EXIT(s) OpenWFFatalExit(s, __FUNCTION__, __FILE__, __LINE__)",{"id":687,"title":339,"titles":688,"content":689,"level":144},"\u002Fblog\u002Fopenopenwf-analysis#注意事项",[110],"私服与进程注入工具仅用于学习研究。使用前阅读 Digital Extremes 服务条款。 支持 Warframe 42.0+，更新后可能需要更新特征码不可与官方 OpenWF Bootstrapper 共存仅支持请求重定向，不支持脚本\u002F内容修改需同时部署 OpenWF 服务器实例 项目地址：github.com\u002Fmskimi7\u002Fopenopenwf html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":39,"title":40,"titles":691,"content":41,"level":138},[],{"id":693,"title":141,"titles":694,"content":695,"level":144},"\u002Fblog\u002Fpm2-process-manager-guide#背景",[40],"Node.js 应用部署到生产环境后，需要一个可靠的守护进程来处理崩溃重启、日志管理、多核负载和零停机更新。PM2 是目前最成熟的方案之一，内置了负载均衡、监控仪表盘和开机自启支持。 本文覆盖从单次启动到生产级配置的完整路径，大部分场景不需要安装其他工具。",{"id":697,"title":698,"titles":699,"content":700,"level":144},"\u002Fblog\u002Fpm2-process-manager-guide#安装与基础使用","安装与基础使用",[40],"# 全局安装\nnpm install -g pm2\n\n# 验证版本\npm2 --version\n\n# 启动一个 Node.js 应用\npm2 start app.js\npm2 start app.js --name my-api          # 指定进程名称\npm2 start app.js -i max                 # 以集群模式启动，使用所有 CPU 核心\npm2 start app.js -- --port=3001         # 向应用传递参数 PM2 默认在后台运行。首次启动后可以用 pm2 save 保存当前进程列表，配合 pm2 startup 实现服务器重启后自动恢复。",{"id":702,"title":703,"titles":704,"content":705,"level":144},"\u002Fblog\u002Fpm2-process-manager-guide#常用命令速查","常用命令速查",[40],"# 进程管理\npm2 list              # 查看所有进程状态\npm2 show my-api       # 查看单个进程的详细信息\npm2 logs              # 实时查看所有日志\npm2 logs my-api       # 查看指定进程日志\npm2 monit            # 终端监控面板（CPU \u002F 内存实时曲线）\n\n# 生命周期\npm2 restart my-api    # 重启\npm2 reload my-api     # 零停机重载（集群模式）\npm2 stop my-api       # 停止\npm2 delete my-api     # 从 PM2 列表中移除\n\n# 批量操作\npm2 restart all       # 重启所有进程\npm2 stop all          # 停止所有进程\npm2 delete all        # 清空所有进程",{"id":707,"title":708,"titles":709,"content":710,"level":155},"\u002Fblog\u002Fpm2-process-manager-guide#零停机重载-vs-重启","零停机重载 vs 重启",[40,703],"操作行为适用场景restart杀死进程 → 启动新进程（有短暂停机）单实例、开发环境reload逐个 worker 重启，始终保持至少一个在线生产环境集群模式gracefulReload等待现有请求处理完毕再重启长连接、WebSocket",{"id":712,"title":713,"titles":714,"content":715,"level":155},"\u002Fblog\u002Fpm2-process-manager-guide#日志管理","日志管理",[40,703],"# 查看日志\npm2 logs --lines 200                     # 显示最近 200 行\npm2 logs my-api --err                    # 只看错误日志\npm2 flush                                # 清空所有日志\n\n# 日志轮转（内置模块）\npm2 install pm2-logrotate\n\n# 配置轮转参数\npm2 set pm2-logrotate:max_size 50M       # 单文件上限\npm2 set pm2-logrotate:retain 7           # 保留最近 7 个归档\npm2 set pm2-logrotate:compress true      # 归档后 gzip 压缩",{"id":717,"title":718,"titles":719,"content":720,"level":144},"\u002Fblog\u002Fpm2-process-manager-guide#ecosystem-配置文件","Ecosystem 配置文件",[40],"对于正式项目，应该使用 ecosystem.config.js 替代命令行参数。这个文件应该提交到版本库。 module.exports = {\n  apps: [{\n    name: 'api-server',\n    script: 'dist\u002Fmain.js',\n    instances: 'max',\n    exec_mode: 'cluster',\n    env: {\n      NODE_ENV: 'production',\n      PORT: 3000,\n    },\n    env_development: {\n      NODE_ENV: 'development',\n      PORT: 3001,\n      watch: ['src'],\n      watch_delay: 1000,\n      ignore_watch: ['node_modules', 'dist', 'logs'],\n    },\n    \u002F\u002F 错误处理\n    max_restarts: 10,\n    restart_delay: 5000,\n    min_uptime: '30s',\n    \u002F\u002F 日志\n    error_file: '.\u002Flogs\u002Ferr.log',\n    out_file: '.\u002Flogs\u002Fout.log',\n    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',\n    merge_logs: true,\n    \u002F\u002F 优雅退出\n    kill_timeout: 5000,\n    listen_timeout: 3000,\n    \u002F\u002F 健康检查\n    max_memory_restart: '500M',\n  }],\n} 启动时选择环境： pm2 start ecosystem.config.js                  # 默认使用 env\npm2 start ecosystem.config.js --env development # 使用 env_development",{"id":722,"title":723,"titles":724,"content":725,"level":144},"\u002Fblog\u002Fpm2-process-manager-guide#集群模式详解","集群模式详解",[40],"Node.js 是单线程的，一台服务器有多少个 CPU 核心，理论上应该启动多少个 worker 来充分利用硬件。 instances: 'max',      \u002F\u002F 自动检测 CPU 核心数\ninstances: 4,           \u002F\u002F 手动指定数量\ninstances: 0,           \u002F\u002F 与 max 相同 集群模式下 reload 的执行流程： worker 1 ████████░░░░    ← 正在服务的连接\nworker 2 ████████░░░░\nworker 3 ████████░░░░\nworker 4 ████████░░░░\n\npm2 reload api-server\n\nworker 1 ████████░░░░   ← 正在关闭\nworker 2 ░░░░░░░░░░░░   ← 已启动新版\nworker 3 ████████░░░░   ← 正在关闭\nworker 4 ░░░░░░░░░░░░   ← 已启动新版 这个过程逐个替换 worker，始终保持有 worker 在响应请求。 集群模式要求应用无状态。Session、Socket 连接等状态数据不能保存在进程内存中，必须使用 Redis 或数据库等外部存储。",{"id":727,"title":728,"titles":729,"content":730,"level":144},"\u002Fblog\u002Fpm2-process-manager-guide#开机自启","开机自启",[40],"# 生成系统自启脚本\npm2 startup\n\n# 保存当前进程列表（重启后自动恢复）\npm2 save\n\n# 查看已保存的进程\npm2 resurrect pm2 startup 会自动检测系统初始化系统（systemd \u002F launchd \u002F rc.d）并生成对应的脚本。",{"id":732,"title":733,"titles":734,"content":735,"level":144},"\u002Fblog\u002Fpm2-process-manager-guide#部署搭配-git-的远程部署","部署：搭配 Git 的远程部署",[40],"PM2 内置了 deploy 功能，支持从 Git 拉取代码并自动重启。 module.exports = {\n  apps: [{\n    name: 'api',\n    script: 'dist\u002Fmain.js',\n  }],\n  deploy: {\n    production: {\n      user: 'deploy',\n      host: ['192.168.1.100'],\n      ref: 'origin\u002Fmain',\n      repo: 'git@github.com:user\u002Fproject.git',\n      path: '\u002Fopt\u002Fapp\u002Fapi',\n      'pre-deploy': 'git fetch --all',\n      'post-deploy': 'pnpm install && pnpm build && pm2 reload ecosystem.config.js',\n      'pre-setup': 'echo \"Starting deployment...\"',\n    },\n  },\n} # 首次部署\npm2 deploy production setup\n\n# 后续更新\npm2 deploy production",{"id":737,"title":738,"titles":739,"content":740,"level":144},"\u002Fblog\u002Fpm2-process-manager-guide#监控与告警","监控与告警",[40],"# 终端监控面板\npm2 monit\n\n# 基于 Keymetrics 的 Web 仪表盘（免费额度足够个人项目）\npm2 link \u003Csecret> \u003Cpublic-key>\n\n# 自定义指标（在应用代码中）\nconst io = require('@pm2\u002Fio')\nio.counter('requests\u002Fmin').inc()\nio.meter('req_rate').mark()\nio.histogram('response_time').update(duration) 也可以直接通过 pm2 describe 和日志系统对接外部监控（Prometheus + Grafana 或自建告警脚本）。",{"id":742,"title":743,"titles":744,"content":160,"level":144},"\u002Fblog\u002Fpm2-process-manager-guide#常见问题","常见问题",[40],{"id":746,"title":747,"titles":748,"content":749,"level":155},"\u002Fblog\u002Fpm2-process-manager-guide#内存泄漏自动重启","内存泄漏自动重启",[40,743],"max_memory_restart: '500M',   \u002F\u002F 达到 500MB 时自动重启",{"id":751,"title":752,"titles":753,"content":754,"level":155},"\u002Fblog\u002Fpm2-process-manager-guide#日志时间戳缺失","日志时间戳缺失",[40,743],"确保 ecosystem.config.js 中设置了 log_date_format，否则日志中只有原始文本没有时间。",{"id":756,"title":757,"titles":758,"content":759,"level":155},"\u002Fblog\u002Fpm2-process-manager-guide#端口占用","端口占用",[40,743],"# 找出占用端口的进程\nlsof -i :3000\n# 或\nss -tlnp | grep 3000 kill -9 (SIGKILL) 会强制杀死进程，进程没有机会做优雅关闭。应优先使用 kill -15 (SIGTERM) 或通过 PM2 的 pm2 stop 进行受控停止。 kill -9 \u003CPID>",{"id":761,"title":762,"titles":763,"content":764,"level":155},"\u002Fblog\u002Fpm2-process-manager-guide#pm2-命令找不到","PM2 命令找不到",[40,743],"# 检查全局 node_modules 路径是否正确\nnpm root -g\n# 如果指向非预期目录，设置 N_PREFIX 或重新安装 Node",{"id":766,"title":767,"titles":768,"content":769,"level":155},"\u002Fblog\u002Fpm2-process-manager-guide#重启频率过高保护","重启频率过高保护",[40,743],"PM2 默认在短时间内反复崩溃时会自动停止尝试，避免进入 crash loop。通过 max_restarts 和 restart_delay 控制： max_restarts: 10,      \u002F\u002F 30 秒内最多重启次数\nrestart_delay: 5000,   \u002F\u002F 每次重启间隔 5 秒",{"id":771,"title":447,"titles":772,"content":773,"level":144},"\u002Fblog\u002Fpm2-process-manager-guide#总结",[40],"PM2 的核心配置可以归结为三点： 进程守护 — pm2 start + pm2 startup + pm2 save，确保应用随系统启动并在崩溃后自动恢复集群模式 — instances: 'max' + exec_mode: 'cluster'，利用多核 CPU优雅运维 — 用 ecosystem.config.js 替代命令行，用 reload 替代 restart，用 pm2-logrotate 管理日志 推荐的新项目入口配置模板见上方的 ecosystem.config.js，大多数场景直接复制修改 env 环境变量和项目名称即可使用。 html pre.shiki code .skTid, html code.shiki .skTid{--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sW7EW, html code.shiki .sW7EW{--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sYBhb, html code.shiki .sYBhb{--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .s5NuB, html code.shiki .s5NuB{--shiki-default:#569CD6;--shiki-dark:#569CD6}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sfmjH, html code.shiki .sfmjH{--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sx6KH, html code.shiki .sx6KH{--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .s215V, html code.shiki .s215V{--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .skSZV, html code.shiki .skSZV{--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .s1R3v, html code.shiki .s1R3v{--shiki-default:#C8C8C8;--shiki-dark:#C8C8C8}",{"id":49,"title":50,"titles":775,"content":51,"level":138},[],{"id":777,"title":778,"titles":779,"content":160,"level":144},"\u002Fblog\u002Fpostgresql-commands-guide#连接与基础操作","连接与基础操作",[50],{"id":781,"title":782,"titles":783,"content":784,"level":155},"\u002Fblog\u002Fpostgresql-commands-guide#连接数据库","连接数据库",[50,778],"# 连接到本地数据库\npsql -U postgres -d mydb\n\n# 连接到远程数据库\npsql -h db.example.com -p 5432 -U app_user -d app_db\n\n# 使用连接字符串\npsql \"postgresql:\u002F\u002Fapp_user:password@db.example.com:5432\u002Fapp_db?sslmode=require\"\n\n# 直接在命令行执行 SQL\npsql -U postgres -d mydb -c \"SELECT NOW();\"\npsql -U postgres -d mydb -f dump.sql     # 执行 SQL 文件",{"id":786,"title":787,"titles":788,"content":789,"level":155},"\u002Fblog\u002Fpostgresql-commands-guide#psql-常用元命令","psql 常用元命令",[50,778],"\\l                    # 列出所有数据库\n\\c mydb               # 切换到 mydb\n\\d                    # 列出当前 schema 的所有表、视图、序列\n\\d tablename          # 查看表结构（列、类型、约束、索引）\n\\di                   # 列出所有索引\n\\du                   # 列出所有用户\u002F角色\n\\dn                   # 列出所有 schema\n\\df                   # 列出所有函数\n\\dv                   # 列出所有视图\n\\dt                   # 只列出表\n\\db                   # 列出表空间\n\\l+                   # 显示更详细的数据库信息（包括大小、编码）\n\n\\i \u002Fpath\u002Fto\u002Ffile.sql  # 执行 SQL 文件\n\\o \u002Fpath\u002Fto\u002Foutput    # 将查询结果写入文件\n\\e                    # 用外部编辑器编辑查询\n\\x                    # 切换扩展显示（行转列，适合宽表）\n\\x auto               # 自动选择显示模式\n\\timing               # 显示每条 SQL 的执行时间\n\\conninfo             # 显示当前连接信息\n\\! clear              # 执行 shell 命令（清屏）",{"id":791,"title":792,"titles":793,"content":794,"level":144},"\u002Fblog\u002Fpostgresql-commands-guide#数据库与用户管理","数据库与用户管理",[50],"-- 创建数据库\nCREATE DATABASE mydb WITH ENCODING 'UTF8' LC_COLLATE 'zh_CN.UTF-8' LC_CTYPE 'zh_CN.UTF-8';\n\n-- 创建用户并授权\nCREATE USER app_user WITH PASSWORD 'secure_password';\nGRANT ALL PRIVILEGES ON DATABASE mydb TO app_user;\n\n-- 授予 schema 级别权限（连接数据库后还需要 schema 权限）\n\\c mydb\nGRANT ALL ON SCHEMA public TO app_user;\nGRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO app_user;\nGRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO app_user;\n\n-- 修改用户属性\nALTER USER app_user WITH CONNECTION LIMIT 50;        -- 限制并发连接数\nALTER USER app_user VALID UNTIL '2027-01-01';        -- 设置密码过期时间\n\n-- 查看当前连接\nSELECT pid, usename, application_name, client_addr, state, query\nFROM pg_stat_activity\nWHERE datname = 'mydb';",{"id":796,"title":797,"titles":798,"content":160,"level":144},"\u002Fblog\u002Fpostgresql-commands-guide#表操作与常用查询","表操作与常用查询",[50],{"id":800,"title":801,"titles":802,"content":803,"level":155},"\u002Fblog\u002Fpostgresql-commands-guide#建表与约束","建表与约束",[50,797],"CREATE TABLE users (\n    id          BIGSERIAL PRIMARY KEY,\n    username    VARCHAR(64) NOT NULL UNIQUE,\n    email       VARCHAR(255) NOT NULL,\n    status      SMALLINT NOT NULL DEFAULT 1,\n    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n    CONSTRAINT chk_status CHECK (status IN (0, 1, 2))\n);\n\n-- 添加索引\nCREATE INDEX idx_users_email ON users (email);\nCREATE INDEX idx_users_created_at ON users (created_at DESC);\n\n-- 部分索引（只索引活跃用户）\nCREATE INDEX idx_users_active ON users (created_at) WHERE status = 1;\n\n-- 唯一复合索引\nCREATE UNIQUE INDEX idx_users_email_status ON users (email, status);",{"id":805,"title":806,"titles":807,"content":808,"level":155},"\u002Fblog\u002Fpostgresql-commands-guide#常用查询模式","常用查询模式",[50,797],"-- 分页查询（游标分页优于 OFFSET 分页）\n-- 游标分页：WHERE id > $last_seen_id ORDER BY id LIMIT 20\n-- OFFSET 分页在深翻页时性能急剧下降\nSELECT * FROM users WHERE id > 1000 ORDER BY id LIMIT 20;\n\n-- 去重统计\nSELECT DATE_TRUNC('day', created_at) AS day, COUNT(DISTINCT user_id)\nFROM orders\nWHERE created_at >= NOW() - INTERVAL '7 days'\nGROUP BY day\nORDER BY day;\n\n-- 窗口函数：分组 TOP N\nSELECT * FROM (\n    SELECT *,\n        ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY score DESC) AS rn\n    FROM products\n) ranked WHERE rn \u003C= 5;\n\n-- CTE 递归查询（树形结构）\nWITH RECURSIVE org_tree AS (\n    SELECT id, name, parent_id, 1 AS depth\n    FROM departments WHERE parent_id IS NULL\n    UNION ALL\n    SELECT d.id, d.name, d.parent_id, t.depth + 1\n    FROM departments d JOIN org_tree t ON d.parent_id = t.id\n)\nSELECT * FROM org_tree ORDER BY depth, id;",{"id":810,"title":811,"titles":812,"content":160,"level":144},"\u002Fblog\u002Fpostgresql-commands-guide#索引与性能诊断","索引与性能诊断",[50],{"id":814,"title":815,"titles":816,"content":817,"level":155},"\u002Fblog\u002Fpostgresql-commands-guide#查看查询计划","查看查询计划",[50,811],"-- 分析查询执行计划\nEXPLAIN ANALYZE\nSELECT * FROM orders WHERE user_id = 123 AND created_at > '2026-01-01';\n\n-- 重点关注的指标：\n-- Seq Scan on large_table  → 需要加索引\n-- Index Scan               → 正在使用索引，效果良好\n-- Bitmap Heap Scan         → 多索引组合，还可接受\n-- Sort Method: external    → 排序内存不足，需要增加 work_mem\n-- Rows Removed by Filter   → 大量行被过滤，索引选择性不够",{"id":819,"title":820,"titles":821,"content":822,"level":155},"\u002Fblog\u002Fpostgresql-commands-guide#索引维护","索引维护",[50,811],"-- 查看表的大小和索引使用情况\nSELECT\n    relname AS table_name,\n    pg_size_pretty(pg_total_relation_size(relid)) AS total_size,\n    pg_size_pretty(pg_relation_size(relid)) AS table_size,\n    pg_size_pretty(pg_indexes_size(relid)) AS indexes_size,\n    n_live_tup AS row_count\nFROM pg_stat_user_tables\nORDER BY pg_total_relation_size(relid) DESC;\n\n-- 查找未使用的索引（pg_stat_user_indexes 的 idx_scan 接近 0 的索引考虑删除）\nSELECT\n    schemaname, tablename, indexname, idx_scan, idx_tup_read,\n    pg_size_pretty(pg_relation_size(indexrelid)) AS index_size\nFROM pg_stat_user_indexes\nWHERE idx_scan \u003C 100\nORDER BY idx_scan ASC, pg_relation_size(indexrelid) DESC;\n\n-- 重建索引（避免索引膨胀）\nREINDEX INDEX idx_users_email;\nREINDEX TABLE users;",{"id":824,"title":825,"titles":826,"content":827,"level":155},"\u002Fblog\u002Fpostgresql-commands-guide#常见慢查询原因","常见慢查询原因",[50,811],"-- 当前运行的慢查询\nSELECT pid, NOW() - pg_stat_activity.query_start AS duration, query, state\nFROM pg_stat_activity\nWHERE state != 'idle'\n  AND NOW() - pg_stat_activity.query_start > INTERVAL '5 seconds'\nORDER BY duration DESC; 现象常见原因对策Seq Scan on 大表缺少索引或查询条件不匹配索引根据 WHERE 条件创建索引Bitmap Heap Scan 过多查询条件组合复杂创建复合索引排序导致临时文件work_mem 太小增加 work_mem索引未被使用数据类型不匹配或函数包裹了字段避免 WHERE DATE(col) = ...Nested Loop 嵌套过深多表 JOIN 缺少索引在 JOIN 列上建索引 不要在索引列上包裹函数，例如 WHERE DATE(created_at) = '2026-01-01' 会使索引失效。应使用范围查询：WHERE created_at >= '2026-01-01' AND created_at \u003C '2026-01-02'。",{"id":829,"title":830,"titles":831,"content":832,"level":144},"\u002Fblog\u002Fpostgresql-commands-guide#备份与恢复","备份与恢复",[50],"# 备份单个数据库（自定义格式，支持压缩和并行）\npg_dump -U postgres -Fc -j 4 mydb > mydb.dump\n\n# 备份单个表\npg_dump -U postgres -t users -Fc mydb > users.dump\n\n# 备份所有数据库\npg_dumpall -U postgres > all_databases.sql\n\n# 恢复自定义格式备份\npg_restore -U postgres -d mydb -j 4 mydb.dump\npg_restore -U postgres -d mydb -t users users.dump   # 恢复特定表\n\n# SQL 格式备份恢复\npsql -U postgres -d mydb \u003C dump.sql\n\n# 远程备份\npg_dump -h prod.example.com -U app_user -Fc mydb > prod_backup.dump",{"id":834,"title":835,"titles":836,"content":837,"level":155},"\u002Fblog\u002Fpostgresql-commands-guide#备份策略建议","备份策略建议",[50,830],"以下 cron 示例中 % 需要转义，这是 crontab 的语法要求： # 每天凌晨 3 点执行完整备份并保留 7 天\n0 3 * * * pg_dump -U postgres -Fc -j 4 mydb > \u002Fbackups\u002Fmydb_$(date +\\%Y\\%m\\%d).dump && \\\n          find \u002Fbackups -name \"mydb_*.dump\" -mtime +7 -delete 生产环境建议使用 .pgpass 文件管理密码，避免在脚本中明文写入；定期验证备份文件的可用性（pg_restore --list 可列出备份内容而不实际恢复）。",{"id":839,"title":840,"titles":841,"content":160,"level":144},"\u002Fblog\u002Fpostgresql-commands-guide#事务与锁排查","事务与锁排查",[50],{"id":843,"title":844,"titles":845,"content":846,"level":155},"\u002Fblog\u002Fpostgresql-commands-guide#事务隔离级别","事务隔离级别",[50,840],"-- 查看当前事务隔离级别\nSHOW transaction_isolation;\n\n-- 设置事务隔离级别\nBEGIN;\nSET TRANSACTION ISOLATION LEVEL REPEATABLE READ;\n-- 执行查询...\nCOMMIT; PostgreSQL 默认使用 READ COMMITTED，对大多数应用已经足够。SERIALIZABLE 提供最强一致性保证，但并发性能会显著下降。",{"id":848,"title":849,"titles":850,"content":851,"level":155},"\u002Fblog\u002Fpostgresql-commands-guide#锁等待排查","锁等待排查",[50,840],"-- 查看锁等待的会话\nSELECT\n    blocked.pid AS blocked_pid,\n    blocked.query AS blocked_query,\n    blocking.pid AS blocking_pid,\n    blocking.query AS blocking_query,\n    blocked_age.age AS blocked_duration\nFROM pg_stat_activity blocked\nJOIN pg_locks blocked_locks ON blocked.pid = blocked_locks.pid\nJOIN pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype\n    AND blocking_locks.database = blocked_locks.database\n    AND blocking_locks.relation = blocked_locks.relation\n    AND blocking_locks.pid != blocked.pid\nJOIN pg_stat_activity blocking ON blocking.pid = blocking_locks.pid\nCROSS JOIN LATERAL (\n    SELECT NOW() - blocked.query_start AS age\n) blocked_age\nWHERE NOT blocked_locks.granted;\n\n-- 终止阻塞的会话（谨慎使用）\nSELECT pg_terminate_backend(\u003Cblocking_pid>); pg_terminate_backend 会强制杀死后台进程，可能导致未提交的事务回滚。在生产环境中执行前请确认影响。",{"id":853,"title":854,"titles":855,"content":856,"level":144},"\u002Fblog\u002Fpostgresql-commands-guide#配置调优","配置调优",[50],"以下参数默认值偏保守，适合开发环境。生产服务器应根据硬件调整。 -- 查看当前配置\nSHOW shared_buffers;\nSHOW work_mem;\nSHOW effective_cache_size;\nSHOW maintenance_work_mem;\nSHOW random_page_cost;\n\n-- 建议配置（以 16GB RAM 服务器为例）\n-- 修改 postgresql.conf 后需要重启 # 内存配置\nshared_buffers = 4GB              # 总内存的 25%\neffective_cache_size = 12GB       # 总内存的 75%（OS 缓存估算）\nwork_mem = 64MB                   # 每个查询排序可用内存\nmaintenance_work_mem = 1GB        # VACUUM、CREATE INDEX 可用内存\n\n# 写入配置\nwal_buffers = 16MB\nmax_wal_size = 4GB\ncheckpoint_completion_target = 0.9\n\n# 连接配置\nmax_connections = 200",{"id":858,"title":859,"titles":860,"content":861,"level":144},"\u002Fblog\u002Fpostgresql-commands-guide#日常健康检查","日常健康检查",[50],"-- 1. 数据库大小排名\nSELECT datname, pg_size_pretty(pg_database_size(datname)) AS size\nFROM pg_database\nORDER BY pg_database_size(datname) DESC;\n\n-- 2. 表膨胀率（死元组占比）\nSELECT\n    schemaname, relname,\n    n_dead_tup, n_live_tup,\n    ROUND(100 * n_dead_tup \u002F NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_pct\nFROM pg_stat_user_tables\nWHERE n_dead_tup > 1000\nORDER BY dead_pct DESC;\n\n-- 3. autovacuum 是否健康运行\nSELECT relname, last_autovacuum, last_autoanalyze\nFROM pg_stat_user_tables\nWHERE last_autovacuum IS NULL OR last_autoanalyze IS NULL;\n\n-- 4. 长事务\nSELECT pid, state, xact_start, NOW() - xact_start AS duration, query\nFROM pg_stat_activity\nWHERE state = 'idle in transaction'\n   OR (state = 'active' AND NOW() - xact_start > INTERVAL '10 minutes')\nORDER BY xact_start;\n\n-- 5. 未使用的索引浪费的空间\nSELECT\n    schemaname, tablename, indexname,\n    pg_size_pretty(pg_relation_size(indexrelid)) AS size\nFROM pg_stat_user_indexes\nWHERE idx_scan = 0\nORDER BY pg_relation_size(indexrelid) DESC;",{"id":863,"title":447,"titles":864,"content":865,"level":144},"\u002Fblog\u002Fpostgresql-commands-guide#总结",[50],"PostgreSQL 日常运维的四个核心习惯： 日常检查 — 每周运行一次健康检查 SQL，关注死元组率、长事务和未使用索引索引先行 — 写查询之前先 EXPLAIN ANALYZE，不出意外再用到生产备份保底 — 配置定时 pg_dump，并定期验证备份文件可用性配置匹配硬件 — shared_buffers、work_mem、effective_cache_size 三项内存参数按硬件比例调整 后续可以继续深入：VACUUM 原理与调优、流复制搭建、分区表设计，以及使用 pg_stat_statements 进行长期性能基线分析。 html pre.shiki code .skTid, html code.shiki .skTid{--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sW7EW, html code.shiki .sW7EW{--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .s5NuB, html code.shiki .s5NuB{--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sYBhb, html code.shiki .sYBhb{--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .sfmjH, html code.shiki .sfmjH{--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s215V, html code.shiki .s215V{--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sa4-K, html code.shiki .sa4-K{--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}",{"id":66,"title":67,"titles":867,"content":68,"level":138},[],{"id":869,"title":870,"titles":871,"content":872,"level":144},"\u002Fblog\u002Fsteam-balance-guide#原理","原理",[67],"在第三方平台（Buff \u002F 悠悠有品）用 RMB 买入饰品，再到 Steam 市场卖出得余额。中间的价差就是折扣。 折价率 = 第三方买入价 ÷ (Steam 挂牌价 × 0.85) × 100%\n\n折价率 85% → 花 85 元得 100 元余额 Steam 市场扣 15% 手续费（5% Steam + 10% 开发商分成），所以税后到手 = 挂牌价 × 0.85。",{"id":874,"title":875,"titles":876,"content":160,"level":144},"\u002Fblog\u002Fsteam-balance-guide#选品四维","选品四维",[67],{"id":878,"title":879,"titles":880,"content":881,"level":155},"\u002Fblog\u002Fsteam-balance-guide#_1-折价率","1. 折价率",[67,875],"优先 82%-88%。高于 90% 不如直接充值，低于 80% 通常有坑。",{"id":883,"title":884,"titles":885,"content":886,"level":155},"\u002Fblog\u002Fsteam-balance-guide#_2-流动性","2. 流动性",[67,875],"日成交量建议 > 100 单。买卖单价差 \u003C 5%。 等级举例高AK-47 红线、Dota 2 至宝、热门不朽中略磨\u002F久经主流皮肤、绝版套装低冷门枪皮、老贴纸",{"id":888,"title":889,"titles":890,"content":891,"level":155},"\u002Fblog\u002Fsteam-balance-guide#_3-价格稳定","3. 价格稳定",[67,875],"避开：刚结束的 Major 贴纸（虚高）、新箱子（持续跌）、活动饰品（可能回调）。",{"id":893,"title":894,"titles":895,"content":896,"level":155},"\u002Fblog\u002Fsteam-balance-guide#_4-单位交易成本","4. 单位交易成本",[67,875],"单价 50-200 元最合适。太低（\u003C20）操作次数多效率低，太高（>500）流动性可能不足。",{"id":898,"title":899,"titles":900,"content":901,"level":144},"\u002Fblog\u002Fsteam-balance-guide#实操流程","实操流程",[67],"1. Buff 筛选 → 选折价率适中、成交量高的饰品\n2. 第三方买入 → 游戏内确认收货\n3. Steam 按 Buy Order 低 1 元挂单 → 快速成交\n4. 余额买游戏\u002FDLC\u002F通行证",{"id":903,"title":904,"titles":905,"content":906,"level":144},"\u002Fblog\u002Fsteam-balance-guide#方案对比","方案对比",[67],"方案流动性折价率风险上手CS2 皮肤⭐⭐⭐⭐⭐82-88%中低Dota 2 饰品⭐⭐⭐⭐80-85%低中集换卡⭐⭐⭐90-95%极低最低",{"id":908,"title":909,"titles":910,"content":911,"level":144},"\u002Fblog\u002Fsteam-balance-guide#风险","风险",[67],"单品持仓不超过总资金 20%Steam 求购价跌 5% 以上时观望Major 期间 CS 饰品波动大不要用第三方代充或泄露 API Key开启手机令牌（15 天冷却的不适合做余额） 余额不能提现、转账或跨账户赠送饰品。倒余额不是为了赚钱，而是以折扣价获得 Steam 余额用于消费。",{"id":913,"title":914,"titles":915,"content":916,"level":144},"\u002Fblog\u002Fsteam-balance-guide#核心数字","核心数字",[67],"目标折价率：82% - 88%\n单品单价：50 - 200 元\n单品持仓上限：20%\n出手周期：24 小时内",[918,920,925,930,932,937,942,947],{"id":130,"title":131,"titles":919,"content":132,"level":138},[],{"id":921,"title":922,"titles":923,"content":924,"level":144},"\u002Fnotes\u002Fquick-index#前端地址","前端地址",[131],"中文站 英文站 中文站（.cn）",{"id":926,"title":927,"titles":928,"content":929,"level":144},"\u002Fnotes\u002Fquick-index#后台地址","后台地址",[131],"内容管理系统（关闭网络代理，或配置路由规则）",{"id":121,"title":122,"titles":931,"content":123,"level":138},[],{"id":933,"title":934,"titles":935,"content":936,"level":144},"\u002Fnotes\u002Fsite-roadmap-next-phase#备忘录","备忘录",[122],"下一阶段开发任务梳理，按交付方向分组。",{"id":938,"title":939,"titles":940,"content":941,"level":155},"\u002Fnotes\u002Fsite-roadmap-next-phase#前端优化","前端优化",[122,934],"About 页面 荣誉墙（honor）模块样式打磨Timeline 模块样式打磨当前已实现触摸滚动和键盘导航，重点在视觉对齐、间距和响应式适配 详情页（产品\u002F新闻） 正文排版样式打磨（标题层级、段落间距、引用、图片对齐等）新增一个 Tab，内容为 specification \u002F ordering 风格的表格",{"id":943,"title":944,"titles":945,"content":946,"level":155},"\u002Fnotes\u002Fsite-roadmap-next-phase#后端工具","后端工具",[122,934],"数据导入 微信公众号数据导入脚本表格数据（Excel\u002FCSV）导入脚本 编辑体验 数据编辑页面新增撤销（undo）和重做（redo）按钮",{"id":948,"title":949,"titles":950,"content":951,"level":155},"\u002Fnotes\u002Fsite-roadmap-next-phase#国际化扩展","国际化扩展",[122,934],"开发日文站（ja），内容模型需确认是否与中英文共用、翻译管理策略、域名\u002F路由方案",1783866115722]