<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
>
<channel>
<title><![CDATA[迫事部]]></title> 
<atom:link href="https://iokle.cn/rss.php" rel="self" type="application/rss+xml" />
<description><![CDATA[一郎工作室 · 特别紧迫事务联席快速反应与处理部]]></description>
<link>https://iokle.cn/</link>
<language>zh-cn</language>

<item>
    <title>把部署交给 AI 助手：人定目标，Agent 执行，关键节点人确认</title>
    <link>https://iokle.cn/automation/5.html</link>
    <description><![CDATA[<p>服务器部署这类&quot;步骤多、重复度高、出错了要反复试&quot;的活儿，现在完全可以交给 AI 助手来跑。这篇文章讲的是怎么分工才靠谱：<strong>人定目标、Agent 执行、关键节点人确认</strong>，以及它凭什么值得信任、边界又在哪里。</p>
<p><img src="/content/uploadfile/202609/ai-workflow.png" alt="人机协作流程" /></p>
<h2>一个典型任务长什么样</h2>
<p>假设要在一台新服务器上部署一套开源博客系统，并配上 HTTPS。传统流程是：查文档 → 装环境 → 传文件 → 配数据库 → 配 Web 服务 → 签证书 → 验证…… 每一步都可能踩坑，来回折腾一晚上很正常。</p>
<p>把它交给 AI 助手后，人只需要说一句：</p>
<blockquote>
<p>&quot;把博客站部署到 blog.example.com，域名已经解析好了。&quot;</p>
</blockquote>
<p>剩下的勘察、执行、排错、验证，全部由 Agent 自动完成。</p>
<h2>分工原则：人只出现在三个节点</h2>
<p>把活交给 Agent 不等于当甩手掌柜。合理的分工是：</p>
<ol>
<li><strong>给目标</strong>——需求一句话说清，剩下的让 Agent 自己拆解；</li>
<li><strong>拍方案</strong>——Agent 动手前必须先把&quot;只读勘察结果 + 实施步骤 + 数据落点&quot;摆出来，人工看一眼点头它才继续；</li>
<li><strong>交关键凭据</strong>——比如软件授权码、初始密码这类必须由人持有的东西。</li>
</ol>
<p>除此之外，Agent 自己勘察、自己排错、自己验证、自己收尾。</p>
<p><img src="/content/uploadfile/202609/ai-timeline.png" alt="一次标准化的部署流程" /></p>
<h2>它实际会干什么</h2>
<p>以部署博客类应用为例，Agent 的执行链条大致是：</p>
<ul>
<li><strong>勘察先行，不盲动。</strong> 先查软件官网的下载渠道（主下载要不要登录？有没有镜像源或官方容器镜像？），再确认域名解析是否已指向服务器，最后扫一遍服务器环境：Web 服务有没有、容器环境有没有、数据库装没装。<strong>结论全是&quot;看&quot;出来的，不是猜的。</strong></li>
<li><strong>方案可逆。</strong> 给出的方案应该&quot;新增不动存量&quot;：新目录、新容器、新配置文件，原有服务一行配置都不碰；改数据库前先备份，删文件前先改名。<strong>每一步都能退回去。</strong></li>
<li><strong>执行一条龙。</strong> 拉镜像 → 写容器编排（应用 + 数据库两个容器，端口只绑本机回环）→ 签发 TLS 证书 → 配置反向代理 → 跑安装向导建库建管理员 → 完成初始化。中间遇到的坑（证书链兼容性、安装残留文件清理之类）顺手处理掉。</li>
<li><strong>交付带证据。</strong> 收尾不是一句&quot;好了&quot;，而是：各页面逐一请求验证状态码、证书链验证通过、把访问地址/凭据存放位置/备份方法列成清单交付。</li>
</ul>
<h2>为什么敢让它碰生产环境</h2>
<p>说到底是三条信任基础：</p>
<ul>
<li><strong>只读先于写操作</strong>：凡是可能改动系统的事，前面必然有一轮只读排查，证据摆出来才动手；</li>
<li><strong>操作都可逆</strong>：移动备份优先于删除，配置新增优先于修改，最坏情况一条命令回滚；</li>
<li><strong>全量回归验证</strong>：改完不是看&quot;好像没问题&quot;，而是逐项验证响应状态，对比改动前的基线。</li>
</ul>
<h2>Agent 的边界：它不知道的，它不会装懂</h2>
<p>这类协作里，软件授权码、管理员初始密码、站点想叫什么名字——这些 Agent 一概不知道，它也<strong>不会假装知道</strong>，而是明确留出节点让人类确认。真正的信任不是它&quot;什么都会&quot;，而是<strong>它清楚自己不知道什么，并且在该问的时候问</strong>。</p>
<p>AI 助手目前最合适的定位，是&quot;一个全天候在线的实习生 + 一整套能自动化的工具链&quot;：重复性的几十个来回，压缩成一条消息就能跑完；脏活累活它全包，关键决策你拍板，交付标准你来定。省下来的时间，拿去琢磨真正需要人的判断力的事。</p>]]></description>
    <pubDate>Thu, 03 Sep 2026 11:05:08 +0800</pubDate>
    <dc:creator>Luffy</dc:creator>
    <guid>https://iokle.cn/automation/5.html</guid>
</item>
<item>
    <title>Docker 数据不丢的秘密：bind mount 持久化与&quot;目录即资产&quot;备份法</title>
    <link>https://iokle.cn/container/4.html</link>
    <description><![CDATA[<p>用 Docker 跑应用的人都会遇到同一个灵魂拷问：<strong>容器删了，数据还在吗？</strong> 答案取决于你把数据放在了哪里。这篇文章用一次典型的博客类应用部署复盘 bind mount 持久化和&quot;目录即资产&quot;的备份思路。</p>
<p><img src="/content/uploadfile/202609/docker-persist.png" alt="容器会失忆，数据卷不会" /></p>
<h2>先记住一句话：容器是一次性的</h2>
<p>镜像（image）是&quot;模板&quot;，容器（container）是&quot;运行中的实例&quot;。容器可以被随意删除、重建、升级——这是容器最大的优点，也是最大的陷阱：<strong>如果你把数据写进了容器的可写层，容器一删，数据跟着蒸发。</strong></p>
<pre><code class="language-bash"># 反面教材：数据默认落在容器里
docker run -d --name blog-db mariadb:10.11
docker rm -f blog-db
# → 数据库文件全部没了</code></pre>
<p>所以凡是&quot;删了会心疼&quot;的东西——数据库文件、上传的图片、用户配置——都必须住在容器外面。</p>
<h2>把宿主目录挂进去：bind mount</h2>
<p>让数据住在外面的标准做法是挂载宿主目录：</p>
<pre><code class="language-yaml">services:
  db:
    image: mariadb:10.11
    container_name: blog-db
    volumes:
      - ./mysql:/var/lib/mysql       # 宿主机 ./mysql 目录 = 数据库目录

  web:
    image: wordpress:php8.1-apache   # 换成任意 Web 应用都同理
    container_name: blog-web
    volumes:
      - ./html:/var/www/html         # 宿主机 ./html 目录 = 整站程序 + 上传文件</code></pre>
<p>之后容器随便 <code>docker rm -f</code>、<code>docker compose up -d</code> 重建，数据原样回来。以上面的目录布局为例，整个站点的全部身家，就是项目目录这一个文件夹。</p>
<blockquote>
<p><strong>和 named volume 怎么选？</strong> named volume（<code>-v blog_data:/var/lib/mysql</code>）由 Docker 管理、更&quot;官方&quot;，但文件藏在 <code>/var/lib/docker/volumes/</code> 深处，想看想备份都要绕一层。bind mount 直接把目录摊在明面上，<code>ls</code>、<code>tar</code>、<code>rsync</code> 想怎么操作就怎么操作——<strong>小规模自托管，bind mount 更好用</strong>。</p>
</blockquote>
<h2>目录即资产：备份一条 tar 搞定</h2>
<p>代码在镜像里（随时能重新拉），配置和数据都在目录里——所以备份整站 = 备份一个目录，不需要进容器东翻西找，也不怕漏文件。</p>
<pre><code class="language-bash"># 稳妥起见先停容器，保证数据一致
cd ~/blog &amp;&amp; docker compose stop

# 整个项目目录打成一个包
cd ~ &amp;&amp; tar -czf blog_$(date +%Y%m%d).tar.gz blog

# 拷走(异地/对象存储)，再拉起来
docker compose up -d</code></pre>
<p><img src="/content/uploadfile/202609/backup-flow.png" alt="备份与灾难恢复流程" /></p>
<p>数据库在跑的时候直接打包文件有风险（可能备份到写到一半的数据），所以流程里先 <code>stop</code> 再打包。对评论、上传不活跃的小站点，每晚停几十秒做个快照完全无感；大流量站点可以改用 <code>mysqldump</code> 热备数据库 + 增量同步文件。</p>
<h2>恢复演练：比备份更重要</h2>
<p>备份做了不演练等于没有。真到灾难那天才第一次解包，大概率手忙脚乱。花十分钟完整走一遍：</p>
<pre><code class="language-bash"># 新机器(或清空的目录)上
cd ~ &amp;&amp; tar -xzf blog_20260101.tar.gz
cd blog &amp;&amp; docker compose up -d

# 验证三件事
curl -sI https://blog.example.com/ | head -1        # 1. 站点起来了
ls html/wp-config.php                                # 2. 配置文件回来了
docker exec blog-db ls /var/lib/mysql | head         # 3. 数据库文件齐了</code></pre>
<p>能完整跑通一次&quot;删库跑路演练&quot;，你才算真正睡了个安稳觉。</p>
<h2>几个实战小提醒</h2>
<ul>
<li><strong>目录权限</strong>：容器内进程常以非 root 用户运行（如 www-data），挂载目录属主要对，否则容器启动就报 Permission denied。<code>chown -R www-data:www-data</code> 是常见解药。</li>
<li><strong>重启策略</strong>：<code>restart: unless-stopped</code> 一定要写，机器重启后容器自动拉起，不用半夜爬起来敲命令。</li>
<li><strong>容器日志限容</strong>：compose 里给日志加 <code>max-size: 10m</code> / <code>max-file: 3</code>，不然日志文件能把磁盘吃满。</li>
<li><strong>升级不丢数据</strong>：换镜像版本升级时，先备份目录，再 <code>docker compose pull &amp;&amp; up -d</code>，出问题一条命令回滚到旧镜像——数据目录从头到尾没动过。</li>
</ul>
<p>容器负责&quot;跑&quot;，目录负责&quot;存&quot;，两者分开，这套架构就拥有了最朴素的抗风险能力：<strong>镜像丢了能重拉，目录丢了能还原，最坏的情况也只是重新部署，而不是重新开始。</strong></p>]]></description>
    <pubDate>Thu, 03 Sep 2026 10:36:08 +0800</pubDate>
    <dc:creator>Luffy</dc:creator>
    <guid>https://iokle.cn/container/4.html</guid>
</item>
<item>
    <title>一台服务器怎么跑多个网站？Nginx 反向代理与 HTTPS 配置实战</title>
    <link>https://iokle.cn/ops/3.html</link>
    <description><![CDATA[<p>一台服务器怎么跑多个网站？答案是：一个 Nginx 反向代理，加上一份规范的 HTTPS 配置。这篇文章把&quot;单 IP 多站点&quot;的完整部署过程拆开讲——从&quot;一个公网 IP 怎么装多个站&quot;到&quot;证书怎么签才不踩老设备兼容坑&quot;，全程可复现，示例域名统一用 example.com 系列。</p>
<p><img src="/content/uploadfile/202609/arch-5sites.png" alt="单服务器多站点架构" /></p>
<h2>问题：只有一个公网 IP，却要跑多个站</h2>
<p>服务器只有 80 / 443 两个&quot;对外入口&quot;，但背后可能要跑：企业官网、商城、博客、API 服务、内部工具…… 总不能一个站开一个公网端口，那既不安全也不优雅。</p>
<p>解决思路一句话：<strong>对外只开 80/443，Nginx 按域名（Host 头）把请求分流到不同的后端服务</strong>。后端可以是一台机器上的不同端口，也可以是 Docker 容器，甚至可以是另一台内网机器——对访问者完全透明。</p>
<h2>反向代理要转发哪些东西</h2>
<p>除了基本的 <code>proxy_pass</code>，有三样东西必须跟着走：</p>
<pre><code class="language-nginx">location / {
    proxy_pass http://127.0.0.1:8080;            # 转发到后端
    proxy_set_header Host $host;                 # 让后端知道用户访问的是哪个域名
    proxy_set_header X-Real-IP $remote_addr;     # 真实客户端 IP
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 完整链路
    proxy_set_header X-Forwarded-Proto $scheme;  # 是 http 还是 https
}</code></pre>
<blockquote>
<p><strong>坑 1</strong>：不传 <code>Host</code> 头，后端按 IP 或默认站点响应，多个站全串台。<br />
<strong>坑 2</strong>：不传 <code>X-Real-IP</code>，后端日志里全是 127.0.0.1，排错全靠猜。<br />
<strong>坑 3</strong>：Web 应用开了 HTTPS 却不知道 <code>X-Forwarded-Proto</code>，容易生成 http 开头的链接，甚至登录态失效。</p>
</blockquote>
<h2>HTTPS：先跳转，再签证书</h2>
<p>规范的做法是 80 端口只干两件事：响应 ACME 验证、把其余请求 301 到 https。</p>
<pre><code class="language-nginx">server {
    listen 80;
    server_name blog.example.com www.blog.example.com;

    location /.well-known/acme-challenge/ {      # 证书续期验证专用
        root /var/www/acme-challenge;
    }
    location / { return 301 https://blog.example.com$request_uri; }
}</code></pre>
<p>证书用 Let's Encrypt，一条命令签下来：</p>
<pre><code class="language-bash">sudo certbot certonly --webroot -w /var/www/acme-challenge \
    -d blog.example.com -d www.blog.example.com \
    --key-type rsa --agree-tos --email admin@example.com</code></pre>
<p><img src="/content/uploadfile/202609/https-flow.png" alt="一次 HTTPS 访问的完整链路" /></p>
<blockquote>
<p><strong>为什么要显式 <code>--key-type rsa</code>？</strong> 新版 Let's Encrypt 默认签 ECDSA 证书，证书链走到 ISRG Root X2——这个根比较新，部分老 Android 和国产浏览器不认。RSA 证书走的是被 IdenTrust 交叉签名的 ISRG Root X1，几乎所有设备都信任。面向国内访客的场景，宁可要兼容性。</p>
</blockquote>
<h2>后端端口：宁关勿开</h2>
<p>Nginx 反代之后，后端服务（8080 之类的端口）完全不需要暴露到公网。两个手段叠加：</p>
<pre><code class="language-bash"># 手段一：容器端口只绑本机回环
docker run -p 127.0.0.1:8080:80 ...

# 手段二：iptables 对公网来源直接 DROP(以 8080 为例)
iptables -A INPUT -p tcp --dport 8080 -s 0.0.0.0/0 -j DROP
iptables-save &gt; /etc/iptables/rules.v4</code></pre>
<p>对外<strong>只有 80/443 两个入口</strong>，扫描面小到可以忽略，这是多站一机最重要的安全底线。</p>
<h2>上线前的自检清单</h2>
<pre><code class="language-bash"># 1. 配置语法 + 平滑重载
sudo nginx -t &amp;&amp; sudo systemctl reload nginx

# 2. 绕过 DNS 直接验证本机各站点(排除域名解析干扰)
curl -sk --resolve blog.example.com:443:127.0.0.1 -o /dev/null -w '%{http_code}\n' https://blog.example.com/

# 3. 验证重定向链：www → 主站、http → https
curl -sI http://blog.example.com/ | grep Location

# 4. 验证证书链没断
echo | openssl s_client -connect 127.0.0.1:443 -servername blog.example.com 2&gt;/dev/null \
    | grep "Verify return code"</code></pre>
<p>如果返回 <code>Verify return code: 0 (ok)</code>，证书链就是完整的。</p>
<h2>两个容易被忽略的 nginx 坑</h2>
<ul>
<li><strong>配置目录里别放 .bak 备份文件</strong>。nginx 会把这个目录下所有文件都当配置加载，同名 server_name 的备份文件会导致 &quot;conflicting server name&quot; 警告，而且先加载的那份说了算——你改了半天发现没生效，其实是被备份文件盖住了。备份请放目录外面或改名移走。</li>
<li><strong>同端口 server 块的 listen 参数必须一致</strong>。一个写 <code>listen 443 ssl http2;</code>，另一个写 <code>listen 443 ssl;</code>，重载时 nginx 会警告 &quot;protocol options redefined&quot;。要带就都带 http2。</li>
</ul>
<p>一台普通云服务器、一个公网 IP、多个站点，跑得稳稳的——靠的就是把&quot;入口收口&quot;这件事做干净：证书只在一层、跳转只在一层、暴露面缩到最小。下一篇聊聊这套架构里 Docker 容器数据怎么持久化、怎么备份。</p>]]></description>
    <pubDate>Thu, 03 Sep 2026 10:06:08 +0800</pubDate>
    <dc:creator>Luffy</dc:creator>
    <guid>https://iokle.cn/ops/3.html</guid>
</item>
<item>
    <title>演示文章</title>
    <link>https://iokle.cn/1.html</link>
    <description><![CDATA[<p>这是一篇演示文章</p>]]></description>
    <pubDate>Thu, 03 Sep 2026 09:59:14 +0800</pubDate>
    <dc:creator>Luffy</dc:creator>
    <guid>https://iokle.cn/1.html</guid>
</item>
</channel>
</rss>