<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>阿涛的小破站</title><description>Docker技术分享</description><link>https://emohe.cn/</link><language>zh_CN</language><item><title>Docker使用教程和镜像加速</title><link>https://emohe.cn/posts/docker/</link><guid isPermaLink="true">https://emohe.cn/posts/docker/</guid><pubDate>Sun, 23 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Docker Hub 镜像加速&lt;/h1&gt;
&lt;p&gt;国内拉取镜像有时会遇到困难，对于学习或者开发者来说很难受，此时可以配置镜像加速。&lt;/p&gt;
&lt;h3&gt;安装Docker&lt;/h3&gt;
&lt;p&gt;官方安装脚本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -fsSL https://get.docker.com | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;国内一键安装脚本&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash &amp;lt;(curl -sSL https://emohe.cn/docker.sh)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt; 手动离线安装Docker &amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;h4&gt;下载 Docker:&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://download.docker.com/linux/static/stable/x86_64/&quot;&gt;官方文件下载地址——下载后上传到root目录&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/static/stable/x86_64/&quot;&gt;清华大学下载地址&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tar xzvf docker-26.1.3.tgz     # 替换版本号
sudo mv docker/* /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;创建 Docker 服务文件&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/systemd/system/docker.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;添加以下内容&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=Docker Application Container Engine
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/local/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=2
StartLimitBurst=3
StartLimitInterval=60s
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Delegate=yes
KillMode=process

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;启动并启用 Docker 服务&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo chmod +x /usr/local/bin/dockerd
sudo systemctl daemon-reload
sudo systemctl start docker
sudo systemctl enable docker
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;查看版本&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;docker -v
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt; 手动离线安装Docker-compose &amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;国内环境手动安装Docker-compose&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/docker/compose/releases&quot;&gt;点这里手动下载文件&lt;/a&gt; 上传到服务器的&lt;code&gt;/usr/local/bin&lt;/code&gt;目录&lt;/p&gt;
&lt;p&gt;重命名为docker-compose&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo cp docker-compose-linux-x86_64 /usr/local/bin/docker-compose
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;增加执行权限&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chmod +x /usr/local/bin/docker-compose
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;验证安装&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：
由于是以二进制文件安装的&lt;code&gt;docker-compose&lt;/code&gt;，所以运行命令有所变化，运行示例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;区别在于中间的&lt;code&gt;-&lt;/code&gt;，官方安装脚本是以插件形式安装的&lt;code&gt;docker-compose&lt;/code&gt;，所以中间不需要&lt;code&gt;-&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;配置加速地址&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Ubuntu 16.04+、Debian 8+、CentOS 7+&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;创建或修改 &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo mkdir -p /etc/docker
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo tee /etc/docker/daemon.json &amp;lt;&amp;lt;EOF
{
    &quot;registry-mirrors&quot;: [
        &quot;https://docker.m.ixdev.cn&quot;,
        &quot;https://docker.1ms.run&quot;
    ]
}
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;提示：如果不方便重启Docker服务，也可以不用设置全局加速地址，拉取镜像时增加加速地址即可，示例：&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;docker pull docker.1panel.live/library/mysql:5.7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明：&lt;code&gt;library&lt;/code&gt;是一个特殊的命名空间，它代表的是官方镜像。如果是某个用户的镜像就把&lt;code&gt;library&lt;/code&gt;替换为镜像的用户名。&lt;/p&gt;
&lt;h3&gt;Docker Desktop 配置&lt;/h3&gt;
&lt;p&gt;对于&lt;code&gt;Windows&lt;/code&gt;系统的&lt;code&gt;Docker Desktop&lt;/code&gt;用户，点击右上角&lt;code&gt;设置&lt;/code&gt;，找到&lt;code&gt;Docker Engine&lt;/code&gt;然后修改配置，修改后的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;builder&quot;: {
    &quot;gc&quot;: {
      &quot;defaultKeepStorage&quot;: &quot;20GB&quot;,
      &quot;enabled&quot;: true
    }
  },
  &quot;experimental&quot;: false,
  &quot;registry-mirrors&quot;: [
    &quot;https://docker.1ms.run&quot;,
    &quot;https://docker.1panel.live&quot;
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后点击右下角的&lt;code&gt;Apply &amp;amp; restart&lt;/code&gt;保存并重启即可。&lt;/p&gt;
&lt;h3&gt;检查加速是否生效&lt;/h3&gt;
&lt;p&gt;查看docker系统信息 &lt;code&gt;docker info&lt;/code&gt;，如果从结果中看到了你配置的加速地址，说明配置成功。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Registry Mirrors:
 [...]
 https://docker.1ms.run
 https://docker.1panel.live
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用代理拉取镜像&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;注意：使用了加速源就别使用这个方法了&lt;/li&gt;
&lt;li&gt;此方法支持&lt;code&gt;login&lt;/code&gt;和&lt;code&gt;push&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;创建配置文件&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo mkdir -p /etc/systemd/system/docker.service.d
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;在文件中添加代理&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;[Service]
Environment=&quot;HTTP_PROXY=http://127.0.0.1:1080&quot;
Environment=&quot;HTTPS_PROXY=http://127.0.0.1:1080&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;重启Docker&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;查看环境变量&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl show --property=Environment docker
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;本地流量转发到服务器&lt;/h4&gt;
&lt;p&gt;使用SSH反向转发把本地的10808端口的流量转发给远程服务器1080端口&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh -R 1080:127.0.0.1:10808 root@服务器地址 -N
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-N&lt;/code&gt; 代表仅连接但不打开对话框&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;备用方法：打包镜像到本地&lt;/h2&gt;
&lt;p&gt;1：压缩保存镜像到本地&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker save 镜像名 &amp;gt; 镜像名.tar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2：手动上传到另一个服务器&lt;/p&gt;
&lt;p&gt;3：另一个服务器解压镜像&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker load &amp;lt; 镜像名.tar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4：查看镜像&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker images
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Docker Hub 镜像测速&lt;/h2&gt;
&lt;p&gt;拉取镜像时，可使用 &lt;code&gt;time&lt;/code&gt; 统计所花费的总时间。测速前记得移除本地的镜像。&lt;/p&gt;
&lt;p&gt;例如：&lt;code&gt;time docker pull node:latest&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;修改最大并发数加快镜像下载速度&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;registry-mirrors&quot;: [
    &quot;https://docker.m.ixdev.cn&quot;,
    &quot;https://docker.1ms.run&quot;
  ],
  &quot;max-concurrent-downloads&quot;: 10,
  &quot;max-concurrent-uploads&quot;: 10,
  &quot;max-download-attempts&quot;: 5,
  &quot;default-ulimits&quot;: {
    &quot;nofile&quot;: {
      &quot;Hard&quot;: 64000,
      &quot;Name&quot;: &quot;nofile&quot;,
      &quot;Soft&quot;: 64000
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;为Docker启用IPV6&lt;/h2&gt;
&lt;p&gt;创建或修改&lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;文件&lt;/p&gt;
&lt;p&gt;增加如下配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;ipv6&quot;: true,
  &quot;fixed-cidr-v6&quot;: &quot;2001:db8:1::/64&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后配置一下流量路由&lt;/p&gt;
&lt;p&gt;重启：&lt;code&gt;sudo systemctl restart docker&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;卸载Docker&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl stop docker
sudo apt-get purge docker-ce docker-ce-cli containerd.io
sudo rm -rf /etc/docker /var/lib/docker
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Docker最新稳定加速源列表&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;企业级优质稳定加速源&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;提供者&lt;/th&gt;
&lt;th&gt;镜像加速地址&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;加速类型&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://m.ixdev.cn/&quot;&gt;CNIX&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://docker.m.ixdev.cn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;无限制&amp;amp;多仓库支持&lt;/td&gt;
&lt;td&gt;Docker Hub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://1panel.cn/docs/user_manual/containers/setting/&quot;&gt;1panel&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://docker.1panel.live&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;无限制&lt;/td&gt;
&lt;td&gt;Docker Hub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://docker.xuanyuan.me/&quot;&gt;轩辕镜像&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://docker.xuanyuan.me&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;无限制&lt;/td&gt;
&lt;td&gt;Docker Hub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://docker.1ms.run&quot;&gt;毫秒镜像&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://docker.1ms.run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;有黑名单&amp;amp;可选国内cdn&lt;/td&gt;
&lt;td&gt;Docker Hub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/DaoCloud/public-image-mirror&quot;&gt;DaoCloud&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://docker.m.daocloud.io&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;白名单和限流&lt;/td&gt;
&lt;td&gt;Docker Hub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://console.huaweicloud.com/swr/#/swr/dashboard&quot;&gt;华为云&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://***.mirror.swr.myhuaweicloud.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;需登录分配&lt;/td&gt;
&lt;td&gt;Docker Hub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://cloud.tencent.com/document/product/1207/45596&quot;&gt;腾讯云&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mirror.ccs.tencentyun.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;仅限腾讯云机器&lt;/td&gt;
&lt;td&gt;Docker Hub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://doc.nju.edu.cn/books/e1654&quot;&gt;南京大学&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://ghcr.nju.edu.cn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ghcr加速&lt;/td&gt;
&lt;td&gt;ghcr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://doc.nju.edu.cn/books/e1654&quot;&gt;南京大学&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://k8s.nju.edu.cn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;k8s加速&lt;/td&gt;
&lt;td&gt;k8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://m.ixdev.cn/&quot;&gt;CNIX&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://ghcr.m.ixdev.cn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;无限制&amp;amp;多仓库支持&lt;/td&gt;
&lt;td&gt;ghcr&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;Docker常用命令:&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;编译镜像&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker build -t 镜像名 .&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;先&lt;code&gt;docker login&lt;/code&gt;登录docker hub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;推送镜像&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker push 用户名/镜像名&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;需先标记镜像 &lt;code&gt;docker tag 53321f173e 用户名/镜像名&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查看容器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker ps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-a&lt;/code&gt;查看包括已停止的容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;容器资源占用&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker stats&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看所有容器资源占用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;容器详细信息&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker inspect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;挂载看&lt;code&gt;Mounts&lt;/code&gt;网络看&lt;code&gt;Networks&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;进入容器内部&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker exec -it 容器名 sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;结尾使用&lt;code&gt;/bash&lt;/code&gt;也可以&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;创建容器网络&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker network create my-network&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;my-network&lt;/code&gt;为网络名称&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;容器加入网络&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker network connect my-network 容器名&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;替换容器名或ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;宿主机网络&lt;/td&gt;
&lt;td&gt;&lt;code&gt;network_mode: host&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker-compose&lt;/code&gt;使用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;宿主机网络&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--network host&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker run&lt;/code&gt;使用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查看网络&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker network inspect my-network&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看&lt;code&gt;my-network&lt;/code&gt;网络中的容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;停止容器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker stop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker stop 容器名或ID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;启动容器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker start 容器名或ID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;重启容器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker restart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker restart 容器名或ID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删除容器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker rm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker rm 容器名或ID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;查看镜像&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker images&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker images 镜像名或ID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删除镜像&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker rmi -f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker rmi -f 镜像名或ID&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;清除资源&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker system prune&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;清除所有未使用资源&lt;code&gt;容器 网络 镜像 缓存&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删除所有镜像&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker rmi -f $(docker images -aq)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除所有镜像&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;删除所有容器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker container prune -f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除所有已停止容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;停止所有容器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker stop $(docker ps -aq)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;停止所有容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;停止并删除&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker compose down&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;停止并删除编排容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;重新创建容器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker compose up -d --force-recreate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;强制删除并重启编排容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;复制文件&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker cp wordpress:/app/data.yaml /home&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;从容器复制到宿主机&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;复制文件&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker cp /home/data.yaml wordpress:/app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;从宿主机复制到容器&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>给你的电脑增加一个自定义右键菜单</title><link>https://emohe.cn/posts/39/</link><guid isPermaLink="true">https://emohe.cn/posts/39/</guid><pubDate>Thu, 05 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Windows右键菜单&lt;/h2&gt;
&lt;p&gt;有时候写一些简单的html网页，当必须使用HTTP服务加载的时候，都需要手动启动一下命令，感觉步骤很繁琐 效率也很低，都是一些重复性动作。
需要在当前目录下打开终端，然后执行&lt;code&gt;python -m http.server 8080&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;所以我就想着直接右键菜单就能在当前目录自动执行这个命令就好了。&lt;/p&gt;
&lt;p&gt;目前最简单的方式就是注册表实现右键菜单，所以我就直接写了个注册表注入脚本，并且在启动HTTP服务的时候自动打开浏览器，代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\Background\shell\HttpServer]
@=&quot;启动HTTP服务 (9090)&quot;
&quot;Icon&quot;=&quot;imageres.dll,-5302&quot;
&quot;Position&quot;=&quot;Top&quot;

[HKEY_CLASSES_ROOT\Directory\Background\shell\HttpServer\command]
@=&quot;cmd.exe /s /k pushd \&quot;%V\&quot; &amp;amp;&amp;amp; (start /b cmd /c \&quot;timeout /t 1 /nobreak &amp;gt;nul &amp;amp;&amp;amp; start http://127.0.0.1:9090\&quot;) &amp;amp;&amp;amp; python -m http.server 9090&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将代码保存为&lt;code&gt;.reg&lt;/code&gt;后缀的注册表导入脚本，例如&lt;code&gt;install.reg&lt;/code&gt;，然后双击执行。需要注意的是要以&lt;code&gt;UTF-16 LE&lt;/code&gt;编码保存此文件，不然中文会乱码。&lt;/p&gt;
&lt;p&gt;右键菜单效果图：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;png/youjiancaidan.png&quot; alt=&quot;右键菜单&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;代码解析&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心机制&lt;/strong&gt;：向 &lt;code&gt;HKEY_CLASSES_ROOT\Directory\Background\shell&lt;/code&gt; 写入键值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;作用域&lt;/strong&gt;：&lt;code&gt;Directory\Background&lt;/code&gt; 代表在文件夹空白处点击右键。如果是点在文件夹图标上，则需要写到 &lt;code&gt;Directory\shell&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;命令解析&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pushd &quot;%V&quot;&lt;/code&gt;: 将 CMD 工作目录切换到当前文件夹（&lt;code&gt;%V&lt;/code&gt; 是变量）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start http://127.0.0.1:9090&lt;/code&gt;：调用默认浏览器打开此地址。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;python -m http.server 9090&lt;/code&gt;: Python自带的启动静态服务器快捷命令，我电脑基本必装Python。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优化体验&lt;/strong&gt;：使用异步执行 优化了一下使用体验。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;进阶&lt;/h3&gt;
&lt;p&gt;此时你会发现这个右键菜单在windows 11系统里需要点击&lt;code&gt;显示更多选项&lt;/code&gt;才能看到。&lt;/p&gt;
&lt;p&gt;这是因为 Windows 11 重构了右键菜单，传统的注册表方式&lt;code&gt;IContextMenu&lt;/code&gt;默认被放入二级菜单。&lt;/p&gt;
&lt;p&gt;想要直接显示在一级菜单里，只有实现了&lt;code&gt;IExplorerCommand&lt;/code&gt;接口并具有&lt;code&gt;Package Identity (包身份)&lt;/code&gt;的应用，才有资格进入一级菜单。&lt;/p&gt;
&lt;h3&gt;那么想要进入一级菜单，需要做什么？&lt;/h3&gt;
&lt;p&gt;如果想要在一级菜单直接显示，单纯改注册表已经做不到了，必须升级技术栈，大致三个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;语言首选 C++&lt;/strong&gt;：写一个 DLL，实现 COM 接口&lt;code&gt;IExplorerCommand&lt;/code&gt;。比改注册表要复杂得多，需要处理引用计数、接口查询等底层逻辑。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;打包 (Sparse Package)&lt;/strong&gt;：必须给程序一个&lt;code&gt;身份证&lt;/code&gt; (AppxManifest.xml)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;签名 (Identity)&lt;/strong&gt;：必须要有数字签名才行。自己用的话，可以生成一个自签名证书并信任它。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当然我这种简单的小众需求还是使用注册表方式最合适，要是写一个DLL就有点小题大做了。&lt;/p&gt;
</content:encoded></item><item><title>安装部署openclaw并对接QQ机器人教程</title><link>https://emohe.cn/posts/37/</link><guid isPermaLink="true">https://emohe.cn/posts/37/</guid><pubDate>Sat, 31 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;openclaw（原ClawdBot）最近实在太火了，我玩了一下感觉确实很强大，本文介绍一下国内环境的安装和对接QQ机器人。&lt;/p&gt;
&lt;h3&gt;准备工作&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;模型API&lt;/li&gt;
&lt;li&gt;2H4G以上的硬件配置&lt;/li&gt;
&lt;li&gt;linux/mac/windows都可以&lt;/li&gt;
&lt;li&gt;QQ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;大模型以deepseek为例，官方购买地址：https://platform.deepseek.com&lt;/p&gt;
&lt;p&gt;部署环境以windows本地部署为例，其他系统步骤都一样，只是配置目录不一样，openclaw的默认配置路径都是在用户目录，三大系统都一样。&lt;/p&gt;
&lt;h3&gt;环境安装&lt;/h3&gt;
&lt;p&gt;首先安装nodejs环境，需要v22.22.0以上的版本，下载地址：https://nodejs.org/zh-cn/download&lt;/p&gt;
&lt;p&gt;其次需要Git，下载地址：https://git-scm.com/install/windows&lt;/p&gt;
&lt;h3&gt;允许执行脚本&lt;/h3&gt;
&lt;p&gt;有时候安装环境后不会自动刷新变量，需要重启电脑，然后还需要管理员打开PowerShell执行如下命令，并选择&lt;code&gt;A&lt;/code&gt;允许执行脚本&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;国内环境配置&lt;/h3&gt;
&lt;p&gt;设置npm镜像&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm config set registry https://registry.npmmirror.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置Git全局加速（可忽略）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git config --global url.&quot;https://hub.cmoko.com/https://github.com/&quot;.insteadOf https://github.com/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;移除Git全局加速的命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git config --global --unset url.&quot;https://hub.cmoko.com/https://github.com/&quot;.insteadOf
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;开始部署&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;npm安装openclaw&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;npm install -g openclaw-cn@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;初始化配置&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;openclaw-cn setup
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;打开配置文件&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;%USERPROFILE%\.openclaw
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;修改&lt;code&gt;openclaw.json&lt;/code&gt;配置，贴入以下配置并修改对应的字段&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;gateway&quot;: {
    &quot;mode&quot;: &quot;local&quot;,
    &quot;bind&quot;: &quot;loopback&quot;,
    &quot;port&quot;: 18789,
    &quot;auth&quot;: {
      &quot;mode&quot;: &quot;token&quot;,
      &quot;token&quot;: &quot;设置一个token令牌&quot;
    }
  },

  &quot;agents&quot;: {
    &quot;defaults&quot;: {
      &quot;model&quot;: {
        &quot;primary&quot;: &quot;openai-compat/填写模型名称&quot;
      },
      &quot;elevatedDefault&quot;: &quot;full&quot;,
      &quot;compaction&quot;: {
        &quot;mode&quot;: &quot;safeguard&quot;
      },
      &quot;maxConcurrent&quot;: 4
    }
  },

  &quot;models&quot;: {
    &quot;mode&quot;: &quot;merge&quot;,
    &quot;providers&quot;: {
      &quot;openai-compat&quot;: {
        &quot;baseUrl&quot;: &quot;https://api.example.com/v1&quot;,
        &quot;apiKey&quot;: &quot;填写你的模型API密钥&quot;,
        &quot;api&quot;: &quot;openai-completions&quot;,
        &quot;models&quot;: [
          {
            &quot;id&quot;: &quot;填写模型名称&quot;,
            &quot;name&quot;: &quot;填写模型名称&quot;
          }
        ]
      }
    }
  },

  &quot;tools&quot;: {
    &quot;exec&quot;: {
      &quot;backgroundMs&quot;: 10000,
      &quot;timeoutSec&quot;: 1800,
      &quot;cleanupMs&quot;: 1800000,
      &quot;notifyOnExit&quot;: true
    },
    &quot;elevated&quot;: {
      &quot;enabled&quot;: true,
      &quot;allowFrom&quot;: {}
    },
    &quot;allow&quot;: [
      &quot;exec&quot;,
      &quot;process&quot;,
      &quot;read&quot;,
      &quot;write&quot;,
      &quot;edit&quot;,
      &quot;web_search&quot;,
      &quot;web_fetch&quot;,
      &quot;cron&quot;
    ]
  },

  &quot;channels&quot;: {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;创建QQ机器人&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;浏览器访问 &lt;a href=&quot;https://q.qq.com/qqbot/openclaw/login.html&quot;&gt;QQ机器人Openclaw专区&lt;/a&gt;，然后直接在专区内创建机器人即可。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;安装机器人插件&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;openclaw-cn channels add
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;根据交互式提示选择QQ (社区版)，按提示输入&lt;code&gt;AppID&lt;/code&gt;和&lt;code&gt;AppSecret&lt;/code&gt;即可。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;启动&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;openclaw-cn gateway start
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;其他命令&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查看状态
openclaw-cn gateway status

# 重启
openclaw-cn gateway restart

# 查看日志
openclaw-cn logs

# 停止
openclaw-cn gateway stop

# 卸载
npm uninstall -g openclaw-cn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;至此，全部部署完成，可以向你的QQ机器人对话了。&lt;/p&gt;
&lt;h3&gt;常见问题&lt;/h3&gt;
&lt;p&gt;Linux和mac系统部署都一样，只是配置文件的目录在用户目录下。&lt;/p&gt;
&lt;p&gt;web访问需要带上token令牌：&lt;code&gt;http://127.0.0.1:18789/?token=你的网关令牌&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;有任何问题先查看日志：&lt;code&gt;openclaw-cn logs&lt;/code&gt;，然后问AI。&lt;/p&gt;
&lt;h3&gt;中文文档&lt;/h3&gt;
&lt;p&gt;https://clawd.org.cn/reference/cli-cheatsheet.html&lt;/p&gt;
</content:encoded></item><item><title>OpenWrt固件编译</title><link>https://emohe.cn/posts/36/</link><guid isPermaLink="true">https://emohe.cn/posts/36/</guid><pubDate>Wed, 19 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;介绍&lt;/h1&gt;
&lt;p&gt;OpenWrt 是一个 基于 Linux 的路由器操作系统，专门为嵌入式设备（路由器、NAS、小型网关设备等）设计。&lt;/p&gt;
&lt;p&gt;本篇教程基于&lt;code&gt;immortalwrt&lt;/code&gt;，immortalwrt 是基于 openwrt 开发的优化版本，是专门针对中国大陆环境优化的版本。国内用户基本都使用这个版本。&lt;/p&gt;
&lt;p&gt;项目地址：https://github.com/immortalwrt/immortalwrt&lt;/p&gt;
&lt;h1&gt;immortalwrt 在线构建&lt;/h1&gt;
&lt;p&gt;官方提供的网页在线构建叫&lt;code&gt;ImageBuilder&lt;/code&gt;，不是编译源码，而是借助官方的服务器资源，使用预编译好的SDK，快速选择包然后生成固件。优点是构建很快，缺点是自定义程度不是很高，但是常用的配置都可以自定义，例如提前安装插件，配置网口信息和防火墙什么的。&lt;/p&gt;
&lt;p&gt;官方在线编译地址：https://firmware-selector.immortalwrt.org&lt;/p&gt;
&lt;h2&gt;必备软件&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;curl luci-theme-argon luci-i18n-homeproxy-zh-cn luci-i18n-ttyd-zh-cn luci-i18n-diskman-zh-cn luci-i18n-filemanager-zh-cn luci-i18n-package-manager-zh-cn luci-i18n-firewall-zh-cn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当你安装一个插件包时，他会自动下载所需的软件和依赖，所以只需添加对应插件的汉化包即可。&lt;/p&gt;
&lt;p&gt;ImmortalWrt软件包查询（注意替换实际的版本和设备架构）：&lt;/p&gt;
&lt;p&gt;https://downloads.immortalwrt.org/releases/24.10.4/packages/x86_64/luci/index.json&lt;/p&gt;
&lt;h2&gt;初始化构建脚本&lt;/h2&gt;
&lt;p&gt;要修改的地方请去掉注释&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/sh
exec &amp;gt;/tmp/setup.log 2&amp;gt;&amp;amp;1

###########################################################
#                  自 定 义 配 置 区 域
###########################################################

### 系统后台密码（为空则不修改）
root_password=&quot;admin&quot;

### LAN 的 IPv4 地址（也是后台地址，例如 192.168.2.1）
lan_ip_address=&quot;192.168.2.1&quot;

### LAN 的子网掩码（例如 255.255.255.0）
# lan_netmask=&quot;255.255.255.0&quot;

### LAN 的 IPv4 网关（可为空）
# lan_gateway=&quot;192.168.1.1&quot;

### LAN 的 DNS（多个 DNS 可空格分隔，如 &quot;8.8.8.8 1.1.1.1&quot;）
# lan_dns=&quot;8.8.8.8 223.5.5.5&quot;

### DHCP 是否开启（1=开启，0=关闭）
# lan_dhcp_enable=&quot;1&quot;

### DHCP 起始地址
# lan_dhcp_start=&quot;100&quot;

### DHCP 地址池数量
# lan_dhcp_limit=&quot;150&quot;

### DHCP 租约时间
# lan_dhcp_leasetime=&quot;12h&quot;

### WiFi 名称 SSID（为空则不修改）
# wlan_name=&quot;ImmortalWrt&quot;

### WiFi 密码（≥ 8 位才生效）
# wlan_password=&quot;12345678&quot;

### PPPoE 宽带账号（为空则跳过）
# pppoe_username=&quot;&quot;

### PPPoE 宽带密码
# pppoe_password=&quot;&quot;

###########################################################

# ------------ root 密码 ------------
if [ -n &quot;$root_password&quot; ]; then
  (echo &quot;$root_password&quot;; sleep 1; echo &quot;$root_password&quot;) | passwd &amp;gt;/dev/null
fi

# ------------ LAN 基础配置 ------------
if [ -n &quot;$lan_ip_address&quot; ]; then
  uci set network.lan.ipaddr=&quot;$lan_ip_address&quot;
fi

if [ -n &quot;$lan_netmask&quot; ]; then
  uci set network.lan.netmask=&quot;$lan_netmask&quot;
fi

if [ -n &quot;$lan_gateway&quot; ]; then
  uci set network.lan.gateway=&quot;$lan_gateway&quot;
fi

# DNS
if [ -n &quot;$lan_dns&quot; ]; then
  uci delete network.lan.dns 2&amp;gt;/dev/null
  for d in $lan_dns; do
    uci add_list network.lan.dns=&quot;$d&quot;
  done
fi

uci commit network

# ------------ DHCP 设置 ------------
if [ -n &quot;$lan_dhcp_enable&quot; ]; then
  uci set dhcp.lan.ignore=$([ &quot;$lan_dhcp_enable&quot; = &quot;1&quot; ] &amp;amp;&amp;amp; echo 0 || echo 1)
fi

[ -n &quot;$lan_dhcp_start&quot; ] &amp;amp;&amp;amp; uci set dhcp.lan.start=&quot;$lan_dhcp_start&quot;
[ -n &quot;$lan_dhcp_limit&quot; ] &amp;amp;&amp;amp; uci set dhcp.lan.limit=&quot;$lan_dhcp_limit&quot;
[ -n &quot;$lan_dhcp_leasetime&quot; ] &amp;amp;&amp;amp; uci set dhcp.lan.leasetime=&quot;$lan_dhcp_leasetime&quot;

uci commit dhcp

# ------------ WIFI 配置 ------------
if [ -n &quot;$wlan_name&quot; ] &amp;amp;&amp;amp; [ -n &quot;$wlan_password&quot; ] &amp;amp;&amp;amp; [ ${#wlan_password} -ge 8 ]; then
  uci set wireless.@wifi-device[0].disabled=&apos;0&apos;
  uci set wireless.@wifi-iface[0].disabled=&apos;0&apos;
  uci set wireless.@wifi-iface[0].encryption=&apos;psk2&apos;
  uci set wireless.@wifi-iface[0].ssid=&quot;$wlan_name&quot;
  uci set wireless.@wifi-iface[0].key=&quot;$wlan_password&quot;
  uci commit wireless
fi

# ------------ PPPoE 宽带拨号 ------------
if [ -n &quot;$pppoe_username&quot; ] &amp;amp;&amp;amp; [ -n &quot;$pppoe_password&quot; ]; then
  uci set network.wan.proto=pppoe
  uci set network.wan.username=&quot;$pppoe_username&quot;
  uci set network.wan.password=&quot;$pppoe_password&quot;
  uci commit network
fi

echo &quot;All done!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;构建完成后下载对应的固件包刷入系统即可。&lt;/p&gt;
&lt;h1&gt;immortalwrt 基于源码编译&lt;/h1&gt;
&lt;p&gt;使用干净的&lt;code&gt;Debian 12&lt;/code&gt;或者&lt;code&gt;ubuntu 22.04&lt;/code&gt;系统，国外网络通畅，有50G以上的空闲存储空间。&lt;/p&gt;
&lt;h3&gt;1：安装依赖&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update -y
sudo apt full-upgrade -y
sudo apt install -y \
  ack antlr3 asciidoc autoconf automake autopoint binutils bison build-essential \
  bzip2 ccache clang cmake cpio curl device-tree-compiler ecj fastjar flex gawk gettext \
  gcc-multilib g++-multilib git gperf haveged help2man intltool libc6-dev-i386 libelf-dev \
  libglib2.0-dev libgmp-dev libltdl-dev libmpc-dev libmpfr-dev libncurses-dev libpython3-dev \
  libreadline-dev libssl-dev libtool libyaml-dev lld llvm lrzsz genisoimage \
  ninja-build p7zip-full patch pkgconf python3 python3-pip python3-ply python3-docutils \
  python3-pyelftools qemu-utils re2c rsync scons squashfs-tools subversion swig texinfo \
  uglifyjs unzip wget nano xmlto xxd zlib1g-dev upx zstd
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2：下载对应tags的源码（以&lt;code&gt;v24.10.4&lt;/code&gt;为例）&lt;/h3&gt;
&lt;p&gt;后续步骤建议切换为普通用户，不要用root用户编译。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone -b v24.10.4 --single-branch --filter=blob:none https://github.com/immortalwrt/immortalwrt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3：进入项目目录&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;cd immortalwrt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4：获取最新软件包清单&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;./scripts/feeds update -a
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5：安装软件包符号链接&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;./scripts/feeds install -a
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6：配置固件信息&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;make menuconfig
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这一步很重要，前三个选项分别是&lt;code&gt;目标系统&lt;/code&gt; - &lt;code&gt;子架构&lt;/code&gt; - &lt;code&gt;目标机型&lt;/code&gt;。根据你的实际设备来选。&lt;/p&gt;
&lt;p&gt;然后第四个选项&lt;code&gt;Target Images&lt;/code&gt;是修改固件配置的，其中&lt;code&gt;Root filesystem partition size&lt;/code&gt;是&lt;code&gt;根文件系统分区大小&lt;/code&gt;建议修改，根据你设备的存储空间来选择，这里的值就是最大存储空间。&lt;/p&gt;
&lt;p&gt;其他配置都是可选的，其中&lt;code&gt;luci&lt;/code&gt;选项中可以预安装一些插件包。&lt;/p&gt;
&lt;h3&gt;7：修改LAN口IP地址等等信息&lt;/h3&gt;
&lt;p&gt;可以在这里查看默认值：https://github.com/immortalwrt/immortalwrt/blob/master/package/base-files/files/bin/config_generate&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nano package/base-files/files/bin/config_generate
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;8：编译固件&lt;/h3&gt;
&lt;p&gt;单线程编译&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;make -j1 V=s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者多线程编译&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;make -j$(nproc --ignore=1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编译出来的固件在&lt;code&gt;bin&lt;/code&gt;目录下&lt;/p&gt;
&lt;h3&gt;9：重新编译说明&lt;/h3&gt;
&lt;p&gt;如果需要重新编译 则执行&lt;code&gt;make distclean&lt;/code&gt;清理一些残留和工具链等等，然后再从第四步重新开始。&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;VirtualBox虚拟机运行immortalwrt&lt;/h1&gt;
&lt;p&gt;1：选择&lt;code&gt;x86/64&lt;/code&gt;型号，编译后，下载&lt;code&gt;COMBINED (EXT4)&lt;/code&gt;格式的镜像，并解压到下载目录&lt;/p&gt;
&lt;p&gt;2：在文件目录下打开 PowerShell&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将镜像转换成VDI格式&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp; &quot;C:\Program Files\Oracle\VirtualBox\VBoxManage.exe&quot; convertfromraw `
    &quot;immortalwrt-24.10.4-f726c678216d-x86-64-generic-ext4-combined.img&quot; `
    &quot;immortalwrt.vdi&quot; `
    --format VDI
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3：打开VirtualBox，新建虚拟机，OS选择&lt;code&gt;Linux&lt;/code&gt;，然后选择&lt;code&gt;Other Linux&lt;/code&gt;，然后指定虚拟硬盘，选择&lt;code&gt;使用已有的虚拟硬盘文件&lt;/code&gt;，选择&lt;code&gt;immortalwrt.vdi&lt;/code&gt;文件，然后点击完成，然后设置里找到网络，选择&lt;code&gt;桥接网卡&lt;/code&gt;，勾选&lt;code&gt;Virtual Cable Connected&lt;/code&gt;，注意你的openwrt系统的&lt;code&gt;LAN&lt;/code&gt;口IP地址要和电脑在同一网段。网关和DNS也要和电脑的一致。&lt;/p&gt;
&lt;p&gt;系统内修改网络配置的命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vi /etc/config/network
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;/etc/init.d/network restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4：浏览器进入&lt;code&gt;LAN&lt;/code&gt;口IP地址，密码是脚本中设置的密码。&lt;/p&gt;
&lt;h1&gt;X86主机设备将镜像写入到硬盘&lt;/h1&gt;
&lt;p&gt;先将镜像烧录到U盘，然后使用U盘启动进入到openwrt系统，然后使用DD命令写入镜像，就可以拔掉U盘运行openwrt系统了。&lt;/p&gt;
&lt;h4&gt;查看U盘和目标硬盘&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;lsblk -f
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;例如 U 盘是 &lt;code&gt;/dev/sdb&lt;/code&gt;  硬盘是 &lt;code&gt;/dev/sda&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;如果目标硬盘有被挂载则需要卸载，例如之前装了系统之类的&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;umount /dev/sda1
umount /dev/sda2
umount /dev/sda3
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;检查是否卸载成功&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;mount | grep sda
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;如果返回为空就代表卸载成功了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;写入镜像（注意替换实际的U盘和硬盘）&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;dd if=/dev/sdb of=/dev/sda bs=4M conv=fsync
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;如果没报错，并且看到了两行数字就代表成功了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;强制刷新缓存&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sync
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;命令解释：&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;if=/dev/sdb&lt;/code&gt; ：输入源，U 盘设备&lt;/p&gt;
&lt;p&gt;&lt;code&gt;of=/dev/sda&lt;/code&gt; ：输出目标，硬盘/闪存设备&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bs=4M&lt;/code&gt; ：每次写入 4M，提高速度&lt;/p&gt;
&lt;p&gt;&lt;code&gt;conv=fsync&lt;/code&gt; ：写完后刷新缓存，确保数据落盘&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sync&lt;/code&gt; ：再次确保所有数据写入完成&lt;/p&gt;
</content:encoded></item><item><title>家庭网络之旁路由配置总结</title><link>https://emohe.cn/posts/35/</link><guid isPermaLink="true">https://emohe.cn/posts/35/</guid><pubDate>Fri, 14 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;上次买的香橙派玩了一段时间就吃灰了，想着不能浪费，得把他用上，因为只有一个网口所以就用来做旁路由了，装了openwrt系统。&lt;/p&gt;
&lt;p&gt;说一下我踩的坑：首先我看网上都是用旁路由做DHCP，主路由关闭DHCP，但是我这样做发现主路由没网，不知道什么情况。所以就用主路由做DHCP 给所有设备下发旁路的IP做网关，这样所有连接wifi的设备的网络都能经过旁路由了，而旁路由想要有网就得把网关指向路由器，所以路由器的地址得固定，并且旁路由在主路由的同一网段。网线则是旁路由的LAN口接主路由的LAN口，下面就是我已经跑通的配置，只需要配置主路由和旁路由就行了。&lt;/p&gt;
&lt;h2&gt;一、现有的网络环境示例&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;光猫拨号&lt;/li&gt;
&lt;li&gt;光猫 IP：&lt;code&gt;192.168.1.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;路由器 IP：&lt;code&gt;192.168.2.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;所有设备通过路由器的WIFI网络上网&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;二、路由器配置&lt;/h2&gt;
&lt;h3&gt;LAN口设置（也就是后台地址）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;IP 地址：&lt;code&gt;192.168.2.1&lt;/code&gt;（手动固定为此IP，防止变动）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;DHCP服务器&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;开启 DHCP&lt;/li&gt;
&lt;li&gt;地址池：&lt;code&gt;192.168.2.2&lt;/code&gt; – &lt;code&gt;192.168.2.254&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;网关：&lt;code&gt;192.168.2.2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;DNS：&lt;code&gt;192.168.2.2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;给所有连接wifi的设备下发旁路由的网关IP，方便设备的网络走旁路由。&lt;/p&gt;
&lt;h2&gt;三、旁路由配置（OpenWrt系统）&lt;/h2&gt;
&lt;h3&gt;LAN口设置（也就是后台地址）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;IP 地址：&lt;code&gt;192.168.2.2&lt;/code&gt;（手动固定为此IP，防止变动）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;DHCP设置&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;关闭 DHCP 服务&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;网关&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;设置为主路由器 IP：&lt;code&gt;192.168.2.1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;此配置适用于旁路由位于主路由的下级设备时，保证 IP 不冲突且网络稳定，且所有设备的网络能经过旁路由。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>解决UFW无法管理Docker映射端口的问题</title><link>https://emohe.cn/posts/34/</link><guid isPermaLink="true">https://emohe.cn/posts/34/</guid><pubDate>Sun, 21 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;解决UFW防火墙无法管理Docker映射出来的端口的问题&lt;/h3&gt;
&lt;p&gt;首先最简单的解决方案就是启动容器时，映射端口监听本地即可，例如&lt;code&gt;-p 127.0.0.1:8080:8080&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;支持管理正在运行中的容器的最佳解决方案&lt;/h3&gt;
&lt;p&gt;当然还有最佳的解决方案只需要修改一个 UFW 配置文件即可，Docker 的所有配置和选项都保持默认。&lt;/p&gt;
&lt;p&gt;修改 UFW 的配置文件 &lt;code&gt;/etc/ufw/after.rules&lt;/code&gt;，在最后添加上如下规则：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward

-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN

-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12

-A DOCKER-USER -j RETURN

-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix &quot;[UFW DOCKER BLOCK] &quot;
-A ufw-docker-logging-deny -j DROP

COMMIT
# END UFW AND DOCKER
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后重启 UFW，&lt;code&gt;sudo systemctl restart ufw&lt;/code&gt;。现在外部就已经无法访问 Docker 发布出来的任何端口了，但是容器内部以及私有网络地址上可以正常互相访问，而且容器也可以正常访问外部的网络。&lt;strong&gt;可能由于某些未知原因，重启 UFW 之后规则也无法生效，请重启服务器。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果希望允许外部网络访问 Docker 容器提供的服务，比如有一个容器的服务端口是 &lt;code&gt;80&lt;/code&gt;。那就可以用以下命令来允许外部网络访问这个服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ufw route allow proto tcp from any to any port 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个命令会允许外部网络访问所有用 Docker 发布出来的并且内部服务端口为 &lt;code&gt;80&lt;/code&gt; 的所有服务。&lt;/p&gt;
&lt;p&gt;请注意，这个端口 &lt;code&gt;80&lt;/code&gt; 是容器的端口，而非使用 &lt;code&gt;-p 0.0.0.0:8080:80&lt;/code&gt; 选项发布在服务器上的 &lt;code&gt;8080&lt;/code&gt; 端口。&lt;/p&gt;
&lt;p&gt;如果有多个容器的服务端口为 80，但只希望外部网络访问某个特定的容器。比如该容器的私有地址为 &lt;code&gt;172.17.0.2&lt;/code&gt;，就用类似下面的命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ufw route allow proto tcp from any to 172.17.0.2 port 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果一个容器的服务是 UDP 协议，假如是 DNS 服务，可以用下面的命令来允许外部网络访问所有发布出来的 DNS 服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ufw route allow proto udp from any to any port 53
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同样的，如果只针对一个特定的容器，比如 IP 地址为 &lt;code&gt;172.17.0.2&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ufw route allow proto udp from any to 172.17.0.2 port 53
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解释&lt;/h3&gt;
&lt;p&gt;在新增的这段规则中，下面这段规则是为了让私有网络地址可以互相访问。通常情况下，私有网络是比公共网络更信任的。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下面的规则是为了可以用 UFW 来管理外部网络是否允许访问 Docker 容器提供的服务，这样我们就可以在一个地方来管理防火墙的规则了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-A DOCKER-USER -j ufw-user-forward
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如，我们要阻止一个 IP 地址为 172.17.0.9 的容器内的所有对外连接，也就是阻止该容器访问外部网络，使用下列命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ufw route deny from 172.17.0.9 to any
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下面的规则阻止了所有外部网络发起的连接请求，但是允许内部网络访问外部网络。对于 TCP 协议，是阻止了从外部网络主动建立 TCP 连接。对于 UDP，是阻止了所有小余端口 &lt;code&gt;32767&lt;/code&gt; 的访问。为什么是这个端口的？由于 UDP 协议是无状态的，无法像 TCP 那样阻止发起建立连接请求的握手信号。在 GNU/Linux 上查看文件 &lt;code&gt;/proc/sys/net/ipv4/ip_local_port_range&lt;/code&gt; 可以看到发出 TCP/UDP 数据后，本地源端口的范围，默认为 &lt;code&gt;32768 60999&lt;/code&gt;。当从一个运行的容器对外访问一个 UDP 协议的服务时，本地端口将会从这个端口范围里面随机选择一个，服务器将会把数据返回到这个随机端口上。所以，我们可以假定所有容器内部的 UDP 协议的监听端口都小余 &lt;code&gt;32768&lt;/code&gt;，不允许外部网络主动连接小余 &lt;code&gt;32768&lt;/code&gt; 的 UDP 端口。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12

-A DOCKER-USER -j RETURN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果一个容器在接受数据的时候，端口号没有遵循操作系统的设定，也就是说最小端口号要小余 &lt;code&gt;32768&lt;/code&gt;。比如运行了一个 Dnsmasq 的容器，Dnsmasq 用于接受数据的最小端口号默认是 &lt;code&gt;1024&lt;/code&gt;。那可以用下面的命令来允许 Dnsmasq 这个容器使用一个更大的端口范围来接受数据。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ufw route allow proto udp from any port 53 to any port 1024:65535
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为 DNS 是一个非常常见的服务，所以已经有一条规则用于允许使用一个更大的端口范围来接受 DNS 数据包&lt;/p&gt;
</content:encoded></item><item><title>香橙派开发板折腾日记</title><link>https://emohe.cn/posts/33/</link><guid isPermaLink="true">https://emohe.cn/posts/33/</guid><pubDate>Sat, 06 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Orange Pi Zero3 香橙派开发板折腾日记&lt;/p&gt;
&lt;p&gt;主包最近从拼夕夕入手了Orange Pi Zero3开发板，4G内存，价格是199人民币。&lt;/p&gt;
&lt;p&gt;到货后就迫不及待的折腾了起来。&lt;/p&gt;
&lt;h3&gt;首先需要准备这些东西来安装系统&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;TF内存卡一个（16G以上）&lt;/li&gt;
&lt;li&gt;TF读卡器一个&lt;/li&gt;
&lt;li&gt;路由器用的网线一根&lt;/li&gt;
&lt;li&gt;&lt;code&gt;5V/2A&lt;/code&gt;USB充电头&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Type C&lt;/code&gt;口数据线&lt;/li&gt;
&lt;li&gt;写盘软件&lt;a href=&quot;https://etcher.balena.io/&quot;&gt;balenaEtcher&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意不要和SD卡搞混了，SD卡是大的，TF卡是小的&lt;/p&gt;
&lt;h3&gt;写入系统&lt;/h3&gt;
&lt;p&gt;首先去&lt;a href=&quot;http://www.orangepi.cn/&quot;&gt;香橙派官网&lt;/a&gt;，找到服务与下载，找到对应的型号，我这里是&lt;code&gt;Orange Pi Zero3&lt;/code&gt;，然后点击进去找到&lt;code&gt;官方镜像&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;点击进入官方提供的百度网盘地址，下载你想要的镜像，我这里下载的是&lt;code&gt;Debian 12&lt;/code&gt;系统，全称是&lt;code&gt;Orangepizero3_1.0.4_debian_bookworm_server_linux6.1.31.7z&lt;/code&gt;其中bookworm代表是12的版本，serve代表是服务器版本，不带桌面的那种。&lt;/p&gt;
&lt;p&gt;下载后用读卡器把TF卡插到电脑上，使用&lt;a href=&quot;https://etcher.balena.io/&quot;&gt;balenaEtcher&lt;/a&gt;将img格式的系统镜像烧录进去，完事后将TF卡插到香橙派开发板上。&lt;/p&gt;
&lt;p&gt;然后使用&lt;code&gt;5V/2A&lt;/code&gt;的USB充电头和&lt;code&gt;Type C&lt;/code&gt;数据线给香橙派接入电源。接入电源后不要拔掉，他会自动引导并安装系统，等一会后就可以用网线将香橙派连上路由器。连上路由器是为了方便远程连接。因为没有接外设的线。&lt;/p&gt;
&lt;h3&gt;使用SSH远程连接系统&lt;/h3&gt;
&lt;p&gt;现在就可以进入路由器后台找到香橙派的局域网IP地址，使用此IP地址进行SSH连接。&lt;/p&gt;
&lt;p&gt;Debian和Ubuntu系统的默认SSH用户名是&lt;code&gt;orangepi&lt;/code&gt;  密码是&lt;code&gt;orangepi&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;png/pai1.jpg&quot; alt=&quot;1&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;设置系统&lt;/h3&gt;
&lt;p&gt;通过SSH进入系统后，首先&lt;code&gt;sudo -i&lt;/code&gt;切换为root权限，然后使用&lt;code&gt;passwd&lt;/code&gt;命令设置一个root密码，请务必设置一个复杂的密码。&lt;/p&gt;
&lt;p&gt;设置完密码后使用&lt;code&gt;apt update&lt;/code&gt;更新一下源，然后安装一下常用的包&lt;code&gt;apt install -y curl wget git zip tar lsof vim sudo&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;禁用默认用户登录&lt;/h3&gt;
&lt;p&gt;我宽带是有公网的，为了安全起见，防止SSH被爆破，建议禁用默认用户远程登录，以Debian或者Ubuntu系统为例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 编辑SSH配置文件
nano /etc/ssh/sshd_config

# 文件末尾添加以下内容
DenyUsers orangepi

# 重启SSH服务
sudo systemctl restart ssh
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;连接WIFI&lt;/h3&gt;
&lt;p&gt;这个板子是支持wifi的，进入系统后，可以连上wifi，就不用插网线了。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;nmcli dev wifi&lt;/code&gt;命令搜索附件的WIFI&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;png/pai2.jpg&quot; alt=&quot;1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后使用如下命令连接WIFI&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nmcli device wifi connect &quot;Wi-Fi名称&quot; password &quot;Wi-Fi密码&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后使用&lt;code&gt;nmcli device status&lt;/code&gt;查看连接状态，如果输出的结果中有你连接的Wi-Fi名称，就代表连接成功。&lt;/p&gt;
&lt;p&gt;然后就可以使用&lt;code&gt;ip a&lt;/code&gt;来查看IP地址了，一般&lt;code&gt;end0&lt;/code&gt;是有线网卡，&lt;code&gt;wlan0&lt;/code&gt;是无线网卡，其他局域网地址可以通过这些IP来互联，或者SSH连接。当然也可以在路由器里查看分配的IP。&lt;/p&gt;
&lt;p&gt;然后后就可以跑各种服务了&lt;/p&gt;
</content:encoded></item><item><title>linux服务器免密ssh连接教程</title><link>https://emohe.cn/posts/31/</link><guid isPermaLink="true">https://emohe.cn/posts/31/</guid><pubDate>Tue, 12 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1：电脑本地生成SSH密钥对&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;ssh-keygen -t ed25519
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一路回车即可&lt;/p&gt;
&lt;h4&gt;本机是Win系统：&lt;/h4&gt;
&lt;p&gt;默认生成在&lt;code&gt;C:\Users\用户名\.ssh\&lt;/code&gt;目录&lt;/p&gt;
&lt;h4&gt;本机是Linux系统：&lt;/h4&gt;
&lt;p&gt;默认生成在&lt;code&gt;~/.ssh/&lt;/code&gt;目录&lt;/p&gt;
&lt;h2&gt;2：密钥对说明&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;id_ed25519&lt;/code&gt;是私钥，需要保存在本地，不能泄漏。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;id_ed25519.pub&lt;/code&gt;是公钥，需要将里面的内容复制到要连接的目标主机&lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;中，可以公开。&lt;/p&gt;
&lt;p&gt;这样就可以免密连接目标主机了，其他的都可以不用管，不过为了安全，建议关闭密码认证。&lt;/p&gt;
&lt;p&gt;私钥相当于钥匙，公钥相当于锁，将锁放在目标主机上，本机就可以使用钥匙开锁。&lt;/p&gt;
&lt;p&gt;当然也可以将锁放在多个目标主机上，实现一把钥匙开多个锁。也就是一个私钥免密连接多个主机。&lt;/p&gt;
&lt;h2&gt;3：&lt;code&gt;~&lt;/code&gt;目录说明&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;~&lt;/code&gt;代表当前用户的家目录&lt;/p&gt;
&lt;h4&gt;Linux系统：&lt;/h4&gt;
&lt;p&gt;普通用户：&lt;code&gt;~&lt;/code&gt;等于&lt;code&gt;/home/用户名/&lt;/code&gt;目录&lt;/p&gt;
&lt;p&gt;root用户：&lt;code&gt;~&lt;/code&gt;等于&lt;code&gt;/root/&lt;/code&gt;目录&lt;/p&gt;
&lt;h4&gt;Windows系统：&lt;/h4&gt;
&lt;p&gt;当前用户：&lt;code&gt;~&lt;/code&gt;等于&lt;code&gt;C:\Users\用户名\&lt;/code&gt;目录&lt;/p&gt;
&lt;h2&gt;4：使用命令将公钥复制到目标主机&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;ssh-copy-id -i ~/.ssh/id_ed25519.pub root@192.168.2.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你的目标主机ssh端口不是默认的22，则需要指定端口参数，例如2233端口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2233 root@192.168.2.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这条命令会自动把&lt;code&gt;id_ed25519.pub&lt;/code&gt;的内容追加到目标主机的&lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt;中&lt;/p&gt;
&lt;p&gt;多个主机可以使用脚本for循环批量执行&lt;/p&gt;
&lt;h2&gt;5：注意事项&lt;/h2&gt;
&lt;p&gt;目标主机上需要正确的权限设置，一般默认的权限就是正确的。无需改动。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你是在目标主机上生成SSH密钥对的话，则把私钥下载到本地即可。&lt;/p&gt;
</content:encoded></item><item><title>你绝对不知道的Docker高级实用技巧</title><link>https://emohe.cn/posts/32/</link><guid isPermaLink="true">https://emohe.cn/posts/32/</guid><pubDate>Tue, 12 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Docker-compose 实现一键编译并运行远程项目&lt;/h2&gt;
&lt;p&gt;众所周知&lt;code&gt;Docker-compose&lt;/code&gt;是可以直接在编排文件里实现自动构建并运行，无需额外&lt;code&gt;docker buiild&lt;/code&gt;，示例配置如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  app:
    build: .
    container_name: myapp
    ports:
      - &quot;3000:3000&quot;
    volumes:
      - ./app:/app
    restart: always
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Docker&lt;/code&gt;会自动构建运行编排项目，并自动寻找&lt;code&gt;Dockerfile&lt;/code&gt;文件并根据文件里构建步骤编译镜像，一般也都会将自己的项目文件&lt;code&gt;COPY&lt;/code&gt;到镜像里构建自己的项目镜像。&lt;/p&gt;
&lt;p&gt;此时有个小技巧，只需一个编排文件，无需项目文件也能实现同样的需求.&lt;/p&gt;
&lt;p&gt;那就是利用&lt;code&gt;Docker-compose&lt;/code&gt;自带的&lt;code&gt;git clone&lt;/code&gt;拉取代码的特性，实现本地构建远程仓库的项目。&lt;/p&gt;
&lt;h4&gt;参考编排文件如下：&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;services:
  live:
    build: https://cnb.cool/wanfeng789/live.git
    container_name: live
    ports:
      - &quot;1935:1935&quot;
      - &quot;80:80&quot;
      - &quot;443:443&quot;
    restart: always
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此配置可以直接构建远程仓库的代码，&lt;code&gt;Docker&lt;/code&gt;会先临时将&lt;code&gt;https://cnb.cool/wanfeng789/live.git&lt;/code&gt;远程仓库&lt;code&gt;git clone&lt;/code&gt;到一个临时目录.&lt;/p&gt;
&lt;p&gt;并根据仓库中的&lt;code&gt;Dockerfile&lt;/code&gt;进行编译。然后会自动清理刚刚下载的代码。&lt;/p&gt;
&lt;p&gt;这样就很方便编译远程仓库的项目并运行，同时不占用空间。很适合有洁癖的用户。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;PS：&lt;code&gt;cnb.cool/wanfeng789/live&lt;/code&gt;是我写的一个简约个人直播间项目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Docker bake介绍&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Docker bake&lt;/code&gt;是&lt;code&gt;Docker&lt;/code&gt;官方在&lt;code&gt;BuildKit&lt;/code&gt;里提供的一个高级构建命令&lt;/p&gt;
&lt;p&gt;主要作用是支持多目标、多平台的并行构建，并且可以用一个&lt;code&gt;bake&lt;/code&gt;文件（通常是&lt;code&gt;docker-bake.hcl&lt;/code&gt;或者&lt;code&gt;docker-bake.json&lt;/code&gt;）定义复杂的构建任务&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;Docker bake&lt;/code&gt;命令&lt;/h3&gt;
&lt;p&gt;执行&lt;code&gt;docker bake&lt;/code&gt;命令，会自动寻找当前目录的&lt;code&gt;docker-bake.hcl&lt;/code&gt;文件来自动构建&lt;/p&gt;
&lt;h3&gt;配置文件解释&lt;/h3&gt;
&lt;p&gt;1：&lt;code&gt;docker-bake.hcl&lt;/code&gt;构建多架构镜像，并且每个架构的镜像分开&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 定义一个构建组，组名叫 default
# 这个组包含两个目标：hello1 和 hello2
group &quot;default&quot; {
  targets = [&quot;hello1&quot;, &quot;hello2&quot;]
}

# 定义第一个构建目标 hello1
target &quot;hello1&quot; {
  context = &quot;.&quot;               # 构建上下文，当前目录（包含 Dockerfile）
  dockerfile = &quot;Dockerfile&quot;  # 指定 Dockerfile 文件路径
  tags = [&quot;hello/alpine:amd64&quot;]  
  platforms = [&quot;linux/amd64&quot;]  # 构建平台为 linux amd64 架构
}

# 定义第二个构建目标 hello2
target &quot;hello2&quot; {
  context = &quot;.&quot;               # 构建上下文，当前目录（包含 Dockerfile）
  dockerfile = &quot;Dockerfile&quot;  # 指定 Dockerfile 文件路径
  tags = [&quot;hello/alpine:arm64&quot;]
  platforms = [&quot;linux/arm64&quot;]  # 构建平台为 linux arm64 架构
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2：&lt;code&gt;docker-bake.hcl&lt;/code&gt;构建完成后自动推送到仓库&lt;/p&gt;
&lt;p&gt;需要事先&lt;code&gt;docker login&lt;/code&gt;登录仓库&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 定义构建组 default，只包含一个多平台目标 hello
group &quot;default&quot; {
  targets = [&quot;hello&quot;]
}

# 定义多平台构建目标 hello
target &quot;hello&quot; {
  context = &quot;.&quot;               # 构建上下文，当前目录（包含 Dockerfile）
  dockerfile = &quot;Dockerfile&quot;  # 指定 Dockerfile 文件路径

  # 镜像标签，自动推送到远程仓库，记得替换 hello 为你的用户名或仓库名
  tags = [&quot;hello/alpine:latest&quot;]

  # 同时构建 amd64 和 arm64 多个平台
  platforms = [&quot;linux/amd64&quot;, &quot;linux/arm64&quot;]

  # 开启构建完成后自动推送镜像，需要事先docker login登录仓库
  push = true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3：&lt;code&gt;docker-bake.hcl&lt;/code&gt;同时构建多个任务，并自动推送到仓库&lt;/p&gt;
&lt;p&gt;需要事先&lt;code&gt;docker login&lt;/code&gt;登录仓库&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;group &quot;default&quot; {
  targets = [&quot;php&quot;, &quot;nginx&quot;]
}

target &quot;php&quot; {
  context = &quot;.&quot;               # 构建上下文
  dockerfile = &quot;Dockerfile.php&quot;  # 第一个 Dockerfile
  tags = [&quot;hello/alpine:latest&quot;]
  platforms = [&quot;linux/amd64&quot;, &quot;linux/arm64&quot;]
  push = true # 动推送到仓库
}

target &quot;nginx&quot; {
  context = &quot;.&quot;                         # 构建上下文
  dockerfile = &quot;Dockerfile.nginx&quot;       # 第二个 Dockerfile 文件
  tags = [&quot;hello/ubuntu:latest&quot;]
  platforms = [&quot;linux/amd64&quot;, &quot;linux/arm64&quot;]
  push = true # 动推送到仓库
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;指定某个任务文件构建&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker bake --file my-bake.hcl
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;利用Docker bake批量并发拉取镜像&lt;/h3&gt;
&lt;p&gt;众所周知docker是不支持同时批量并发拉取镜像的.&lt;/p&gt;
&lt;p&gt;哪怕你把多个镜像放在&lt;code&gt;docker-compose.yml&lt;/code&gt;编排文件里，他也是一个个拉取，不是批量并发拉取的。&lt;/p&gt;
&lt;p&gt;此时可以借助&lt;code&gt;Docker bake&lt;/code&gt;的特性来实现批量并发拉取多个镜像。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ARG BASE_IMAGE=scratch
FROM ${BASE_IMAGE}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;docker-bake.hcl&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;group &quot;default&quot; {
  targets = [&quot;nginx&quot;, &quot;alpine&quot;, &quot;redis&quot;, &quot;mysql&quot;, &quot;caddy&quot;, &quot;busybox&quot;, &quot;python&quot;, &quot;node&quot;, &quot;golang&quot;, &quot;httpd&quot;]
}

target &quot;nginx&quot; {
  context = &quot;.&quot;
  dockerfile = &quot;Dockerfile&quot;
  args = { BASE_IMAGE = &quot;nginx:latest&quot; }
  tags = [&quot;nginx:latest&quot;]
}

target &quot;alpine&quot; {
  context = &quot;.&quot;
  dockerfile = &quot;Dockerfile&quot;
  args = { BASE_IMAGE = &quot;alpine:latest&quot; }
  tags = [&quot;alpine:latest&quot;]
}

target &quot;redis&quot; {
  context = &quot;.&quot;
  dockerfile = &quot;Dockerfile&quot;
  args = { BASE_IMAGE = &quot;redis:latest&quot; }
  tags = [&quot;redis:latest&quot;]
}

target &quot;mysql&quot; {
  context = &quot;.&quot;
  dockerfile = &quot;Dockerfile&quot;
  args = { BASE_IMAGE = &quot;mysql:latest&quot; }
  tags = [&quot;mysql:latest&quot;]
}

target &quot;caddy&quot; {
  context = &quot;.&quot;
  dockerfile = &quot;Dockerfile&quot;
  args = { BASE_IMAGE = &quot;caddy:latest&quot; }
  tags = [&quot;caddy:latest&quot;]
}

target &quot;busybox&quot; {
  context = &quot;.&quot;
  dockerfile = &quot;Dockerfile&quot;
  args = { BASE_IMAGE = &quot;busybox:latest&quot; }
  tags = [&quot;busybox:latest&quot;]
}

target &quot;python&quot; {
  context = &quot;.&quot;
  dockerfile = &quot;Dockerfile&quot;
  args = { BASE_IMAGE = &quot;python:3.11-slim&quot; }
  tags = [&quot;python:3.11-slim&quot;]
}

target &quot;node&quot; {
  context = &quot;.&quot;
  dockerfile = &quot;Dockerfile&quot;
  args = { BASE_IMAGE = &quot;node:18-alpine&quot; }
  tags = [&quot;node:18-alpine&quot;]
}

target &quot;golang&quot; {
  context = &quot;.&quot;
  dockerfile = &quot;Dockerfile&quot;
  args = { BASE_IMAGE = &quot;golang:1.21-alpine&quot; }
  tags = [&quot;golang:1.21-alpine&quot;]
}

target &quot;httpd&quot; {
  context = &quot;.&quot;
  dockerfile = &quot;Dockerfile&quot;
  args = { BASE_IMAGE = &quot;httpd:latest&quot; }
  tags = [&quot;httpd:latest&quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行拉取命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker buildx bake --load
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>写了一个简约直播间</title><link>https://emohe.cn/posts/30/</link><guid isPermaLink="true">https://emohe.cn/posts/30/</guid><pubDate>Mon, 11 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;简约优雅的个人直播间&lt;/h2&gt;
&lt;p&gt;闲着没事开发了一个网页直播间，基于 Tailwind CSS + shadcn/ui 风格。轻量，简约，自托管，使用rtmp协议推流。&lt;/p&gt;
&lt;p&gt;代码地址：https://cnb.cool/wanfeng789/live&lt;/p&gt;
&lt;h3&gt;Docker一键运行&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  --name live \
  -p 1935:1935 \
  -p 80:80 \
  -p 443:443 \
  --restart always \
  docker.cnb.cool/wanfeng789/live
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;可选映射：-v ./Caddyfile:/etc/caddy/Caddyfile \&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;可以修改&lt;code&gt;Caddyfile&lt;/code&gt;配置中第一行为你的域名，如果不修改则默认使用&lt;code&gt;80&lt;/code&gt;端口&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;查看推流密钥&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker exec live wget -qO- 127.0.0.1:8090/control/get?room=movie
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;配置直播软件&lt;/h3&gt;
&lt;p&gt;使用 OBS 或FFmpeg等软件推流直播。&lt;/p&gt;
&lt;p&gt;推流地址为 &lt;code&gt;rtmp://example.com:1935/live/密钥&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;查看直播&lt;/h3&gt;
&lt;p&gt;浏览器地址输入你的&lt;code&gt;地址&lt;/code&gt;查看您的直播。&lt;/p&gt;
&lt;h3&gt;预览&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;png/live.png&quot; alt=&quot;1&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>Windows使用Scoop包管理器</title><link>https://emohe.cn/posts/29/</link><guid isPermaLink="true">https://emohe.cn/posts/29/</guid><pubDate>Mon, 30 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Windows系统使用Scoop包管理器教程&lt;/h1&gt;
&lt;h3&gt;Scoop 包管理器优势&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;无需管理员权限&lt;/strong&gt;：安装在用户目录，干净无系统污染。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;绿色便携&lt;/strong&gt;：软件以解压包形式安装，卸载即删目录。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多版本管理&lt;/strong&gt;：支持同一软件多版本安装与切换。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Git + JSON驱动&lt;/strong&gt;：包描述开源，灵活可扩展。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开发友好&lt;/strong&gt;：一键自动安装，自动配置环境变量，多版本管理等等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优秀的开发环境支持&lt;/strong&gt;：一键安装Node.js、Python、Go等等多种开发工具。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;软件众多&lt;/strong&gt;：支持各种软件包，开发环境，以及常用的Gui软件。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;步骤 1：启用 PowerShell 执行策略&lt;/h2&gt;
&lt;p&gt;在安装 Scoop 之前，您需要允许 PowerShell 执行脚本。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PowerShell 执行以下命令：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当提示时，输入 &lt;code&gt;A&lt;/code&gt; 并按回车键确认。&lt;/p&gt;
&lt;h2&gt;步骤 2：安装 Scoop&lt;/h2&gt;
&lt;p&gt;先&lt;a href=&quot;https://git-scm.com/&quot;&gt;安装Git工具&lt;/a&gt;，Scoop依赖Git工具的支持，安装完成后就可以安装 Scoop 了&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在当前 PowerShell 窗口中，执行以下命令：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;irm get.scoop.sh | iex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这将下载并执行 Scoop 的安装脚本。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;验证安装成功&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;scoop help
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;步骤 3：bucket&lt;/h2&gt;
&lt;p&gt;为了能够安装更多软件，您可以添加一些常用的 bucket。&lt;/p&gt;
&lt;h3&gt;Scoop 官方常用 Bucket 介绍&lt;/h3&gt;
&lt;p&gt;也就是Github仓库上的软件清单列表&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;main&lt;br /&gt;
地址：https://github.com/ScoopInstaller/Main&lt;br /&gt;
说明：官方主仓库，常用软件和基础工具，默认存在，无需配置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;extras&lt;br /&gt;
地址：https://github.com/ScoopInstaller/Extras&lt;br /&gt;
说明：较多 GUI 软件、实用工具&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;versions&lt;br /&gt;
地址：https://github.com/ScoopInstaller/Versions&lt;br /&gt;
说明：多版本软件（Node.js、Python、JDK 等）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更多包搜索：https://scoop.sh/&lt;/p&gt;
&lt;h2&gt;添加更多Bucket&lt;/h2&gt;
&lt;p&gt;先删除默认源，也就是Bucket&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;scoop bucket rm main
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;main&lt;/code&gt;代表源的名称，此源是默认就有的源。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;scoop的源也叫&lt;code&gt;bucket仓库&lt;/code&gt;，托管在Github，所以需要添加Github加速：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;scoop bucket add main https://gh-proxy.com/https://github.com/ScoopInstaller/Main.git

scoop bucket add versions https://gh-proxy.com/https://github.com/ScoopInstaller/Versions.git

scoop bucket add extras https://gh-proxy.com/https://github.com/ScoopInstaller/Extras.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看所有bucket仓库&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;scoop bucket list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装的软件存放目录&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Users\&amp;lt;你的用户名&amp;gt;\scoop\
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常用命令示例&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;搜索软件：&lt;/strong&gt; &lt;code&gt;scoop search 软件名&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安装软件：&lt;/strong&gt; &lt;code&gt;scoop install 软件名&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更新软件：&lt;/strong&gt; &lt;code&gt;scoop update 软件名&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更新所有软件：&lt;/strong&gt; &lt;code&gt;scoop update *&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;卸载软件：&lt;/strong&gt; &lt;code&gt;scoop uninstall 软件名&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;查看安装缓存：&lt;/strong&gt; &lt;code&gt;scoop cache&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;清理所有缓存：&lt;/strong&gt; &lt;code&gt;scoop cache rm *&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;安装多个版本（示例）&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;scoop install nodejs   # 最新稳定版
scoop install nodejs20 # 20.x 版本
scoop install nodejs18 # 18.x 版本
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;查看已安装版本&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;scoop list nodejs*
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;使用 scoop reset 切换版本&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;scoop reset nodejs18
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这条命令会把 node 命令指向 nodejs18 版本。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;验证当前版本&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;node -v
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;安装完成后记得清理下载的缓存&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;scoop cache rm *
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>腾讯云免费Pages配合Github-CICD自动部署教程</title><link>https://emohe.cn/posts/28/</link><guid isPermaLink="true">https://emohe.cn/posts/28/</guid><pubDate>Sat, 28 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;腾讯云免费Pages配合Github-CICD自动部署教程&lt;/p&gt;
&lt;p&gt;地址：https://console.cloud.tencent.com/edgeone/pages&lt;/p&gt;
&lt;h3&gt;1：获取api token&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;./png/p1.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;创建一个token，名称随便填，有效期看情况选择，我选的永久。&lt;/p&gt;
&lt;h3&gt;2：Github-CICD配置，以我的配置为例&lt;/h3&gt;
&lt;p&gt;Github仓库文件路径&lt;code&gt;.github/workflows/edgeone.yml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;查看配置代码&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: 腾讯pages推送

on:
  push:
    paths:
      - &apos;README.md&apos;
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: &quot;build&quot;
  cancel-in-progress: false

env:
  BUILD_PATH: &quot;.&quot;

jobs:
  build:
    name: 构建并部署
    runs-on: ubuntu-latest
    steps:
      - name: 检出代码
        uses: actions/checkout@v4

      - name: 安装 Node.js
        uses: actions/setup-node@v4
        with:
          node-version: &apos;22&apos;

      - name: 安装 pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 9
          standalone: true

      - name: 安装 edgeone CLI
        run: npm install -g edgeone

      - name: 检测包管理器
        id: detect-package-manager
        run: |
          if [ -f &quot;${{ github.workspace }}/yarn.lock&quot; ]; then
            echo &quot;manager=yarn&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
            echo &quot;command=install&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
            echo &quot;runner=yarn&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
            echo &quot;lockfile=yarn.lock&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
            exit 0
          elif [ -f &quot;${{ github.workspace }}/package.json&quot; ]; then
            echo &quot;manager=pnpm&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
            echo &quot;command=install&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
            echo &quot;runner=pnpm&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
            echo &quot;lockfile=pnpm-lock.yaml&quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT
            exit 0
          else
            echo &quot;无法检测到包管理器&quot;
            exit 1
          fi

      - name: 安装依赖
        run: pnpm install
        working-directory: ${{ env.BUILD_PATH }}

      - name: 安装 sharp 依赖
        run: pnpm add sharp
        working-directory: ${{ env.BUILD_PATH }}

      - name: 构建产物
        run: pnpm run build
        working-directory: ${{ env.BUILD_PATH }}

      - name: 上传构建产物
        uses: actions/upload-artifact@v4
        with:
          name: astro-build-artifact
          path: ${{ env.BUILD_PATH }}/dist
          retention-days: 1

      - name: 部署到 edgeone
        env:
          EDGEONE_API_TOKEN: ${{ secrets.EDGEONE_API_TOKEN }}
        run: |
          edgeone pages deploy ./dist -n project-name -t &quot;$EDGEONE_API_TOKEN&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;此流水线的配置环境是&lt;code&gt;node 22&lt;/code&gt;和&lt;code&gt;pnpm 9&lt;/code&gt;，可以根据自己情况修改，触发条件是有新的推送即可自动触发任务，README.md文件除外，同时也支持手动点击触发。&lt;/p&gt;
&lt;h3&gt;3：在仓库的设置里添加token变量，是仓库的设置，不是账号的设置。&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;./png/p2.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/p3.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;4：构建&lt;/h3&gt;
&lt;p&gt;配置好了后就可以触发构建了，提交一次代码或者手动点击触发构建，等待构建完成后，就可以回到刚刚的腾讯云pages后台查看了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/p4.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;5：配置自定义域名&lt;/h3&gt;
&lt;p&gt;点击这个项目，然后找到项目设置就可以添加自定义域名了，添加后然后将域名CNAME解析一下就完成了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/p5.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我的腾讯云Pages域名是：&lt;a href=&quot;https://blog.emohe.cn&quot;&gt;blog.emohe.cn&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>支付宝收款码前端动态渲染</title><link>https://emohe.cn/posts/27/</link><guid isPermaLink="true">https://emohe.cn/posts/27/</guid><pubDate>Wed, 14 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import AlipayTip from &apos;@/components/alipay/AlipayTip.astro&apos;&lt;/p&gt;
&lt;h1&gt;支付宝收款码使用浏览器动态渲染&lt;/h1&gt;
&lt;p&gt;无需自己上传收款码图片，用户输入金额后前端自动生成对应金额的转账二维码，个人账户原生支持，只需到官网获取账户ID即可调用。&lt;/p&gt;
&lt;h3&gt;先看成果：&lt;/h3&gt;
&lt;p&gt;&amp;lt;AlipayTip /&amp;gt;&lt;/p&gt;
&lt;h3&gt;技术解析&lt;/h3&gt;
&lt;p&gt;原理是前端调用&lt;code&gt;alipays://&lt;/code&gt;支付宝私有协议，是支付宝&lt;code&gt;Alipay&lt;/code&gt;客户端使用的私有 URL 协议，也叫&lt;code&gt;URL Scheme&lt;/code&gt;，用于通过网页、App 或其他外部应用调用支付宝客户端，执行特定动作，比如打开某个页面、发起支付、跳转小程序等。&lt;/p&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alipays://platformapi/startapp?appId=20000123&amp;amp;actionType=scan&amp;amp;biz_data={&quot;s&quot;:&quot;money&quot;,&quot;u&quot;:&quot;2088xxxxxx&quot;,&quot;a&quot;:&quot;10&quot;,&quot;m&quot;:&quot;打赏支持&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后使用&lt;code&gt;qrcode&lt;/code&gt;将私有协议链接转换为二维码就行了。&lt;/p&gt;
&lt;p&gt;参数解析：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;appId=20000123&lt;/code&gt;：支付宝内置的&quot;转账到个人账户&quot;功能编号&lt;/p&gt;
&lt;p&gt;&lt;code&gt;actionType=scan&lt;/code&gt;：指定操作为扫码支付&lt;/p&gt;
&lt;p&gt;&lt;code&gt;biz_data&lt;/code&gt;：核心业务参数（JSON格式，需URL编码）：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;s: &quot;money&quot;&lt;/code&gt;：固定值，表示转账业务&lt;/p&gt;
&lt;p&gt;&lt;code&gt;u: &quot;2088xxxxxx&quot;&lt;/code&gt;：收款方支付宝UID（用户唯一标识）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;a: &quot;10&quot;&lt;/code&gt;：初始转账金额（单位：元）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;m: &quot;打赏支持&quot;&lt;/code&gt;：转账备注（显示在支付宝账单）&lt;/p&gt;
</content:encoded></item><item><title>前端性能优化技术汇总</title><link>https://emohe.cn/posts/26/</link><guid isPermaLink="true">https://emohe.cn/posts/26/</guid><pubDate>Tue, 06 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;🚀 前端性能优化技术合集与汇总（含示例）&lt;/h1&gt;
&lt;h2&gt;1. 资源加载优化&lt;/h2&gt;
&lt;h3&gt;异步加载（Asynchronous Loading）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：不阻塞页面渲染，后台加载资源，加载完成后执行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：使用 &lt;code&gt;async&lt;/code&gt;、&lt;code&gt;defer&lt;/code&gt; 属性异步加载 JS 脚本。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- async: 下载完成后立即执行，可能中断HTML解析，执行顺序不定 --&amp;gt;
&amp;lt;script async src=&quot;analytics.js&quot;&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;!-- defer: HTML解析完成后，DOMContentLoaded事件前按顺序执行 --&amp;gt;
&amp;lt;script defer src=&quot;main-bundle.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;懒加载（Lazy Loading）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：仅在需要时加载资源（如图片、视频、组件等）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：图片、视频、组件、评论等在进入视口时再加载。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- 使用 loading=&quot;lazy&quot; 属性（浏览器原生支持） --&amp;gt;
&amp;lt;img src=&quot;placeholder.jpg&quot; data-src=&quot;real-image.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Lazy loaded image&quot;&amp;gt;
&amp;lt;iframe src=&quot;placeholder.html&quot; data-src=&quot;real-content.html&quot; loading=&quot;lazy&quot;&amp;gt;&amp;lt;/iframe&amp;gt;

&amp;lt;!-- 使用 Intersection Observer API 实现自定义懒加载 --&amp;gt;
&amp;lt;script&amp;gt;
  const images = document.querySelectorAll(&apos;img[data-src]&apos;);
  const observer = new IntersectionObserver((entries, observer) =&amp;gt; {
    entries.forEach(entry =&amp;gt; {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        img.removeAttribute(&apos;data-src&apos;);
        observer.unobserve(img);
      }
    });
  });
  images.forEach(img =&amp;gt; observer.observe(img));
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;预加载（Preload）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：页面加载时提前加载未来可能需要的资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：使用 &lt;code&gt;&amp;lt;link rel=&quot;preload&quot; href=&quot;...&quot; as=&quot;...&quot;&amp;gt;&lt;/code&gt; 提前加载重要资源（如字体、脚本）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- 预加载关键CSS文件 --&amp;gt;
&amp;lt;link rel=&quot;preload&quot; href=&quot;critical.css&quot; as=&quot;style&quot;&amp;gt;

&amp;lt;!-- 预加载将在稍后使用的JS文件 --&amp;gt;
&amp;lt;link rel=&quot;preload&quot; href=&quot;late-loaded-script.js&quot; as=&quot;script&quot;&amp;gt;

&amp;lt;!-- 预加载字体文件 --&amp;gt;
&amp;lt;link rel=&quot;preload&quot; href=&quot;font.woff2&quot; as=&quot;font&quot; type=&quot;font/woff2&quot; crossorigin&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;空闲时间调度（Idle Time Scheduling）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 &lt;code&gt;requestIdleCallback&lt;/code&gt; 在浏览器空闲时执行低优先级任务，提升页面响应。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：适用于非关键任务的加载和执行，如发送分析数据、预渲染不可见内容。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;requestIdleCallback((deadline) =&amp;gt; {
  // 如果有剩余时间，或者任务必须执行
  if (deadline.timeRemaining() &amp;gt; 0 || deadline.didTimeout) {
    // 执行低优先级任务，例如发送统计数据
    sendAnalyticsData();
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. 资源压缩与合并&lt;/h2&gt;
&lt;h3&gt;图片压缩（Image Optimization）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：压缩图片文件，减少图片体积，使用高效格式（如 WebP、AVIF）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：网站中所有使用的图片资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工具&lt;/strong&gt;: 使用在线工具如 TinyPNG、Squoosh.app 或构建工具插件（如 &lt;code&gt;imagemin-webpack-plugin&lt;/code&gt;）进行自动化压缩。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;格式选择&lt;/strong&gt;: 使用 &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 标签提供多种格式供浏览器选择。&lt;pre&gt;&lt;code&gt;&amp;lt;picture&amp;gt;
  &amp;lt;source srcset=&quot;image.avif&quot; type=&quot;image/avif&quot;&amp;gt;
  &amp;lt;source srcset=&quot;image.webp&quot; type=&quot;image/webp&quot;&amp;gt;
  &amp;lt;img src=&quot;image.jpg&quot; alt=&quot;Optimized image&quot;&amp;gt;
&amp;lt;/picture&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;JS / CSS 压缩（Minification）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：去除代码中的空格、注释等，减少文件体积，提升加载速度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：生产环境中的所有 JavaScript 和 CSS 文件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;构建工具&lt;/strong&gt;: 使用 Webpack、Rollup、Parcel 等构建工具，并配置相应的插件（如 &lt;code&gt;TerserWebpackPlugin&lt;/code&gt; 用于 JS，&lt;code&gt;CssMinimizerWebpackPlugin&lt;/code&gt; 用于 CSS）在生产构建时自动压缩代码。&lt;pre&gt;&lt;code&gt;// webpack.config.js (示例)
const TerserPlugin = require(&apos;terser-webpack-plugin&apos;);
const CssMinimizerPlugin = require(&apos;css-minimizer-webpack-plugin&apos;);

module.exports = {
  // ...
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin(),
      new CssMinimizerPlugin(),
    ],
  },
  // ...
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CSS 和 JS 合并（Concatenation）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：合并多个文件，减少 HTTP 请求次数（在 HTTP/1.1 环境下尤其重要，HTTP/2 中重要性降低但仍有益）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：将多个小的 CSS 或 JS 文件合并成一个或少数几个较大的文件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;构建工具&lt;/strong&gt;: Webpack、Rollup 等现代构建工具通常在打包过程中自动处理模块合并。确保配置合理，避免生成过大的单一文件，可以结合代码分割使用。&lt;pre&gt;&lt;code&gt;// main.js (示例入口文件)
import &apos;./moduleA.js&apos;;
import &apos;./moduleB.js&apos;;
import &apos;./styles.css&apos;;
import &apos;./more-styles.css&apos;;

// 构建工具会将这些导入合并到输出的 bundle 文件中
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. 代码优化&lt;/h2&gt;
&lt;h3&gt;代码分割（Code Splitting）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：按需加载 JS 代码，减小首屏加载体积，常见于单页应用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：使用动态 &lt;code&gt;import()&lt;/code&gt; 和路由懒加载，按需加载模块。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 使用动态 import() 按需加载模块
document.getElementById(&apos;loadButton&apos;).addEventListener(&apos;click&apos;, () =&amp;gt; {
  import(&apos;./heavy-module.js&apos;)
    .then(module =&amp;gt; {
      module.doSomething();
    })
    .catch(err =&amp;gt; {
      console.error(&apos;Failed to load module:&apos;, err);
    });
});

// 路由懒加载 (以 React Router 为例)
import React, { Suspense, lazy } from &apos;react&apos;;
import { BrowserRouter as Router, Route, Switch } from &apos;react-router-dom&apos;;

const HomePage = lazy(() =&amp;gt; import(&apos;./routes/HomePage&apos;));
const AboutPage = lazy(() =&amp;gt; import(&apos;./routes/AboutPage&apos;));

const App = () =&amp;gt; (
  &amp;lt;Router&amp;gt;
    &amp;lt;Suspense fallback={&amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}&amp;gt;
      &amp;lt;Switch&amp;gt;
        &amp;lt;Route exact path=&quot;/&quot; component={HomePage} /&amp;gt;
        &amp;lt;Route path=&quot;/about&quot; component={AboutPage} /&amp;gt;
      &amp;lt;/Switch&amp;gt;
    &amp;lt;/Suspense&amp;gt;
  &amp;lt;/Router&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Tree Shaking&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：删除未使用的代码（dead code elimination），减小打包体积，优化代码执行效率。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：适用于 Webpack、Rollup 等支持 Tree Shaking 的工具，需要使用 ES6 模块语法（&lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;构建工具配置&lt;/strong&gt;: 在 Webpack 中，将 &lt;code&gt;mode&lt;/code&gt; 设置为 &lt;code&gt;production&lt;/code&gt; 会自动启用 Tree Shaking。确保你的代码使用 ES6 模块，并且没有副作用（side effects）阻止 Tree Shaking。&lt;pre&gt;&lt;code&gt;// webpack.config.js
module.exports = {
  mode: &apos;production&apos;, // 启用包括 Tree Shaking 在内的多项优化
  // ...
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标记副作用&lt;/strong&gt;: 如果某个模块有副作用（例如，全局样式注入、polyfill），可以在 &lt;code&gt;package.json&lt;/code&gt; 中标记。&lt;pre&gt;&lt;code&gt;// package.json
{
  &quot;name&quot;: &quot;my-library&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;sideEffects&quot;: false // 默认无副作用，利于 Tree Shaking
  // 或者指定有副作用的文件
  // &quot;sideEffects&quot;: [&quot;./src/polyfill.js&quot;, &quot;*.css&quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Font Subsetting&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：只加载网页中使用的字符集，减少字体文件的体积。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：适用于自定义字体加载和优化，特别是中文字体等字符集庞大的字体。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工具&lt;/strong&gt;: 使用 &lt;code&gt;font-spider&lt;/code&gt; (国人开发，适合中文字体)、&lt;code&gt;glyphhanger&lt;/code&gt; 或在线字体子集化工具，根据项目实际使用的文字生成精简后的字体文件。&lt;pre&gt;&lt;code&gt;# 使用 font-spider (示例)
# 1. 在 CSS 中正常引用字体
# @font-face {
#   font-family: &apos;MyFont&apos;;
#   src: url(&apos;../fonts/MyFont.ttf&apos;);
# }
# body {
#   font-family: &apos;MyFont&apos;;
# }
# 2. 运行命令扫描 HTML 文件并生成子集字体
font-spider ./index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4. 浏览器渲染优化&lt;/h2&gt;
&lt;h3&gt;减少重排与重绘（Reflow &amp;amp; Repaint）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：避免频繁修改布局（如 &lt;code&gt;width&lt;/code&gt;、&lt;code&gt;height&lt;/code&gt;、&lt;code&gt;top&lt;/code&gt;、&lt;code&gt;left&lt;/code&gt;），减少重排（Reflow/Layout）。优化 DOM 操作，避免页面卡顿和性能瓶颈。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：涉及 DOM 元素尺寸、位置、内容变化的 JavaScript 操作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 不好的做法：每次循环都读取 offsetHeight，可能触发重排
for (let i = 0; i &amp;lt; elements.length; i++) {
  elements[i].style.width = elements[i].offsetHeight + &apos;px&apos;; // 读取触发重排
}

// 改进：先读后写，分离读写操作
const heights = [];
for (let i = 0; i &amp;lt; elements.length; i++) {
  heights[i] = elements[i].offsetHeight; // 批量读取
}
for (let i = 0; i &amp;lt; elements.length; i++) {
  elements[i].style.width = heights[i] + &apos;px&apos;; // 批量写入
}

// 使用 CSS transform 代替 top/left 实现位移动画，避免重排
// 不推荐
// element.style.left = x + &apos;px&apos;;
// element.style.top = y + &apos;px&apos;;

// 推荐
element.style.transform = `translate(${x}px, ${y}px)`;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;合并 DOM 操作&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：将多次 DOM 操作合并成一次，减少重排和重绘的频率。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：需要向 DOM 中插入多个元素时。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const list = document.getElementById(&apos;myList&apos;);
const items = [&apos;Apple&apos;, &apos;Banana&apos;, &apos;Cherry&apos;];

// 不好的做法：每次循环都操作 DOM
// items.forEach(itemText =&amp;gt; {
//   const li = document.createElement(&apos;li&apos;);
//   li.textContent = itemText;
//   list.appendChild(li); // 每次 appendChild 都可能触发重排/重绘
// });

// 推荐：使用 DocumentFragment
const fragment = document.createDocumentFragment();
items.forEach(itemText =&amp;gt; {
  const li = document.createElement(&apos;li&apos;);
  li.textContent = itemText;
  fragment.appendChild(li); // 操作 Fragment 不会触发重排/重绘
});
list.appendChild(fragment); // 最后一次性插入 DOM
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;硬件加速（Transform &amp;amp; Opacity）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 &lt;code&gt;transform&lt;/code&gt; 和 &lt;code&gt;opacity&lt;/code&gt; 代替布局属性（如 &lt;code&gt;top&lt;/code&gt;、&lt;code&gt;left&lt;/code&gt;）进行动画，利用 GPU 加速，提高动画流畅度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：实现位移、缩放、旋转、透明度等动画效果。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.animated-element {
  /* 不推荐：使用 top/left 可能导致重排，动画可能卡顿 */
  /* position: absolute; */
  /* left: 0; */
  /* transition: left 0.3s ease; */

  /* 推荐：使用 transform 利用 GPU 加速 */
  transform: translateX(0);
  transition: transform 0.3s ease, opacity 0.3s ease;
  opacity: 1;
}

.animated-element.move {
  /* transform: translateX(100px); */
  transform: translate3d(100px, 0, 0); /* 强制开启 GPU 加速 */
}

.animated-element.fade-out {
  opacity: 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;will-change 提前通知浏览器&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 &lt;code&gt;will-change&lt;/code&gt; 提前告知浏览器即将发生的样式变化，让浏览器可以提前进行优化准备，避免渲染瓶颈。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：用于即将发生复杂变化的元素，特别是动画元素。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element-about-to-animate {
  /* 告知浏览器 transform 和 opacity 属性即将发生变化 */
  will-change: transform, opacity;
}

.element-about-to-animate:hover {
  transform: scale(1.1);
  opacity: 0.8;
}

/* 注意：不要滥用 will-change，仅在确实需要时添加，并在变化结束后移除 */
/* 可以通过 JavaScript 在动画开始前添加，结束后移除 */
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. 网络优化&lt;/h2&gt;
&lt;h3&gt;HTTP/2 / HTTP/3 协议&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：启用 HTTP/2 或 HTTP/3，利用其多路复用、头部压缩、服务器推送（HTTP/2）、基于 UDP 的 QUIC（HTTP/3）等特性，提高并行传输效率，减少请求延迟。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：Web 服务器配置。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;服务器配置&lt;/strong&gt;: 在 Nginx, Apache 或其他 Web 服务器上启用 HTTP/2 或 HTTP/3 支持（通常需要 HTTPS）。&lt;pre&gt;&lt;code&gt;# Nginx 配置启用 HTTP/2 (示例)
server {
    listen 443 ssl http2;
    # ... 其他 SSL 配置 ...
}
# Nginx 配置启用 HTTP/3 (需要较新版本和额外模块)
server {
    listen 443 quic reuseport;
    listen 443 ssl http2;
    # ... 其他 SSL 和 HTTP/3 配置 ...
    add_header Alt-Svc &apos;h3=&quot;:443&quot;; ma=86400&apos;; # 告知浏览器支持 HTTP/3
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;验证&lt;/strong&gt;: 使用浏览器开发者工具的网络(Network)面板查看协议版本。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Content Delivery Network (CDN)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 CDN 将静态资源（如图片、CSS、JS）缓存到全球各地的边缘节点，用户从最近的节点获取资源，减少网络延迟，提高加载速度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：网站的静态资源分发。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;服务商&lt;/strong&gt;: 选择 CDN 服务商（如 Cloudflare, Akamai, AWS CloudFront, 阿里云 CDN, 腾讯云 CDN 等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置&lt;/strong&gt;: 将静态资源的 URL 指向 CDN 提供的域名。&lt;pre&gt;&lt;code&gt;&amp;lt;!-- 原始路径 --&amp;gt;
&amp;lt;!-- &amp;lt;script src=&quot;/assets/app.js&quot;&amp;gt;&amp;lt;/script&amp;gt; --&amp;gt;
&amp;lt;!-- &amp;lt;img src=&quot;/images/logo.png&quot;&amp;gt; --&amp;gt;

&amp;lt;!-- 使用 CDN 路径 --&amp;gt;
&amp;lt;script src=&quot;https://cdn.example.com/assets/app.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;img src=&quot;https://cdn.example.com/images/logo.png&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;缓存优化（Caching）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 HTTP 缓存头（如 &lt;code&gt;Cache-Control&lt;/code&gt;、&lt;code&gt;ETag&lt;/code&gt;、&lt;code&gt;Last-Modified&lt;/code&gt;）优化资源缓存，让浏览器可以复用已下载的资源，减少重复请求。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：所有可以通过 HTTP 请求的资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;服务器配置&lt;/strong&gt;: 配置 Web 服务器发送合适的缓存头。&lt;pre&gt;&lt;code&gt;# Nginx 配置示例
location ~* \.(?:css|js)$ {
    # 强缓存：缓存 1 年
    add_header Cache-Control &quot;public, max-age=31536000, immutable&quot;;
    access_log off;
}

location ~* \.(?:jpg|jpeg|png|gif|ico|webp|avif)$ {
    # 强缓存：缓存 1 个月
    add_header Cache-Control &quot;public, max-age=2592000&quot;;
    access_log off;
}

location = /index.html {
    # 协商缓存：每次验证
    add_header Cache-Control &quot;no-cache&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ETag&lt;/strong&gt;: 服务器为资源生成唯一标识，浏览器下次请求时通过 &lt;code&gt;If-None-Match&lt;/code&gt; 发送此标识，服务器比对后若无变化则返回 304 Not Modified。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Last-Modified&lt;/strong&gt;: 服务器告知资源最后修改时间，浏览器下次通过 &lt;code&gt;If-Modified-Since&lt;/code&gt; 发送此时间，服务器比对后若无更新则返回 304。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;DNS 预解析 / 预连接（DNS Prefetch / Preconnect）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：提前解析域名或建立到目标源（域名+端口）的 TCP 连接（甚至 TLS 握手），减少后续资源请求时的延迟。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：页面中引用了来自其他域名的资源（如 CDN、API、第三方脚本）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- DNS 预解析：提前解析域名 --&amp;gt;
&amp;lt;link rel=&quot;dns-prefetch&quot; href=&quot;//fonts.googleapis.com&quot;&amp;gt;
&amp;lt;link rel=&quot;dns-prefetch&quot; href=&quot;//api.example.com&quot;&amp;gt;

&amp;lt;!-- 预连接：提前完成 DNS 解析 + TCP 握手 + TLS 协商 --&amp;gt;
&amp;lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.gstatic.com&quot; crossorigin&amp;gt;
&amp;lt;link rel=&quot;preconnect&quot; href=&quot;https://api.example.com&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. 服务端优化&lt;/h2&gt;
&lt;h3&gt;Server-Side Rendering (SSR) / Static Site Generation (SSG)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 SSR（服务器端渲染）或 SSG（静态站点生成）在服务器端生成完整的 HTML 页面或预渲染的静态 HTML 文件，直接发送给浏览器，加快首屏显示速度，并有利于 SEO。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：内容型网站、需要良好 SEO 的应用、追求极致首屏性能的场景。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;框架&lt;/strong&gt;: 使用支持 SSR/SSG 的前端框架，如 Next.js (React), Nuxt.js (Vue), SvelteKit (Svelte), Gatsby (React, SSG), Astro 等。&lt;pre&gt;&lt;code&gt;// Next.js 页面示例 (SSR)
export async function getServerSideProps(context) {
  const res = await fetch(`https://api.example.com/data`);
  const data = await res.json();
  return { props: { data } }; // 数据将作为 props 传递给页面组件
}
function Page({ data }) {
  // 渲染页面...
}
export default Page;

// Next.js 页面示例 (SSG)
export async function getStaticProps() {
  const res = await fetch(`https://api.example.com/data`);
  const data = await res.json();
  return { props: { data } };
}
// ... Page 组件同上 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;API 优化&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：缩短 API 接口的响应时间，使用合适的数据格式（如 JSON），采用有效的缓存策略（如 Redis 缓存查询结果），减少 API 请求处理的延迟。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：所有前后端数据交互的接口。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;后端&lt;/strong&gt;: 优化数据库查询（添加索引、慢查询分析）、使用缓存层（Redis, Memcached）、优化业务逻辑、使用异步处理非核心任务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据格式&lt;/strong&gt;: 确保 API 返回精简的 JSON 数据，避免冗余字段。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络&lt;/strong&gt;: 减少 API 服务器与客户端之间的网络延迟（如使用 CDN 加速 API）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;GraphQL 优化&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：采用 GraphQL 代替传统 RESTful API，允许客户端精确指定需要获取的数据结构，避免了 REST 中常见的 over-fetching（获取过多数据）和 under-fetching（需要多次请求才能获取足够数据）的问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：复杂数据关联、移动端应用、需要灵活数据查询的场景。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# GraphQL 查询示例：只请求需要的字段
query GetUserProfile {
  user(id: &quot;123&quot;) {
    id
    name
    email
    posts(last: 5) { # 只获取最近 5 篇文章
      title
      createdAt
    }
  }
}

# 相比之下，REST 可能需要多个请求或返回大量不需要的数据
# GET /users/123
# GET /users/123/posts?limit=5
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7. 前端缓存与持久化&lt;/h2&gt;
&lt;h3&gt;LocalStorage / SessionStorage&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 Web Storage API (LocalStorage, SessionStorage) 在浏览器端存储少量键值对数据。LocalStorage 数据持久存在，除非手动清除；SessionStorage 数据在会话结束后（通常是浏览器标签页关闭时）清除。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：存储用户偏好设置、少量非敏感数据、临时状态等，减少不必要的服务器请求。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// LocalStorage: 持久存储
localStorage.setItem(&apos;theme&apos;, &apos;dark&apos;);
const currentTheme = localStorage.getItem(&apos;theme&apos;);
localStorage.removeItem(&apos;theme&apos;);
localStorage.clear(); // 清除所有

// SessionStorage: 会话级存储
sessionStorage.setItem(&apos;sessionId&apos;, &apos;abc123xyz&apos;);
const sessionId = sessionStorage.getItem(&apos;sessionId&apos;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;: Web Storage 容量有限（通常 5-10MB），且是同步操作，可能阻塞主线程，不适合存储大量数据。&lt;/p&gt;
&lt;h3&gt;IndexedDB&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：一个在浏览器中存储大量结构化数据（包括文件/Blob）的底层 API。它创建了一个事务型数据库，支持索引，可以进行高性能搜索。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：离线数据存储、大型数据集缓存、PWA（Progressive Web Apps）的数据存储。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 打开（或创建）数据库
const request = indexedDB.open(&apos;myDatabase&apos;, 1);

request.onupgradeneeded = event =&amp;gt; {
  const db = event.target.result;
  // 创建一个对象存储空间（类似表）
  const objectStore = db.createObjectStore(&apos;customers&apos;, { keyPath: &apos;id&apos; });
  // 创建索引
  objectStore.createIndex(&apos;name&apos;, &apos;name&apos;, { unique: false });
};

request.onsuccess = event =&amp;gt; {
  const db = event.target.result;
  // 使用事务进行数据操作
  const transaction = db.transaction([&apos;customers&apos;], &apos;readwrite&apos;);
  const objectStore = transaction.objectStore(&apos;customers&apos;);

  // 添加数据
  const addRequest = objectStore.add({ id: &apos;1&apos;, name: &apos;Alice&apos;, email: &apos;alice@example.com&apos; });
  addRequest.onsuccess = () =&amp;gt; console.log(&apos;Data added&apos;);

  // 获取数据
  const getRequest = objectStore.get(&apos;1&apos;);
  getRequest.onsuccess = () =&amp;gt; console.log(&apos;Retrieved data:&apos;, getRequest.result);
};

request.onerror = event =&amp;gt; {
  console.error(&apos;Database error:&apos;, event.target.errorCode);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;: IndexedDB API 较为复杂，通常建议使用封装库（如 Dexie.js, idb）。&lt;/p&gt;
&lt;h3&gt;缓存 API (Cache API)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：通常与 Service Worker 结合使用，提供一个用于存储和检索网络请求及其相应响应的系统。它允许你缓存资源，以便在离线时或为了提高性能而使用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：PWA 的离线缓存、静态资源缓存、API 响应缓存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 在 Service Worker 中使用 Cache API
const CACHE_NAME = &apos;my-site-cache-v1&apos;;
const urlsToCache = [
  &apos;/&apos;,
  &apos;/styles/main.css&apos;,
  &apos;/script/main.js&apos;
];

self.addEventListener(&apos;install&apos;, event =&amp;gt; {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache =&amp;gt; {
        console.log(&apos;Opened cache&apos;);
        return cache.addAll(urlsToCache); // 将资源添加到缓存
      })
  );
});

self.addEventListener(&apos;fetch&apos;, event =&amp;gt; {
  event.respondWith(
    caches.match(event.request) // 尝试从缓存中查找匹配的请求
      .then(response =&amp;gt; {
        // 如果缓存中有匹配的响应，则返回它
        if (response) {
          return response;
        }
        // 否则，从网络获取
        return fetch(event.request);
      })
  );
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8. 响应式设计与适配&lt;/h2&gt;
&lt;h3&gt;媒体查询（Media Queries）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 CSS 媒体查询根据设备的特性（如视口宽度、高度、方向、分辨率等）应用不同的样式规则。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：实现响应式布局，为不同屏幕尺寸提供优化体验，加载适合的资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* 默认样式 (移动优先) */
.container {
  width: 95%;
  margin: 0 auto;
}

/* 平板设备 */
@media (min-width: 768px) {
  .container {
    width: 90%;
  }
  .sidebar {
    display: block; /* 在平板上显示侧边栏 */
  }
}

/* 桌面设备 */
@media (min-width: 1024px) {
  .container {
    width: 80%;
    max-width: 1200px;
  }
}

/* 加载不同背景图 */
body {
  background-image: url(&apos;background-small.jpg&apos;);
}
@media (min-width: 768px) {
  body {
    background-image: url(&apos;background-large.jpg&apos;);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;图片适配（Responsive Images）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用 HTML 的 &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 元素或 &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 元素的 &lt;code&gt;srcset&lt;/code&gt; 和 &lt;code&gt;sizes&lt;/code&gt; 属性，让浏览器根据设备特性（如屏幕尺寸、分辨率、网络状况）选择加载最合适的图片资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：为不同设备提供不同尺寸或格式的图片，节省带宽，提高加载速度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- 使用 srcset 和 sizes --&amp;gt;
&amp;lt;img srcset=&quot;image-320w.jpg 320w,
             image-480w.jpg 480w,
             image-800w.jpg 800w&quot;
     sizes=&quot;(max-width: 320px) 280px,
            (max-width: 480px) 440px,
            800px&quot;
     src=&quot;image-800w.jpg&quot; alt=&quot;Responsive image&quot;&amp;gt;

&amp;lt;!-- 使用 &amp;lt;picture&amp;gt; 元素提供不同格式或裁剪 --&amp;gt;
&amp;lt;picture&amp;gt;
  &amp;lt;source media=&quot;(min-width: 650px)&quot; srcset=&quot;image-large.webp&quot; type=&quot;image/webp&quot;&amp;gt;
  &amp;lt;source media=&quot;(min-width: 465px)&quot; srcset=&quot;image-medium.webp&quot; type=&quot;image/webp&quot;&amp;gt;
  &amp;lt;source srcset=&quot;image-small.webp&quot; type=&quot;image/webp&quot;&amp;gt;
  &amp;lt;!-- Fallback for browsers that don&apos;t support WebP or &amp;lt;picture&amp;gt; --&amp;gt;
  &amp;lt;source media=&quot;(min-width: 650px)&quot; srcset=&quot;image-large.jpg&quot;&amp;gt;
  &amp;lt;source media=&quot;(min-width: 465px)&quot; srcset=&quot;image-medium.jpg&quot;&amp;gt;
  &amp;lt;img src=&quot;image-small.jpg&quot; alt=&quot;Art directed image&quot;&amp;gt;
&amp;lt;/picture&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9. 智能化和延迟加载&lt;/h2&gt;
&lt;h3&gt;智能加载（Smart Loading）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：根据用户的行为、网络状况（如使用 Network Information API）、设备性能或数据节省偏好，智能地决定加载哪些内容或何种质量的内容。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：在慢速网络下加载低质量图片或延迟加载非关键脚本，根据用户交互历史预测并预加载可能访问的页面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 检查网络状况决定加载资源质量 (概念示例)
if (&apos;connection&apos; in navigator) {
  const connection = navigator.connection;
  if (connection.saveData === true) {
    // 用户启用了数据节省模式，加载低质量资源
    loadLowQualityResources();
  } else if (connection.effectiveType === &apos;4g&apos;) {
    // 网络良好，加载高质量资源
    loadHighQualityResources();
  } else {
    // 网络一般或未知，加载标准资源
    loadStandardResources();
  }
} else {
  // 不支持 Network Information API，加载标准资源
  loadStandardResources();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;按需加载（On-demand Loading）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：只有在用户明确需要时（如点击按钮、滚动到特定区域）才加载更多内容或功能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：无限滚动列表、点击“加载更多”按钮、加载大型库或组件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 点击按钮加载更多评论
const loadMoreButton = document.getElementById(&apos;loadMoreComments&apos;);
let currentPage = 1;

loadMoreButton.addEventListener(&apos;click&apos;, () =&amp;gt; {
  currentPage++;
  fetch(`/api/comments?page=${currentPage}`)
    .then(response =&amp;gt; response.json())
    .then(comments =&amp;gt; {
      renderComments(comments);
      if (comments.length === 0) {
        loadMoreButton.style.display = &apos;none&apos;; // 没有更多评论了
      }
    });
});

// 结合 Intersection Observer 实现无限滚动加载
const sentinel = document.getElementById(&apos;infinite-scroll-sentinel&apos;);
const observer = new IntersectionObserver(entries =&amp;gt; {
  if (entries[0].isIntersecting) {
    loadMoreContent();
  }
});
observer.observe(sentinel);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10. 字体优化&lt;/h2&gt;
&lt;h3&gt;字体懒加载&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：仅在需要显示相应文本时才开始加载字体文件，或者使用 &lt;code&gt;font-display&lt;/code&gt; CSS 属性控制字体加载过程中的文本显示行为，避免字体加载阻塞页面渲染或导致文本闪烁（FOIT/FOUT）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：优化使用了自定义 Web 字体的页面加载体验。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@font-face {
  font-family: &apos;MyCustomFont&apos;;
  src: url(&apos;myfont.woff2&apos;) format(&apos;woff2&apos;);
  /* font-display 控制字体加载行为 */
  /* swap: 先显示后备字体，字体加载完后替换。可能导致 FOUT (Flash of Unstyled Text) */
  font-display: swap;

  /* block: 短暂阻塞（约3秒），期间不显示文本。若超时则显示后备字体，加载完后替换。*/
  /* font-display: block; */

  /* fallback: 极短阻塞（约100ms），期间不显示文本。若超时则显示后备字体，后续不再替换。*/
  /* font-display: fallback; */

  /* optional: 极短阻塞（约100ms），期间不显示文本。若超时则显示后备字体，字体仍在后台下载，但仅在下次导航时使用。*/
  /* font-display: optional; */
}

body {
  font-family: &apos;MyCustomFont&apos;, sans-serif; /* 指定后备字体 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JS 懒加载&lt;/strong&gt;: 可以使用 JavaScript 监听特定元素进入视口或其他条件，然后动态添加包含 &lt;code&gt;@font-face&lt;/code&gt; 规则的 CSS 或直接加载字体。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;合并字体文件&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：如果页面使用了同一字体家族的多个字重（如 Regular, Bold, Italic），并且这些字重分别在不同的字体文件中，可以将它们合并成一个或少数几个文件（如果格式支持，如 WOFF2 可变字体），或者只加载必要的字重和字符集，以减少 HTTP 请求次数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：使用了多个字体文件的网站。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;策略&lt;/strong&gt;: 评估是否所有字重都是必需的。如果可能，使用可变字体（Variable Fonts），一个文件包含所有变体。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具&lt;/strong&gt;: 使用字体编辑工具（如 FontForge）或专门的服务来合并字体文件或创建子集。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSS&lt;/strong&gt;: 确保 &lt;code&gt;@font-face&lt;/code&gt; 规则正确指向合并后的文件或只引用需要的字重。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;11. WebP 和 AVIF 格式&lt;/h2&gt;
&lt;h3&gt;WebP / AVIF 图片格式&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：使用现代图片格式 WebP 或 AVIF 替代传统的 JPG、PNG、GIF。它们通常能在相同视觉质量下提供更小的文件体积（WebP 比 JPG 小约 25-35%，AVIF 比 JPG 小约 50%），支持有损和无损压缩、透明度以及动画。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：网站上所有使用的图片。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- 使用 &amp;lt;picture&amp;gt; 元素提供多种格式 --&amp;gt;
&amp;lt;picture&amp;gt;
  &amp;lt;!-- 优先尝试 AVIF --&amp;gt;
  &amp;lt;source srcset=&quot;image.avif&quot; type=&quot;image/avif&quot;&amp;gt;
  &amp;lt;!-- 其次尝试 WebP --&amp;gt;
  &amp;lt;source srcset=&quot;image.webp&quot; type=&quot;image/webp&quot;&amp;gt;
  &amp;lt;!-- 最后回退到 JPG --&amp;gt;
  &amp;lt;img src=&quot;image.jpg&quot; alt=&quot;Modern image format example&quot;&amp;gt;
&amp;lt;/picture&amp;gt;

&amp;lt;!-- 在 CSS 中使用 --&amp;gt;
&amp;lt;style&amp;gt;
.hero {
  /* 浏览器会自动选择它支持的第一个格式 */
  background-image: url(&apos;hero.avif&apos;), url(&apos;hero.webp&apos;), url(&apos;hero.jpg&apos;);
}
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;转换工具&lt;/strong&gt;: 使用 Squoosh.app、cwebp/avifenc 命令行工具或构建插件（如 &lt;code&gt;imagemin-webp&lt;/code&gt;）将现有图片转换为 WebP/AVIF。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;12. JavaScript 性能优化&lt;/h2&gt;
&lt;h3&gt;减少 JavaScript 阻塞&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：避免长时间运行的 JavaScript 任务阻塞主线程，导致页面无响应。通过异步加载（&lt;code&gt;async&lt;/code&gt;/&lt;code&gt;defer&lt;/code&gt;）、延迟执行非关键脚本、将耗时任务移至 Web Worker 或使用 &lt;code&gt;requestIdleCallback&lt;/code&gt; 来实现。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：优化页面加载和交互过程中的 JavaScript 执行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;async/defer&lt;/strong&gt;: 见 1.1 异步加载示例。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;延迟执行&lt;/strong&gt;: 对于非首屏必需的 JS（如聊天插件、广告脚本），可以在页面主要内容加载完成后再加载和执行。&lt;pre&gt;&lt;code&gt;window.addEventListener(&apos;load&apos;, () =&amp;gt; {
  const script = document.createElement(&apos;script&apos;);
  script.src = &apos;non-critical-script.js&apos;;
  document.body.appendChild(script);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web Worker&lt;/strong&gt;: 见 12.3 Web Worker 示例。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;requestIdleCallback&lt;/strong&gt;: 见 1.4 空闲时间调度示例。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;优化垃圾回收（GC）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：编写更有效的代码以减少内存泄漏和不必要的内存分配，从而降低垃圾回收（GC）的频率和持续时间，避免 GC 暂停导致页面卡顿。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：长时间运行的应用、包含大量动态数据和事件监听器的页面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;避免全局变量&lt;/strong&gt;: 全局变量不易被回收。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;及时移除事件监听器&lt;/strong&gt;: 在元素移除或组件卸载时，使用 &lt;code&gt;removeEventListener&lt;/code&gt; 清除不再需要的监听器。&lt;pre&gt;&lt;code&gt;function handleClick() { /* ... */ }
element.addEventListener(&apos;click&apos;, handleClick);
// ... 当不再需要时 ...
element.removeEventListener(&apos;click&apos;, handleClick);
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;管理闭包&lt;/strong&gt;: 注意闭包可能意外地持有不再需要的变量引用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用 WeakMap / WeakSet&lt;/strong&gt;: 对于对象键或集合成员，如果希望它们在没有其他引用的情况下能被 GC 回收，可以使用 WeakMap 或 WeakSet。&lt;pre&gt;&lt;code&gt;const metadata = new WeakMap(); // 使用 WeakMap 存储对象元数据
let obj = {};
metadata.set(obj, { info: &apos;some data&apos; });
// 当 obj 不再被引用时，WeakMap 中的条目也会被自动移除，不会阻止 obj 被回收
obj = null; // 假设这是 obj 的最后一个引用
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Web Worker&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：将计算密集型或长时间运行的 JavaScript 任务放到后台线程（Web Worker）中执行，避免阻塞主线程，保持 UI 的响应性。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：复杂计算、数据处理、图像处理、后台数据同步等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// main.js (主线程)
const worker = new Worker(&apos;worker.js&apos;);

// 向 Worker 发送数据
worker.postMessage({ data: [1, 2, 3, 4, 5] });

// 接收来自 Worker 的消息
worker.onmessage = event =&amp;gt; {
  console.log(&apos;Result from worker:&apos;, event.data.result);
};

// 处理错误
worker.onerror = error =&amp;gt; {
  console.error(&apos;Worker error:&apos;, error);
};

// worker.js (后台线程)
self.onmessage = event =&amp;gt; {
  console.log(&apos;Data received in worker:&apos;, event.data.data);
  // 执行耗时计算
  const result = event.data.data.reduce((sum, val) =&amp;gt; sum + val * val, 0);

  // 将结果发送回主线程
  self.postMessage({ result: result });
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;13. Web API 性能优化&lt;/h2&gt;
&lt;h3&gt;Intersection Observer API&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：提供一种异步观察目标元素与其祖先元素或顶级文档视口交叉状态变化的方法。比传统的滚动事件监听更高效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：图片/组件懒加载、无限滚动、广告可见性跟踪、触发动画等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const targetElement = document.getElementById(&apos;observeMe&apos;);

const callback = (entries, observer) =&amp;gt; {
  entries.forEach(entry =&amp;gt; {
    if (entry.isIntersecting) {
      // 元素进入视口
      console.log(&apos;Element is visible!&apos;);
      targetElement.classList.add(&apos;visible&apos;);
      // 如果只需要触发一次，可以停止观察
      // observer.unobserve(targetElement);
    } else {
      // 元素离开视口
      console.log(&apos;Element is hidden!&apos;);
      targetElement.classList.remove(&apos;visible&apos;);
    }
  });
};

const options = {
  root: null, // 相对于视口
  rootMargin: &apos;0px&apos;,
  threshold: 0.5 // 元素 50% 可见时触发回调
};

const observer = new IntersectionObserver(callback, options);
observer.observe(targetElement);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Performance API&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：提供访问浏览器性能相关信息的接口，可以用来精确测量代码执行时间、资源加载时间、页面导航性能等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：性能监控、代码性能分析、资源加载优化分析。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 测量代码块执行时间
performance.mark(&apos;start-calculation&apos;);
// ... 执行一些耗时操作 ...
calculateFibonacci(40);
performance.mark(&apos;end-calculation&apos;);
performance.measure(&apos;calculation-duration&apos;, &apos;start-calculation&apos;, &apos;end-calculation&apos;);

// 获取所有测量结果
const measures = performance.getEntriesByType(&apos;measure&apos;);
measures.forEach(measure =&amp;gt; {
  console.log(`${measure.name}: ${measure.duration}ms`);
});

// 获取资源加载性能数据
const resources = performance.getEntriesByType(&apos;resource&apos;);
resources.forEach(resource =&amp;gt; {
  console.log(`Resource ${resource.name} loaded in ${resource.duration}ms`);
});

// 获取导航性能数据
const navigation = performance.getEntriesByType(&apos;navigation&apos;)[0];
console.log(`DOM content loaded in ${navigation.domContentLoadedEventEnd}ms`);
console.log(`Page loaded in ${navigation.loadEventEnd}ms`);

// 清除标记和测量
performance.clearMarks();
performance.clearMeasures();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Service Worker&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;描述&lt;/strong&gt;：一个运行在浏览器后台的脚本，独立于网页，可以拦截和处理网络请求、推送通知、后台同步等。是构建 PWA 的核心技术之一。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：实现离线缓存、资源拦截与代理、推送通知、后台数据同步。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// main.js (注册 Service Worker)
if (&apos;serviceWorker&apos; in navigator) {
  window.addEventListener(&apos;load&apos;, () =&amp;gt; {
    navigator.serviceWorker.register(&apos;/sw.js&apos;)
      .then(registration =&amp;gt; {
        console.log(&apos;ServiceWorker registration successful with scope: &apos;, registration.scope);
      })
      .catch(error =&amp;gt; {
        console.log(&apos;ServiceWorker registration failed: &apos;, error);
      });
  });
}

// sw.js (Service Worker 脚本 - 缓存优先策略示例)
const CACHE_NAME = &apos;my-app-cache-v1&apos;;

self.addEventListener(&apos;install&apos;, event =&amp;gt; {
  // 安装时缓存核心资源
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache =&amp;gt; {
      return cache.addAll([
        &apos;/&apos;,
        &apos;/index.html&apos;,
        &apos;/styles.css&apos;,
        &apos;/app.js&apos;
      ]);
    })
  );
});

self.addEventListener(&apos;fetch&apos;, event =&amp;gt; {
  event.respondWith(
    caches.match(event.request)
      .then(response =&amp;gt; {
        // 缓存命中，返回缓存的响应
        if (response) {
          return response;
        }
        // 缓存未命中，从网络获取
        return fetch(event.request).then(networkResponse =&amp;gt; {
          // 可选：将新的响应添加到缓存
          // caches.open(CACHE_NAME).then(cache =&amp;gt; cache.put(event.request, networkResponse.clone()));
          return networkResponse;
        });
      })
      .catch(() =&amp;gt; {
        // 网络和缓存都失败时，可以返回一个备用的离线页面
        // return caches.match(&apos;/offline.html&apos;);
      })
  );
});
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>使用DOH和ECH防止DNS污染和劫持</title><link>https://emohe.cn/posts/25/</link><guid isPermaLink="true">https://emohe.cn/posts/25/</guid><pubDate>Fri, 14 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;DoH（DNS over HTTPS）是一种安全协议，它通过 HTTPS（TLS 加密）传输 DNS 解析请求，防止 DNS 查询被窃听、篡改或屏蔽。&lt;/p&gt;
&lt;p&gt;正常情况下，当你访问一个 &lt;code&gt;HTTPS&lt;/code&gt; 网站时，需要先向 &lt;code&gt;DNS&lt;/code&gt; 发送查询该域名 &lt;code&gt;IP&lt;/code&gt; 地址的请求。由于传统 &lt;code&gt;DNS&lt;/code&gt; 查询是明文传输的，ISP 或其他网络中间人可以看到你查询了哪个域名。虽然 &lt;code&gt;HTTPS&lt;/code&gt; 内容是加密的，无法看到具体内容，但可以得知你在访问什么网站。&lt;/p&gt;
&lt;p&gt;另外，访问 &lt;code&gt;HTTPS&lt;/code&gt; 网站需要进行 &lt;code&gt;TLS&lt;/code&gt; 握手，握手时会携带域名信息，也就是 &lt;code&gt;SNI&lt;/code&gt;（Server Name Indication）。&lt;code&gt;ISP&lt;/code&gt; 同样能看到这个信息。&lt;/p&gt;
&lt;p&gt;此时，中间人可以劫持并篡改 &lt;code&gt;DNS&lt;/code&gt; 查询返回的 &lt;code&gt;IP&lt;/code&gt; 地址。&lt;/p&gt;
&lt;p&gt;当我们使用加密 &lt;code&gt;DNS&lt;/code&gt; 后，可以隐藏 &lt;code&gt;DNS&lt;/code&gt; 查询的域名信息，但由于 &lt;code&gt;TLS&lt;/code&gt; 握手仍会携带 &lt;code&gt;SNI&lt;/code&gt; 信息，中间人依然能够监控。为了进一步保护隐私，网站可以配置 &lt;code&gt;ECH&lt;/code&gt;（Encrypted Client Hello）来加密 &lt;code&gt;SNI&lt;/code&gt; 信息。&lt;/p&gt;
&lt;p&gt;目前 &lt;code&gt;Cloudflare&lt;/code&gt; 已支持 &lt;code&gt;ECH&lt;/code&gt;，使用其 &lt;code&gt;CDN&lt;/code&gt; 服务的网站会默认开启此功能。&lt;code&gt;ECH&lt;/code&gt; 会加密真实的 &lt;code&gt;SNI&lt;/code&gt; 信息，只有支持 &lt;code&gt;ECH&lt;/code&gt; 的服务器才能解密，从而实现对真实访问目标的隐藏。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ECH&lt;/code&gt; 配合 &lt;code&gt;DoH&lt;/code&gt; 加密 DNS 可以提供更完整的隐私保护。&lt;/p&gt;
&lt;h3&gt;享受ECH加密的一些注意事项&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;服务端域名开启了ECH&lt;/li&gt;
&lt;li&gt;服务端域名支持TLS 1.3&lt;/li&gt;
&lt;li&gt;域名托管商支持HTTPS解析&lt;/li&gt;
&lt;li&gt;客户端使用国际主流浏览器&lt;/li&gt;
&lt;li&gt;客户端不要用代理&lt;/li&gt;
&lt;li&gt;客户端使用加密DNS&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;Windows 11&lt;/code&gt; 配置加密 DNS&lt;/h3&gt;
&lt;p&gt;由于网络环境限制，国外的加密 &lt;code&gt;DNS&lt;/code&gt; 服务可能无法直接访问。本文教大家配置阿里云的加密 &lt;code&gt;DNS&lt;/code&gt; 服务。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;系统设置方法：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开 &lt;code&gt;设置&lt;/code&gt; &amp;gt; &lt;code&gt;网络和 Internet&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;找到当前网络连接的 &lt;code&gt;属性&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;DNS 服务器分配&lt;/code&gt; 中选择 &lt;code&gt;手动&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;首选 DNS 填入 &lt;code&gt;223.5.5.5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DNS over HTTPS&lt;/code&gt; 选择 &lt;code&gt;手动模板&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;模板地址填入 &lt;code&gt;https://dns.alidns.com/dns-query&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;控制面板配置方法：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开控制面板，选择 &lt;code&gt;查看网络状态和任务&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;点击你的网卡连接&lt;/li&gt;
&lt;li&gt;选择 &lt;code&gt;属性&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;双击 &lt;code&gt;Internet 协议版本 4 (TCP/IPv4)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;点击 &lt;code&gt;属性&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;首选 DNS 填入 &lt;code&gt;223.5.5.5&lt;/code&gt;，备选 DNS 填入 &lt;code&gt;8.8.8.8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;点击 &lt;code&gt;确定&lt;/code&gt; 保存设置&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;配置完成后，你的 DNS 查询将通过加密通道进行，提升上网安全性和隐私保护。&lt;/p&gt;
&lt;h3&gt;验证是否开启&lt;/h3&gt;
&lt;p&gt;访问域名 https://cdnjs.com/cdn-cgi/trace 查看&lt;code&gt;sni&lt;/code&gt;参数，如果是图中这样，则代表开启成功。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/dns2.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;或者也可以访问https://tls-ech.dev 如果如图所示则代表开启成功。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/dns1.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;服务端域名配置ECH教程&lt;/h3&gt;
&lt;p&gt;由于Cloudflare CDN国内访问速度慢，所以我介绍一下不使用CDN的教程&lt;/p&gt;
&lt;p&gt;我使用caddy较多，所以用caddy做演示，其他同理&lt;/p&gt;
&lt;p&gt;&lt;code&gt;caddy&lt;/code&gt;的 &lt;a href=&quot;https://github.com/caddyserver/caddy/releases/tag/v2.10.0&quot;&gt;2.10.0正式版本&lt;/a&gt; 已经加入了ECH的支持，需要使用&lt;code&gt;2.10.0&lt;/code&gt;以上的版本。&lt;/p&gt;
&lt;p&gt;要使用&lt;code&gt;caddy&lt;/code&gt;自动配置&lt;code&gt;ech&lt;/code&gt;则需要编译&lt;code&gt;cloudflare dns&lt;/code&gt;插件，用于caddy自动添加DNS记录，官方编译的包默认不带此插件。&lt;/p&gt;
&lt;h3&gt;编译&lt;code&gt;caddy&lt;/code&gt;并加入&lt;code&gt;cloudflare DNS&lt;/code&gt;插件的支持&lt;/h3&gt;
&lt;p&gt;1：安装&lt;code&gt;go&lt;/code&gt;环境&lt;/p&gt;
&lt;p&gt;2：下载&lt;code&gt;xcaddy&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3：编译带&lt;code&gt;cloudflare dns&lt;/code&gt;插件的&lt;code&gt;caddy&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xcaddy build --with github.com/caddy-dns/cloudflare
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时你的当前目录会生成一个已经包含了&lt;code&gt;cloudflare dns&lt;/code&gt;插件的&lt;code&gt;caddy&lt;/code&gt;二进制文件&lt;/p&gt;
&lt;h3&gt;以&lt;code&gt;debug&lt;/code&gt;模式测试运行&lt;/h3&gt;
&lt;p&gt;创建&lt;code&gt;/etc/caddy/Caddyfile&lt;/code&gt;文件，并写入以下文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    debug
    dns cloudflare xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    ech ech.example.com

    log {
        output stdout
        format console
        level DEBUG
    }
}

test.example.com {
    root * /tmp
    file_server browse
    encode zstd gzip
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;配置说明&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;dns cloudflare&lt;/code&gt;这个配置填CF的&lt;code&gt;区域 DNS API 令牌&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ech ech.example.com&lt;/code&gt;替换你的任意二级域名，并且解析到你的IP，用于发布ECH公钥，或者第三方提供的ECH配置服务域名也行。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;test.example.com&lt;/code&gt;替换你的域名，并且解析到你的IP，不要开小黄云。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;root * /tmp&lt;/code&gt;这个配置代表以网页浏览文件的形式，浏览你服务器的&lt;code&gt;/tmp&lt;/code&gt;目录，这里只是测试为了方便起服务。&lt;/p&gt;
&lt;h3&gt;启动&lt;code&gt;caddy&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo ./caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不出意外的话就启动成功了，然后可以访问你的域名看下是否能成功访问&lt;/p&gt;
&lt;p&gt;并且&lt;code&gt;/root/.local/share/caddy&lt;/code&gt;目录会生成一个锁文件，如果需要重新部署则需要删除这个目录&lt;/p&gt;
&lt;p&gt;CF里也会自动添加一个类型为&lt;code&gt;HTTPS&lt;/code&gt;的解析记录&lt;/p&gt;
&lt;h3&gt;检查&lt;code&gt;ech&lt;/code&gt;是否配置成功&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;dig test.example.com TYPE65
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行这个命令后，在输出的信息里可以看到有如下类似的信息就代表启用成功&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ech=AEr+DEBUGAgACBDEMOnixVAfd/ASODJKADKSODAPSkZIwAMADQABAAIASDASDADHw9lY2guZXhhbXBsZS5jb20AAA==
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;生产环境&lt;/h3&gt;
&lt;p&gt;移动二进制文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mv ~/caddy /usr/bin/caddy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建系统服务配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;touch /etc/systemd/system/caddy.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写入配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=Caddy Web Server
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Wants=network-online.target

[Service]
User=root
Group=root
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;管理命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 重新加载 systemd 配置
sudo systemctl daemon-reexec
sudo systemctl daemon-reload

# 启动 Caddy
sudo systemctl start caddy

# 设置开机启动
sudo systemctl enable caddy

# 查看运行状态
sudo systemctl status caddy
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;生产环境反代配置示例&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;{
	dns cloudflare xxxxxxxxxxxxxxxxxxxxx
	ech ech.example.com
}

test.example.com {
	reverse_proxy localhost:8080
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重新部署记得删除：&lt;code&gt;/root/.local/share/caddy&lt;/code&gt;锁文件，和CF里的&lt;code&gt;HTTPS&lt;/code&gt;解析记录&lt;/p&gt;
</content:encoded></item><item><title>tailscale异地组网教程</title><link>https://emohe.cn/posts/24/</link><guid isPermaLink="true">https://emohe.cn/posts/24/</guid><pubDate>Tue, 11 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://tailscale.com/&quot;&gt;Tailscale&lt;/a&gt; 是一种新型组网工具.
它能帮助我们把安装了&lt;code&gt;Tailscale&lt;/code&gt;服务的机器，都放到同一个局域网内，实现内网互联。
即公司或者家里的 PC 机器连到同一网络，包括云服务器等等都能放到同一个局域网。
并且能够自动发现点对点直连，如果无法直连则会通过他的公共中继服务器来转发，他的公共网络我实测大概有&lt;code&gt;30M&lt;/code&gt;带宽，并且永久免费。
当然也可以自建中继服务器，本文有介绍。部署和使用过程都非常简单方便。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;安卓，ios，windows，mac 直接官网下载即可&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Docker部署&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  --name tailscale \
  --privileged \
  --network host \
  --restart always \
  -v $(pwd)/tailscale:/var/lib/tailscale \
  tailscale/tailscale:latest \
  tailscaled --state=/var/lib/tailscale/tailscaled.state
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进入容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker exec -it tailscale sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生成登录链接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tailscale up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;（可选）使用密钥连接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tailscale up --auth-key=&amp;lt;你的AuthKey&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看中继网络&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tailscale netcheck
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看是否点对点直连&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tailscale status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果看到&lt;code&gt;relay &quot;tok&quot;&lt;/code&gt;则说明使用了公共中继连接，&lt;code&gt;tok&lt;/code&gt;代表日本公共节点&lt;/p&gt;
&lt;h3&gt;指定密钥运行&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  tailscale:
    image: tailscale/tailscale:latest
    container_name: tailscale
    privileged: true
    network_mode: host
    restart: always
    volumes:
      - ./tailscale:/var/lib/tailscale
    command:
      - tailscaled
      - --state=/var/lib/tailscale/tailscaled.state
      - --tun=tailscale0
      - --auth-key=你的AuthKey
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;宿主机部署&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 安装
sudo apt install tailscale -y

# 登录
sudo tailscale up

# 查看运行状态
sudo systemctl status tailscaled

# 开机自启
sudo systemctl enable tailscaled

# 停止运行
sudo systemctl stop tailscaled

# 重启
sudo systemctl restart tailscaled

# 查看日志
sudo journalctl -u tailscaled -f
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;自建&lt;code&gt;derper&lt;/code&gt;中继服务器&lt;/h3&gt;
&lt;p&gt;自动申请证书&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  derper:
    image: fredliang/derper:latest
    container_name: derper
    restart: unless-stopped
    environment:
      - DERP_DOMAIN=derper.your-domain.com  # 替换为您的域名
      - DERP_CERT_MODE=letsencrypt
      - DERP_STUN=true
      - DERP_HTTP_PORT=80
      - DERP_ADDR=:443
      - DERP_VERIFY_CLIENTS=true  # 本地 tailscaled 实例验证客户端，只允许自己使用
    ports:
      - &quot;80:80&quot;
      - &quot;443:443&quot;
      - &quot;3478:3478/udp&quot;
    volumes:
      - ./certs:/app/certs # 证书持久化存储
      - /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;手动配置证书&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  derper:
    image: fredliang/derper:latest
    container_name: derper
    restart: unless-stopped
    environment:
      - DERP_DOMAIN=derper.your-domain.com  # 替换为您的域名
      - DERP_CERT_MODE=manual
      - DERP_CERT_DIR=/app/certs
      - DERP_STUN=true
      - DERP_HTTP_PORT=80
      - DERP_ADDR=:443
      - DERP_VERIFY_CLIENTS=true  # 通过本地 tailscaled 实例验证客户端
    ports:
      - &quot;80:80&quot;
      - &quot;443:443&quot;
      - &quot;3478:3478/udp&quot;
    volumes:
      - ./certs:/app/certs # 手动挂载证书
      - /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://login.tailscale.com/admin/acls/file&quot;&gt;修改Tailscale后台配置文件&lt;/a&gt; 添加如下内容&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        &quot;derpMap&quot;: {
                &quot;OmitDefaultRegions&quot;: true,
                // OmitDefaultRegions 忽略官方的中继节点
                &quot;Regions&quot;: {
                        // 这里的 901 从 900 开始随便取数字
                        &quot;901&quot;: {
                                // RegionID 和上面的相等
                                &quot;RegionID&quot;: 901,
                                // RegionCode 名称
                                &quot;RegionCode&quot;: &quot;Vultr-SG&quot;,
                                &quot;Nodes&quot;: [
                                        {
                                                // Name 保持 1不动
                                                &quot;Name&quot;:     &quot;1&quot;,
                                                // 这个也和 RegionID 一样
                                                &quot;RegionID&quot;: 901,
                                                // 域名
                                                &quot;HostName&quot;: &quot;&amp;lt;你的域名&amp;gt;&quot;,
                                                // 端口号
                                                &quot;DERPPort&quot;: 443,
                                        },
                                ],
                        },
                },
        },
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Docker变量&lt;/th&gt;
&lt;th&gt;必需&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;th&gt;值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DERP_DOMAIN&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;td&gt;derper 服务器主机名&lt;/td&gt;
&lt;td&gt;your-hostname.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DERP_CERT_DIR&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;存储证书的目录 (如果地址端口是 :443)&lt;/td&gt;
&lt;td&gt;/app/certs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DERP_CERT_MODE&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;获取证书的模式。可选项: manual, letsencrypt&lt;/td&gt;
&lt;td&gt;letsencrypt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DERP_ADDR&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;服务器监听地址&lt;/td&gt;
&lt;td&gt;:443&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DERP_STUN&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;是否同时运行 STUN 服务器&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DERP_HTTP_PORT&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;提供 HTTP 服务的端口。设置为 -1 禁用&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DERP_VERIFY_CLIENTS&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;td&gt;是否通过本地 tailscaled 实例验证此 DERP 服务器的客户端&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>服务器SSH防爆破最简单的两种方案</title><link>https://emohe.cn/posts/23/</link><guid isPermaLink="true">https://emohe.cn/posts/23/</guid><pubDate>Thu, 27 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;互联网上有黑客无时无刻都在扫端口，我也看到过很多网友的惨痛经历，服务器的SSH密码被黑客爆破后进入服务器捣乱或者植入后门，所以网络安全要牢记心中。本篇文章为大家分享防止SSH被爆破的两种方案，并且最简单方便。&lt;/p&gt;
&lt;h3&gt;方案一：关闭密码登录改为使用私钥登录&lt;/h3&gt;
&lt;p&gt;简介：通过关闭SSH密码登录，改用公钥认证，只有拥有对应私钥的用户才能登录。
服务器存储用户的公钥，客户端使用私钥进行身份验证，非对称加密确保安全性，彻底杜绝密码暴力破解。&lt;/p&gt;
&lt;p&gt;1：生成&lt;code&gt;ED25519&lt;/code&gt;类型的 SSH 密钥对&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh-keygen -t ed25519
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;一路回车即可，生成的&lt;code&gt;id_ed25519&lt;/code&gt;文件为私钥，使用这个私钥文件连接服务器，&lt;code&gt;id_ed25519.pub&lt;/code&gt;文件为公钥。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;2：然后进入存储SSH密钥的目录，并配置公钥&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /root/.ssh
cat id_ed25519.pub &amp;gt;&amp;gt; authorized_keys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3：修改SSH配置文件&lt;/p&gt;
&lt;p&gt;文件路径在&lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4：找到对应的配置然后修改，这里仅展示需要修改的地方&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 修改SSH服务端口
Port 2222

# 启用公钥认证
PubkeyAuthentication yes

# 指定存储公钥的文件位置(增加此项)
AuthorizedKeysFile .ssh/authorized_keys

# 禁止使用空密码登录
PermitEmptyPasswords no

# 禁止使用密码认证登录
PasswordAuthentication no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;5：重启SSH服务&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart ssh
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;方案二：端口敲门&lt;/h3&gt;
&lt;p&gt;:::note[注意]
请先看完教程再配置，配置后记得先测试一下，免得把自己关在门外了。
:::&lt;/p&gt;
&lt;p&gt;简介：端口敲门通过关闭SSH端口，服务器监听预设的端口序列，当客户端按正确顺序&lt;code&gt;敲门&lt;/code&gt;后，防火墙规则动态开放SSH端口，仅允许敲门成功的IP访问，阻止未授权访问。&lt;/p&gt;
&lt;p&gt;1：安装&lt;code&gt;iptables&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;大部分常见的Linux发行版已经默认安装了，无需额外安装，并且你安装了Docker后也是肯定安装了&lt;code&gt;iptables&lt;/code&gt;。可以运行&lt;code&gt;iptables --version&lt;/code&gt;查看版本。如果没有安装，可以执行这个命令安装：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt install iptables -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2：安装端口敲门程序&lt;code&gt;knockd&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt install knockd -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3：配置&lt;code&gt;knockd&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;knockd&lt;/code&gt;的默认配置文件路径在&lt;code&gt;/etc/knockd.conf&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[options]
    UseSyslog
    logfile = /var/log/knockd.log

# 开启SSH访问 - 只允许敲门的IP访问
[openSSH]
    sequence    = 5003,5001
    seq_timeout = 15
    start_command = /sbin/iptables -C INPUT -s %IP% -p tcp --dport 22 -j ACCEPT || /sbin/iptables -I INPUT 1 -s %IP% -p tcp --dport 22 -j ACCEPT
    tcpflags    = syn
    cmd_timeout = 10

# 关闭所有SSH访问 - 阻止所有IP
[closeSSH]
    sequence    = 7001
    seq_timeout = 15
    start_command = /sbin/iptables -C INPUT -p tcp --dport 22 -j DROP || /sbin/iptables -I INPUT 1 -p tcp --dport 22 -j DROP &amp;amp;&amp;amp; /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT 2&amp;gt;/dev/null
    tcpflags    = syn
    cmd_timeout = 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4：启动&lt;code&gt;knockd&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable knockd
sudo systemctl start knockd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;5：关门&lt;/p&gt;
&lt;p&gt;网页访问&lt;code&gt;7001&lt;/code&gt;端口关闭SSH服务，阻止所有IP访问SSH&lt;/p&gt;
&lt;p&gt;6：敲门&lt;/p&gt;
&lt;p&gt;按顺序网页访问&lt;code&gt;5003&lt;/code&gt;和&lt;code&gt;5001&lt;/code&gt;端口，需要15秒内完成动作，敲门后会自动放行敲门的IP允许连接SSH。&lt;/p&gt;
&lt;p&gt;Liunx可以使用wget等命令敲门&lt;/p&gt;
&lt;h4&gt;（可选）关闭端口敲门&lt;/h4&gt;
&lt;p&gt;停止并禁用&lt;code&gt;knockd&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl stop knockd
sudo systemctl disable knockd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;清除防火墙所有的自定义规则&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo iptables -F
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;端口敲门不仅限于SSH端口，还能实现更多玩法。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>自定义域名邮箱可任意收发邮件📩白嫖阿里云企业邮箱</title><link>https://emohe.cn/posts/22/</link><guid isPermaLink="true">https://emohe.cn/posts/22/</guid><pubDate>Wed, 26 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;当我们自建网站和一些服务的时候，开启注册验证功能需要邮件发送验证码给用户，自己部署需要额外的成本不说还大概率进垃圾箱。最近我发现了阿里云可以白嫖企业邮箱5年，所以分享给大家。实测QQ和gmail邮箱等等都能正常发送。本篇文章教大家白嫖阿里云企业邮箱并配置&lt;code&gt;SMTP&lt;/code&gt;服务。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://account.aliyun.com/login/login.htm?oauth_callback=https%3A%2F%2Fcommon-buy.aliyun.com%2F%3FcommodityCode%3Dalimail%26userCode%3Da5fdv0ky%26specCode%3Dlx_18482&quot;&gt;阿里云白嫖链接&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;前提条件&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1：拥有自己的域名，这步简单就不多说了，随便注册个便宜域名就行。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2：注册一个阿里云账号，这步有手就行。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3：访问&lt;a href=&quot;https://account.aliyun.com/login/login.htm?oauth_callback=https%3A%2F%2Fcommon-buy.aliyun.com%2F%3FcommodityCode%3Dalimail%26userCode%3Da5fdv0ky%26specCode%3Dlx_18482&quot;&gt;阿里云入口链接&lt;/a&gt;登录后，选择你的阿里云域名，注意：&lt;code&gt;选择域名后才能0元购买&lt;/code&gt;。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/e1.png&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4：购买邮箱服务后搜索&lt;code&gt;阿里邮箱&lt;/code&gt;，然后进入&lt;code&gt;阿里邮箱&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/e2.png&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5：点击&lt;code&gt;马上解析&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/e3.png&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6：点击&lt;code&gt;设置解析&lt;/code&gt;，然后点击&lt;code&gt;一键添加&lt;/code&gt;，这里记得先点击&lt;code&gt;初始化密码&lt;/code&gt;设置一下邮箱密码。这个密码也是你的&lt;code&gt;SMTP&lt;/code&gt;的密码。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/e4.png&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7：解析好后需要等待10分钟，显示解析生效后，登录邮箱管理页面。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/e5.png&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;8：在邮箱管理页面左侧找到&lt;code&gt;员工账号管理&lt;/code&gt;，点击&lt;code&gt;姓名&lt;/code&gt;那里进入配置页面&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/e6.png&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;9：开启&lt;code&gt;SMTP服务&lt;/code&gt;，然后点击下面的保存&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/e7.png&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;10：左侧找到&lt;code&gt;账号安全策略&lt;/code&gt;，开启&lt;code&gt;允许使用第三方客户端&lt;/code&gt;，然后下面保存。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/e8.png&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;11：&lt;code&gt;SMTP&lt;/code&gt;配置信息。&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;信息&lt;/th&gt;
&lt;th&gt;示例值&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;用户名&lt;/td&gt;
&lt;td&gt;postmaster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SMTP&lt;/td&gt;
&lt;td&gt;smtp.qiye.aliyun.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;端口&lt;/td&gt;
&lt;td&gt;465 (SSL加密)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;账号&lt;/td&gt;
&lt;td&gt;&lt;code&gt;postmaster@example.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;密码&lt;/td&gt;
&lt;td&gt;你设置的初始化密码（忘了的话可以重置）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;12：&lt;code&gt;SMTP&lt;/code&gt;配置官方文档&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://help.aliyun.com/document_detail/36687.html&quot;&gt;文档地址&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.aliuyun.com.cn/news/help/294.html&quot;&gt;文档地址&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>海外域名注册平台推荐和Cloudflare托管域名</title><link>https://emohe.cn/posts/21/</link><guid isPermaLink="true">https://emohe.cn/posts/21/</guid><pubDate>Tue, 25 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;海外域名注册&lt;/h3&gt;
&lt;h4&gt;前言&lt;/h4&gt;
&lt;p&gt;众所周知国内平台购买的域名都需要实名认证，我一直想找一个海外免实名的域名注册平台，使用了好几个发现都不如意，要么不支持支付宝付款，要么操作逻辑太复杂功能也不好找，要么不支持中文语言，找来找去我发现&lt;code&gt;spaceship&lt;/code&gt;符合我的需求。&lt;/p&gt;
&lt;p&gt;官网地址：https://www.spaceship.com/zh/domains&lt;/p&gt;
&lt;p&gt;&lt;code&gt;spaceship&lt;/code&gt;特点如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持支付宝付款&lt;/li&gt;
&lt;li&gt;网站支持中文语言&lt;/li&gt;
&lt;li&gt;操作逻辑简单好找&lt;/li&gt;
&lt;li&gt;免费的隐私保护&lt;/li&gt;
&lt;li&gt;国际大平台&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;1：进入网站后点击右上角登录，然后点击下面的注册，使用邮箱注册，填写信息后注册完成就可以购买域名了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;注册和购买的步骤都很简单，按照文字提示操作就行了。过程我就省略了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2：域名购买完成后，就可以更改域名设置了。点击右上角头像，点击管理&lt;code&gt;您的产品和应用&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/cf1.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3：进入管理页面点击&lt;code&gt;域管理器&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/cf2.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4：然后点击你刚刚买的域名，然后右边找到&lt;code&gt;名称服务器和DNS&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/cf3.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5：可以直接在这里&lt;code&gt;添加DNS解析&lt;/code&gt;，但是我建议托管到&lt;code&gt;Cloudflare&lt;/code&gt;。托管过去则需要更改&lt;code&gt;自定义名称服务器&lt;/code&gt;，选择&lt;code&gt;自定义名称服务器&lt;/code&gt;填入&lt;code&gt;Cloudflare&lt;/code&gt;提供给你的名称服务器就行啦。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/cf4.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;Cloudflare&lt;/code&gt;托管域名教程&lt;/h3&gt;
&lt;p&gt;官网注册地址：https://dash.cloudflare.com&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1：进入官网在右上角把语言改成中文，然后使用邮箱注册后，登录进去，左边找到&lt;code&gt;账户主页&lt;/code&gt;，然后选择&lt;code&gt;添加域名&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注册的步骤都很简单，按照文字提示操作就行了。过程我就省略了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/cf5.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2：然后填入你的域名，点击继续&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/cf6.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3：然后下面选中免费计划，点击继续&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/cf7.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4：然后点击&lt;code&gt;前往继续激活&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/cf8.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5：然后上面教程中的域名注册平台里的最后一步里，将这里&lt;code&gt;Cloudflare&lt;/code&gt;分配给你的&lt;code&gt;名称服务器&lt;/code&gt;复制过去&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./png/cf9.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6：然后点击&lt;code&gt;继续&lt;/code&gt;就完成啦。完成这些操作后需要等待DNS广播完成，通常需要十几分钟到半个小时左右，部分情况也会更慢。稍后&lt;code&gt;Cloudflare&lt;/code&gt;主页里的域名&lt;code&gt;状态&lt;/code&gt;显示为&lt;code&gt;活动&lt;/code&gt;就是成功了。&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
</content:encoded></item><item><title>Docker部署DeepSeek-R1本地大模型</title><link>https://emohe.cn/posts/20/</link><guid isPermaLink="true">https://emohe.cn/posts/20/</guid><pubDate>Sat, 08 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;使用&lt;code&gt;docker&lt;/code&gt;部署&lt;code&gt;OpenUI + Ollama&lt;/code&gt; + &lt;code&gt;DeepSeek-R1:7B&lt;/code&gt;，通过浏览器访问&lt;code&gt;OpenUI&lt;/code&gt;进行交互。部署完成后可以离线使用&lt;code&gt;DeepSeek-R1&lt;/code&gt;大模型。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Ollama&lt;/code&gt;的&lt;code&gt;DeepSeek-R1&lt;/code&gt;大模型官网：https://ollama.com/library/deepseek-r1:7b&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;1.5B：CPU最低4核，内存8GB+，若GPU加速可选4GB+显存，适合低资源设备部署等场景。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;7B：CPU 8核以上，内存16GB+，硬盘8GB+，显卡推荐8GB+显存，可用于本地开发测试等场景。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;8B：硬件需求与7B相近略高，适合需更高精度的轻量级任务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;14B：CPU 12核以上，内存32GB+，硬盘15GB+，显卡16GB+显存，可用于企业级复杂任务等场景。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;32B：CPU 16核以上，内存64GB+，硬盘30GB+，显卡24GB+显存，适合高精度专业领域任务等场景。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;70B：CPU 32核以上，内存128GB+，硬盘70GB+，显卡需多卡并行，适合科研机构等进行高复杂度生成任务等场景。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;部署教程&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;open-webui&lt;/code&gt;镜像大小：8 GB&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;配置示例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:ollama
    container_name: open-webui
    ports:
      - &quot;3000:8080&quot;
    volumes:
      - ./ollama:/root/.ollama
      - ./open-webui:/app/backend/data
    restart: always
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;国内网络环境可以使用南京大学 ghcr 镜像加速&lt;code&gt;ghcr.nju.edu.cn&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;容器内安装&lt;code&gt;DeepSeek-R1 7b&lt;/code&gt;模型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker exec -it open-webui sh
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;ollama run deepseek-r1:7b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;部署完成后浏览器访问&lt;code&gt;3000&lt;/code&gt;端口使用web面板进行对话，如果需要域名访问反代一下即可。&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;如果有GPU服务器可以使用如下命令&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;docker run -d -p 3000:8080 --gpus=all \
  -v ./ollama:/root/.ollama \
  -v ./open-webui:/app/backend/data \
  --name open-webui \
  --restart always \
  ghcr.io/open-webui/open-webui:ollama
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;电脑本地安装ollama&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;官方地址：https://ollama.com&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;下载对应的系统版本&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装完成后打开电脑终端&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;查看版本&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;ollama --version
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;下载并运行 deepseek-r1:7b 模型&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;ollama run deepseek-r1:7b
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;可以在终端对话使用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;也可以部署&lt;code&gt;open-webui&lt;/code&gt;访问并使用本地&lt;code&gt;ollama&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker run -d -p 3000:8080 \
  --add-host=host.docker.internal:host-gateway \
  -e OLLAMA_API_URL=http://host.docker.internal:11434 \
  -v ./open-webui:/app/backend/data \
  --name open-webui \
  --restart always \
  ghcr.io/open-webui/open-webui:main
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h4&gt;ollama api 调用示例 POST 请求&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;curl http://localhost:11434/api/generate -d &apos;{
  &quot;model&quot;: &quot;deepseek-r1:7b&quot;,
  &quot;prompt&quot;: &quot;你是什么模型?&quot;
}&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;API 会返回生成的结果，通常是 JSON 格式&lt;/p&gt;
</content:encoded></item><item><title>一生真的太短了</title><link>https://emohe.cn/posts/38/</link><guid isPermaLink="true">https://emohe.cn/posts/38/</guid><pubDate>Wed, 29 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;又是一年冬。&lt;/p&gt;
&lt;p&gt;我回到了村子里，时间仿佛突然放慢了脚步。于城市里那种急促而机械的节奏而言，这里的冬天显得格外压抑——枯藤缠绕着老树，残破的落叶铺在地上，空气里弥漫着寒意与衰败的气息。&lt;/p&gt;
&lt;p&gt;家人的脸庞也在不经意间苍老了许多。&lt;/p&gt;
&lt;p&gt;家里没有城市里永不停歇的机车轰鸣，没有人流穿梭的嘈杂声响。破旧的村庄静静地躺在冬天里，安静得近乎冷漠，让人无处可逃。&lt;/p&gt;
&lt;p&gt;时间过得真快。&lt;/p&gt;
&lt;p&gt;此刻我执笔之时是 2025 年 1 月 29 日，农历新年的清晨。凌晨四点，被鞭炮声惊醒，我才意识到又过年了。便再也睡不着了，躺在床上，任由思绪在黑暗中不受控制的游走。&lt;/p&gt;
&lt;p&gt;焦虑与恐慌悄然蔓延。&lt;/p&gt;
&lt;p&gt;依稀记得这间屋子从我小时候起几乎没有任何变化。墙壁的斑驳、陈旧的摆设，它们像是一只无形的手，把我拉回过去。那些被尘封的记忆无情的侵入大脑——刚踏入社会的那几年，我曾对世界充满好奇，对未来充满希望。&lt;/p&gt;
&lt;p&gt;一晃眼，十年过去了，时间真的快到无法想象。&lt;/p&gt;
&lt;p&gt;回头再看，我仍然停留在原地。没有一丝丝改变，没有任何收获。依旧是一个人，依旧过着重复且忧伤的生活。时间没有把我推向诗和远方，反而一点点地把我压进更深的抑郁里。&lt;/p&gt;
&lt;p&gt;昨天，家人随口提起隔壁村一位老人去世了。
他们说，冬天一到，老人往往更容易扛不住，说走就走。&lt;/p&gt;
&lt;p&gt;这句话在我心里反复回响。
人一旦死去，就再也见不到了。永远。&lt;/p&gt;
&lt;p&gt;从这一刻开始，死亡的恐惧毫无征兆地袭来。&lt;/p&gt;
&lt;p&gt;我开始不停地想：死了之后，什么都没有了。连感受&quot;黑&quot;的能力都没有了。甚至连&quot;世界&quot;本身，也似乎是依附于&quot;我&quot;的存在而存在的——如果我消失了，这个世界于我而言，也将彻底消散。&lt;/p&gt;
&lt;p&gt;想到这里，我的心跳骤然加快，呼吸变得困难。&lt;/p&gt;
&lt;p&gt;生不带来，死不带去。
一切仿佛都失去了意义。&lt;/p&gt;
&lt;p&gt;人生终将落幕。若干年后，我会死去；那些记忆中曾经认识我的人，也终将死去；直到关于我的所有痕迹彻底消散，仿佛我从未存在过一样。此时此刻正在思考的这个&quot;我&quot;，也将不复存在。&lt;/p&gt;
&lt;p&gt;我好不甘...&lt;/p&gt;
&lt;p&gt;这一生如此凄凉，甚至连&quot;平庸&quot;都谈不上，这种无可回避的结局，让人感到彻骨的绝望。&lt;/p&gt;
&lt;p&gt;地球终会毁灭，人类终将消亡，连宇宙本身也拥有尽头。
当宇宙走向死亡——&lt;a href=&quot;https://www.baike.com/wikiid/7257034255048556556&quot;&gt;热寂&lt;/a&gt;降临，一切物质与能量都会归于沉寂，世界陷入无尽的黑暗、虚无与孤独。没有任何波动，什么都不剩。&lt;/p&gt;
&lt;p&gt;那种荒凉，深入骨髓。&lt;/p&gt;
&lt;p&gt;有时候，我会刻意的去感受&quot;死亡&quot;的边缘。
在夜晚极度困倦的时候，我努力感受从意识模糊到彻底沉睡的那一瞬间，去尝试意识消散的感觉。可越接近，我就越害怕。我不知道明天和意外哪一个会先到来，害怕自己一旦睡着，就再也无法醒来。&lt;/p&gt;
&lt;p&gt;我害怕再也无法感受这个世界的温度。
害怕再也见不到朋友，见不到家人。&lt;/p&gt;
&lt;p&gt;其实，我是那么渴望未来。
我想知道地球会变成什么样，人类会走向何方，宇宙在死亡之后是否还会有另一种形态。&lt;/p&gt;
&lt;p&gt;可那一切，都注定与我无关。无论如何都无法看见。这种无论如何都无法改变的结局，绝望透顶......&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;所谓的百年功名，千秋霸业，万古流芳，也终究不过一场梦。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Docker部署MC游戏开服</title><link>https://emohe.cn/posts/18/</link><guid isPermaLink="true">https://emohe.cn/posts/18/</guid><pubDate>Sat, 18 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;首先安装&lt;code&gt;Docker&lt;/code&gt;和&lt;code&gt;Docker-compose&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;国内环境可以使用我修改的开源脚本安装，和配置镜像加速&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash &amp;lt;(curl -sSL https://gitee.com/wanfeng789/shell/raw/master/docker.sh)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;创建配置文件&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;配置示例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  minecraft:
    image: itzg/minecraft-server
    environment:
      EULA: &quot;true&quot;
      TYPE: &quot;FORGE&quot;  # 可选使用 Forge 服务器
      VERSION: &quot;1.20.1&quot;  # 可选指定 Minecraft 版本
    ports:
      - &quot;25565:25565&quot;
    volumes:
      - ./data:/data
    stdin_open: true
    tty: true
    restart: always
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后一键启动&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进入游戏后选择多人服务器，服务器地址填：&lt;code&gt;公网IP:25565&lt;/code&gt;，如果你是用的nat服务器则需要将&lt;code&gt;25565&lt;/code&gt;端口映射出来，然后服务器地址那里的端口替换成你映射出来的端口。&lt;/p&gt;
&lt;p&gt;映射出来的配置文件在当前目录的&lt;code&gt;data&lt;/code&gt;目录下&lt;/p&gt;
&lt;h3&gt;更多环境变量&lt;/h3&gt;
&lt;h3&gt;1. &lt;strong&gt;基础配置&lt;/strong&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;变量名&lt;/th&gt;
&lt;th&gt;默认值&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EULA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;false&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;必须设置为 &lt;code&gt;&quot;true&quot;&lt;/code&gt; 以接受 Minecraft 的最终用户许可协议（EULA）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TYPE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;VANILLA&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;服务器类型，例如 &lt;code&gt;&quot;FORGE&quot;&lt;/code&gt;、&lt;code&gt;&quot;FABRIC&quot;&lt;/code&gt;、&lt;code&gt;&quot;SPIGOT&quot;&lt;/code&gt; 等。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;VERSION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;LATEST&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Minecraft 版本，例如 &lt;code&gt;&quot;1.20.1&quot;&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MEMORY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;1G&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;分配给服务器的内存大小，例如 &lt;code&gt;&quot;2G&quot;&lt;/code&gt; 或 &lt;code&gt;&quot;4G&quot;&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;JVM_OPTS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;自定义 JVM 参数，例如 &lt;code&gt;&quot;-XX:+UseG1GC&quot;&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;JVM_XX_OPTS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;自定义 JVM 的 &lt;code&gt;-XX&lt;/code&gt; 参数，例如 &lt;code&gt;&quot;-XX:+UseStringDeduplication&quot;&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;2. &lt;strong&gt;服务器类型相关&lt;/strong&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;变量名&lt;/th&gt;
&lt;th&gt;默认值&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FORGE_VERSION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;指定 Forge 版本，例如 &lt;code&gt;&quot;47.3.0&quot;&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FABRIC_VERSION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;指定 Fabric 版本，例如 &lt;code&gt;&quot;0.14.22&quot;&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SPIGOT_DOWNLOAD_URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;自定义 Spigot 的下载 URL。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;3. &lt;strong&gt;网络和连接&lt;/strong&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;变量名&lt;/th&gt;
&lt;th&gt;默认值&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SERVER_NAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;Minecraft Server&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;服务器名称，显示在客户端服务器列表中。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MOTD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;A Minecraft Server&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;服务器欢迎信息（MOTD）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ONLINE_MODE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;true&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否启用正版验证，设置为 &lt;code&gt;&quot;false&quot;&lt;/code&gt; 允许非正版玩家连接。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MAX_PLAYERS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;20&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;服务器最大玩家数量。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;VIEW_DISTANCE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;10&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;玩家视野距离（区块数）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ENABLE_RCON&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;false&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否启用 RCON（远程控制）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RCON_PASSWORD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;RCON 密码。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RCON_PORT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;25575&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;RCON 端口。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;4. &lt;strong&gt;世界和游戏设置&lt;/strong&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;变量名&lt;/th&gt;
&lt;th&gt;默认值&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LEVEL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;world&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;世界名称。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LEVEL_TYPE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;default&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;世界类型，例如 &lt;code&gt;&quot;flat&quot;&lt;/code&gt;、&lt;code&gt;&quot;largebiomes&quot;&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GAMEMODE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;survival&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;默认游戏模式，例如 &lt;code&gt;&quot;creative&quot;&lt;/code&gt;、&lt;code&gt;&quot;adventure&quot;&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DIFFICULTY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;easy&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;游戏难度，例如 &lt;code&gt;&quot;normal&quot;&lt;/code&gt;、&lt;code&gt;&quot;hard&quot;&lt;/code&gt;。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ALLOW_FLIGHT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;false&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否允许飞行。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ALLOW_NETHER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;true&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否允许下界传送门。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SPAWN_ANIMALS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;true&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否生成动物。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SPAWN_MONSTERS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;true&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否生成怪物。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SPAWN_NPCS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;true&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否生成村民。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GENERATE_STRUCTURES&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;true&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否生成结构（如村庄、神庙）。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;5. &lt;strong&gt;插件和模组&lt;/strong&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;变量名&lt;/th&gt;
&lt;th&gt;默认值&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MODS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;自动下载并安装模组的 URL 列表（以逗号分隔）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REMOVE_OLD_MODS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;false&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否在启动时删除旧的模组文件。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REMOVE_OLD_MODS_INCLUDE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;指定要删除的模组文件（支持通配符）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REMOVE_OLD_MODS_EXCLUDE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;指定要保留的模组文件（支持通配符）。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;6. &lt;strong&gt;备份和日志&lt;/strong&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;变量名&lt;/th&gt;
&lt;th&gt;默认值&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ENABLE_AUTOMATIC_BACKUPS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;false&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否启用自动备份。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BACKUP_INTERVAL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;24h&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;自动备份的时间间隔。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BACKUP_TARGET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;world&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;备份的目标文件夹。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LOG_TIMESTAMP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;false&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否在日志中添加时间戳。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;7. &lt;strong&gt;其他配置&lt;/strong&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;变量名&lt;/th&gt;
&lt;th&gt;默认值&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OPS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;管理员列表（以逗号分隔的玩家名称）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WHITELIST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;白名单列表（以逗号分隔的玩家名称）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BANNED_IPS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;封禁的 IP 列表（以逗号分隔）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BANNED_PLAYERS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;封禁的玩家列表（以逗号分隔）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ENABLE_COMMAND_BLOCK&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;false&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;是否启用命令方块。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MAX_TICK_TIME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;60000&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;服务器最大 tick 时间（毫秒）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MAX_WORLD_SIZE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;29999984&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;最大世界大小（区块数）。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>给IP申请SSL证书并开启HTTPS访问</title><link>https://emohe.cn/posts/17/</link><guid isPermaLink="true">https://emohe.cn/posts/17/</guid><pubDate>Fri, 17 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;IP证书是一种特殊的SSL证书，它直接绑定到服务器的公网IP地址上，当用户通过这个IP地址访问时，也能享受到如同访问经过域名验证的HTTPS网站一样的加密安全连接。这样一来，即便是没有注册域名或仅通过IP地址访问的服务，也能确保数据传输过程中的安全性，防止信息被窃取或篡改，同时也提供了对服务器身份的验证，增加了用户对服务提供者的信任度。&lt;/p&gt;
&lt;p&gt;本教程以&lt;code&gt;caddy&lt;/code&gt;作为演示，如何安装&lt;code&gt;caddy&lt;/code&gt;请参考本博客的教程，使用&lt;code&gt;nginx&lt;/code&gt;的话思路也一样。&lt;/p&gt;
&lt;h3&gt;1. 打开免费申请IP SSL证书的网站&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;https://zerossl.com/&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1：打开后首页就直接输入你要申请的IP，点击&lt;code&gt;Next Step&lt;/code&gt;进入下一步。&lt;/p&gt;
&lt;p&gt;2：输入注册邮箱和密码（邮箱可以随便填，不会验证真实性）&lt;/p&gt;
&lt;p&gt;3：免费版IP SSL证书有效期是3个月。需要在第二项里手动选择下。否则是默认的1年付费版。&lt;/p&gt;
&lt;h3&gt;2. 验证IP所有权&lt;/h3&gt;
&lt;p&gt;以下配置中的&lt;code&gt;123.123.123.123&lt;/code&gt;为示例&lt;code&gt;IP地址&lt;/code&gt;，请根据自己情况替换。&lt;/p&gt;
&lt;p&gt;1：下载&lt;code&gt;Auth&lt;/code&gt;验证文件&lt;/p&gt;
&lt;p&gt;2：在网站目录里创建&lt;code&gt;/.well-known/pki-validation/&lt;/code&gt;目录，以&lt;code&gt;caddy&lt;/code&gt;为例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p /var/www/.well-known/pki-validation
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;caddy&lt;/code&gt;配置示例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://123.123.123.123 {
    root * /var/www
    encode zstd gzip
    file_server
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3：将刚刚下载的验证文件上传到&lt;code&gt;/var/www/.well-known/pki-validation/&lt;/code&gt;目录里&lt;/p&gt;
&lt;p&gt;4：启动&lt;code&gt;caddy&lt;/code&gt;，访问你的公网IP，如果能看到验证文件，则代表成功&lt;/p&gt;
&lt;h3&gt;3. 生成SSL证书&lt;/h3&gt;
&lt;p&gt;然后&lt;code&gt;zerossl&lt;/code&gt;网站里点击验证，验证成功后下载&lt;code&gt;zip&lt;/code&gt;证书压缩包，上传到服务器&lt;code&gt;/etc/caddy&lt;/code&gt;目录，并使用&lt;code&gt;unzip&lt;/code&gt;命令解压&lt;/p&gt;
&lt;h3&gt;4. 合并证书文件&lt;/h3&gt;
&lt;p&gt;在&lt;code&gt;/etc/caddy&lt;/code&gt;目录下执行如下命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /etc/caddy
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;cat certificate.crt ca_bundle.crt &amp;gt; fullchain.crt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. 启动站点&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;caddy&lt;/code&gt;配置示例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://123.123.123.123 {
    root * /var/www
    encode zstd gzip
    file_server

    tls /etc/caddy/fullchain.crt /etc/caddy/private.key
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;/var/www&lt;/code&gt;为站点目录，&lt;code&gt;123.123.123.123&lt;/code&gt;为示例&lt;code&gt;IP地址&lt;/code&gt;，请根据自己情况替换。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;nginx&lt;/code&gt;的话思路也一样。&lt;/p&gt;
</content:encoded></item><item><title>Docker部署开源的Cloudreve网盘</title><link>https://emohe.cn/posts/16/</link><guid isPermaLink="true">https://emohe.cn/posts/16/</guid><pubDate>Thu, 16 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;介绍&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Cloudreve&lt;/code&gt;是一款开源的网盘软件，支持多种存储策略。可以帮助您快速、便捷地搭建一套属于自己或团队共享的云同步网盘，从而实现跨平台跨设备文件同步、文件共享、离线下载、团队协作等功能。&lt;/p&gt;
&lt;h3&gt;Docker-compose快速部署&lt;/h3&gt;
&lt;p&gt;创建项目文件夹&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p cloudreve &amp;amp;&amp;amp; cd cloudreve
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建配置文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -vp cloudreve/{uploads,avatar} \
&amp;amp;&amp;amp; touch cloudreve/conf.ini \
&amp;amp;&amp;amp; touch cloudreve/cloudreve.db \
&amp;amp;&amp;amp; mkdir -p aria2/config \
&amp;amp;&amp;amp; mkdir -p data/aria2 \
&amp;amp;&amp;amp; chmod -R 777 data/aria2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  cloudreve:
    container_name: cloudreve
    image: cloudreve/cloudreve:latest
    restart: unless-stopped
    ports:
      - &quot;5212:5212&quot;      # 映射访问端口
    volumes:
      - temp_data:/data
      - ./cloudreve/uploads:/cloudreve/uploads
      - ./cloudreve/conf.ini:/cloudreve/conf.ini
      - ./cloudreve/cloudreve.db:/cloudreve/cloudreve.db
      - ./cloudreve/avatar:/cloudreve/avatar
    depends_on:
      - aria2
  aria2:
    container_name: aria2
    image: p3terx/aria2-pro
    restart: unless-stopped
    environment:
      - RPC_SECRET=aria_rpc_token-kmcxadiikjcxCCAA7890    # 随意设置个强密码
      - RPC_PORT=6800
    volumes:
      - ./aria2/config:/config
      - temp_data:/data
volumes:
  temp_data:
    driver: local
    driver_opts:
      type: none
      device: $PWD/data
      o: bind
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看默认管理员信息&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logs cloudreve
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置完成后可以反代&lt;code&gt;5212&lt;/code&gt;端口并配置HTTPS加密公网访问，反代教程可以参考本博客的&lt;code&gt;caddy&lt;/code&gt;教程。&lt;/p&gt;
</content:encoded></item><item><title>Docker部署数据库管理面板和定时自动备份</title><link>https://emohe.cn/posts/15/</link><guid isPermaLink="true">https://emohe.cn/posts/15/</guid><pubDate>Wed, 15 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;部署&lt;code&gt;phpmyadmin&lt;/code&gt;数据库管理面板&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;docker run --name phpmyadmin -d -p 7890:80 phpmyadmin:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;环境变量参数：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-p 7890:80                 // 映射面板的端口。
-e PMA_HOST=172.17.0.1     // 指定连接到的数据库地址。
-e PMA_PORT=3306           // 指定 MySQL 数据库的端口号。
-e PMA_USER=root           // 指定登录数据库的用户名。
-e PMA_PASSWORD=123456     // 指定登录数据库的密码。
-e PMA_DATABASE=mysqldb    // 默认连接的数据库名称
--network my_network       // 指定容器网络
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;docker-compose.yaml&lt;/code&gt;部署&lt;/h4&gt;
&lt;p&gt;连接到指定数据库示例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  phpmyadmin:
    image: phpmyadmin:latest
    container_name: phpmyadmin
    ports:
      - &quot;7890:80&quot;
    environment:
      - UPLOAD_LIMIT=512M             # 设置上传文件大小限制      
      # 数据库连接设置
      - PMA_HOST=mysql                    # MySQL 地址
      - PMA_PORT=3306                     # MySQL 端口号
      - PMA_DATABASE=mysql                # 默认连接的数据库名称
    
    networks:
      - home_default        # 连接到指定网络

networks:
  home_default:
    external: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进入面板使用root用户名登录，密码就是数据库root密码&lt;/p&gt;
&lt;p&gt;如果要使用宿主机网络则移除网络配置，修改为&lt;code&gt;network_mode: host&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;查看容器网络的命令&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;docker inspect -f &apos;{{.HostConfig.NetworkMode}}&apos; 容器名称或ID
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;Docker部署数据库定时自动备份工具&lt;/h3&gt;
&lt;p&gt;支持&lt;code&gt;mysql&lt;/code&gt;和&lt;code&gt;mariadb&lt;/code&gt;数据库&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  backup-db:
    image: fradelg/mysql-cron-backup
    container_name: backup-db
    environment:
      - MYSQL_HOST=mysql            # 数据库地址
      - MYSQL_PORT=3306             # 数据库端口
      - MYSQL_USER=db_user          # 数据库用户名
      - MYSQL_PASS=db_password      # 数据库密码
      - MYSQL_DATABASE=db_name      # 数据库名称
      - MAX_BACKUPS=10             # 保留的备份数量，旧的备份将被清理
      - CRON_TIME=0 3 * * *        # 每天凌晨3点自动执行备份
    volumes:
      - ./backup:/backup          # 挂载本地目录用于保存备份
    restart: always

    networks:
      - home_default  # 连接到指定网络

networks:
  home_default:
    external: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;恢复备份的数据库&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker container exec backup-db /restore.sh ./backup/&amp;lt;your_sql_backup_gz_file&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;恢复当前目录内的&lt;code&gt;./backup/&amp;lt;your_sql_backup_gz_file&amp;gt;&lt;/code&gt;文件，需替换具体文件名称&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;如果恢复成功，会输出&lt;code&gt;Restore succeeded&lt;/code&gt;  否则会输出&lt;code&gt;Restore failed&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;添加变量&lt;code&gt;- INIT_BACKUP=1&lt;/code&gt;则在容器启动时立即创建备份&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;如果要使用宿主机网络则移除网络配置，增加&lt;code&gt;network_mode: host&lt;/code&gt;配置&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;再推荐一个轻量级数据库管理面板&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;支持更多数据库&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d --name adminer --network mynetwork -p 8080:8080 adminer:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加入到指定网络的变量：&lt;code&gt;--network mynetwork&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;host网络模式：&lt;code&gt;--network host&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;查看容器网络的命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker inspect -f &apos;{{.HostConfig.NetworkMode}}&apos; 容器名称或ID
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;修改导入大小和上传大小，修改容器内的&lt;code&gt;php.ini&lt;/code&gt;变量&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;max_input_vars = 1000           # POST数据和GET数据的最大值
upload_max_filesize = 128M      # PHP最大上传文件大小
post_max_size = 128M            # 服务器最大数据量和文件大小
memory_limit = 128M             # PHP内存占用限制
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;修改命令&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;docker exec -u 0 -it adminer /bin/sh

echo &quot;max_input_vars = 5000&quot; &amp;gt; /etc/php/7.4/cli/conf.d/custom-php.ini
echo &quot;upload_max_filesize = 512M&quot; &amp;gt;&amp;gt; /etc/php/7.4/cli/conf.d/custom-php.ini
echo &quot;post_max_size = 512M&quot; &amp;gt;&amp;gt; /etc/php/7.4/cli/conf.d/custom-php.ini
echo &quot;memory_limit = 512M&quot; &amp;gt;&amp;gt; /etc/php/7.4/cli/conf.d/custom-php.ini
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker restart adminer
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Docker部署Poste.io企业邮局</title><link>https://emohe.cn/posts/14/</link><guid isPermaLink="true">https://emohe.cn/posts/14/</guid><pubDate>Tue, 14 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;很多企业都有自建邮局的需求，本篇介绍如何使用Docker部署开源的&lt;code&gt;Poste.io&lt;/code&gt;邮局系统。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需要占用的端口&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;80 - HTTP（用于 web 界面和未加密的邮件服务）
443 - HTTPS（用于加密的 web 界面和邮件服务）
25 - SMTP（用于发送邮件）
587 - SMTP（用于加密的邮件发送）
993 - IMAP（用于加密的 IMAP 邮件接收）
995 - POP3（用于加密的 POP3 邮件接收）
110 - POP3（用于未加密的 POP3 邮件接收）
143 - IMAP（用于未加密的 IMAP 邮件接收）
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1：检查25端口是否能通&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;apt update &amp;amp;&amp;amp; apt install telnet -y
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;telnet smtp.gmail.com 25
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;如果显示下面的信息就代表是通的&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;Connected to smtp.gmail.com.
Escape character is &apos;^]&apos;.
220 smtp.gmail.com ESMTP d2e1a72fcca58-71dd9d6e713sm17347b3a.23 - gsmtp
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2：域名解析（以cloudflare为例）&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;名称&lt;/th&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;th&gt;代理状态&lt;/th&gt;
&lt;th&gt;TTL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;mail&lt;/td&gt;
&lt;td&gt;服务器IP&lt;/td&gt;
&lt;td&gt;仅 DNS&lt;/td&gt;
&lt;td&gt;自动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CNAME&lt;/td&gt;
&lt;td&gt;imap&lt;/td&gt;
&lt;td&gt;mail.example.com&lt;/td&gt;
&lt;td&gt;仅 DNS&lt;/td&gt;
&lt;td&gt;自动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CNAME&lt;/td&gt;
&lt;td&gt;pop&lt;/td&gt;
&lt;td&gt;mail.example.com&lt;/td&gt;
&lt;td&gt;仅 DNS&lt;/td&gt;
&lt;td&gt;自动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CNAME&lt;/td&gt;
&lt;td&gt;smtp&lt;/td&gt;
&lt;td&gt;mail.example.com&lt;/td&gt;
&lt;td&gt;仅 DNS&lt;/td&gt;
&lt;td&gt;自动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MX&lt;/td&gt;
&lt;td&gt;example.com&lt;/td&gt;
&lt;td&gt;mail.example.com&lt;/td&gt;
&lt;td&gt;仅 DNS&lt;/td&gt;
&lt;td&gt;自动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TXT&lt;/td&gt;
&lt;td&gt;example.com&lt;/td&gt;
&lt;td&gt;v=spf1 mx ~all&lt;/td&gt;
&lt;td&gt;仅 DNS&lt;/td&gt;
&lt;td&gt;自动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TXT&lt;/td&gt;
&lt;td&gt;s20241002362._domainkey&lt;/td&gt;
&lt;td&gt;k=rsa; p=MIIBIjA.............xXX&lt;/td&gt;
&lt;td&gt;仅 DNS&lt;/td&gt;
&lt;td&gt;自动&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;最后一条&lt;code&gt;TXT&lt;/code&gt;记录需要部署完成后进面板查看名称和内容。&lt;/p&gt;
&lt;p&gt;替换&lt;code&gt;example.com&lt;/code&gt;为你的域名&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3：&lt;code&gt;docker-compose.yaml&lt;/code&gt;启动&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;services:
  mailer:
    image: analogic/poste.io
    container_name: mailer
    restart: always
    hostname: mail.example.com  # 容器内主机名替换你的域名
    network_mode: host
    environment:
      - TZ=Asia/Shanghai  # 时区设置
      - DISABLE_CLAMAV=TRUE  # 禁用 ClamAV
      - DISABLE_RSPAMD=FALSE  # 启用 Rspamd
      - DISABLE_ROUNDCUBE=FALSE  # 启用 Roundcube
    volumes:
      - ./mailer:/data
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4：进入面板&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;mail.example.com&lt;/code&gt;使用这个域名进入管理面板&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第一行默认，第二行设置管理员邮箱，例如：&lt;code&gt;admin@example.com&lt;/code&gt;，第三行输入管理员密码，smtp密码也是这个&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;左侧选择&lt;code&gt;系统设置&lt;/code&gt;，然后上面找到TLS证书，然后申请证书。通用名默认，替代名称里把&lt;code&gt;smtp&lt;/code&gt;这些域名也填入进去，然后申请，查看下面的日志，申请完成后保存即可。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后左侧选择&lt;code&gt;虚拟域名&lt;/code&gt;，然后点击域名，找到&lt;code&gt;DKlM key&lt;/code&gt;，然后点击钥匙按钮激活，然后域名解析&lt;code&gt;TXT&lt;/code&gt;类型的验证。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后用管理员邮箱登录，测试发邮件即可。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;poste.io批量创建邮箱脚本&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# Poste.io 容器ID或名称
CONTAINER_ID=&quot;mailer&quot;

# 邮箱的@后缀，也就是根域名
DOMAIN=&quot;example.com&quot;

# 所有邮箱账户的统一密码
PASSWORD=&quot;admin123456&quot;

# 如果域名不存在，则创建域名
echo &quot;创建域名 $DOMAIN (如果不存在)&quot;
docker exec $CONTAINER_ID poste domain:create $DOMAIN

# 创建邮箱账户
for i in {100..200}
do
    EMAIL=&quot;$i@$DOMAIN&quot;
    echo &quot;正在创建邮箱: $EMAIL&quot;
    docker exec $CONTAINER_ID poste email:create $EMAIL $PASSWORD
    
    # 检查上一个命令的退出状态
    if [ $? -eq 0 ]; then
        echo &quot;成功创建邮箱 $EMAIL&quot;
    else
        echo &quot;创建邮箱 $EMAIL 失败&quot;
    fi
    
    # 可选：添加小延迟以避免对服务器造成过大压力
    sleep 1
done

echo &quot;邮箱创建过程完成。&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
</content:encoded></item><item><title>亚马逊云CDN配置教程</title><link>https://emohe.cn/posts/13/</link><guid isPermaLink="true">https://emohe.cn/posts/13/</guid><pubDate>Mon, 13 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;众所周知，海外有一些免费的CDN，而且还是大厂，其中最强大的就是&lt;code&gt;cloudflare&lt;/code&gt;，这个配置最简单，只需开启小黄云即可，但是&lt;code&gt;cloudflare&lt;/code&gt;的很多IP国内访问速度不佳，所以本篇介绍一下亚马逊云CDN的配置方法，亚马逊云的IP相对CF的速度稍微好点，需要注意的是，亚马逊云CDN的免费额度是每个月1000G流量，并且只是下载的流量是免费，上传是收费的（不过一般的网站很少用到上传流量），注意别被反薅了，注册亚马逊云需要验证外币卡，注册方法网上有很多，就不介绍了。&lt;/p&gt;
&lt;h3&gt;配置&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;本教程是基于不改动源站的配置下使用亚马逊云CDN，默认源站已经开启TLS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1：源域直接填源站域名，协议选&lt;code&gt;HTTPS&lt;/code&gt;，最小源选&lt;code&gt;TLSv1&lt;/code&gt;，&lt;/p&gt;
&lt;p&gt;2：行为里的压缩建议选&lt;code&gt;NO&lt;/code&gt;，查看器协议策略选&lt;code&gt;Redirect HTTP to HTTPS&lt;/code&gt;，缓存键和源请求要选&lt;code&gt;旧版缓存设置&lt;/code&gt;，也就是第二个。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里是我踩过的一个坑，必须选&lt;code&gt;旧版缓存&lt;/code&gt;，不然访问站点会报错502&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;3：&lt;code&gt;WAF&lt;/code&gt;防火墙选&lt;code&gt;不启用&lt;/code&gt;，因为这个是付费的。&lt;/p&gt;
&lt;p&gt;4：&lt;code&gt;支持的 HTTP 版本&lt;/code&gt;建议全部选中，然后点击&lt;code&gt;创建分配&lt;/code&gt;，等待部署完成，会给你分配一个域名，访问这个域名查看是否正常。&lt;/p&gt;
&lt;h4&gt;自定义域名&lt;/h4&gt;
&lt;p&gt;1：进入到&lt;code&gt;常规&lt;/code&gt;的&lt;code&gt;设置&lt;/code&gt;里的&lt;code&gt;编辑&lt;/code&gt;，添加&lt;code&gt;备用域名&lt;/code&gt;  &amp;gt; 也就是给用户访问的域名，然后&lt;code&gt;申请证书&lt;/code&gt;，然后在申请证书的页面里直接点下一步，输入一个域名，验证方法就用默认的&lt;code&gt;DNS 验证&lt;/code&gt;，然后点请求。&lt;/p&gt;
&lt;p&gt;2：这里以&lt;code&gt;cloudflare&lt;/code&gt;为例，在域名里添加一个&lt;code&gt;CNAME&lt;/code&gt;，名称和值直接复制亚马逊云里的即可，等待一会亚马逊云里会显示验证成功，需要耐心等待。&lt;/p&gt;
&lt;p&gt;3：证书验证完成后，记得回到上一个页面，选中刚刚颁发的域名，然后点保存，保存成功后等待部署完成。&lt;/p&gt;
&lt;p&gt;4：部署完成后，在cloudflare里把刚刚的那个用于验证域名的&lt;code&gt;CNAME&lt;/code&gt;修改一下，&lt;code&gt;名称&lt;/code&gt;就填你刚刚申请证书的二级域名，&lt;code&gt;目标&lt;/code&gt;填亚马逊云给你分配的域名即可。&lt;/p&gt;
&lt;p&gt;5：如果无法访问可能是aws正在部署中，多等待一会即可。&lt;/p&gt;
</content:encoded></item><item><title>wordpress资源加速</title><link>https://emohe.cn/posts/12/</link><guid isPermaLink="true">https://emohe.cn/posts/12/</guid><pubDate>Sun, 12 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;前段时间，国内环境部署的wordpress执行任何有关插件、主题、核心的升级 / 安装时均会提示&lt;code&gt;429 Too Many Requests&lt;/code&gt;导致操作失败。具体原因为 &lt;code&gt;download.wordpress.org&lt;/code&gt;  遭受了大流量攻击从而面向国内的 CDN 服务停摆。&lt;/p&gt;
&lt;p&gt;该问题已持续数月，在很大程度上阻碍了国内网站正常更新 WordPress 核心及相关周边产品，站点安全性得不到任何保障。直到数月之后才恢复。为了防止以后再出现这样的事件，所以有了本篇教程。&lt;/p&gt;
&lt;h3&gt;介绍&lt;/h3&gt;
&lt;p&gt;本篇教程是通过一个开源项目来实现&lt;code&gt;wordpress&lt;/code&gt;加速，其功能如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[x] 优化 WordPress 相关服务在中国大陆的访问速度&lt;/li&gt;
&lt;li&gt;[x] 优化 WordPress 后台加载速度&lt;/li&gt;
&lt;li&gt;[x] 优化 WordPress 前台加载速度&lt;/li&gt;
&lt;li&gt;[x] 移除后台无用请求与组件&lt;/li&gt;
&lt;li&gt;[x] 替换 Gravatar 头像为 Cravatar&lt;/li&gt;
&lt;li&gt;[x] 优化 谷歌字体 加载速度&lt;/li&gt;
&lt;li&gt;[x] 优化 谷歌前端库 加载速度&lt;/li&gt;
&lt;li&gt;[x] 优化 CDNJS 加载速度&lt;/li&gt;
&lt;li&gt;[x] 优化 Jsdelivr 加载速度&lt;/li&gt;
&lt;li&gt;[x] 集成 WPMirror 镜像更新源&lt;/li&gt;
&lt;li&gt;[x] 集成 Windfonts 中文网页 Webfonts&lt;/li&gt;
&lt;li&gt;[x] 集成 adminCDN 前端公共库&lt;/li&gt;
&lt;li&gt;[x] 启用 飞行模式 可屏蔽外部 API 请求&lt;/li&gt;
&lt;li&gt;[x] 启用 节点监控 可自动切换加速节点&lt;/li&gt;
&lt;li&gt;[x] 启用 品牌白标 可自定义 OEM 插件品牌&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;开源地址：https://github.com/WenPai-org/wp-china-yes&lt;/h3&gt;
&lt;h3&gt;安装&lt;/h3&gt;
&lt;p&gt;同其他 &lt;code&gt;WordPress&lt;/code&gt; 插件一样，&lt;strong&gt;从 Release 页面下载最新版本的插件&lt;/strong&gt;（不要直接下载源码！！！），在后台插件管理页面上传并启用即可。&lt;/p&gt;
&lt;p&gt;当然，你也可以选择将插件手动上传到&lt;code&gt;wp-content/plugins&lt;/code&gt;目录下，然后在后台启用。&lt;/p&gt;
&lt;h3&gt;该插件的加速源如下&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;资源&lt;/th&gt;
&lt;th&gt;提供者&lt;/th&gt;
&lt;th&gt;🇨🇳 加速源&lt;/th&gt;
&lt;th&gt;🇭🇰 中继源&lt;/th&gt;
&lt;th&gt;官方源&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API 接口&lt;/td&gt;
&lt;td&gt;文派&lt;/td&gt;
&lt;td&gt;api.wenpai.net&lt;/td&gt;
&lt;td&gt;api.wpmirror.com&lt;/td&gt;
&lt;td&gt;api.wordpress.org&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;下载&lt;/td&gt;
&lt;td&gt;文派&lt;/td&gt;
&lt;td&gt;downloads.wenpai.net&lt;/td&gt;
&lt;td&gt;downloads.wpmirror.com&lt;/td&gt;
&lt;td&gt;downloads.wordpress.org&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;插件资源&lt;/td&gt;
&lt;td&gt;文派&lt;/td&gt;
&lt;td&gt;ps.wenpai.net&lt;/td&gt;
&lt;td&gt;ps.wpmirror.com&lt;/td&gt;
&lt;td&gt;ps.w.org&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;主题资源&lt;/td&gt;
&lt;td&gt;文派&lt;/td&gt;
&lt;td&gt;ts.wenpai.net&lt;/td&gt;
&lt;td&gt;ts.wpmirror.com&lt;/td&gt;
&lt;td&gt;ts.w.org&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;静态资源&lt;/td&gt;
&lt;td&gt;文派&lt;/td&gt;
&lt;td&gt;s.wenpai.net&lt;/td&gt;
&lt;td&gt;s.wpmirror.com&lt;/td&gt;
&lt;td&gt;s.w.org&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;头像&lt;/td&gt;
&lt;td&gt;初认&lt;/td&gt;
&lt;td&gt;cravatar.cn&lt;/td&gt;
&lt;td&gt;cravatar.com&lt;/td&gt;
&lt;td&gt;gravatar.wpmirror.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;谷歌字体&lt;/td&gt;
&lt;td&gt;文风&lt;/td&gt;
&lt;td&gt;googlefonts.admincdn.com&lt;/td&gt;
&lt;td&gt;googlefonts.wpmirror.com&lt;/td&gt;
&lt;td&gt;fonts.google.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;谷歌前端库&lt;/td&gt;
&lt;td&gt;萌芽&lt;/td&gt;
&lt;td&gt;googleajax.admincdn.com&lt;/td&gt;
&lt;td&gt;googleajax.wpmirror.com&lt;/td&gt;
&lt;td&gt;ajax.google.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;谷歌静态资源&lt;/td&gt;
&lt;td&gt;萌芽&lt;/td&gt;
&lt;td&gt;gstatic.admincdn.com&lt;/td&gt;
&lt;td&gt;gstatic.wpmirror.com&lt;/td&gt;
&lt;td&gt;fonts.gstatic.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WP 静态资源&lt;/td&gt;
&lt;td&gt;萌芽&lt;/td&gt;
&lt;td&gt;wpstatic.admincdn.com&lt;/td&gt;
&lt;td&gt;wpstatic.wpmirror.com&lt;/td&gt;
&lt;td&gt;wordpress.org&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CDNJS 加速&lt;/td&gt;
&lt;td&gt;萌芽&lt;/td&gt;
&lt;td&gt;cdnjs.admincdn.com&lt;/td&gt;
&lt;td&gt;cdnjs.wpmirror.com&lt;/td&gt;
&lt;td&gt;cdnjs.cloudflare.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;主题预览&lt;/td&gt;
&lt;td&gt;文派&lt;/td&gt;
&lt;td&gt;wpthemes.cn&lt;/td&gt;
&lt;td&gt;wp-themes.wpmirror.com&lt;/td&gt;
&lt;td&gt;wp-themes.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;项目主页&lt;/td&gt;
&lt;td&gt;——&lt;/td&gt;
&lt;td&gt;WenPai.org&lt;/td&gt;
&lt;td&gt;WPMirror.com&lt;/td&gt;
&lt;td&gt;WordPress.org&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;备案状态&lt;/td&gt;
&lt;td&gt;——&lt;/td&gt;
&lt;td&gt;已备案&lt;/td&gt;
&lt;td&gt;未备案&lt;/td&gt;
&lt;td&gt;未备案&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;维护周期&lt;/td&gt;
&lt;td&gt;——&lt;/td&gt;
&lt;td&gt;长期&lt;/td&gt;
&lt;td&gt;长期&lt;/td&gt;
&lt;td&gt;长期&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;镜像供应商&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;文派 （广州） 科技有限公司&lt;/td&gt;
&lt;td&gt;汉中菲比斯网络技术有限公司&lt;/td&gt;
&lt;td&gt;Automattic/Google/Cloudflare&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>Linux换源和CentOS切换备用源</title><link>https://emohe.cn/posts/11/</link><guid isPermaLink="true">https://emohe.cn/posts/11/</guid><pubDate>Sat, 11 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;众所周知 &lt;code&gt;CentOS 7&lt;/code&gt;系统已于2024年06月30日停止维护，并且再也没有新版本会维护了，所以我建议大佬们能迁移还是尽量迁移，推荐迁移到&lt;code&gt;Ubuntu&lt;/code&gt;或者&lt;code&gt;Debian&lt;/code&gt;系统，我自己比较喜欢&lt;code&gt;Debian&lt;/code&gt;系统，因为轻量也稳定。新手小白我推荐使用&lt;code&gt;Ubuntu&lt;/code&gt;系统，因为预装了很多工具和库。虽然&lt;code&gt;CentOS&lt;/code&gt;系统全都停止维护了，但是还是可以使用的，只是yum源失效了，所以本文介绍换源的操作。&lt;/p&gt;
&lt;h3&gt;使用开源的换源脚本，支持多种Linux系统换源。&lt;/h3&gt;
&lt;p&gt;国内环境：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash &amp;lt;(curl -sSL https://gitee.com/SuperManito/LinuxMirrors/raw/main/ChangeMirrors.sh)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;海外环境切换官方源：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash &amp;lt;(curl -sSL https://raw.githubusercontent.com/SuperManito/LinuxMirrors/main/ChangeMirrors.sh) --use-official-source true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;此脚本会自动识别你的&lt;code&gt;Linux&lt;/code&gt;版本，&lt;code&gt;CentOS&lt;/code&gt;系统切换官方源时会自动使用备用源。推荐使用！&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;可选项：手动换源教程&lt;/h3&gt;
&lt;p&gt;这里只列出了我常用的系统，其他系统请网上搜索一下对应的源替换一下就行了，步骤都是一样的，然后换源是需要root权限的。&lt;/p&gt;
&lt;p&gt;建议先备份&lt;code&gt;sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后打开文件&lt;code&gt;/etc/apt/sources.list&lt;/code&gt;替换源&lt;/p&gt;
&lt;p&gt;国内清华大学&lt;code&gt;debian 11&lt;/code&gt;源&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free
deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free
deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free
deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;国内清华大学&lt;code&gt;ubuntu 20.04&lt;/code&gt;源&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse

## Pre-released source, not recommended.
# deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方&lt;code&gt;debian 11&lt;/code&gt;源&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deb https://deb.debian.org/debian/ bullseye main contrib non-free
deb-src https://deb.debian.org/debian/ bullseye main contrib non-free
deb https://deb.debian.org/debian/ bullseye-updates main contrib non-free
deb-src https://deb.debian.org/debian/ bullseye-updates main contrib non-free
deb https://deb.debian.org/debian/ bullseye-backports main contrib non-free
deb-src https://deb.debian.org/debian/ bullseye-backports main contrib non-free
deb https://deb.debian.org/debian-security/ bullseye-security main contrib non-free
deb-src https://deb.debian.org/debian-security/ bullseye-security main contrib non-free
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;官方&lt;code&gt;debian 12&lt;/code&gt;源&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb http://deb.debian.org/debian-security/ bookworm-security main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian-security/ bookworm-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后更新源就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;CentOS 7.9&lt;/code&gt;切换官方备用vault源&lt;/h4&gt;
&lt;p&gt;创建和修改&lt;code&gt;/etc/yum.repos.d/CentOS-Base.repo&lt;/code&gt;文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[base]
name=CentOS-$releasever - Base
baseurl=http://vault.centos.org/7.9.2009/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[updates]
name=CentOS-$releasever - Updates
baseurl=http://vault.centos.org/7.9.2009/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[extras]
name=CentOS-$releasever - Extras
baseurl=http://vault.centos.org/7.9.2009/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;清理缓存并生成新的缓存&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo yum clean all
sudo yum makecache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行 &lt;code&gt;yum repolist&lt;/code&gt; 命令，确保新源已生效&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo yum repolist
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;CentOS 7&lt;/code&gt;切换阿里源&lt;/h4&gt;
&lt;p&gt;下载源到指定目录&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;清理缓存并生成新的缓存&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo yum clean all
sudo yum makecache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行 &lt;code&gt;yum repolist&lt;/code&gt; 命令，确保新源已生效&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo yum repolist
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Docker部署哪吒监控</title><link>https://emohe.cn/posts/10/</link><guid isPermaLink="true">https://emohe.cn/posts/10/</guid><pubDate>Fri, 10 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;简介&lt;/h3&gt;
&lt;p&gt;哪吒监控是一款开源的轻量化的服务器监控和运维工具，提供实时性能监控与告警通知。&lt;/p&gt;
&lt;p&gt;1：安装Docker参考我博客的教程&lt;/p&gt;
&lt;p&gt;2：创建&lt;code&gt;docker-compose.yml&lt;/code&gt;文件写入如下配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  dashboard:
    image: ghcr.io/nezhahq/nezha
    restart: always
    ports:
      - &quot;127.0.0.1:8008:8008&quot;
    volumes:
      - ./data:/dashboard/data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;监听本地防止被扫端口&lt;/p&gt;
&lt;p&gt;然后&lt;code&gt;docker compose up -d&lt;/code&gt;启动&lt;/p&gt;
&lt;p&gt;3：我选择使用&lt;code&gt;caddy&lt;/code&gt;作为web服务，简单方便，安装命令如下&lt;/p&gt;
&lt;p&gt;使用apt包一键安装caddy：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install -yq debian-keyring debian-archive-keyring apt-transport-https curl &amp;amp;&amp;amp; curl -1sLf &apos;https://dl.cloudsmith.io/public/caddy/stable/gpg.key&apos; | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg &amp;amp;&amp;amp; curl -1sLf &apos;https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt&apos; | sudo tee /etc/apt/sources.list.d/caddy-stable.list &amp;amp;&amp;amp; sudo apt update -q &amp;amp;&amp;amp; sudo apt install -yq caddy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4：写入&lt;code&gt;Caddyfile&lt;/code&gt;反代配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com {
    reverse_proxy /proto.NezhaService/* h2c://127.0.0.1:8008
    
    reverse_proxy /* 127.0.0.1:8008
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意替换你的域名，caddy会自动配置证书，启动caddy后就部署完成了。&lt;/p&gt;
&lt;p&gt;5：哪吒面板配置&lt;/p&gt;
&lt;p&gt;后台路径&lt;code&gt;/dashboard&lt;/code&gt;默认用户名密码&lt;code&gt;admin&lt;/code&gt; &lt;code&gt;admin&lt;/code&gt;，进入后台后首先修改用户名和密码，必须修改强密码，因为如果被爆破后你的小鸡将会被恶意者完全掌控。&lt;/p&gt;
&lt;p&gt;然后到设置里配置面板后台Agent对接地址，示例：&lt;code&gt;example.com:443&lt;/code&gt;，并选中&lt;code&gt;使用 TLS 连接&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;如果你要套cf cdn，则域名设置里的网络需要开启&lt;code&gt;grpc&lt;/code&gt;选项，并且SSL加密模式改成完全。&lt;/p&gt;
&lt;p&gt;6：国内网络环境说明&lt;/p&gt;
&lt;p&gt;哪吒官方镜像托管在github，国内网络拉取很慢，可以使用南京大学的镜像加速，&lt;code&gt;docker-compose.yml&lt;/code&gt;示例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  dashboard:
    image: ghcr.nju.edu.cn/nezhahq/nezha
    restart: always
    ports:
      - &quot;127.0.0.1:8008:8008&quot;
    volumes:
      - ./data:/dashboard/data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;国内环境安装Docker也可以参考我博客的教程&lt;/p&gt;
&lt;p&gt;国内小鸡安装Agent请替换哪吒官方的码云地址，将复制出来的Agent安装脚本替换如下地址即可，其他参数不变&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://gitee.com/naibahq/scripts/raw/main/agent/install.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;卸载v1版本的Agent方法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;v1版本的Agent多次安装不会覆盖，而是会出现多个重复监控的情况，所以我提供一下卸载干净的方法&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 停止并禁用
sudo systemctl stop nezha-agent.service
sudo systemctl disable nezha-agent.service

# 删除服务文件
rm -f /etc/systemd/system/nezha-a*.service
rm -f /lib/systemd/system/nezha-a*.service

# 删除相关文件夹
sudo rm -rf /opt/nezha

# 重新加载 systemd
sudo systemctl daemon-reload

# 验证服务是否有残留
systemctl list-units --type=service | grep nezha
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>windows重装系统教程</title><link>https://emohe.cn/posts/9/</link><guid isPermaLink="true">https://emohe.cn/posts/9/</guid><pubDate>Thu, 09 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;windows重装系统之U盘引导&lt;/h3&gt;
&lt;p&gt;微软官网系统镜像下载：https://www.microsoft.com/zh-cn/software-download/windows11&lt;/p&gt;
&lt;p&gt;1：下载&lt;code&gt;Windows 11 安装媒体&lt;/code&gt;并执行程序写入到U盘&lt;/p&gt;
&lt;p&gt;2：开机重复按&lt;code&gt;F2&lt;/code&gt;或者&lt;code&gt;F12&lt;/code&gt;或者&lt;code&gt;DELETE&lt;/code&gt;键 进入BIOS界面&lt;/p&gt;
&lt;p&gt;3：U盘引导，&lt;code&gt;UEFI&lt;/code&gt; ——&amp;gt; 对应&lt;code&gt;GPT&lt;/code&gt;磁盘分区格式&lt;/p&gt;
&lt;p&gt;4：将U盘改为第一启动项，然后保存并重启&lt;/p&gt;
&lt;p&gt;5：第一个分区默认是C盘，建议分区300G：填&lt;code&gt;307200&lt;/code&gt;MB。剩下的全给第二个分区，记得给盘符命名。&lt;/p&gt;
&lt;p&gt;6：进入系统后，右键打开显示设置——&amp;gt;个性化——&amp;gt;主题——&amp;gt;桌面图标设置——&amp;gt;勾选想要的桌面图标&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;重装系统前先关闭&lt;code&gt;Bitlocker&lt;/code&gt;磁盘加密，现在的大部分电脑都是&lt;code&gt;UEFI&lt;/code&gt;引导，和&lt;code&gt;GPT&lt;/code&gt;磁盘分区格式。如果无法进入安装系统的界面，需要关闭安全启动&lt;code&gt;Secure Boot&lt;/code&gt;选项。比较旧的电脑或者主板是&lt;code&gt;Legacy BIOS&lt;/code&gt;引导，和&lt;code&gt;MBR&lt;/code&gt;磁盘分区格式。Linux 系统默认的磁盘分区格式主要是&lt;code&gt;ext4&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;windows重装系统之本地重装&lt;/h3&gt;
&lt;p&gt;1：微软官网下载&lt;code&gt;Windows 11 磁盘映像 (ISO)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;2：解压下载的&lt;code&gt;iso&lt;/code&gt;文件，点击&lt;code&gt;5etup&lt;/code&gt;按提示重装即可&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;系统内给磁盘分区&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;打开磁盘管理并压缩C盘&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Win&lt;/code&gt; + &lt;code&gt;X&lt;/code&gt; 快捷键 → 选择“磁盘管理”&lt;/li&gt;
&lt;li&gt;右键点击 &lt;strong&gt;(C:)&lt;/strong&gt; 分区 → 选择“压缩卷”&lt;/li&gt;
&lt;li&gt;输入要分出的空间大小（单位：MB）→ 点击“压缩”&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;创建新分区&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;右键新出现的 &lt;strong&gt;未分配&lt;/strong&gt; 空间 → 选择“新建简单卷”&lt;/li&gt;
&lt;li&gt;按照向导完成&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;安装界面绕过硬件检查&lt;/h3&gt;
&lt;p&gt;报错信息：这台电脑不符合安装此版本的 Windows 所需的最低系统要求。&lt;/p&gt;
&lt;p&gt;1：在安装界面按下&lt;code&gt;Shift+F10&lt;/code&gt;组合键调出管理员命令窗口&lt;/p&gt;
&lt;p&gt;2：输入&lt;code&gt;regedit&lt;/code&gt;按回车键调出注册表&lt;/p&gt;
&lt;p&gt;3：依次展开&lt;code&gt;HKEY_LOCAL_MACHINE \ SYSTEM \ Setup&lt;/code&gt;目录，右键点击&lt;code&gt;Setup&lt;/code&gt;选择新建&lt;code&gt;项&lt;/code&gt;，命名为&lt;code&gt;LabConfig&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;4：选择&lt;code&gt;LabConfig&lt;/code&gt;右键–新建–DWORD（32 位）值，需要创建5个，分别命名为：&lt;code&gt;BypassCPUCheck&lt;/code&gt;、&lt;code&gt;BypassRAMCheck&lt;/code&gt;、&lt;code&gt;BypassSecureBootCheck&lt;/code&gt;、&lt;code&gt;BypassStorageCheck&lt;/code&gt;、&lt;code&gt;BypassTPMCheck&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;5：将这些十进制的值都改成&lt;code&gt;1&lt;/code&gt;确定后即可绕过硬件检测，继续安装&lt;/p&gt;
&lt;h3&gt;安装界面绕过联网&lt;/h3&gt;
&lt;p&gt;1：打开命令窗口：&lt;code&gt;Shift + F10&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;2：修改注册表跳过联网&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE /v BypassNRO /t REG_DWORD /d 1 /f

shutdown /r /t 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行完成后会自动重启，然后就可以直接创建本地账户，而无需使用联网账户。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;或者直接通过命令创建本地账户来跳过联网&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;net user 你的用户名 /add

net localgroup Administrators 你的用户名 /add

cd OOBE

msoobe &amp;amp;&amp;amp; shutdown -r
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行完成后会自动重启，然后就可以直接登录本地账户了&lt;/p&gt;
&lt;h3&gt;磁盘分区格式&lt;/h3&gt;
&lt;p&gt;如果磁盘分区格式不对，可以按&lt;code&gt;Shift + F10&lt;/code&gt;，打开命令窗口，更改磁盘存储格式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;diskpart                     # 进入磁盘管理
list disk                    # 列出所有磁盘
select disk 0                # 选择要操作的磁盘，0 是磁盘编号
clean                        # 清除磁盘上的所有分区和数据
convert gpt                  # 将磁盘转换为 GPT 分区格式
exit                         # 退出
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完成以上步骤后，硬盘已被格式化并转换为 &lt;strong&gt;UEFI&lt;/strong&gt; 的 &lt;strong&gt;GPT&lt;/strong&gt; 分区格式。然后刷新可以继续进行操作系统安装。&lt;/p&gt;
&lt;p&gt;驱动器0，即表示第一块物理磁盘，该类型索引从0开始&lt;/p&gt;
&lt;p&gt;分区1、2、3编号，即第一个分区……依次排列，分区从1开始索引编号。&lt;/p&gt;
&lt;h3&gt;备注：&lt;/h3&gt;
&lt;p&gt;1：&lt;code&gt;win+R&lt;/code&gt;运行&lt;code&gt;msinfo32&lt;/code&gt;查看BIOS引导模式，或者&lt;code&gt;cmd&lt;/code&gt;命令运行&lt;code&gt;bcdedit&lt;/code&gt;查看引导模式，如果是&lt;code&gt;\WINDOWS\system32\winload.efi&lt;/code&gt;则是&lt;code&gt;UEFI&lt;/code&gt;引导&lt;/p&gt;
&lt;p&gt;2：重装系统时有的机器需要进入&lt;code&gt;UEFI BIOS&lt;/code&gt;固件设置，关闭安全启动&lt;code&gt;Secure Boot&lt;/code&gt;选项。&lt;/p&gt;
&lt;p&gt;3：如果启动时有多个系统，可以&lt;code&gt;win+R&lt;/code&gt;运行&lt;code&gt;msconfig&lt;/code&gt;查看&lt;code&gt;引导&lt;/code&gt;选项卡，删掉不需要的。&lt;/p&gt;
&lt;p&gt;4：&lt;code&gt;可靠性历史&lt;/code&gt;可以查看当前系统的错误日志，&lt;code&gt;事件查看器&lt;/code&gt;也有更详细的日志&lt;/p&gt;
&lt;p&gt;5：更多问题可以问AI：https://chat.deepseek.com&lt;/p&gt;
&lt;h3&gt;系统修复命令：&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 内存诊断
mdsched.exe

# 检查并修复磁盘文件系统错误和坏道
chkdsk /f /r C:

# 扫描并修复损坏的系统文件
sfc /scannow

# 修复 Windows 系统映像及更新组件问题
dism /online /cleanup-image /restorehealth

# 修复启动引导(MBR)(UEFI)和(BCD)启动配置
bootrec /fixmbr
bootrec /fixboot
bootrec /rebuildbcd

# 重置网络设置
netsh int ip reset
netsh winsock reset

# 扫描远程计算机上的磁盘错误
chkdsk /scan

# 重置计算机，恢复出厂设置
systemreset

# 配置系统启动选项和服务
msconfig

# 修复驱动器错误
powershell -Command &quot;Repair-Volume -DriveLetter C&quot;

# 仅验证系统文件的完整性，不修复
sfc /verifyonly

# 显示系统的详细配置信息
systeminfo
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;系统激活代码&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;PowerShell&lt;/code&gt;脚本命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;irm https://get.activated.win | iex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行命令可以看到激活选项。选择 &lt;code&gt;[1] HWID&lt;/code&gt; 用于 &lt;code&gt;Windows&lt;/code&gt; 激活。选择 &lt;code&gt;[2] Ohook&lt;/code&gt; 用于 &lt;code&gt;Office&lt;/code&gt; 激活。&lt;/p&gt;
&lt;p&gt;旧命令：&lt;code&gt;irm https://massgrave.dev/get | iex&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/massgravel/Microsoft-Activation-Scripts&quot;&gt;开源地址&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;新机常用软件安装&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;chorme浏览器：https://www.google.com/chrome/&lt;/li&gt;
&lt;li&gt;7z解压工具：https://www.7-zip.org/&lt;/li&gt;
&lt;li&gt;驱动总裁：https://www.sysceo.com/dc&lt;/li&gt;
&lt;li&gt;图吧工具箱：https://www.tbtool.cn/&lt;/li&gt;
&lt;li&gt;致美化：https://zhutix.com/&lt;/li&gt;
&lt;li&gt;蓝屏分析工具：https://learn.microsoft.com/zh-cn/windows-hardware/drivers/debugger/&lt;/li&gt;
&lt;li&gt;Windows官方系统工具箱：https://learn.microsoft.com/zh-cn/windows/powertoys/&lt;/li&gt;
&lt;li&gt;文件搜索：https://www.listary.net/&lt;/li&gt;
&lt;li&gt;文件备份和同步：https://freefilesync.org/&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;国内BT下载&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;BT下载：https://www.qbittorrent.org&lt;/li&gt;
&lt;li&gt;比特彗星：https://www.bitcomet.com/cn&lt;/li&gt;
&lt;li&gt;Windows镜像：https://next.itellyou.cn/&lt;/li&gt;
&lt;li&gt;Windows镜像：https://www.hellowindows.cn/&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;系统安装工具&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;微PE：https://www.wepe.com.cn/ PE系统&lt;/li&gt;
&lt;li&gt;https://www.ventoy.net/ 支持多系统&lt;/li&gt;
&lt;li&gt;https://rufus.ie/zh/ 支持嵌入式烧录&lt;/li&gt;
&lt;li&gt;https://etcher.balena.io/  跨平台嵌入式烧录工具&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;官方Windows启动盘文件结构&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/
├── boot/              &amp;lt;- 启动文件
├── efi/               &amp;lt;- UEFI 启动文件（适用于 UEFI 模式）
├── sources/           &amp;lt;- 安装源文件
│   ├── install.wim    &amp;lt;- 安装镜像文件
│   ├── boot.wim       &amp;lt;- 启动映像
├── autorun.inf        &amp;lt;- 自动运行配置文件
└── setup.exe          &amp;lt;- 安装程序
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以在启动盘中创建&lt;code&gt;driver&lt;/code&gt;文件夹，驱动压缩包放至&lt;code&gt;driver&lt;/code&gt;目录下，并将其解压，然后安装系统界面可以加载驱动程序，最好是将驱动解压缩并按硬件类别放置在子文件夹中。这样就可以实现离线安装网卡驱动了。&lt;/p&gt;
</content:encoded></item><item><title>数据库学习笔记</title><link>https://emohe.cn/posts/8/</link><guid isPermaLink="true">https://emohe.cn/posts/8/</guid><pubDate>Wed, 08 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;MySQL和MariaDB常用命令&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;数据库&lt;/th&gt;
&lt;th&gt;操作&lt;/th&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MySQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;更新软件包列表&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;更新可用软件包列表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;安装 MySQL 服务器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt install mysql-server&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;安装 MySQL 服务器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;启动 MySQL 服务&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl start mysql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;启动 MySQL 服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;检查 MySQL 服务状态&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl status mysql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;检查 MySQL 服务的运行状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;运行安全安装脚本&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo mysql_secure_installation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;配置 MySQL 安全选项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;登录 MySQL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo mysql -u root -p&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;登录 MySQL，输入 root 用户密码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MariaDB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;更新软件包列表&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;更新可用软件包列表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;安装 MariaDB 服务器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt install mariadb-server&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;安装 MariaDB 服务器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;启动 MariaDB 服务&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl start mariadb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;启动 MariaDB 服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;检查 MariaDB 服务状态&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl status mariadb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;检查 MariaDB 服务的运行状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;运行安全安装脚本&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo mysql_secure_installation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;配置 MariaDB 安全选项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;登录 MariaDB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo mysql -u root -p&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;登录 MariaDB，输入 root 用户密码&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;功能分类&lt;/th&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;登录数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mysql -u 用户名 -p&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;登录 MySQL，使用指定的用户名，&lt;code&gt;-p&lt;/code&gt; 会提示输入密码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;显示数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHOW DATABASES;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;列出当前 MySQL 服务器中的所有数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;使用数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;USE 数据库名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;切换到指定数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;创建数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE DATABASE 数据库名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;创建一个新的数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;删除数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DROP DATABASE 数据库名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除指定数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;显示当前数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SELECT DATABASE();&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示当前正在使用的数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;显示数据库表&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHOW TABLES;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;列出当前数据库中的所有表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查看表结构&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DESCRIBE 表名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看表的结构 (字段、类型、主键等)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;创建表&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE TABLE 表名 (字段1 数据类型, 字段2 数据类型, ...);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;创建一张表，指定列和数据类型&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;删除表&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DROP TABLE 表名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除指定的表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;插入数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;插入一条数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查询数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SELECT 字段1, 字段2 FROM 表名 WHERE 条件;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查询表中的数据，可以使用条件过滤&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;更新数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UPDATE 表名 SET 字段1=值1 WHERE 条件;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;更新指定的表数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;删除数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DELETE FROM 表名 WHERE 条件;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除符合条件的数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;显示创建表语句&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHOW CREATE TABLE 表名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示指定表的创建语句&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;清空表数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TRUNCATE TABLE 表名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;清空表中的所有数据，但保留表结构&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查看索引&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHOW INDEX FROM 表名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看表中所有的索引&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;创建索引&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE INDEX 索引名 ON 表名 (字段);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;创建索引，提升查询速度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;删除索引&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DROP INDEX 索引名 ON 表名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除指定的索引&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;备份数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mysqldump -u 用户名 -p 数据库名 &amp;gt; 备份文件.sql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;备份数据库，将数据库内容导出为 &lt;code&gt;.sql&lt;/code&gt; 文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;恢复数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mysql -u 用户名 -p 数据库名 &amp;lt; 备份文件.sql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;恢复数据库，将 &lt;code&gt;.sql&lt;/code&gt; 文件导入指定数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;创建用户&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE USER &apos;用户名&apos;@&apos;localhost&apos; IDENTIFIED BY &apos;密码&apos;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;创建一个新的 MySQL 用户&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;删除用户&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DROP USER &apos;用户名&apos;@&apos;localhost&apos;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除 MySQL 用户&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;授权权限&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GRANT ALL PRIVILEGES ON 数据库名.* TO &apos;用户名&apos;@&apos;localhost&apos;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;授予用户对某个数据库的所有权限&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;显示用户权限&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHOW GRANTS FOR &apos;用户名&apos;@&apos;localhost&apos;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示指定用户的权限&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;撤销权限&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;REVOKE ALL PRIVILEGES ON 数据库名.* FROM &apos;用户名&apos;@&apos;localhost&apos;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;撤销指定用户对某个数据库的权限&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;刷新权限&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;FLUSH PRIVILEGES;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;刷新 MySQL 权限表，使权限更改生效&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查看服务器状态&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHOW STATUS;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看 MySQL 服务器的状态和性能指标&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查看数据库引擎&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHOW ENGINES;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示 MySQL 支持的所有存储引擎&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查看连接信息&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SHOW PROCESSLIST;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示当前 MySQL 的所有连接信息&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;大多数 SQL 语句都以分号 &lt;code&gt;;&lt;/code&gt; 结尾。&lt;/li&gt;
&lt;li&gt;如果 MySQL 的权限系统发生变动（如添加或撤销用户权限），建议运行 &lt;code&gt;FLUSH PRIVILEGES;&lt;/code&gt; 以刷新权限。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;SQLite常用命令&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;功能分类&lt;/th&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;安装 SQLite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt install sqlite3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在 Linux（Ubuntu）中安装 SQLite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;连接 SQLite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sqlite3 数据库名.db&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;连接到 SQLite 数据库（如果不存在则创建）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;退出 SQLite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.quit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;退出 SQLite 命令行工具&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;显示数据库表&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.tables&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示当前数据库中的所有表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查看表结构&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.schema 表名&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示指定表的创建语句&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;创建表&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE TABLE 表名 (字段1 数据类型, 字段2 数据类型, ...);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;创建一张表，指定字段和数据类型&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;插入数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;INSERT INTO 表名 (字段1, 字段2, ...) VALUES (值1, 值2, ...);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;插入一条数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查询数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SELECT 字段1, 字段2 FROM 表名 WHERE 条件;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查询表中的数据，可以使用条件过滤&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;更新数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;UPDATE 表名 SET 字段1=值1 WHERE 条件;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;更新指定的表数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;删除数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DELETE FROM 表名 WHERE 条件;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除符合条件的数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;删除表&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DROP TABLE 表名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除指定的表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查看索引&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PRAGMA index_list(表名);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看指定表的索引&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;创建索引&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE INDEX 索引名 ON 表名 (字段);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;创建索引，提升查询速度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;删除索引&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DROP INDEX 索引名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除指定的索引&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;导出数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;先&lt;code&gt;.output 文件名.sql&lt;/code&gt; 再&lt;code&gt;.dump&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;导出整个数据库，保存到指定的 SQL 文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;导入数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.read 文件名.sql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;从 SQL 文件导入数据到当前数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;打开数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.open 数据库名.db&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;打开或切换到另一个数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;PostgreSQL常用命令&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;操作&lt;/th&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;安装 PostgreSQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt update&lt;/code&gt; &amp;lt;br&amp;gt; &lt;code&gt;sudo apt install postgresql postgresql-contrib&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;更新包管理器并安装 PostgreSQL 和相关插件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;启动 PostgreSQL 服务&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl start postgresql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;启动 PostgreSQL 服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;重启 PostgreSQL 服务&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl restart postgresql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;重启 PostgreSQL 服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;停止 PostgreSQL 服务&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl stop postgresql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;停止 PostgreSQL 服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;检查 PostgreSQL 状态&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl status postgresql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;检查 PostgreSQL 服务的当前状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;设置 PostgreSQL 开机启动&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl enable postgresql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;设置 PostgreSQL 随系统启动自动运行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;切换到 postgres 用户&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo -i -u postgres&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;以 &lt;code&gt;postgres&lt;/code&gt; 管理员用户登录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;以指定用户登录&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;psql -U 用户名 -d 数据库名&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;以指定用户登录指定数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;进入 PostgreSQL shell&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;psql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;进入 PostgreSQL 的交互式命令行 shell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;退出 PostgreSQL shell&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\q&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;退出 PostgreSQL shell&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查看数据库列表&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示当前 PostgreSQL 实例中的所有数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;创建数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE DATABASE 数据库名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;创建一个新数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;删除数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DROP DATABASE 数据库名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除指定的数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查看表格列表&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\dt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;显示当前数据库中的所有表格&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;创建表格&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE TABLE 表格名 (列1 数据类型, 列2 数据类型, ...);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在数据库中创建一个新表格，并定义其列和数据类型&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;插入数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;INSERT INTO 表格名 (列1, 列2, ...) VALUES (值1, 值2, ...);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;向表格中插入一条数据记录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;查询数据&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SELECT * FROM 表格名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;从表格中查询所有数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;创建用户&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CREATE USER 用户名 WITH PASSWORD &apos;密码&apos;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;创建一个新用户，并为其设置密码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;给用户授权&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GRANT ALL PRIVILEGES ON DATABASE 数据库名 TO 用户名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;为指定的用户授权访问和操作指定数据库的所有权限&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;删除用户&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DROP USER 用户名;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除一个指定的用户&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;修改用户密码&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ALTER USER 用户名 WITH PASSWORD &apos;新密码&apos;;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;修改指定用户的密码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;备份数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pg_dump 数据库名 &amp;gt; 备份文件名.sql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;将指定数据库备份到一个 &lt;code&gt;.sql&lt;/code&gt; 文件中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;还原数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;psql 数据库名 &amp;lt; 备份文件名.sql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;从备份的 &lt;code&gt;.sql&lt;/code&gt; 文件还原数据库&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>alist网盘部署与美化</title><link>https://emohe.cn/posts/7/</link><guid isPermaLink="true">https://emohe.cn/posts/7/</guid><pubDate>Tue, 07 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Docker部署alist网盘&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;docker-compose.yaml&lt;/code&gt;配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  alist:
    image: xhofe/alist:latest
    container_name: alist
    restart: always
    volumes:
      - ./alist:/opt/alist/data
    ports:
      - &quot;54321:5244&quot;
    environment:
      - PUID=0
      - PGID=0
      - UMASK=022
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;修改密码&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;docker exec -it alist ./alist admin set 你的密码
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进入方式为：&lt;code&gt;ip:54321&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;用户名为：&lt;code&gt;admin&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;端口可自行修改&lt;/p&gt;
&lt;p&gt;管理路径为&lt;code&gt;/@manage&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;美化&lt;/h3&gt;
&lt;p&gt;替换自定义头部代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- 引入字符串替换功能的 JavaScript Polyfill --&amp;gt;
&amp;lt;script src=&quot;https://polyfill.alicdn.com/v3/polyfill.min.js?features=String.prototype.replaceAll&quot;&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;style type=&quot;text/css&quot;&amp;gt;
    /* 图标和按钮样式设置 */
    .hope-icon {
        color: #393939 !important; /* 设置所有图标颜色为黑色 */
    }

    .hope-button {
        color: #fff !important; /* 设置按钮字体为白色 */
        background-color: #393939 !important; /* 设置按钮背景为黑色 */
    }

    /* 特定元素的背景颜色设置 */
    .hope-ui-dark .hope-c-ivMHWx-hZistB-cv.hope-c-PJLV.hope-c-PJLV-iikaotv-css {
        background-color: #202425 !important; /* 设置特定元素在暗色模式下的背景色 */
    }

    /* 一些文本和图标颜色设置 */
    .hope-c-PJLV-ijzCLcW-css,
    .hope-c-mHASU-kFfbLQ-colorScheme-info,
    .hope-ui-dark .hope-c-ivMHWx-hZistB-cv.hope-c-PJLV.hope-c-PJLV-iikaotv-css svg {
        color: #000000 !important; /* 设置文本和图标颜色为黑色 */
    }

    .hope-c-mHASU-kFfbLQ-colorScheme-info[data-focus] {
        border-color: #000000 !important; /* 设置具有焦点的元素边框颜色为黑色 */
        box-shadow: 0 0 0 2px #ffcdd4 !important; /* 设置具有焦点的元素阴影效果 */
    }

    .hope-ui-light .hope-c-mHASU-kFfbLQ-colorScheme-info svg {
        color: white !important; /* 设置浅色模式下的特定图标颜色为白色 */
    }

    .hope-ui-dark .hope-c-mHASU-kFfbLQ-colorScheme-info svg {
        color: #000000 !important; /* 设置暗色模式下的特定图标颜色为黑色 */
    }

    /*导航条*/ 
    /*白天模式*/
    .hope-ui-light .hope-c-PJLV-idaeksS-css {
        background-color: rgba(255, 255, 255, 0.5) !important;
        border-radius: var(--hope-radii-xl) !important;
    }

    /* 吸附到页面顶部 */
    /*顶部*/
    .hope-c-PJLV-icWrYmg-css {
        background: rgba(255, 255, 255, 0) !important;
    }

    /*导航条*/
    .hope-c-PJLV-icKsjdm-css::after {
        background: rgba(255, 255, 255, 0) !important;
    }

    /*白天模式*/
    .hope-ui-light .hope-c-PJLV-icKsjdm-css {
        background-color: rgba(255, 255, 255, 0.5) !important;
        border-radius: var(--hope-radii-xl) !important;
    }

    /* 工具栏图标的悬停效果设置 */
    .left-toolbar-box svg:hover,
    .center-toolbar svg:hover {
        color: white !important;
        background-color: #393939;
    }

    .hope-c-PJLV-icHSmvX-css {
        border-radius: 5px;
    }

    /* 标题栏样式设置 */
    .hope-ui-light .hope-breadcrumb__list {
        border-radius: 10px !important;
    }

    /* 搜索框样式设置 */
    .hope-c-PJLV-ihYBJPK-css {
        display: none !important; /* 隐藏搜索框 */
    }

    .hope-ui-light .hope-c-PJLV-ikEIIxw-css {
        background-color: rgba(255, 255, 255, .7); /* 设置浅色模式下搜索框的背景色和透明度 */
    }

    .hope-c-dhzjXW.hope-c-XNyZK.hope-c-PJLV.hope-c-PJLV-ijhzIfm-css:hover {
        color: #000000 !important; /* 设置特定元素悬停时的颜色为黑色 */
        background: none; /* 设置特定元素悬停时的背景为透明 */
    }

    /* 弹出框样式设置 */
    .hope-ui-light section[id*=&quot;hope-modal-cl&quot;] {
        background-color: rgba(250, 250, 250, .75) !important; /* 设置浅色模式下弹出框的背景色和透明度 */
        backdrop-filter: blur(5px);
    }

    /* 公告板样式设置 */
    .hope-notification__list.hope-c-UdTFD.hope-c-UdTFD-jEXiZO-placement-top-end.hope-c-PJLV.hope-c-PJLV-ijhzIfm-css {
        max-width: fit-content;
    }

    /* 目录框和工具栏样式设置 */
    .hope-ui-light .hope-breadcrumb__list,
    .hope-ui-light .obj-box,
    .hope-ui-light .hope-c-PJLV-ikSuVsl-css,
    .hope-ui-light .hope-c-PJLV-ijgzmFG-css {
        background-color: rgba(255, 255, 255, .6) !important;
    }

    .footer span, .footer a:nth-of-type(1) {
        display: none;
    }

    .hope-ui-light {
        background-image: url(https://api.aixiaowai.cn/mcapi/mcapi.php); /* 设置浅色模式下的背景图（PC） */
        background-position: center;
        background-attachment: fixed;
        background-size: cover;
        background-repeat: no-repeat;
    }

    @media screen and (max-width: 960px) {
        .hope-ui-light {
            background-image: url(https://api.aixiaowai.cn/mcapi/mcapi.php); /* 设置浅色模式下的背景图（手机） */
        }
    }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;看板娘&lt;/h3&gt;
&lt;p&gt;放入自定义内容部分&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script src=&quot;https://eqcn.ajz.miesnfu.com/wp-content/plugins/wp-3d-pony/live2dw/lib/L2Dwidget.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
 
&amp;lt;!-- 看板娘 --&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/font-awesome/css/font-awesome.min.css&quot;&amp;gt;
&amp;lt;script src=&quot;https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/autoload.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;滚动字幕（放入元信息——顶部说明）&lt;/h3&gt;
&lt;p&gt;黑色字体&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;marquee&amp;gt;
&amp;lt;b id=&quot;nr&quot;&amp;gt;(｡･∀･)ﾉﾞ嗨，欢迎来到我的小破站。帅气漂亮的小哥哥小姐姐&amp;lt;/b&amp;gt; 
&amp;lt;/marquee&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;炫彩字体&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;style&amp;gt;#nr{font-size:20px;margin: 0;background: -webkit-linear-gradient(left,#ffffff,#ff0000 6.25%,#ff7d00 12.5%,#ffff00 18.75%,#00ff00 25%,#00ffff 31.25%,#0000ff 37.5%,#ff00ff 43.75%,#ffff00 50%,#ff0000 56.25%,#ff7d00 62.5%,#ffff00 68.75%,#00ff00 75%,#00ffff 81.25%,#0000ff 87.5%,#ff00ff 93.75%,#ffff00 100%);-webkit-background-clip: text;-webkit-text-fill-color: transparent;background-size: 200% 100%;animation: masked-animation 2s infinite linear;}@keyframes masked-animation {0% {background-position: 0 0;}100% {background-position: -100%, 0;}}&amp;lt;/style&amp;gt;&amp;lt;div style=&quot;background-color:#333;border-radius:25px;box-shadow:0px 0px 5px #f200ff;padding:5px;margin-top:10px;margin-bottom:0px;&quot;&amp;gt;&amp;lt;marquee&amp;gt;
&amp;lt;b id=&quot;nr&quot;&amp;gt;(｡･∀･)ﾉﾞ嗨，欢迎来到我的小破站。帅气漂亮的小哥哥小姐姐&amp;lt;/b&amp;gt; &amp;lt;/marquee&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ICP备案&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;span style=&quot;width:300px;margin:0 auto; padding:20px 0;&quot;&amp;gt;
    &amp;lt;a target=&quot;_blank&quot; href=&quot;https://beian.miit.gov.cn/&quot;
       style=&quot;display:inline-block;text-decoration:none;height:20px;line-height:20px;&quot;&amp;gt;
        &amp;lt;p style=&quot;height:20px;line-height:20px;margin: 0px 0px 0px 5px; color:#939393;&quot;&amp;gt;
            ICP备案号：实际的备案号
        &amp;lt;/p&amp;gt;
    &amp;lt;/a&amp;gt;
&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>wordpress和typecho和halo三种博客部署教程</title><link>https://emohe.cn/posts/6/</link><guid isPermaLink="true">https://emohe.cn/posts/6/</guid><pubDate>Mon, 06 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;使用Docker部署&lt;/h2&gt;
&lt;h3&gt;Docker-compose部署wordpress&lt;/h3&gt;
&lt;p&gt;创建项目文件夹&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir wordpress &amp;amp;&amp;amp; cd wordpress
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建&lt;code&gt;docker-compose.yml&lt;/code&gt;文件并写入以下代码配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  db:
    image: mysql:8.0
    volumes:
      - ./data/mysql:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: wordpressyyds
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    networks:
      - wp

  wordpress:
    container_name: wordpress
    depends_on:
      - db
    image: wordpress:latest
    volumes:
      - ./data/wp:/var/www/html
    ports:
      - &quot;8000:80&quot;
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    networks:
      - wp

networks:
  wp:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;站点端口为 &lt;code&gt;8000&lt;/code&gt;     后台路径 &lt;code&gt;/wp-admin&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;修改docker中wordpress的上传限制。&lt;/h3&gt;
&lt;p&gt;进入 wordpress 容器&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker exec -it wordpress /bin/bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;wordpress 容器中的这个路径&lt;code&gt;/usr/local/etc/php/&lt;/code&gt;，是存放 &lt;code&gt;php.ini&lt;/code&gt; 的地方，但是默认是没有 &lt;code&gt;php.ini&lt;/code&gt; 这个文件的，所以我们要通过复制一份&lt;code&gt;php.ini-production&lt;/code&gt;文件，来生成 &lt;code&gt;php.ini&lt;/code&gt; 文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /usr/local/etc/php/
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;cp php.ini-production php.ini
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后使用vim编辑器修改即可，如果没有则需要安装一下&lt;/p&gt;
&lt;p&gt;更新及安装vim，使用如下代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt-get update
apt-get install vim
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装完成vim，现在就可以对php.ini进行编辑了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vim php.ini
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;找到这几个变量，根据自己需求修改。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;upload_max_filesize = 2M      # PHP最大上传文件大小
post_max_size = 8M            # 服务器最大数据量和文件大小
memory_limit = 128M           # PHP内存占用限制
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后一步！&lt;/p&gt;
&lt;p&gt;重启wordpress&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker restart wordpress
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;hr /&gt;
&lt;h3&gt;wordpress启用redis缓存的部署方法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;services:
  db:
    image: mysql:8.0
    volumes:
      - ./data/mysql:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: wordpressyyds
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    networks:
      - wp

  wordpress:
    container_name: wordpress
    depends_on:
      - db
      - redis  # 添加redis
    image: wordpress:latest
    volumes:
      - ./data/wp:/var/www/html
    ports:
      - &quot;8000:80&quot;
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_REDIS_HOST: redis
    networks:
      - wp

  redis:
    image: redis:alpine
    container_name: redis
    restart: always
    networks:
      - wp

networks:
  wp:
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;在&lt;code&gt;wp-config.php&lt;/code&gt;文件中添加以下代码&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;define(&apos;WP_REDIS_HOST&apos;, &apos;redis&apos;);
define(&apos;WP_CACHE&apos;, true);

// 确保添加在这个代码前面
/* That&apos;s all, stop editing! Happy blogging. */
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;容器内安装redis扩展&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;docker exec -it wordpress /bin/bash
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y libz-dev libssl-dev

pecl install redis           # 这里直接一路回车

docker-php-ext-enable redis
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;重启容器&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;docker restart wordpress
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;插件商城搜索安装&lt;code&gt;redis&lt;/code&gt;官方插件：&lt;code&gt;Redis Object Cache&lt;/code&gt;    并启用&lt;code&gt;redis&lt;/code&gt;缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;修改后台路径插件&lt;code&gt;WPS Hide Login&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;备份插件&lt;code&gt;WPvivid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;直播播放器插件&lt;code&gt;SRS Player&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;优化性能缓存插件&lt;code&gt;WP Fastest Cache&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;压缩图片和懒加载插件&lt;code&gt;Smush&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;Docker部署halo博客&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker run -it -d --name halo -p 8090:8090 -v ./halo2:/root/.halo2 halohub/halo:2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;地址： &lt;code&gt;IP:8090&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;后台路径：&lt;code&gt;/console&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;国内阿里云镜像&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;registry.fit2cloud.com/halo/halo
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;code&gt;docker-compose.yaml&lt;/code&gt;部署&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;services:
  halo:
    image: halohub/halo:2
    restart: always
    depends_on:
      - mysql
    ports:
      - &quot;8090:8090&quot;
    volumes:
      - ./halo2:/root/.halo2
    command:
      - --spring.r2dbc.url=r2dbc:pool:mysql://mysql:3306/halo
      - --spring.r2dbc.username=halo
      - --spring.r2dbc.password=halo_password
      - --spring.sql.init.platform=mysql
      - --halo.external-url=http://公网IP:8090/

  mysql:
    image: mysql:5.7
    container_name: mysql
    environment:
      MYSQL_DATABASE: halo                  # 数据库名称
      MYSQL_USER: halo                      # 数据库用户名
      MYSQL_PASSWORD: halo_password         # 数据库密码
      MYSQL_ROOT_PASSWORD: halo_password    # 数据库root密码
    volumes:
      - ./data/mysql:/var/lib/mysql         # 映射数据库文件
    restart: always
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;hr /&gt;
&lt;h3&gt;Docker部署typecho&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;services:
  mysql:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: typechoPASSWORD
      MYSQL_DATABASE: typecho
      MYSQL_USER: typecho
      MYSQL_PASSWORD: typechoPASSWORD
    volumes:
      - ./mysql-data:/var/lib/mysql

  typecho:
    image: joyqi/typecho:nightly-php8.2-apache
    restart: always
    depends_on:
      - mysql
    ports:
      - &quot;8080:80&quot;
    environment:
      TIMEZONE: Asia/Shanghai
      TYPECHO_SITE_URL: https://your-domain.com
      TYPECHO_DB_HOST: mysql
      TYPECHO_DB_NAME: typecho
      TYPECHO_DB_USER: typecho
      TYPECHO_DB_PASS: typechoPASSWORD
    volumes:
      - ./typecho-data:/var/www/html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;https://your-domain.com&lt;/code&gt;替换为你的网址，提前反代好。&lt;/p&gt;
&lt;p&gt;（可选）重置后台管理员密码：删除站点目录的&lt;code&gt;config.inc.php&lt;/code&gt;文件，然后重新安装选择保留原有数据库即可&lt;/p&gt;
&lt;h4&gt;主题文件目录&lt;code&gt;usr/themes&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;安装git:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下载主题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone 主题Git仓库地址
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;复制到主题目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker cp 主题文件路径 typecho-server:/app/usr/themes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://hub.docker.com/r/joyqi/typecho&quot;&gt;仓库地址&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>frp内网穿透部署教程</title><link>https://emohe.cn/posts/5/</link><guid isPermaLink="true">https://emohe.cn/posts/5/</guid><pubDate>Sun, 05 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Docker部署frp内网穿透&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;可选项：&lt;code&gt;Docker CLI&lt;/code&gt;启动命令示例&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --restart=always --network host -d -v ./frps.toml:/etc/frp/frps.toml --name frps snowdreamtech/frps
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;docker-compose&lt;/code&gt;部署服务端（有公网IP）&lt;/h3&gt;
&lt;p&gt;创建配置文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;touch docker-compose.yml frps.toml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;docker-compose.yaml&lt;/code&gt;配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  frps:
    image: snowdreamtech/frps
    container_name: frps
    network_mode: host
    volumes:
      - ./frps.toml:/etc/frp/frps.toml
    restart: always
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务端&lt;code&gt;frps.toml&lt;/code&gt;配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bindPort = 7000
auth.token = &quot;admin123&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;code&gt;docker-compose&lt;/code&gt;部署客户端（内网）&lt;/h3&gt;
&lt;p&gt;创建配置文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;touch docker-compose.yml frpc.toml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;docker-compose.yaml&lt;/code&gt;配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  frpc:
    image: snowdreamtech/frpc
    container_name: frpc
    network_mode: host
    volumes:
      - ./frpc.toml:/etc/frp/frpc.toml
    restart: always
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;客户端&lt;code&gt;frpc.toml&lt;/code&gt;配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;serverAddr = &quot;8.8.8.8&quot;      # 公网服务器IP
serverPort = 7000           # 对接端口和frps一致
auth.token = &quot;admin123&quot;     # 认证令牌和frps一致

# 暴露SSH服务
[[proxies]]
name = &quot;ssh&quot;
type = &quot;tcp&quot;
localIP = &quot;127.0.0.1&quot;
localPort = 22            # 本地服务端口
remotePort = 6000         # 让frps暴露的公网端口
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;二进制文件部署&lt;/h3&gt;
&lt;p&gt;官方二进制文件下载地址：https://github.com/fatedier/frp/releases&lt;/p&gt;
&lt;p&gt;配置文件和上面一样&lt;/p&gt;
&lt;p&gt;服务端启动命令&lt;code&gt;./frps -c ./frps.toml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;客户端启动命令&lt;code&gt;./frpc -c ./frpc.toml&lt;/code&gt;&lt;/p&gt;
</content:encoded></item><item><title>DNS64和纯IPV6网络使用技巧</title><link>https://emohe.cn/posts/4/</link><guid isPermaLink="true">https://emohe.cn/posts/4/</guid><pubDate>Sat, 04 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;NAT64服务让纯V6网络支持访问纯V4站点&lt;/h2&gt;
&lt;p&gt;众所周知纯v6网络想要访问仅支持v4的网站是无法访问的，尤其是&lt;code&gt;github.com&lt;/code&gt;和&lt;code&gt;api.github.com&lt;/code&gt;居然不支持ipv6，所以很多人都选择使用&lt;code&gt;一键warp脚本&lt;/code&gt;，这个脚本很简单方便，但是对于我这种有洁癖的人有点难受，因为会装一堆东西，想卸载干净也很麻烦。所以我就找到了最简单的方法，当然&lt;code&gt;warp一键脚本&lt;/code&gt;还是很好用的，但是我图简单，就使用NAT64服务了，唯一的不足的是提供公共免费的NAT64很少，下面是我找到的可用的DNS。&lt;/p&gt;
&lt;h3&gt;原理如下：&lt;/h3&gt;
&lt;p&gt;NAT64的作用就是把IPv6网络的数据转换为IPv4网络的数据。它通过将IPv6请求中的地址转换成IPv4地址，使得IPv6设备可以通过NAT64网关访问只支持IPv4的服务器和网站。简单来说，NAT64在IPv6和IPv4之间充当了一个桥梁，负责地址和数据包的转换。&lt;/p&gt;
&lt;h3&gt;配置命令如下：&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo tee /etc/resolv.conf &amp;lt;&amp;lt;EOF
nameserver 2a00:1098:2b::1
nameserver 2a00:1098:2c::1
nameserver 2a01:4f9:c010:3f02::1
nameserver 2a01:4f8:c2c:123f::1
EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;测试能否访问仅支持ipv4的站点：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -I ipv4.google.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;温馨提示&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;以上DNS服务自于 https://nat64.net&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://nat64.xyz/&quot;&gt;更多DNS64服务&lt;/a&gt;来自互联网&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以上都是公益DNS64，超大流量使用有限制，个人使用是完全足够的，请勿滥用&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;永久生效的配置方法&lt;/h3&gt;
&lt;p&gt;1：编辑 &lt;code&gt;/etc/systemd/resolved.conf&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/systemd/resolved.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2：添加或修改以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Resolve]
DNS=2a00:1098:2b::1 2a00:1098:2c::1 2a01:4f9:c010:3f02::1 2a01:4f8:c2c:123f::1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3：重启 &lt;code&gt;systemd-resolved&lt;/code&gt; 服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart systemd-resolved
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>caddy教程：nginx难用？配置证书很麻烦？试试caddy吧</title><link>https://emohe.cn/posts/3/</link><guid isPermaLink="true">https://emohe.cn/posts/3/</guid><pubDate>Fri, 03 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;介绍&lt;/h3&gt;
&lt;p&gt;caddy是和nginx一样的强大的web服务，使用go语言编写并且也是完全开源，&lt;code&gt;优点是配置简单，并且自动申请并部署SSL证书&lt;/code&gt;，无需手动配置，大大简化了运维工作，对小白非常友好，唯一的缺点是并发量稍微不及nginx，但是这点缺点几乎可以忽略不记。除非你的网站流量高的离谱，对于一般的企业是达不到那种流量的，个人就更达不到的。&lt;/p&gt;
&lt;h3&gt;我的使用场景&lt;/h3&gt;
&lt;p&gt;除了一般的网页服务，我经常配合docker使用，由于我比较喜欢用docker，所以经常使用&lt;code&gt;caddy&lt;/code&gt; 或者 &lt;code&gt;nginx-proxy-manager&lt;/code&gt;来反代docker的端口，他俩使用都很简单，本文着重介绍caddy。&lt;/p&gt;
&lt;p&gt;1：安装caddy&lt;/p&gt;
&lt;p&gt;由于CentOS已经停止维护，本文只介绍当前主流的系统debian和ubuntu系统，使用apt包安装。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

curl -1sLf &apos;https://dl.cloudsmith.io/public/caddy/stable/gpg.key&apos; | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

curl -1sLf &apos;https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt&apos; | sudo tee /etc/apt/sources.list.d/caddy-stable.list

sudo apt update

sudo apt install caddy -yq
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2：配置示例&lt;/p&gt;
&lt;p&gt;配置路径 &lt;code&gt;/etc/caddy/Caddyfile&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;将域名&lt;code&gt;example.com&lt;/code&gt;反向代理到本地&lt;code&gt;8080&lt;/code&gt;端口&lt;/p&gt;
&lt;p&gt;&lt;code&gt;caddyfile&lt;/code&gt;配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com {
    encode gzip
    reverse_proxy localhost:8080
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将域名&lt;code&gt;example.com&lt;/code&gt;代理到网站目录&lt;code&gt;/var/www&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;caddyfile&lt;/code&gt;配置&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;example.com {
    root * /var/www
    encode zstd gzip
    file_server
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3：常用命令&lt;/p&gt;
&lt;p&gt;启动caddy&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart caddy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;caddy会占用80和443端口，api服务会占用本地2019端口，启动后会自动接管域名的证书管理，自动申请SSL证书和开启HTTPS加密。Caddy 默认使用 Let&apos;s Encrypt 作为证书颁发机构（CA）来自动签发 SSL/TLS 证书，Let&apos;s Encrypt申请证书有频率限制，如果你是测试使用，可以在caddy配置文件的域名指定为http格式，不开启HTTPS加密，例如caddy配置中域名可以这样写 http://example.com&lt;/p&gt;
&lt;p&gt;查看运行状态&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl status caddy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查配置语法是否正确&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;caddy validate --config /etc/caddy/Caddyfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;停止服务&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl stop caddy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完全卸载&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get purge --auto-remove caddy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;证书路径&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Docker部署flarum论坛</title><link>https://emohe.cn/posts/2/</link><guid isPermaLink="true">https://emohe.cn/posts/2/</guid><pubDate>Thu, 02 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;docker部署flarum论坛网站&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;创建项目文件&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p flarum &amp;amp;&amp;amp; cd flarum &amp;amp;&amp;amp; touch docker-compose.yaml flarum.env
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yaml&lt;/code&gt;配置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;services:
  flarum:
    image:  mondedie/flarum:latest
    container_name: flarum
    env_file:
      - ./flarum.env   # 站点配置文件
    volumes:
      - ./flarum/assets:/flarum/app/public/assets
      - ./flarum/extensions:/flarum/app/extensions

    ports:
      - 8888:8888
    restart: always
    depends_on:
      - mariadb

  mariadb:
    image: mariadb:10.5
    container_name: mariadb
    environment:
      - MYSQL_ROOT_PASSWORD=abc123456
      - MYSQL_DATABASE=flarum
      - MYSQL_USER=flarum
      - MYSQL_PASSWORD=abc123456
    volumes:
      - ./mysql:/var/lib/mysql  # 数据映射到本地
    restart: always
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;flarum.env&lt;/code&gt;配置&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;DEBUG=false
FORUM_URL=https://xxxxxxxxx.com     # 论坛域名

# 数据库信息
DB_HOST=mariadb
DB_NAME=flarum
DB_USER=flarum
DB_PASS=abc123456
DB_PREF=flarum_
DB_PORT=3306

# 站点环境变量
FLARUM_ADMIN_USER=admin                  # 管理员用户名
FLARUM_ADMIN_PASS=admin123456            # 管理员密码
FLARUM_ADMIN_MAIL=admin@admin.com        # 管理员邮箱
FLARUM_TITLE=Test flarum                 # 论坛标题
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;启动&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;docker compose up -d mariadb      # 必须先启动数据库，等待数据库初始化完成

docker compose up -d flarum       # 启动站点
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;扩展使用示例&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;查看所有插件
docker exec -ti flarum extension list

删除插件
docker exec -ti flarum extension remove 作者/插件名

安装插件
docker exec -ti flarum extension require 作者/插件名
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中文语言&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker exec -ti flarum extension require flarum-lang/chinese-simplified:dev-master
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;私信功能插件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker exec -ti flarum extension require neoncube/flarum-private-messages:&quot;*&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;HubUi-X主题&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker exec -ti flarum extension require kk14569/flarum-hubui-x
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;官网-&lt;a href=&quot;https://flarum.org/extensions?tableSortColumn=downloads&amp;amp;tableSortDirection=desc&quot;&gt;更多插件&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>第一篇博客</title><link>https://emohe.cn/posts/1/</link><guid isPermaLink="true">https://emohe.cn/posts/1/</guid><pubDate>Wed, 01 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;博客又搬家了&lt;/h3&gt;
&lt;p&gt;2025年，新的一年，新的开始。&lt;/p&gt;
&lt;p&gt;心血来潮，又开始折腾网站了，继之前的阿里云3M小水管部署的wordpress，感觉越来越卡，于是这次使用纯静态网站，网站托管在&lt;a href=&quot;https://vercel.com/&quot;&gt;vercel&lt;/a&gt;，使用的&lt;a href=&quot;https://github.com/saicaca/fuwari&quot;&gt;fuwari&lt;/a&gt;主题。之前的wordpress也没怎么发布文章，就直接复制粘贴过来了&lt;/p&gt;
&lt;p&gt;终于可以把服务器的钱省了，写作时就直接在Github上用MD语法写作，还是挺方便的，以后就在这里更新一些日常了，还有一些docker教程，因为我是docker的忠实粉，万物皆可docker，不管什么项目我都喜欢用docker部署，哈哈。&lt;/p&gt;
</content:encoded></item></channel></rss>