<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>技术 on Colinx Blog</title>
    
    
    
    <link>/categories/%E6%8A%80%E6%9C%AF/</link>
    <description>Recent content in 技术 on Colinx Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 04 Feb 2026 00:00:00 +0000</lastBuildDate>
    
	<atom:link href="/categories/%E6%8A%80%E6%9C%AF/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>OpenClaw 虽好，搭配沙箱才安心 - 使用 Lume 构建 mac 虚拟环境</title>
      <link>/posts/openclaw%E8%99%BD%E5%A5%BD-%E6%90%AD%E9%85%8D%E6%B2%99%E7%AE%B1%E6%89%8D%E5%AE%89%E5%BF%83-%E4%BD%BF%E7%94%A8lume%E6%9E%84%E5%BB%BAmac%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83/</link>
      <pubDate>Wed, 04 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>/posts/openclaw%E8%99%BD%E5%A5%BD-%E6%90%AD%E9%85%8D%E6%B2%99%E7%AE%B1%E6%89%8D%E5%AE%89%E5%BF%83-%E4%BD%BF%E7%94%A8lume%E6%9E%84%E5%BB%BAmac%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83/</guid>
      <description>
        
          
          
          
        
        
        

&lt;p&gt;&lt;img src=&#34;https://openclaw.ai/og-image.png&#34; alt=&#34;open-claw-img|700x368&#34; /&gt;&lt;/p&gt;

&lt;p&gt;近日 OpenClaw(原 Clawdbot, 曾用名 Moltbot) 爆火，独立自主操控电脑完成各种任务，一个挺 fancy 的 agent 应用。结合 moltbook 网站的新闻，在各种媒体的鼓吹下故事画风变得愈发科幻，巴不得明天就统治全人类。&lt;/p&gt;

&lt;p&gt;爆火没两天，就爆出不少安全新闻，要么是 agent 自作主张直接电脑删空，要么是大量小白用户把实例暴露在公网，别有用心的人可以直接通过 openclaw 的黑洞控制整个电脑。OpenClaw 这种应用最吸引人、最方便的地方在于 ta 可以成为「代理」, 去执行任何「你可以做」的事。你能做，ta 就能做。不过前提便是宽松的权限管理，超级多的权限。&lt;/p&gt;

&lt;p&gt;下面介绍一个 基于 lume 的 Mac OS 虚拟机方案，将其作为沙箱环境节点供 openclaw 调用。&lt;/p&gt;

&lt;h2 id=&#34;openclaw-gateway-安装&#34;&gt;OpenClaw Gateway 安装&lt;/h2&gt;

&lt;p&gt;由于 gateway 节点负责与各个 channel 即 bot 通信，最好有公网 ip, 这里我在 linux 云服务器上进行部署。&lt;/p&gt;

&lt;p&gt;官方默认给的安装命令很简单，&lt;code&gt;npm install -g openclaw&lt;/code&gt; 就可以了。但是为了安全起见我还是偏好使用 docker 容器。官方对 docker 容器的支持并不是很好，文档也有点混乱，实际测下来从代码库自行构建镜像比较好&lt;/p&gt;

&lt;p&gt;首先是克隆仓库。注意默认的 main 分支可能不是很稳定，最好切换到某个 tag 或者 github actions 全部通过的 commit 再构建。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# 示例: 切换到指定tag
git pull --rebase
git fetch --tags
git checkout v2026.1.29
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后准备构建。很多教程包括官方文档是让用户直接在克隆后的 git 仓库里，修改 compose 和 env 文件。但是这样的话后续不方便更新，因为工作区有修改，每次都要 stash 再 pull 还要解决冲突的问题，太麻烦了。建议的方式是在代码库上级目录创建 compose 和 env, 这样下次要更新的话，直接到 repo 里面 git pull 再重新构建镜像就可以了。&lt;/p&gt;

&lt;p&gt;目录结构如下：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;.
├── .env
├── docker-compose.yml
└── **openclaw-repo**
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;compose 文件设置好构建的目录即可。示例如下&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;services:
  openclaw-gateway:
    image: ${OPENCLAW_IMAGE:-openclaw:local}
    container_name: openclaw-gateway
    build: ./openclaw-repo
    environment:
      xxx:xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;准备好目录和 docker compose 之后，即可开始构建&lt;/p&gt;

&lt;p&gt;完整 docker compose&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;services:
  openclaw-gateway:
    image: ${OPENCLAW_IMAGE:-openclaw:local}
    container_name: openclaw-gateway
    build: ./openclaw-repo
    environment:
      HOME: /home/node
      TERM: xterm-256color
      OPENCLAW_GATEWAY_BIND: ${OPENCLAW_GATEWAY_BIND}
      OPENCLAW_GATEWAY_PORT: ${OPENCLAW_GATEWAY_PORT}
      XDG_CONFIG_HOME: ${XDG_CONFIG_HOME}
      PATH: /home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    volumes:
      - ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
      - ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
    ports:
      - &amp;quot;${OPENCLAW_GATEWAY_PORT}:${OPENCLAW_GATEWAY_PORT}&amp;quot;
      # - &amp;quot;${OPENCLAW_BRIDGE_PORT:-18790}:18790&amp;quot;
    init: true
    restart: unless-stopped
    command:
      [
        &amp;quot;node&amp;quot;,
        &amp;quot;dist/index.mjs&amp;quot;,
        &amp;quot;gateway&amp;quot;,
        &amp;quot;--bind&amp;quot;,
        &amp;quot;${OPENCLAW_GATEWAY_BIND:-lan}&amp;quot;,
        &amp;quot;--port&amp;quot;,
        &amp;quot;${OPENCLAW_GATEWAY_PORT}&amp;quot;,
      ]
     
  openclaw-cli:
    image: ${OPENCLAW_IMAGE:-openclaw:local}
    environment:
      HOME: /home/node
      TERM: xterm-256color
      BROWSER: echo
      OPENCLAW_GATEWAY_BIND: ${OPENCLAW_GATEWAY_BIND}
      OPENCLAW_GATEWAY_PORT: ${OPENCLAW_GATEWAY_PORT}
      XDG_CONFIG_HOME: ${XDG_CONFIG_HOME}
      PATH: /home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    volumes:
      - ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
      - ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
    stdin_open: true
    tty: true
    init: true
    entrypoint: [&amp;quot;node&amp;quot;, &amp;quot;dist/index.mjs&amp;quot;]
    restart: none


&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;env 示例&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-ini&#34;&gt;OPENCLAW_IMAGE=openclaw:latest
OPENCLAW_GATEWAY_TOKEN=change-me
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_GATEWAY_PORT=8089

OPENCLAW_CONFIG_DIR=/data/openclaw
OPENCLAW_WORKSPACE_DIR=/data/openclaw/workspace
XDG_CONFIG_HOME=/home/node/.openclaw
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;
# 镜像中的应用默认以uid 1000账户运行, 手动设置data数据目录的权限避免出现预期外的问题
sudo chown -R 1000:1000 /data/openclaw

# 构建镜像
sudo docker compose build

# 第一次使用, 初始化相关配置
docker compose run --rm openclaw-cli onboard

# 之后启动gateway
docker compose up -d openclaw-gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果使用 tg channel ,创建完 bot 后需要配对才可以使用。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;docker compose run --rm openclaw-cli pairing approve telegram &amp;lt;code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;日常配置可以直接使用这个 cli 镜像后面加上需要的参数。或者直接到 Gateway 镜像中执行 &lt;code&gt;node dist/index.mjs xxx&lt;/code&gt; 代替 官方文档里 &lt;code&gt;openclaw xxx&lt;/code&gt; . (官方 Dockerfile 里面对 cli 工具名字的处理有问题，先曲线救国)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;docker compose run --rm openclaw-cli xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;macos-vm-via-lume&#34;&gt;MacOS VM via Lume&lt;/h2&gt;

&lt;p&gt;接下来配置 mac os 的虚拟机。使用 lume 工具&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;brew install lume

brew services start lume
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后可以快捷安装 macos vm. 一般情况下，默认安装当前系统大版本下最新的小版本。你可以通过以下方式查询&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# 查询`latest`参数对应默认的系统镜像和版本, 可以看到显示的url指向的系统版本为15.6.1
~ » lume ipsw                                                                         
[2026-01-31T12:23:12Z] INFO: Fetching latest supported IPSW URL

[2026-01-31T12:23:13Z] INFO: Found latest IPSW URL url=https://updates.cdn-apple.com/2025SummerFCS/fullrestores/093-10809/CFD6DD38-DAF0-40DA-854F-31AAD1294C6F/UniversalMac_15.6.1_24G90_Restore.ipsw

https://updates.cdn-apple.com/2025SummerFCS/fullrestores/093-10809/CFD6DD38-DAF0-40DA-854F-31AAD1294C6F/UniversalMac_15.6.1_24G90_Restore.ipsw


# 查询当前系统版本为15.2
~ » sw_vers                                                                           
ProductName: macOS
ProductVersion: 15.2
BuildVersion: 24C101
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;也可以从这里获取指定版本的系统镜像下载地址，手动下载。&lt;a href=&#34;https://ipsw.me/&#34;&gt;https://ipsw.me/&lt;/a&gt;. 一般 mac os 的镜像大小在 15-20GB&lt;/p&gt;

&lt;p&gt;创建 vm&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# 默认安装最新的版本
lume create openclaw --os macos --ipsw latest

# 如果失败报错&amp;quot;Installation requires a software update.&amp;quot; 可以下载不高于当前系统运行的版本手动创建

lume create openclaw --os macos --cpu 2 --memory 8GB --disk-size 100GB --ipsw ./&amp;lt;YOUR-DOWNLOAD-IPSW-FILE&amp;gt;

# 启动vm
lume run openclaw

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后会输出一个 vnc 地址，可以用 mac 自带的「屏幕共享」app 进行查看。菜单「连接」- 「新建」
&lt;img src=&#34;https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/20260205000147405.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;完成系统安装的几个必要步骤，然后到设置里把远程控制打开，后面 SSH 要用到。系统更新建议关掉。&lt;/p&gt;

&lt;p&gt;![[image-23.png]]&lt;/p&gt;

&lt;p&gt;![[image-24.png]]&lt;/p&gt;

&lt;p&gt;在 mac vm 上安装 openclaw&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# 基础环境配置
## brew 安装 (加速版本, 使用中科大镜像源)

export HOMEBREW_BREW_GIT_REMOTE=&amp;quot;https://mirrors.ustc.edu.cn/brew.git&amp;quot;
export HOMEBREW_CORE_GIT_REMOTE=&amp;quot;https://mirrors.ustc.edu.cn/homebrew-core.git&amp;quot;
export HOMEBREW_BOTTLE_DOMAIN=&amp;quot;https://mirrors.ustc.edu.cn/homebrew-bottles&amp;quot;
export HOMEBREW_API_DOMAIN=&amp;quot;https://mirrors.ustc.edu.cn/homebrew-bottles/api&amp;quot;

/bin/bash -c &amp;quot;$(curl -fsSL https://mirrors.ustc.edu.cn/misc/brew-install.sh)&amp;quot;

## brew 镜像配置

echo &#39;export HOMEBREW_BOTTLE_DOMAIN=&amp;quot;https://mirrors.ustc.edu.cn/homebrew-bottles&amp;quot;&#39; &amp;gt;&amp;gt; ~/.zshrc
echo &#39;export HOMEBREW_API_DOMAIN=&amp;quot;https://mirrors.ustc.edu.cn/homebrew-bottles/api&amp;quot;&#39; &amp;gt;&amp;gt; ~/.zshrc
echo &#39;export HOMEBREW_CORE_GIT_REMOTE=&amp;quot;https://mirrors.ustc.edu.cn/homebrew-core.git&amp;quot;&#39; &amp;gt;&amp;gt; ~/.zshrc
echo &#39;export HOMEBREW_BREW_GIT_REMOTE=&amp;quot;https://mirrors.ustc.edu.cn/brew.git&amp;quot;&#39; &amp;gt;&amp;gt; ~/.zshrc
source ~/.zshrc

## 安装基础环境
brew install node
brew install pnpm
pnpm setup
source ~/.zshrc

echo &amp;quot;registry=https://npmreg.proxy.ustclug.org/&amp;quot; &amp;gt;&amp;gt; ~/.npmrc
pnpm install -g openclaw@latest
openclaw onboard --install-daemon
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;client 端配置好 gateway 地址和 token .第一次连接显示需要配对。在服务端执行&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;
openclaw devices list

openclaw devices apprve &amp;lt;复制的request id&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/20260205000019565.png&#34; alt=&#34;image-25&#34; /&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# 作为node注册

openclaw node install --host &amp;lt;gateway-host&amp;gt; --port 18789 --display-name &amp;quot;Mac mini&amp;quot;

# 然后在服务端approve

# 查看状态
openclaw node status
# 启动节点
openclaw node start
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后就可以让 openclaw 调用这个节点啦&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/20260204235959805.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;THE END&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>Search-as-a-RSS! 把任何搜索查询转换为 RSS! FeedCraft 新功能速递</title>
      <link>/posts/search-as-a-rss-%E6%8A%8A%E4%BB%BB%E4%BD%95%E6%90%9C%E7%B4%A2%E6%9F%A5%E8%AF%A2%E8%BD%AC%E6%8D%A2%E4%B8%BArss-feedcraft-%E6%96%B0%E5%8A%9F%E8%83%BD%E9%80%9F%E9%80%92/</link>
      <pubDate>Mon, 22 Dec 2025 00:00:00 +0000</pubDate>
      
      <guid>/posts/search-as-a-rss-%E6%8A%8A%E4%BB%BB%E4%BD%95%E6%90%9C%E7%B4%A2%E6%9F%A5%E8%AF%A2%E8%BD%AC%E6%8D%A2%E4%B8%BArss-feedcraft-%E6%96%B0%E5%8A%9F%E8%83%BD%E9%80%9F%E9%80%92/</guid>
      <description>
        
          
          
          
        
        
        

&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;

&lt;p&gt;作为 RSS 5 年忠实用户，我非常享受 RSS 主动管理信息源给我带来的掌控感。但是传统 RSS 订阅方式只能基于站点或者频道，更多时候我其实是想关注某一个特定领域信息，比如 AI 领域世界模型有什么新的新闻，或者是想订阅一个特定的信息，比如我关注的 xxx 歌手有没有新的巡演规划。&lt;/p&gt;

&lt;p&gt;这些需求通过传统 RSS 方式难以实现，你只能定向的订阅某个新闻站点，然后过滤一下关键词。使用方式局限性很大。其实最理想的方式是直接把搜索引擎的结果拿来作为信息源。问题主要是噪声太多：&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;/ul&gt;

&lt;p&gt;好在我们有了 AI, 很多问题有了新的解决方法。在 FeedCraft 新版本中，我新增了一个 Search-as-a-RSS 的功能，用户只需要使用自然语言指定好要搜索什么，接下来就可以自动根据搜索结果生成一个 RSS 了。&lt;/p&gt;

&lt;p&gt;接下来简要介绍一下流程：&lt;/p&gt;

&lt;h2 id=&#34;feedcraft-如何通过搜索结果创建-rss&#34;&gt;FeedCraft 如何通过搜索结果创建 RSS&lt;/h2&gt;

&lt;p&gt;FeedCraft 本身是一个一站式处理 RSS 的工具，这里的搜索需要依赖第三方服务。首发支持的搜索服务是 LiteLLM Proxy(一个 AI 服务的代理转发平台，开源可自部署，可以方便对接各种第三方搜索服务比如 Exa, Tavily, Plexirity, Perplexity, Brave 等等)&lt;/p&gt;

&lt;p&gt;以 Tavily 为例，这个平台提供了每月 1000credits 的额度，可以执行上百次搜索，轻度使用绰绰有余了。前往官网注册个账号，生成一个 api key 即可。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://www.tavily.com/&#34;&gt;Tavily&lt;/a&gt; 是一个专为人工智能代理（AI Agents）设计的搜索引擎，旨在优化 AI 在执行任务时的信息检索过程。它不同于传统的面向人类用户的搜索引擎（如 Google 或 Bing），而是专门为 AI 系统“理解”和“查找”所需信息而构建，强调高效、准确和上下文相关的搜索结果。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/202512220059928.png&#34; alt=&#34;image-14&#34; /&gt;&lt;/p&gt;

&lt;p&gt;接下来到 LiteLLM 的后台，Tool - Search Tool 里面增加一个 search tool. 这里 search tool name 可以自定义，先记下来待会在 feed craft 的设置页面需要填入。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/202512220059929.png&#34; alt=&#34;image-15&#34; /&gt;
在 LiteLLM 后台生成一个 API KEY, Key Name 可以随便写主要是备注。这个生成的 api key 可以用于请求 LLM, 也可以调用刚才配置的搜索工具。确认生成后，复制 api key.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/202512220059930.png&#34; alt=&#34;image-16&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在 FeedCraft 后台，设置里面配置搜索服务，这里 API URL 是你的 LiteLLM 服务加上&lt;code&gt;/search&lt;/code&gt; 后缀。
例如你的 LiteLLM 服务部署在 &lt;code&gt;https://my-litellm.example.com&lt;/code&gt;, 那么这里就填写 &lt;code&gt;https://my-litellm.example.com/search&lt;/code&gt; . 工具填写刚才在 LiteLLM 后台接入 Tavily 的时候填写的 search tool name&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/202512220059931.png&#34; alt=&#34;image-17&#34; /&gt;&lt;/p&gt;

&lt;p&gt;之后在「搜索转 RSS」页面，输入你想查询的东西即可。你可以直接用自然语言描述，比如「SpaceX 的最新新闻」. 之后点击下一步即可预览搜索结果。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/202512220059932.png&#34; alt=&#34;image-18&#34; /&gt;&lt;/p&gt;

&lt;p&gt;你可以按需调整搜索语句。确认没问题一直下一步，可以保存为自定义的配方 (Custom Recipe) , 就可以生成一个唯一的 RSS 链接，在你喜欢的任意 RSS 阅读器里面查看啦&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/202512220059934.png&#34; alt=&#34;image-19&#34; /&gt;&lt;/p&gt;

&lt;p&gt;更进一步，你可以使用 FeedCraft 的各种 Craft 来做进一步的处理。比如获取全文，添加总结、翻译文章、以及调用 AI 使用自然语言对文章进行筛选等等&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.cos.ap-shanghai.myqcloud.com/BlogImgs/202512220059935.png&#34; alt=&#34;image-21&#34; /&gt;&lt;/p&gt;

&lt;p&gt;总体功能就是这样啦，欢迎试用 FeedCraft 和 Star 🌟! Have fun!&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/Colin-XKL/FeedCraft&#34;&gt;https://github.com/Colin-XKL/FeedCraft&lt;/a&gt;&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>来谈谈日志集中管理方案 - syslog 是你的好伙伴</title>
      <link>/posts/%E6%9D%A5%E8%B0%88%E8%B0%88%E6%97%A5%E5%BF%97%E9%9B%86%E4%B8%AD%E7%AE%A1%E7%90%86%E6%96%B9%E6%A1%88-syslog%E6%98%AF%E4%BD%A0%E7%9A%84%E5%A5%BD%E4%BC%99%E4%BC%B4/</link>
      <pubDate>Sun, 13 Oct 2024 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E6%9D%A5%E8%B0%88%E8%B0%88%E6%97%A5%E5%BF%97%E9%9B%86%E4%B8%AD%E7%AE%A1%E7%90%86%E6%96%B9%E6%A1%88-syslog%E6%98%AF%E4%BD%A0%E7%9A%84%E5%A5%BD%E4%BC%99%E4%BC%B4/</guid>
      <description>
        
          
          
          
        
        
        

&lt;p&gt;身为一个数码宅，家里总是会有越来越多的数码设备，智能化的设备多起来，总是难免会遇到各种各样的问题，排查问题的时候日志就很重要了，对于一些偶发的 case, 比如偶发网络卡顿，能够看到足够完整清晰的日志，就很方便了。&lt;/p&gt;

&lt;p&gt;对于一些低功耗设备，比如路由器，其磁盘资源很紧张，日志通常不会保存很久。这个时候要排查一些偶发的持续时间长的小 bug 就很头痛了。好在 openwrt 原生就支持将日志通过 syslog 协议发送到远程服务器。不过看了一圈，发送是发送过去了，但是看日志还得命令行一个个看，要想有个方便的地方看的话就得上 ELK 那一套非常繁琐且吃资源的那一套，我的需求是这样的：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;免费，可以持续使用&lt;/li&gt;
&lt;li&gt;能够通过 syslog 协议收集日志&lt;/li&gt;
&lt;li&gt;能够自部署最佳，但是不希望是 ELK 那种繁琐且非常消耗资源的&lt;/li&gt;
&lt;li&gt;有个 web 界面能方便的查找日志&lt;/li&gt;
&lt;li&gt;能够配置监控，那样的话如果设备有 fatal 日志我可以立即知道&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;搜寻了一番，发现有个 datalust 公司出的 seq 看起来挺不错，在自己服务器上部署了一套，完美符合我的需求，分享一下。&lt;/p&gt;

&lt;p&gt;seq 不仅支持 syslog, 还支持程序主动上报、采集容器日志等很多功能，这里只主要围绕 syslog, 收集各种终端设备日志做介绍&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202410132128864.png&#34; alt=&#34;Pasted image 20241013170403&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202410132128865.png&#34; alt=&#34;Pasted image 20241013170340&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;安装-通过-docker-compose-部署-seq&#34;&gt;安装：通过 docker compose 部署 seq&lt;/h2&gt;

&lt;p&gt;首先生成下默认密码，这里需要通过程序自身的指令生成明文密码对应的密文才行。比如我这里指定初始密码的明文为&lt;code&gt;initP@ss&lt;/code&gt;, 运行这个指令，就会输出对应的密文，这个待会部署的时候需要使用&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;➜ echo &#39;initP@ss&#39; | sudo docker run --rm -i datalust/seq config hash


QE6k2bZLWkh7BwWYRNsG3h9sZPcLskSLKJGii4mvU0rsDyN0/UqW1TwEZp43O09wvOCjbOgswZxHX7FeNo05cfiv3KkB8/q/Msj8nlXL4TGd
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后通过 docker compose 进行部署，下面为 compose 文件示例&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;services:
  seq-input-syslog:
    image: datalust/seq-input-syslog:latest
    container_name: seq_syslog_input
    depends_on:
      - seq
    ports:
      - &amp;quot;20014:514/udp&amp;quot; # 接收 syslog 协议请求的端口，这里配置的是 20014, 可以自定义，后面需要用到
    environment:
      SEQ_ADDRESS: &amp;quot;http://seq:5341&amp;quot; # 要转发到主程序进行处理，端口为默认的 5341, 不用改
    restart: unless-stopped

  seq:
    image: datalust/seq:latest
    container_name: seq_log
    ports:
      - &amp;quot;20054:80&amp;quot; # web ui
    environment:
      ACCEPT_EULA: Y
      SEQ_FIRSTRUN_ADMINPASSWORDHASH: QE6k2bZLWkh7BwWYRNsG3h9sZPcLskSLKJGii4mvU0rsDyN0/UqW1TwEZp43O09wvOCjbOgswZxHX7FeNo05cfiv3KkB8/q/Msj8nlXL4TGd # 这里填写刚生成的密文
    restart: unless-stopped
    volumes:
      - /data/seq-data:/data
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后执行 sudo docker compose up -d , 顺利的话，在配置的 web ui 端口，就可以看到管理台了。默认账户为 admin, 密码为刚才设置的密码的原始明文。&lt;/p&gt;

&lt;h2 id=&#34;使用-syslog-配置&#34;&gt;使用：syslog 配置&lt;/h2&gt;

&lt;p&gt;基本上所有 Linux-base 系统都支持将系统日志通过 syslog 协议发送到远端服务器。我手头主要的 openwrt 路由器、运行 truenas 系统的 nas、树莓派上跑的 debian, 以及其他 linux 云服务器都可以无缝接入，这里简单介绍下&lt;/p&gt;

&lt;h3 id=&#34;openwrt-配置远程-log&#34;&gt;openwrt 配置远程 log&lt;/h3&gt;

&lt;p&gt;在 system -&amp;gt; system 菜单下，有个 logging 的 tab, 里面配置好服务器 ip、端口就可以使用了。协议记得选 udp&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202410132128867.png&#34; alt=&#34;Pasted image 20241013165852&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;truenas-配置远程-log&#34;&gt;truenas 配置远程 log&lt;/h3&gt;

&lt;p&gt;在 system setting -&amp;gt; advaned -&amp;gt; syslog 菜单下，配置远程服务器地址和端口，协议选择 udp, 保存就可以了&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202410132128868.png&#34; alt=&#34;Pasted image 20241013171725&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;linux-服务器配置远程-log&#34;&gt;linux 服务器配置远程 log&lt;/h3&gt;

&lt;p&gt;大多数 Linux 发行版已经预装了 rsyslog。可以通过以下命令检查是否已安装：
&lt;code&gt;rsyslogd -version&lt;/code&gt;
如果未安装，可以使用以下命令安装：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# Debian/Ubuntu:
sudo apt update
sudo apt install rsyslog

# CentOS/RHEL:
sudo yum install rsyslog
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;步骤 2：配置客户端的 rsyslog
编辑 rsyslog 配置文件：打开配置文件进行编辑，通常位于 &lt;code&gt;/etc/rsyslog.conf&lt;/code&gt; 或 &lt;code&gt;/etc/rsyslog.d/&lt;/code&gt; 目录下。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;sudo nano /etc/rsyslog.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;添加远程服务器配置：在文件末尾，添加以下行以指定远程服务器的 IP 地址和端口（默认是 UDP 514 或 TCP 514）：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-conf&#34;&gt;*.* @remote-server-ip:514    # 使用 UDP
*.* @@remote-server-ip:514   # 使用 TCP
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这里我们需要使用 udp 协议的。
将 remote-server-ip 替换为远程 Syslog 服务器的实际 IP 地址或者域名，保存并关闭文件。&lt;/p&gt;

&lt;p&gt;比如&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-conf&#34;&gt;*.* @syslog.myserver.com:20014
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;步骤 3：重启 rsyslog 服务
在进行更改后，重启 rsyslog 服务以应用新配置：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;sudo systemctl restart rsyslog
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;其他配置&#34;&gt;其他配置&lt;/h2&gt;

&lt;h3 id=&#34;配置日志定期清理&#34;&gt;配置日志定期清理&lt;/h3&gt;

&lt;p&gt;默认情况下，是没有配置日志清理规则的，时间一长服务器硬盘可能直接满了，所以这里一定不要忘记配置自动清理。在菜单里的 retention 可以配置过多少天删除&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202410132128869.png&#34; alt=&#34;Pasted image 20241013170659&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202410132128870.png&#34; alt=&#34;Pasted image 20241013170654&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;配置告警通知&#34;&gt;配置告警通知&lt;/h3&gt;

&lt;p&gt;各种通知渠道的支持是通过插件形式提供的，在 设置里可以自行安装。可以支持 email、http webhook, 钉钉机器人、telegram 机器人等多种渠道。&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.nuget.org/packages?q=Tags%3A%22seq-app%22&#34;&gt;插件市场链接&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

        
        </description>
    </item>
    
    <item>
      <title>安全不是特权 - 雷池 WAF 使用体验及部署安装教程</title>
      <link>/posts/%E5%AE%89%E5%85%A8%E4%B8%8D%E6%98%AF%E7%89%B9%E6%9D%83-%E9%9B%B7%E6%B1%A0waf%E4%BD%BF%E7%94%A8%E4%BD%93%E9%AA%8C%E5%8F%8A%E9%83%A8%E7%BD%B2%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/</link>
      <pubDate>Mon, 18 Dec 2023 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E5%AE%89%E5%85%A8%E4%B8%8D%E6%98%AF%E7%89%B9%E6%9D%83-%E9%9B%B7%E6%B1%A0waf%E4%BD%BF%E7%94%A8%E4%BD%93%E9%AA%8C%E5%8F%8A%E9%83%A8%E7%BD%B2%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B/</guid>
      <description>
        
          
          
          
        
        
        

&lt;p&gt;自从开始倒腾服务器，部署各种各样服务以来，网站安全一直是那个令我焦虑的一个话题。暴露了那么多服务在公网，总免不了有无聊的人或者别有用心的人在搞事。(当然也有可能不是人类 hhh) 之前也有几次被攻击的历史，比如阿里云控制台一堆 SSH 爆破攻击记录，还有 Wordpress 被攻陷，出现一堆奇怪的文章和评论。虽然损失不是很大，但是处理起来还是有点麻烦的。(被攻击之后学乖了，老老实实定期备份) 况且我在明敌在暗，我们总是处于被动的那个，时间一长，网站的风险和潜在的损失还是不小的，最好是可以有一些防火墙和策略能够拦截点大部分不友好的请求。&lt;/p&gt;

&lt;p&gt;很早以前就有调研过世面上的网站防火墙类产品，主要就几种类型：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;各大云厂商配套的 WAF, 不过收费都很贵&lt;/li&gt;
&lt;li&gt;Cloudflare 等 CDN 服务商提供的服务，不过必须要接入其 CDN 反代才能用。而且大陆地区联通性并不好&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/SpiderLabs/ModSecurity&#34;&gt;ModSecurity&lt;/a&gt; 等开源方案，开源免费可自托管，不过配置比较麻烦，而且没有好用的 web 页面&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;近期刚好关注到雷池 WAF 这个项目比较火，看了下是国内一个安全公司搞得，看 Github Repo 和官方文档像模像样的，虽然文档跟大多数中文项目一样，很多地方写的不够清晰，一些小细节没有跟最新的版本同步，但是&lt;strong&gt;总体而言，可用，不难用。值得一试&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202312182326408.png&#34; alt=&#34;Pasted image 20231218222249&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;使用体验&#34;&gt;使用体验&lt;/h2&gt;

&lt;p&gt;谈一谈我为什么选择使用雷池 WAF:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;免费，开源 (这点存疑，没有详细审计过所有 submoudule, 目前看起来只有部分开源，仓库里大部分都是文档啥的。不过有有安全厂商实名，应该不会做出来一些自毁招牌的操作)&lt;/li&gt;
&lt;li&gt;支持通过 &lt;code&gt;docker compose&lt;/code&gt; 自部署&lt;/li&gt;
&lt;li&gt;功能够用。基本反代站点配置，SSL, 多种规则的黑白名单，频率限制，人机验证，攻击历史看板&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;目前已经使用了有几个月了，来谈一谈一些个人感受&lt;/p&gt;

&lt;p&gt;优点：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;又要免费，又要能自部署，又要有方便使用的 web 页面，目前这个好像是唯一能选的&amp;hellip;&lt;/li&gt;
&lt;li&gt;支持 &lt;code&gt;docker compose&lt;/code&gt; 自部署，可以自行编排和自定义很多配置&lt;/li&gt;
&lt;li&gt;TOTP 认证，加分&lt;/li&gt;
&lt;li&gt;UI 简约清晰，加分&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;缺点：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;有一些小 bug, 挺影响使用体验的，比如我最开始用的那个版本，那时候还不知道这个只能 TOTP 验证，又找不到地方和文档设置初始账号密码，但是进首页直接跳到了仪表盘，又一直刷报错。这种情况没登录就不应该显示仪表盘界面的，非常误导人，我还以为是强制开了 HTTPS 但是我没有上传 SSL 证书导致的后端请求一直报错。&lt;/li&gt;
&lt;li&gt;开源了但是又没有完全开。人家企业做这个的本意是推销自家的收费套餐，这个没毛病。但是请不要挂羊头卖狗肉，影响不好。GitHub Repo 都是些文档内容，有个所谓的语义检测引擎倒是放了一点代码，但是这个代码量级太少了，像个玩具项目，不像是正儿八经投入使用的引擎的源码。看了下这个社区版本的文档之类的，从头到尾就没有提过怎么参与项目贡献代码，挂了个 GitHub 链接似乎只是诱导大家去 star, 这样好做宣传。合着这个所谓的社区版就只是部署了之后有个按钮，可以共享攻击记录的 ip?&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker compose&lt;/code&gt; 写的方式令人费解。竟然需要在&lt;code&gt;.env&lt;/code&gt; 文件中自定义一个内网网段，然后用 docker compose 的时候自动创建一个子网，每个容器根据子网的前缀指定了一个 ip, 然后其他容器连接都是在环境变量里写死&amp;hellip;.明明可以用 compose 文件里定义的 service name 或者 container name 作为 alias 使用内置的 dns 轻松实现的服务发现，为什么搞得如此麻烦？而且有没有考虑过，如果要更新，再执行 compose up 的时候，先前的子网 ip 是被占用的，每次还得先看一下当前用了哪些子网，然后找个没用的，这操作也是没谁了&amp;hellip; 你说人家懂吧，他还通过 env 文件自定义 compose 创建的子网前缀，说人家不懂吧，用 container name 做 alias 自动实现服务发现这么简单的方式竟然不用。可能有安全或者性能方面的考量？不过我个人使用还是全部删掉了写死子网前缀的配置，这个使用方法真实太离谱了&lt;/li&gt;
&lt;li&gt;目前只会记录疑似恶意的请求，正常请求不会记录，没法通过这个来看网站总访问情况了，有点可惜&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;安装部署流程&#34;&gt;安装部署流程&lt;/h2&gt;

&lt;p&gt;简单分享下我调优后的安装流程，不使用写死的子网前缀做服务发现。&lt;/p&gt;

&lt;h3 id=&#34;1-获取-compose-文件&#34;&gt;1. 获取 compose 文件&lt;/h3&gt;

&lt;p&gt;官方文档默认提供的不是通过 &lt;code&gt;docker compose&lt;/code&gt; 安装，而是他们的一个脚本。可能是为了照顾广大墙内被 CSDN &amp;ldquo;惯坏&amp;rdquo;的用户吧，脚本里除了基本的环境检测，主要是提供 docker 的便捷安装，但是怎么说呢&amp;hellip;本意是给墙内用户便捷安装，但是为什么安装的操作还是到 docker 官方安装脚本，有没有一种可能，大部分大陆的服务器访问这个站点都很慢甚至连不上呢？但凡这里切一下 docker ce 镜像源都没这么离谱&amp;hellip;&lt;/p&gt;

&lt;p&gt;回到正题，这里还是大家通过 &lt;code&gt;docker compose&lt;/code&gt; 安装。没安装 docker 的建议先去安装，有条件的可以直接按照官方文档来，&lt;a href=&#34;https://docs.docker.com/engine/install/ubuntu/&#34;&gt;安装文档链接&lt;/a&gt;. 也可以参考我之前写的 RSSMAN 部署文档中 Docker 安装的部分，有讲解在国内环境下提前更换镜像源以更快完成下载安装。&lt;a href=&#34;https://rss101.colinx.one/deploy/rssman-full-guide/#1-docker&#34;&gt;Docker 安装-RSSMAN 部署指南 - RSS101&lt;/a&gt;
&lt;a href=&#34;https://blog.colinx.one/posts/rssmanx%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/&#34;&gt;RSSMan 部署指南&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;之后获取官方最新的 compose 文件。文档里贴的链接是在离线安装的章节有个 compose 文件链接 &lt;a href=&#34;https://waf-ce.chaitin.cn/release/latest/compose.yaml&#34;&gt;https://waf-ce.chaitin.cn/release/latest/compose.yaml&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;当然也可以直接去 Github 找，在 release 文件夹下。&lt;a href=&#34;https://github.com/chaitin/SafeLine/blob/main/release/latest/compose.yaml&#34;&gt;https://github.com/chaitin/SafeLine/blob/main/release/latest/compose.yaml&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;之后需要按照文档指示，在 compose 文件同文件夹位置，创建一个&lt;code&gt;.env&lt;/code&gt;文件，并填写相关的变量。这里推荐使用我调整后的版本。后续如果官方对于整个架构有更新，以官方的为准，可以自行根据需要调整 compose 文件。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;services:
  safeline.manager:
    container_name: safeline-manager
    restart: always
    image: chaitin/safeline-mgt-api:${IMAGE_TAG:?image tag required}
    volumes:
      - ${SAFELINE_DIR?safeline dir required}/resources/management:/resources/management
      - ${SAFELINE_DIR}/resources/nginx:/resources/nginx
      - ${SAFELINE_DIR}/logs:/logs
      - /etc/localtime:/etc/localtime:ro
    ports:
      - ${MGT_PORT:-9443}:1443
    environment:
      - MANAGEMENT_RESOURCES_DIR=/resources/management
      - NGINX_RESOURCES_DIR=/resources/nginx
      - DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-db/safeline-ce
      - MARIO_URL=http://safeline-mario:3335
      - FVM_MANAGER_URL=safeline.fvm-manager:9004
      - MANAGEMENT_LOGS_DIR=/logs/management
    dns:
      - 119.29.29.29
      - 223.5.5.5
      - 8.8.8.8
    networks:
      - safeline
    cap_drop:
      - net_raw
  safeline.detector:
    container_name: safeline-detector
    restart: always
    image: chaitin/safeline-detector:${IMAGE_TAG}
    volumes:
      - ${SAFELINE_DIR}/resources/detector:/resources/detector
      - ${SAFELINE_DIR}/logs/detector:/logs/detector
      - /etc/localtime:/etc/localtime:ro
    environment:
      - LOG_DIR=/logs/detector
    networks:
      - safeline
    cap_drop:
      - net_raw
  safeline.mario:
    container_name: safeline-mario
    restart: always
    image: chaitin/safeline-mario:${IMAGE_TAG}
    volumes:
      - ${SAFELINE_DIR}/resources/mario:/resources/mario
      - ${SAFELINE_DIR}/logs/mario:/logs/mario
      - /etc/localtime:/etc/localtime:ro
    environment:
      - LOG_DIR=/logs/mario
      - GOGC=100
      - DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline.postgres/safeline-ce
    networks:
      - safeline
    cap_drop:
      - net_raw
  safeline.tengine:
    container_name: safeline-gateway
    restart: always
    image: chaitin/safeline-tengine:${IMAGE_TAG}
    volumes:
      - ${SAFELINE_DIR}/resources/nginx:/etc/nginx
      - ${SAFELINE_DIR}/resources/management:/resources/management
      - ${SAFELINE_DIR}/resources/detector:/resources/detector
      - ${SAFELINE_DIR}/logs/nginx:/var/log/nginx
      - /etc/localtime:/etc/localtime:ro
      # - ${SAFELINE_DIR}/resources/cache:/usr/local/nginx/cache
      - tengine-cache:/usr/local/nginx/cache
    environment:
      - MGT_API=https://safeline.manager:1443/api/publish/server
    ulimits:
      nofile: 131072
    networks:
      - safeline
    ports:
      - 80:80
      - 443:443
  safeline.fvm-manager:
    container_name: safeline-fvm-manager
    restart: always
    image: chaitin/safeline-fvm-manager:${IMAGE_TAG}
    environment:
      - FVM_LOGS_DIR=/logs/management
      - DETECTOR_URL=http://safeline-detector:8001
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ${SAFELINE_DIR}/logs:/logs
    networks:
      - safeline
    cap_drop:
      - net_raw

  safeline.postgres:
    container_name: safeline-db
    restart: always
    image: postgres:15-alpine
    volumes:
      - ${SAFELINE_DIR}/resources/postgres/data:/var/lib/postgresql/data
      - /etc/localtime:/etc/localtime:ro
    environment:
      - POSTGRES_USER=safeline-ce
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?postgres password required}
    networks:
      - safeline
    cap_drop:
      - net_raw
    command: [postgres, -c, max_connections=200]

volumes:
  tengine-cache:

networks:
  safeline:
    name: safeline
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: safeline
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;2-安装部署&#34;&gt;2. 安装部署&lt;/h3&gt;

&lt;p&gt;部署成功后，第一次使用理论上会跳转到 TOTP 绑定页面。我之前这里卡到 bug, 第一次访问不是首页，没有看到那个绑定 TOTP 的二维码，后面就一直没法跳转到绑定页面了&amp;hellip;.不知道后面这个 bug 修复了没有，如果大家也遇到这个问题可以考虑全部清理干净，重新安装。&lt;/p&gt;

&lt;p&gt;TOTP 软件推荐和对比：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft Authenticator( 微软出品，支持云同步，国内可用，微软账户验证有单独的通道和验证方式，速度和体积一般)&lt;/li&gt;
&lt;li&gt;Google Authenticator (谷歌出品，简约好用，体积小速度快，可惜大陆地区没法云同步)&lt;/li&gt;
&lt;li&gt;BitWarden (支持使用自建实例，可惜 app 略卡)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;

&lt;p&gt;雷池 WAF 目前来看是一款够用，不难用的免费 WAF, 建议一试。&lt;/p&gt;

&lt;p&gt;此外重要数据还是要经常备份，多副本 + 多地存储，数据无价！&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>关于双语字幕这件小事</title>
      <link>/posts/%E5%85%B3%E4%BA%8E%E5%8F%8C%E8%AF%AD%E5%AD%97%E5%B9%95%E8%BF%99%E4%BB%B6%E5%B0%8F%E4%BA%8B/</link>
      <pubDate>Sun, 10 Sep 2023 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E5%85%B3%E4%BA%8E%E5%8F%8C%E8%AF%AD%E5%AD%97%E5%B9%95%E8%BF%99%E4%BB%B6%E5%B0%8F%E4%BA%8B/</guid>
      <description>
        
          
          
          
        
        
        

&lt;p&gt;今天这篇文章来探讨下双语字幕这件小事。&lt;/p&gt;

&lt;p&gt;首先对于一部外语影片或剧集，原生的英文字幕肯定是能够轻松获得的，但是匹配、高质量的翻译字幕缺并不总是能找到。这里分享一些我在寻找和手动 DIY 双语字幕的一些经验和想法，我自己也编写了一些工具，有同样需求的朋友也可以快速上手:D&lt;/p&gt;

&lt;h2 id=&#34;1-考虑寻找现成的高质量字幕&#34;&gt;1. 考虑寻找现成的高质量字幕&lt;/h2&gt;

&lt;p&gt;很多大火的剧集都会有字幕组第一时间跟进字幕制作和资源的发布，我们可以在各种 BT, PT 站点找到这些字幕组打包好的自带字幕的资源，或者也可以在第三方的字幕站点上寻找合适的字幕。&lt;/p&gt;

&lt;p&gt;这里安利一个油猴脚本：&lt;a href=&#34;https://greasyfork.org/zh-CN/scripts/329484-%E8%B1%86%E7%93%A3%E8%B5%84%E6%BA%90%E4%B8%8B%E8%BD%BD%E5%A4%A7%E5%B8%88-1%E7%A7%92%E6%90%9E%E5%AE%9A%E8%B1%86%E7%93%A3%E7%94%B5%E5%BD%B1-%E9%9F%B3%E4%B9%90-%E5%9B%BE%E4%B9%A6%E4%B8%8B%E8%BD%BD&#34;&gt;豆瓣资源下载大师&lt;/a&gt;，可以在豆瓣的影视详情页右侧显示有资源的站点，非常方便&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202309102054802.png&#34; alt=&#34;Pasted image 20230910152405&#34; /&gt;
效果如下图所示&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202309102054800.png&#34; alt=&#34;image-20220509144533549&#34; /&gt;&lt;/p&gt;

&lt;p&gt;中文字幕推荐 &lt;a href=&#34;http://zimuku.org/&#34;&gt;字幕库&lt;/a&gt;, 大部分字幕都可以在这里找到。其他语言可以到 &lt;a href=&#34;https://www.opensubtitles.org/zh&#34;&gt;OpentSubtitles&lt;/a&gt; 碰碰运气，虽然界面有点古朴，但是人家资源还是很丰富滴&lt;/p&gt;

&lt;h2 id=&#34;2-字幕的时间轴修正&#34;&gt;2. 字幕的时间轴修正&lt;/h2&gt;

&lt;p&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;/ul&gt;

&lt;p&gt;最后一种差异的地方太多，建议重新找字幕。对于前面两种情况，文本的部分没有太多差异，只需要调整字幕的时间轴就可以了。&lt;/p&gt;

&lt;p&gt;这里需要一些对齐时间轴的工具，这个市面上已经有很多了，大部分都是基于将对白音频持续时间和字幕对白持续时间做匹配，然后进行字幕整体时间轴的缩放或平移来实现对齐的。&lt;/p&gt;

&lt;p&gt;比如 &lt;a href=&#34;https://github.com/tp7/Sushi&#34;&gt;Sushi&lt;/a&gt;, 以及&lt;a href=&#34;https://github.com/smacke/ffsubsync&#34;&gt;ffsubsync&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;还有一类是最近比较火的，利用 AI 来对语音进行识别，输出对应的字幕。一半都是通过 Whisper 这个开源的语音识别模型来实现的，比如&lt;a href=&#34;https://github.com/oseiskar/autosubsync&#34;&gt;autosubsync&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;这类语音识别的 AI 目前已经很成熟了，市面上有很多商业应用，比如办公软件 飞书，腾讯会议一般都会支持会议语音转文字。但是这种都是为会议场景准备的。其实国内网易有道在这块做的更早，对英文支持更好，&lt;a href=&#34;https://jianwai.youdao.com/&#34;&gt;网易见外&lt;/a&gt;可以直接对音频进行识别，并生成 srt 文件，甚至还可以直接加上翻译，效率直接拉满。免费额度基本够用，各位轻度使用的朋友不要错过。&lt;/p&gt;

&lt;p&gt;当然，这类 AI 语音识别和翻译现阶段还是差了点意思，在各种影视作品中，各类人名，专有名词，还有各种各样的梗 (比如 The Simpsons ), AI 处理起来还是有点够呛，所以最好还是优先选择人工调教后的字幕比较好。&lt;/p&gt;

&lt;p&gt;上面罗列的那些对齐工具只能处理字幕和影片都是原生语言的情况，比如处理英文电影的英文字幕，但是对于要对时间轴不匹配的中英文双语字幕就基本没辙了。找遍了全网都没找到合适的工具，所以我就自己写了一个 &lt;a href=&#34;https://github.com/Colin-XKL/srt-fuzzy-sync&#34;&gt;srt-fuzzy-sync&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;fuzzy-sync 是一个简单的同步 srt 字幕的工具，通过指定一个与音轨匹配的参考字幕文件，来将另一个未同步的字幕进行匹配，时间轴修正，使得其可以与音轨正确对齐。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;简单点来说呢，这是一个专门用来对双语字幕时间轴进行修正的工具。你手头有一个英文电影资源，一个正确对齐的英文字幕，一个没对齐的双语字幕，这个时候你就可以用 srt-fuzzy-sync 这个工具，将英文字幕设定为参考，然后对双语字幕的时间轴进行修正，就可以得到一个时间轴正确的双语字幕啦！&lt;/p&gt;

&lt;p&gt;为什么叫 fuzzy-sync 呢，这主要是为了通用性，只对两个字幕之间高度相同的一些关键对白进行匹配，其他的对白则只是基于匹配结果进行整体偏移，这样做的好处是即便你找的这两个字幕的对白数量不一样，仍然可以完成同步。&lt;/p&gt;

&lt;p&gt;一般英文的 SDH 无障碍字幕里都会有很多非对白场景下的文字提示，比如&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(Theme Music Playing)&lt;/p&gt;

&lt;p&gt;(sigh)&lt;/p&gt;

&lt;p&gt;(Bird Singing)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;而影片对应中文字幕里一般都不会加上这些翻译。此外中文字幕还常常对影片中出现的标题、店铺招牌、标语、新闻标题做翻译说明，种种因素导致中英文字幕在句子的数量上不是严格对等的。&lt;/p&gt;

&lt;p&gt;此外这些字幕出现的时间，通常是没有对应的对白音频的。上面基于音频匹配的都无法很好地处理这类情况，所以我才抛弃按句匹配的方法，改为按一些句子很长，具有标志性，在影片中通常只会出现一次的关键语句匹配。&lt;/p&gt;

&lt;p&gt;至于找不到的现成双语字幕的，那就需要我们自己动手制作啦。&lt;/p&gt;

&lt;h2 id=&#34;3-自制双语字幕&#34;&gt;3. 自制双语字幕&lt;/h2&gt;

&lt;p&gt;有时只能找到现成的中文字幕和原版英文字幕，但是没有双语的版本，这个时候就需要我们手动合并了。&lt;/p&gt;

&lt;p&gt;这里推荐一个工具网站 &lt;a href=&#34;https://subtitletools.com/merge-subtitles-online&#34;&gt;Subtitle Tools&lt;/a&gt;, 里面有各种简单的字幕工具，比如字幕合并，字幕格式转换。&lt;/p&gt;

&lt;p&gt;对于手上又对齐的英文字幕和对齐的英文字幕，但是数量很多不想一个个到网站上去合并的，可以考虑 srt-merge 这个工具。不过原作者很久没更新了，我这里也编写了一个工具，也可以实现一样的功能。&lt;a href=&#34;https://github.com/Colin-XKL/dual-lang-sub-tool/tree/main&#34;&gt;dual-lang-sub-tool&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;此外还有一种常见的情况，就是我们下载的 WebRip 版本资源，影片已经内置了多国语言分别的字幕，这些资源大部分是来源于 Netfilx, Disney Plus , iTunes 这些，我们可以直接提取影片资源内置的两种语言的字幕然后将它们合并。&lt;/p&gt;

&lt;p&gt;内置字幕的提取可以使用 ffmpeg 工具，首先用 ffmpeg -i 文件路径 来查看基本信息，确定好字幕所在的 track, 比如 Stream #0:3(chi) Subtitle, 这种就是说明 3 号 stream 是中文字幕。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;# example output # ......
Stream #0:1(jpn): Audio: aac (LC), 48000 Hz, stereo, fltp (default)
Metadata: title : 日语

Stream #0:2(chi): Audio: aac (LC), 48000 Hz, stereo, fltp
Metadata: title : 国语

Stream #0:3(chi): Subtitle: ass (default)
Metadata: title : gb

Stream #0:4(chi): Subtitle: ass
Metadata: title : big5
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以用下面的命令将其提取出来并转换成 srt 格式&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;ffmpeg -i xxx.mkv -map 0:3 -c:s srt output.srt
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;提取完成后就可以直接合并得到成品的双语字幕了，但是你应该也会觉得这样提取太麻烦，尤其是一部剧几十集的情况。一般同一个资源，里面各个音轨和字幕的排布是一样的，比如上面只取了一集进行查看，其他集数都是一样的，中文字幕都是在 stream 0:3, shell 循环一下就可以了。&lt;/p&gt;

&lt;p&gt;当然你可能觉得这还是太麻烦了，我也是这么想的，所以 dual-lang-srt-tool 工具也支持自动检测，导出，合并双语字幕啦:D DIY 双语字幕可以很简单&lt;/p&gt;

&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;

&lt;p&gt;对于一些专有名词太多，AI 翻译质量欠佳，又没有现成中文字幕可供参考的，那目前就没有很好的办法了。通常我遇到这种情况是用 AI 的版本将就下，或者直接全英文一把梭。不过随着 AI 技术的发展，后面或许可以考虑将过往季的字幕喂给 AI 让 ta 自己学习人名地名翻译，再辅以各种新闻八卦材料让 AI 也能对各种潮流热梗烂熟于心，到那个时候制作双语字幕就是分分种的事情了，可以预见的是这样的 AI 应该有生之年就可以用上，至于是好事还是坏事，那就交给未来去评判吧。&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>个人向 Linux 新服务器初始化清单</title>
      <link>/posts/%E4%B8%AA%E4%BA%BA%E5%90%91linux%E6%96%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B8%85%E5%8D%95/</link>
      <pubDate>Tue, 14 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E4%B8%AA%E4%BA%BA%E5%90%91linux%E6%96%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B8%85%E5%8D%95/</guid>
      <description>
        
          
          
          
        
        
        

&lt;p&gt;一份 Linux 初始化清单，避免每次拿到新的服务器都要一个个去各种地方搜集指令，以做备忘 &amp;amp; 供有需要的朋友参考。&lt;/p&gt;

&lt;p&gt;服务器发行版我个人推荐 Debian 系列，CentOS 系现在已经开始分裂而且说实话对新手其实并不友好。Debian 是在兼容性，易用性和稳定性之间都取得不错平衡的发行版。新手推荐 Ubuntu, 不过最近商业化有点过度，夹带了越来越多的私活，我个人所有新安装的 Linux 已经全线转向 Debian. 下文以目前最新的 Debian 11 Bullseye 为例。Debian 12 bookworm 也测试通过。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;azure 干净的 debian 11 镜像，资源使用情况供参考：&lt;/p&gt;

&lt;p&gt;~1G Disk, ~100M RAM, ~300 packages&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;本文仅列举主要事项和操作，新手可先行阅读这篇文章熟悉概念。&lt;a href=&#34;https://blog.colinx.one/posts/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/&#34;&gt;云服务器入门指南&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;正文开始&lt;/p&gt;

&lt;h2 id=&#34;1-基础环境搭建&#34;&gt;1 - 基础环境搭建&lt;/h2&gt;

&lt;h3 id=&#34;1-1-防火墙&#34;&gt;1.1 防火墙&lt;/h3&gt;

&lt;p&gt;检查服务商防火墙和系统自带防火墙 (debian 系一般为 &lt;code&gt;ufw&lt;/code&gt;, cent os 系一般为 &lt;code&gt;firewall-cmd&lt;/code&gt;).放行 SSH(22), 新的 SSH(自定义), HTTP, HTTPS, 以及其他常用开发端口&lt;/p&gt;

&lt;h3 id=&#34;1-2-新建用户与检查-sudoer&#34;&gt;1.2 新建用户与检查 sudoer&lt;/h3&gt;

&lt;p&gt;登录到 root 用户，创建个人账户并设定密码&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;// -m 创建对应home文件夹
// 添加到 sudo 用户组自动获得sudo权限, 部分发行版为wheel组

useradd -m --groups sudo colin

// 设定密码
passwd colin
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;也可直接编辑&lt;code&gt;/etc/sudoers&lt;/code&gt; 文件为新用户添加 sudo 权限，使用 &lt;code&gt;visudo&lt;/code&gt; 指令可以自动帮你校验，避免配置写错把系统搞崩&lt;/p&gt;

&lt;h3 id=&#34;1-3-镜像源与基础软件&#34;&gt;1.3 镜像源与基础软件&lt;/h3&gt;

&lt;p&gt;如为境内服务器需要更换镜像源&lt;/p&gt;

&lt;h4 id=&#34;更换国内镜像源&#34;&gt;更换国内镜像源&lt;/h4&gt;

&lt;p&gt;一般情况下，将  &lt;code&gt;/etc/apt/sources.list&lt;/code&gt;  文件中 Debian 默认的源地址  &lt;code&gt;http://deb.debian.org/&lt;/code&gt;  替换为  &lt;code&gt;http://mirrors.ustc.edu.cn&lt;/code&gt;  即可。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;//for debian
sudo sed -i &#39;s/deb.debian.org/mirrors.ustc.edu.cn/g&#39; /etc/apt/sources.list

//for ubuntu
sudo sed -i &#39;s@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g&#39; /etc/apt/sources.list
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;CentOS 系建议启用 EPEL, PowerTools 等 repo 以更方便地安装常用软件和工具。此处不再赘述&lt;/p&gt;

&lt;p&gt;推荐的几个国内镜像站：&lt;a href=&#34;https://mirrors.tuna.tsinghua.edu.cn/&#34;&gt;清华大学 TUNA 镜像站&lt;/a&gt;, &lt;a href=&#34;https://mirrors.ustc.edu.cn/&#34;&gt;中科大 USTC LUG 镜像站&lt;/a&gt;, &lt;a href=&#34;https://mirrors.cloud.tencent.com/&#34;&gt;腾讯镜像站&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&#34;基础软件&#34;&gt;基础软件&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo apt update
sudo apt install wget curl git nano
sudo apt install zsh tmux htop duf htop tldr screenfetch tree
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;1-4-ssh-安全&#34;&gt;1.4 SSH 安全&lt;/h3&gt;

&lt;p&gt;修改端口，配置文件&lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;. 重启机器或 sshd 服务后生效。
此外最好将&lt;code&gt;PermitRootLogin&lt;/code&gt;修改为&lt;code&gt;no&lt;/code&gt;, 可以禁用 root 登录。&lt;/p&gt;

&lt;p&gt;在本机检查&lt;code&gt;~/.ssh/&lt;/code&gt;有无 id_rsa 等已生成的 key. 如没有再使用 &lt;code&gt;ssh-keygen&lt;/code&gt; 生成私钥
将本机的公钥上传到远端，再写入远端的 &lt;code&gt;authorized_keys&lt;/code&gt; 中&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cat ~/id_rsa.pub &amp;gt;&amp;gt; ~/.ssh/authorized_keys&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;注意修改权限，&lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; 权限为 600. &lt;code&gt;~/.ssh/&lt;/code&gt;为 700&lt;/p&gt;

&lt;p&gt;可以参考以下设置
&amp;gt; .ssh/    0700/rwx&amp;mdash;&amp;mdash;&lt;br /&gt;
&amp;gt; .ssh/&lt;em&gt;.pub   644/rw-r&amp;ndash;r&amp;ndash;&lt;br /&gt;
&amp;gt; .ssh/&lt;/em&gt;   0600/rw&amp;mdash;&amp;mdash;-&lt;/p&gt;

&lt;p&gt;如失败可参考这篇文章 debug. &lt;a href=&#34;https://superuser.com/questions/1137438/ssh-key-authentication-fails&#34;&gt;https://superuser.com/questions/1137438/ssh-key-authentication-fails&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;1-5-设置-hostname&#34;&gt;1.5 设置 hostname&lt;/h3&gt;

&lt;p&gt;可选，为了便于识别和后续配置 oh-my-zsh 更美观。这里修改完后还需要更新 hosts 设置，把刚才设置的新的主机名指向 localhost&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo hostnamectl set-hostname my-new-server
sudo hostnamectl status
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;此外&lt;code&gt;/etc/hosts&lt;/code&gt; 中默认会有个本机 hostname 映射到&lt;code&gt;127.0.0.1&lt;/code&gt; 的配置，修改 host 之后这里别名的映射也要修改下，不然终端执行命令会一直弹 &lt;code&gt;sudo: unable to resolve host xxx: Name or service not known&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;修改后需重启&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&#34;1-6-swap&#34;&gt;1.6 SWAP&lt;/h3&gt;

&lt;p&gt;可选，建议内存&amp;lt;2G 配置 swap, 大小至少为 2 倍物理内存，可以有效避免意外爆内存的情况。仅推荐 SSD 盘的服务器开启。&lt;/p&gt;

&lt;p&gt;推荐用 &lt;code&gt;fallocate&lt;/code&gt; , 因为这个是最简单、最快速的创建交换空间的方法。 &lt;code&gt;fallocate&lt;/code&gt;  命令用于为文件预分配块 / 大小。&lt;/p&gt;

&lt;p&gt;使用  &lt;code&gt;fallocate&lt;/code&gt;  创建交换空间，首先在  &lt;code&gt;/&lt;/code&gt;  目录下创建一个名为  &lt;code&gt;swap_space&lt;/code&gt;  的文件。然后分配 2GB 到  &lt;code&gt;swap_space&lt;/code&gt;  文件：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo fallocate -l 2G /swap_space
ls -lh /swap_space

// 然后更改文件权限，让 `/swap_space` 更安全：
sudo chmod 600 /swap_space

// 创建交换空间
sudo mkswap /swap_space

// 启用
sudo swapon /swap_space

// 使用 s 参数查看列表
sudo swapon -s

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;每次重启后都要重新挂载磁盘分区。因此为了使之持久化，就像上面一样，我们编辑  &lt;code&gt;/etc/fstab&lt;/code&gt;  并输入下面行：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/swap_space swap  swap  sw  0  0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;保存并退出文件。现在我们的交换分区会一直被挂载了。我们重启后可以在终端运行  &lt;code&gt;free -m&lt;/code&gt;  来检查交换分区是否生效。&lt;/p&gt;

&lt;p&gt;还可以按需选择使用 zram，提升内存可用量，不过会略微增加 cpu 使用和内存延时。可以搜索 zramctl, zramswap 等关键字&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&#34;1-7-绑定域名&#34;&gt;1.7 绑定域名  &lt;/h3&gt;

&lt;p&gt;可选，绑定一个域名或者改下本地 host 便于后续访问&lt;/p&gt;

&lt;h3 id=&#34;1-8-添加本地-ssh-别名&#34;&gt;1.8 添加本地 SSH 别名&lt;/h3&gt;

&lt;p&gt;配置文件为本机的 &lt;code&gt;~/.ssh/config&lt;/code&gt;
格式如下&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-config&#34;&gt;Host serverA
	HostName myserver.domain.xyz
	User colinx
	Port 2333
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;2-常用工具与配置&#34;&gt;2 - 常用工具与配置&lt;/h2&gt;

&lt;h3 id=&#34;2-1-docker-环境&#34;&gt;2.1 Docker 环境&lt;/h3&gt;

&lt;h4 id=&#34;docker-安装&#34;&gt;Docker 安装&lt;/h4&gt;

&lt;p&gt;可参考官网文档，注意是 docker engine 的安装。&lt;a href=&#34;https://docs.docker.com/engine/install/debian/&#34;&gt;Docker 官方安装文档&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;或者我之前写的 RSS MAN 部署文档中 docker 安装的部分
&lt;a href=&#34;https://blog.colinx.one/posts/rssmanx%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/#1-docker%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87&#34;&gt;RSS MAN X 安装部署指南/#1-docker 环境准备&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&#34;docker-镜像源配置及日志配置&#34;&gt;Docker 镜像源配置及日志配置&lt;/h4&gt;

&lt;p&gt;docker mirror 配置可以加速 image pull, 国内公开可用的加速站点可以参考这里 &lt;a href=&#34;https://gist.github.com/y0ngb1n/7e8f16af3242c7815e7ca2f0833d3ea6&#34;&gt;docker 加速站点&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;此外服务器上的 docker 都是长时间持续运行的，不少容器日志打的很随意，log 文件容易占据过多空间，也最好限制一下。&lt;/p&gt;

&lt;p&gt;文件位置&lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;, 下面的配置供参考&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
    &amp;quot;registry-mirrors&amp;quot;: [
        &amp;quot;https://docker.nastool.de&amp;quot;,
        &amp;quot;https://docker.actima.top&amp;quot;,
        &amp;quot;https://docker.unsee.tech&amp;quot;,
        &amp;quot;https://docker.gh-proxy.com&amp;quot;,
        &amp;quot;https://docker.zhai.cm&amp;quot;,
        &amp;quot;https://docker.1panel.live&amp;quot;,
        &amp;quot;https://docker.1ms.run&amp;quot;,
        &amp;quot;https://docker.imgdb.de&amp;quot;,
        &amp;quot;https://dockerproxy.net&amp;quot;
    ],
    &amp;quot;log-opts&amp;quot;: {
        &amp;quot;max-file&amp;quot;: &amp;quot;5&amp;quot;,
        &amp;quot;max-size&amp;quot;: &amp;quot;1m&amp;quot;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;修改完保存重启 docker 服务即可生效。可使用 &lt;code&gt;docker info&lt;/code&gt; 命令检查是否生效&lt;/p&gt;

&lt;h3 id=&#34;2-2-oh-my-zsh&#34;&gt;2.2 OH-MY-ZSH&lt;/h3&gt;

&lt;p&gt;安装 OH-MY-ZSH, 在此之前确保已安装 &lt;code&gt;git&lt;/code&gt; 和 &lt;code&gt;zsh&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sh -c &amp;quot;$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)&amp;quot;
# 如果在墙内 github 速度不加可以考虑使用清华的镜像
# https://mirrors.tuna.tsinghua.edu.cn/help/ohmyzsh.git/
# 先下载到任意位置，然后指定REMOTE 参数执行安装程序
git clone https://mirrors.tuna.tsinghua.edu.cn/git/ohmyzsh.git --depth=1
cd ohmyzsh/tools
REMOTE=https://mirrors.tuna.tsinghua.edu.cn/git/ohmyzsh.git sh install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;安装插件&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;git clone https://github.com/zsh-users/zsh-autosuggestions $ZSH_CUSTOM/plugins/zsh-autosuggestions --depth=1 

git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting --depth=1 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;git clone 速度不佳可以考虑一些开放的加速服务，比如：
- &lt;a href=&#34;https://ghproxy.org/&#34;&gt;https://ghproxy.org/&lt;/a&gt;
- &lt;a href=&#34;https://mirror.ghproxy.com/&#34;&gt;https://mirror.ghproxy.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;按需修改配置。文件位置&lt;code&gt;~/.zshrc&lt;/code&gt;, 下面为个人常用配置供参考。注意去源文件修改对应项，没有再到末尾加&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;# custom conf override
ZSH_THEME=&amp;quot;af-magic&amp;quot;
CASE_SENSITIVE=&amp;quot;false&amp;quot;
HYPHEN_INSENSITIVE=&amp;quot;false&amp;quot;
plugins=(git z zsh-autosuggestions zsh-syntax-highlighting sudo)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;自定义配置，添加到末尾&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;export ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;保存并应用&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;source ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;2-3-nano-代码文件规则&#34;&gt;2.3 nano 代码文件规则&lt;/h3&gt;

&lt;p&gt;日常常用文本编辑器为 nano, 轻量级编辑需求完全满足。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;curl https://cdn.jsdelivr.net/gh/scopatz/nanorc/install.sh | sh 
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;2-4-时区调整&#34;&gt;2.4 时区调整&lt;/h3&gt;

&lt;p&gt;一般安装完都是 UTC+0, 看日志什么的不方便。服务器初始化的时候配置好后面可以免去很多麻烦&lt;/p&gt;

&lt;p&gt;debian 系可用过 &lt;code&gt;timedatectl&lt;/code&gt; 命令调整时区。东八区可以用这个命令&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo timedatectl set-timezone Asia/Shanghai
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;2-5-厂商监控-sdk-卸载&#34;&gt;2.5 厂商监控/SDK 卸载&lt;/h3&gt;

&lt;p&gt;懂得都懂，自己搜&lt;/p&gt;

&lt;h3 id=&#34;2-6-fail2ban-配置&#34;&gt;2.6 fail2ban 配置&lt;/h3&gt;

&lt;p&gt;使用 fail2ban 可以很好地保护你的服务器，避免被人恶意爆破 SSH 等服务。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;// 安装 fail2ban
sudo apt update &amp;amp;&amp;amp; sudo apt install fail2ban
sudo systemctl enable fail2ban
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后需要按照实际情况修改一下配置文件。这里记录一下最小配置。注意默认的配置 &lt;code&gt;/etc/fail2ban/jail.conf&lt;/code&gt;不要改，不然每次软件更新会被覆盖。在 jaid.d 这个目录下面新建一个文件&lt;code&gt;/etc/fail2ban/jail.d/local.conf&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-conf&#34;&gt;[sshd]
enabled = true
# 这里修改为实际的 sshd 端口
port = 20000
filter = sshd
banaction = iptables-allports

[DEFAULT]
# 1h 时间窗口
findtime = 3600
maxretry = 3
bantime = 6h
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后重启&lt;code&gt;sudo systemctl restart fail2ban&lt;/code&gt;，然后可以看下服务状态是否正常 &lt;code&gt;sudo systemctl status fail2ban&lt;/code&gt;，如果配置文件有问题会报错。如果是显示&lt;code&gt;active (running)&lt;/code&gt; 就说明没有问题了。&lt;/p&gt;

&lt;p&gt;fail2ban 的测试及关闭服务方法：&lt;/p&gt;

&lt;p&gt;查看当前封禁 IP：&lt;code&gt;sudo fail2ban-client status sshd&lt;/code&gt;&lt;br /&gt;
解禁某一 IP: &lt;code&gt;sudo fail2ban-client set sshd unbanip IP_ADDRESS&lt;/code&gt;&lt;br /&gt;
停止 fail2ban 服务：&lt;code&gt;sudo systemctl stop fail2ban&lt;/code&gt;&lt;br /&gt;
关闭 fail2ban 服务：&lt;code&gt;sudo systemctl disable fail2ban&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;刚配置没一会就有 IP 被封禁了，可以看到效果还是很给力，也安心了不少&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;➜ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 1
|  |- Total failed:     6
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 1
   |- Total banned:     1
   `- Banned IP list:   154.216.19.42
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;2-7-git-代理&#34;&gt;2.7 Git 代理&lt;/h3&gt;

&lt;p&gt;一般在 &lt;code&gt;.bashrc&lt;/code&gt;/&lt;code&gt;.zshrc&lt;/code&gt; 中定义 &lt;code&gt;HTTP_PROXY&lt;/code&gt; / &lt;code&gt;HTTPS_PROXY&lt;/code&gt; 可以应对大部分场景。但是对于使用 ssh 协议的 git 仓库 (通过 ssh 方式，相较于 https 的不用每次输用户名和密码。一般对只有克隆公共仓库的时候才会用 https, 其他时候对于自己的仓库我都是用 ssh), 并不会走 http 代理。&lt;/p&gt;

&lt;p&gt;这里需要在 ssh config 中配置转发走代理才行。使用&lt;code&gt;nc&lt;/code&gt;(macOS 等默认会预装) 搭配 socks 代理最方便&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-ini&#34;&gt;Host github.com
    HostName github.com
    User git
    Port 22
    ProxyCommand nc -x 192.168.100.222:8085 %h %p
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;3-进阶内容&#34;&gt;3 - 进阶内容&lt;/h2&gt;

&lt;h3 id=&#34;3-1-内核参数调优&#34;&gt;3.1 内核参数调优&lt;/h3&gt;

&lt;p&gt;一些内核参数调整，交换内存阈值和 bbr, tcp fast open 等，按需启用。启用前务必确认自己了解对应字段的含义，否则不如保留系统初始值。&lt;/p&gt;

&lt;p&gt;配置文件位置 &lt;code&gt;/etc/sysctl.conf&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-conf&#34;&gt;# mem
vm.swappiness = 10

# bbr and network tune 
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
net.ipv4.tcp_fastopen=3
net.ipv4.tcp_slow_start_after_idle=0

# zram 相关配置，配合下文 zram 使用
vm.watermark_boost_factor = 0
vm.watermark_scale_factor = 125
vm.page-cluster = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;配置完之后保存并应用&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo sysctl -p
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;3-2-更多内存空间-zram&#34;&gt;3.2 更多内存空间 - ZRAM&lt;/h3&gt;

&lt;p&gt;ZRAM 内存压缩，对于个人服务器来说，始终活跃的程序占用的内存只有比较小一部分，启用 zram 可以将这部分内存压缩，从而可以部署更多的服务。&lt;/p&gt;

&lt;p&gt;建议使用&lt;code&gt;zramtool&lt;/code&gt;, 简单方便&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo apt install zram-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;修改&lt;code&gt;/etc/default/zramswap&lt;/code&gt;, 末尾添加&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-ini&#34;&gt;ALGO=zstd
PERCENT=60
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后执行&lt;code&gt;sudo service zramswap reload&lt;/code&gt;重载生效。
可以使用 swapon 命令查看生效情况&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~ » sudo swapon -show 
NAME        TYPE        SIZE  USED PRIO
/swap_space file          2G 32.1M   -2
/dev/zram0  partition 489.9M    0B  100
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这样一来，会将机器物理内存的 50% 配置 zram, 使用 zstd 压缩算法，一般压缩比能达到 3:1, 也就是说，1G 的机器，可以相当于有&lt;code&gt;0.5G+3*0.5G=2G&lt;/code&gt;的内存。&lt;/p&gt;

&lt;p&gt;注意 Debian 新版本 swapon 等工具所在的目录 /usr/sbin 不在普通用户的 PATH 中，可能需要手动执行前缀使用。如 /usr/sbin/swapon&lt;/p&gt;

&lt;h3 id=&#34;3-3-更多内存空间-关闭-kdump-释放预留的内存空间&#34;&gt;3.3 更多内存空间 - 关闭 kdump，释放预留的内存空间&lt;/h3&gt;

&lt;p&gt;新服务器开起来之后，你会发现无论是 htop 还是 free 等命令，看到的总内存就是比你买服务器时页面上写的要小。比如我开的两核 1G 的机器，实际机器上看到的总内存只有 816M. 这是因为 linux 系统会默认开启 kdump，预留了一部分内存不让我们使用。&lt;/p&gt;

&lt;p&gt;Kdump 是 Linux 系统的一种内核崩溃转储机制，它允许在系统发生内核崩溃（例如内核 panic）时，捕获内存的转储信息，从而帮助事后分析故障原因。默认的配置&lt;code&gt;2G-8G:256M,8G-16G:512M,16G-:768M&lt;/code&gt;, 如果你买的是 2G 的机器，上来就有 &lt;sup&gt;1&lt;/sup&gt;&amp;frasl;&lt;sub&gt;8&lt;/sub&gt; 的空间用不了。&lt;/p&gt;

&lt;p&gt;但是我们个人日常使用的 linux 机器基本用不到这个功能，不用预留这部分空间。&lt;/p&gt;

&lt;p&gt;操作方法有两种：将预留内存改为 0 or 直接关闭 kdump 服务。对于个人玩家小内存机器我建议直接关闭。操作如下：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# 备份grub配置文件
sudo cp /etc/default/grub /etc/default/grub.bak

# 编辑grub配置,删除 crashkernel=0M-2G:0M,2G-8G:192M 这样的部分 
sudo nano /etc/default/grub

# 部分发行版镜像可能还有单独的kdump配置文件,直接删除
sudo rm /etc/default/grub.d/kdump-tools.cfg

# 更新grub配置
sudo update-grub

# 关闭并禁用Kdump服务
sudo systemctl disable kdump-tools
sudo systemctl stop kdump-tools

# 重启系统
sudo reboot

# 检查是否生效, 状态为 inactive(dead)，即 kdump 服务已停止运行
sudo systemctl status kdump

# 检查 crash size 是否为0
cat /sys/kernel/kexec_crash_size
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;更多内容可以参见这篇文档：&lt;a href=&#34;https://help.aliyun.com/zh/ecs/use-cases/view-and-change-the-size-of-reserved-memory-on-a-linux-instance#7d5ae6803amdp&#34;&gt;预留内存相关文档 - 阿里云&lt;/a&gt; 或者 &lt;a href=&#34;https://cloud.tencent.com/document/product/213/115734&#34;&gt;预留内存相关文档 - 腾讯云&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;3-3-其他进阶配置&#34;&gt;3.3 其他进阶配置&lt;/h3&gt;

&lt;p&gt;一些其他的系统维护技巧与策略，如&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;配置文件管理&lt;/strong&gt;
所有应用 docker 化，通过 &lt;code&gt;docker compose&lt;/code&gt; 文件管理
配置共享存储，&lt;code&gt;rclone&lt;/code&gt; 挂载 webdav, 同步 docker compose 等配置文件;
traefik 网关作为统一出口，负责服务发现和自动维护 HTTPS 证书，自定义配置通过 headless CMS 如 directus 管理，traefik 设定为通过 http 方式获取远端配置即可。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;数据库备份&lt;/strong&gt;
所有数据相关的统一挂载到&lt;code&gt;/data/database/xxx&lt;/code&gt;, 配置定时任务进行备份
以及配置 s3 等，上传到其他存储介质和其他地域。&lt;/p&gt;

&lt;p&gt;这些内容此处不再赘述，有机会再单独写篇文章分享吧&lt;/p&gt;

&lt;p&gt;END&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&#34;附录&#34;&gt;附录&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install Docker Engine &lt;a href=&#34;https://docs.docker.com/engine/install/&#34;&gt;https://docs.docker.com/engine/install/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RSSManX 安装部署指南 &lt;a href=&#34;https://blog.colinx.one/posts/rssmanx%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/&#34;&gt;https://blog.colinx.one/posts/rssmanx%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;云服务器入门指南 &lt;a href=&#34;https://blog.colinx.one/posts/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/&#34;&gt;https://blog.colinx.one/posts/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Portainer Install Doc &lt;a href=&#34;https://docs.portainer.io/start/install-ce/server/docker/linux&#34;&gt;https://docs.portainer.io/start/install-ce/server/docker/linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

        
        </description>
    </item>
    
    <item>
      <title>2023 静态网站托管服务速度对比</title>
      <link>/posts/2023%E9%9D%99%E6%80%81%E7%BD%91%E7%AB%99%E6%89%98%E7%AE%A1%E6%9C%8D%E5%8A%A1%E9%80%9F%E5%BA%A6%E5%AF%B9%E6%AF%94/</link>
      <pubDate>Sun, 25 Dec 2022 00:00:00 +0000</pubDate>
      
      <guid>/posts/2023%E9%9D%99%E6%80%81%E7%BD%91%E7%AB%99%E6%89%98%E7%AE%A1%E6%9C%8D%E5%8A%A1%E9%80%9F%E5%BA%A6%E5%AF%B9%E6%AF%94/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # 2023 静态网站托管服务速度对比 --&gt;

&lt;p&gt;对几家喜闻乐见的静态网站托管服务商 Vercel、Netlify、Cloudflare Pages、Azure Static Pages 测个速&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202212252033118.png&#34; alt=&#34;Pasted image 20221224164447&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202212252033119.png&#34; alt=&#34;Pasted image 20221224173040&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202212252033120.png&#34; alt=&#34;Pasted image 20221224164841&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202212252033121.png&#34; alt=&#34;Pasted image 20221224165726&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;测速后结论：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vercel 全部爆炸，大陆地区全部不通&lt;/li&gt;
&lt;li&gt;Netlify 对三家支持都比较不错，不过都有些不太稳定&lt;/li&gt;
&lt;li&gt;Cloudflare 对电信友好，联通次之，移动大规模连不上&lt;/li&gt;
&lt;li&gt;Azure 电信友好，联通次之，移动也是大规模连不上&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;特邀嘉宾-腾讯云海外-cdn&#34;&gt;特邀嘉宾：腾讯云海外 CDN&lt;/h2&gt;

&lt;p&gt;号称「充钱就可以获得力量」，那么让我们来看下冲了钱后的效果&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202212252033122.png&#34; alt=&#34;Pasted image 20221224181710&#34; /&gt;&lt;/p&gt;

&lt;h5 id=&#34;腾讯云海外-cdn&#34;&gt;腾讯云海外 CDN&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;大陆地区大部分路由到香港，极少数华东地区路由到美国，全部为 AWS 节点&lt;/li&gt;
&lt;li&gt;移动除西北地区外都尚可，联通次之也是除西北外都还行，电信惨不忍睹&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;用腾讯云 CDN 被 D 怎么办？天价账单可付不起&lt;/strong&gt;
小时结计费模式，欠费后保护期为 2 小时，还可以按流量或带宽单独设定防护策略&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;接下来开始真正的试炼：检测晚高峰期间各家的性能，晚上这个点各大运营商的出口都比较拥堵，这个时候更能体现出各家的性能优劣&lt;/p&gt;

&lt;h2 id=&#34;晚高峰测速结果&#34;&gt;晚高峰测速结果&lt;/h2&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202212252033123.png&#34; alt=&#34;Pasted image 20221225190111&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Azure 全线炸裂 ⬆️&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202212252033124.png&#34; alt=&#34;Pasted image 20221225190148&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Netlify 依然给力 ⬆️&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202212252033125.png&#34; alt=&#34;Pasted image 20221225190325&#34; /&gt;
Vercel 依然一片红 ⬆️&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202212252033127.png&#34; alt=&#34;Pasted image 20221225190510&#34; /&gt;
CF 跟白天差不多，电信联通勉强可用 ⬆️&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202212252033128.png&#34; alt=&#34;Pasted image 20221225190728&#34; /&gt;&lt;/p&gt;

&lt;p&gt;TX 海外 CDN 红绿参半，不过可以看到很强的地域特性&lt;/p&gt;

&lt;h4 id=&#34;其他补充信息&#34;&gt;其他补充信息：&lt;/h4&gt;

&lt;h5 id=&#34;vercel&#34;&gt;Vercel&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;不能自定义 HTTPS 证书，走 Let‘s Encrypt&lt;/li&gt;
&lt;li&gt;有 Anycast，76.76.21.21，用 DNS 做负载均衡会比较方便&lt;/li&gt;
&lt;li&gt;使用分钟级监控看过，时不时有连不上的情况，比 Cloudflare 明显差些，不过免费没有 SLA 保障也正常&lt;/li&gt;
&lt;li&gt;大陆地区全部爆炸，不予考虑&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&#34;netlify&#34;&gt;Netlify&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;可以自定义 HTTPS 证书&lt;/li&gt;
&lt;li&gt;无 Anycast，去年看都是 AWS 承载，今年看有近一半由 Google Cloud 承载&lt;/li&gt;
&lt;li&gt;移动可以优先 Netlify&lt;/li&gt;
&lt;li&gt;可以安装插件，网站更新可以自动推送 Google 比较方便&lt;/li&gt;
&lt;li&gt;全部路由到新加坡，北方用户可能延迟较高&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&#34;cloudflare-pages&#34;&gt;Cloudflare Pages&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Cloudflare 可以自己签发证书，不像其他使用 Let‘s Encrypt 的必须要能解析到&lt;/li&gt;
&lt;li&gt;有 Anycast，可以直接解析到 1.1.1.1，做负载均衡方便&lt;/li&gt;
&lt;li&gt;移动 pass，电信联通尚可&lt;/li&gt;
&lt;li&gt;不太稳定，动不动就被墙，需要常检测更新节点联通性&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&#34;azure-static-pages&#34;&gt;Azure Static Pages&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;可以通过 TXT 记录验证和自动申请 HTTPS&lt;/li&gt;
&lt;li&gt;无 Anycast，只有香港的节点，两个 IP，方便负载均衡&lt;/li&gt;
&lt;li&gt;移动 pass，电信联通尚可&lt;/li&gt;
&lt;li&gt;北方用户可能延迟较高&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;策略&#34;&gt;策略&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Vercel 全线不可用，Azure 晚高峰全部炸裂，大陆地区不考虑&lt;/li&gt;
&lt;li&gt;Netlify 做全局默认 fallback&lt;/li&gt;
&lt;li&gt;海外默认走 Cloudflare、Vercel&lt;/li&gt;
&lt;li&gt;电信走 Netlify，无可替代&lt;/li&gt;
&lt;li&gt;移动走 Netlify 和腾讯云海外 CDN&lt;/li&gt;
&lt;li&gt;联通走 Netlify、Cloudflare、腾讯云海外 CDN&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;博客的几个镜像站点我也挂在了仓库的 README 页面，加了几个 badge 可以快速看到几个 mirror 的联通性情况。&lt;a href=&#34;https://github.com/Colin-XKL/Colinx-Blog&#34;&gt;https://github.com/Colin-XKL/Colinx-Blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://img.shields.io/website?label=netlify&amp;amp;style=flat-square&amp;amp;url=https%3A%2F%2Fcolins-blog.netlify.app&#34; alt=&#34;Blog-Netlify&#34; /&gt;
&lt;img src=&#34;https://img.shields.io/website?label=vercel&amp;amp;style=flat-square&amp;amp;url=https%3A%2F%2Fcolinx-blog.vercel.app&#34; alt=&#34;Blog-Vercel&#34; /&gt;
&lt;img src=&#34;https://img.shields.io/website?label=cloudflare%20pages&amp;amp;style=flat-square&amp;amp;url=https%3A%2F%2Fcolinx-blog.pages.dev&#34; alt=&#34;Blog-CloudflarePages&#34; /&gt;
&lt;img src=&#34;https://img.shields.io/website?label=azure%20static%20pages&amp;amp;style=flat-square&amp;amp;url=https%3A%2F%2Fnice-glacier-095b09e00.1.azurestaticapps.net&#34; alt=&#34;Blog-AzureStaticPages&#34; /&gt;
&lt;img src=&#34;https://img.shields.io/website?label=github%20pages&amp;amp;style=flat-square&amp;amp;url=https%3A%2F%2Fgh-pages.colinx.one&#34; alt=&#34;Blog-GithubPages&#34; /&gt;
&lt;img src=&#34;https://img.shields.io/website?label=tencent%20cdn&amp;amp;style=flat-square&amp;amp;url=https%3A%2F%2Fblog-txcdn.colinx.one&#34; alt=&#34;Blog-TencentCDN&#34; /&gt;&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>docker compose 的错误使用姿势</title>
      <link>/posts/docker-compose%E7%9A%84%E9%94%99%E8%AF%AF%E4%BD%BF%E7%94%A8%E5%A7%BF%E5%8A%BF/</link>
      <pubDate>Wed, 11 May 2022 00:00:00 +0000</pubDate>
      
      <guid>/posts/docker-compose%E7%9A%84%E9%94%99%E8%AF%AF%E4%BD%BF%E7%94%A8%E5%A7%BF%E5%8A%BF/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # docker compose 的错误使用姿势 --&gt;

&lt;p&gt;这篇文章记录几个 docker compose 使用过程中几个难以察觉的错误使用姿势&lt;/p&gt;

&lt;h2 id=&#34;1-变量值使用-符号开头&#34;&gt;1. 变量值使用&lt;code&gt;@&lt;/code&gt;符号开头&lt;/h2&gt;

&lt;p&gt;我在 RSS MAN X 的 docker-compose 配置文件中，huignn 的环境变量出来时是这样写的&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;environment:
	- DATABASE_ADAPTER=postgresql
	- DATABASE_HOST=database.huginn
	- DATABASE_USERNAME=postgres
	- DATABASE_PASSWORD=@pass_for_DB
	- DATABASE_PORT=5432
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;自己使用的时候没发现什么问题，别人从零创建容器的时候报错了。刚开始排查了很久，后面发现我默认密码这样写其实是有问题的。&lt;/p&gt;

&lt;p&gt;上面的使用列表来描述环境变量在 docker-compose 解析的时候没有任何报错信息。但是使用下面这种 key-value 的 map 的形式时，&lt;code&gt;docker-compose up&lt;/code&gt;命令报错了，说 YAML 解析时出现问题&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;environment:
	DATABASE_ADAPTER: postgresql
	DATABASE_HOST: database.huginn
	DATABASE_USERNAME: postgres
	DATABASE_PASSWORD: @pass_for_DB
	DATABASE_PORT: 5432
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;yaml: line 17: found character that cannot start any token
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;删除前导&lt;code&gt;@&lt;/code&gt;符号则一切正常了。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;DATABASE_PASSWORD: pass_for_DB
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;后续测试了几次到底是什么原因导致的&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;# error
DATABASE_PASSWORD: @pass_for_DB	

# correct
DATABASE_PASSWORD: pass_for_DB

# correct
DATABASE_PASSWORD: ${DB_Password:-&#39;pass_for_DB&#39;}
## in .env
DB_Password=www_123

# correct
DATABASE_PASSWORD: ${DB_Password:-&#39;@pass_for_DB&#39;}
## in .env
DB_Password=www_123

# error
DATABASE_PASSWORD: ${DB_Password:-&#39;@pass_for_DB&#39;}
## no .env

# error
DATABASE_PASSWORD: ${DB_Password:-&#39;@pass_for_DB&#39;}
## in .env
DB_Password=@www_123

# correct
DATABASE_PASSWORD: ${DB_Password:-&#39;@pass_for_DB&#39;}
## in .env
DB_Password=A@www_123
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;最终发现无论是否使用 docker-compose 变量替换，只要最终设定值的时候，包含前导@符号，最终一定会失败。Huginn 的这边的报错为解析容器内的一个 YAML 文件时失败&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;huginn1     | foreman stderr | 
huginn1     | Caused by:
huginn1     | foreman stderr | Psych::SyntaxError: (&amp;lt;unknown&amp;gt;): found character that cannot start any token while scanning for the next token at line 8 column 13
huginn1     | foreman stderr | /app/vendor/bundle/ruby/2.6.0/gems/railties-6.0.4.4/lib/rails/application/configuration.rb:232:in `database_configuration&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;后面我又进入容器查看了下容器内部读取到的环境变量到底是不是预期的值，发现了问题所在&lt;/p&gt;

&lt;p&gt;能正常使用的情况&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~ » sudo docker exec -it huginn1 /bin/bash
default@3b652a8413fb:~$ echo $DATABASE_HOST
database.huginn
default@3b652a8413fb:~$ echo $DATABASE_PASSWORD
A@www_123
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;出错的情况&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~ » sudo docker exec -it huginn1 /bin/bash
default@42e19e692b24:~$ echo $DATABASE_HOST
database.huginn
default@42e19e692b24:~$ echo $DATABASE_PASSWORD
&#39;@pass_for_DB&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以看到，如果以&lt;code&gt;@&lt;/code&gt;符号开头，最终的环境变量会加上引号，这对于某些应用来说会产生预期之外的结果，如此处测试的 Huginn。&lt;/p&gt;

&lt;h2 id=&#34;2-使用-6000-或-6666-端口&#34;&gt;2. 使用 6000 或 6666 端口&lt;/h2&gt;

&lt;p&gt;这也是一定挺特殊的场景，虽然与 docker compose 关系不大，但是难免会遇到。在映射端口的时候有一个很坑的地方，如果你要部署一个 web 服务，然后映射的时候填写的是&lt;code&gt;6000&lt;/code&gt;端口或者是&lt;code&gt;6666&lt;/code&gt;端口，你会发现无论怎么重启容器、更改容器设置、更换 Edge/Chrome，浏览器就是访问不了页面。&lt;/p&gt;

&lt;p&gt;实在折腾地快疯了，点开 Chrome 的错误详情，才发现这么一句&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;ERR_UNSAFE_PORT&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;一查才发现，Chrome 等浏览器会限制部分特殊端口的网页访问，这些端口一般都已经有特殊的作用。&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.jianshu.com/p/40f79f584eae&#34;&gt;https://www.jianshu.com/p/40f79f584eae&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;这里列出 1000 以上的部分会有相关问题的端口，别的不说，感觉&lt;code&gt;6000&lt;/code&gt;和&lt;code&gt;6666&lt;/code&gt;还是很容易一不小心就会设置的端口。。。。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-c&#34;&gt;  2049, // nfs
  3659, // apple-sasl / PasswordServer
  4045, // lockd
  6000, // X11
  6665, // Alternate IRC
  6666, // Alternate IRC
  6667, // Standard IRC
  6668, // Alternate IRC
  6669, // Alternate IRC
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Chrome、FireFox 等都会有类似的行为，换多少浏览器、换多少版本可能也都不行。。。&lt;/p&gt;

&lt;p&gt;根据网友描述，部分特殊情况下，其他可能会被拦截的端口也包括&lt;code&gt;8080&lt;/code&gt;，&lt;code&gt;8443&lt;/code&gt;，&lt;code&gt;10080&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;总之，日常映射端口还是选取&lt;code&gt;10000&lt;/code&gt;以上的高位端口吧，避免不必要的麻烦：）&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>论如何下载任意网站视频</title>
      <link>/posts/%E8%AE%BA%E5%A6%82%E4%BD%95%E4%B8%8B%E8%BD%BD%E4%BB%BB%E6%84%8F%E7%BD%91%E7%AB%99%E8%A7%86%E9%A2%91/</link>
      <pubDate>Mon, 09 May 2022 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E8%AE%BA%E5%A6%82%E4%BD%95%E4%B8%8B%E8%BD%BD%E4%BB%BB%E6%84%8F%E7%BD%91%E7%AB%99%E8%A7%86%E9%A2%91/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # 论如何下载任意网站视频 --&gt;

&lt;p&gt;视频已然成为当今互联网上信息传播的一个重要载体，有时会需要下载一些网上某个站点的视频插入 PPT，或者视频素材，无论是自己用抑或单纯是给朋友帮个忙，掌握一些使用的下载视频的小技巧总是不会错的，这里分享一些自用的小技巧，包括热门站点下载工具，以及应对冷门网站视频下载的技巧，应该可以覆盖 99.9% 的视频下载场景&lt;/p&gt;

&lt;h2 id=&#34;热门网站电影-电视剧下载&#34;&gt;热门网站电影/电视剧下载&lt;/h2&gt;

&lt;p&gt;这种其实建议直接找对应资源而不是从源站点下载，百度云，阿里云盘等找资源的方式我就不再赘述了，网上教程多的是。如果是电影资源或者是欧美、日韩的剧，可以搜索 BT 资源自行下载。&lt;/p&gt;

&lt;p&gt;这里安利一个油猴脚本：&lt;a href=&#34;https://greasyfork.org/zh-CN/scripts/329484-%E8%B1%86%E7%93%A3%E8%B5%84%E6%BA%90%E4%B8%8B%E8%BD%BD%E5%A4%A7%E5%B8%88-1%E7%A7%92%E6%90%9E%E5%AE%9A%E8%B1%86%E7%93%A3%E7%94%B5%E5%BD%B1-%E9%9F%B3%E4%B9%90-%E5%9B%BE%E4%B9%A6%E4%B8%8B%E8%BD%BD&#34;&gt;豆瓣资源下载大师&lt;/a&gt;，可以在豆瓣的影视详情页右侧显示有资源的站点，非常方便&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205091548956.png&#34; alt=&#34;image-20220509144533549&#34; /&gt;&lt;/p&gt;

&lt;p&gt;分享下个人常用的下载站点：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;欧美资源下载：&lt;a href=&#34;https://www.1337x.to/&#34;&gt;1337X&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;欧美资源下载：&lt;a href=&#34;https://piratebay.live/&#34;&gt;海盗湾&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;动漫资源下载：&lt;a href=&#34;https://acg.rip/?term=JOJO%E7%9A%84%E5%A5%87%E5%A6%99%E5%86%92%E9%99%A9&#34;&gt;ACG RIP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;中文字幕下载：&lt;a href=&#34;http://zimuku.org&#34;&gt;字幕库&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;个人推荐的下载工具：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.qbittorrent.org&#34;&gt;qBittorrent&lt;/a&gt;：强推，老牌专业 BT 工具，有图形化界面，&lt;a href=&#34;https://hub.docker.com/r/linuxserver/qbittorrent&#34;&gt;支持 Docker 部署&lt;/a&gt;且带 Web 界面&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://aria2.github.io&#34;&gt;aria2&lt;/a&gt;：强大的命令行下载工具，灵活但上手成本略高，可&lt;a href=&#34;https://ariang.mayswind.net/zh_Hans/&#34;&gt;自行部署 Web GUI 界面&lt;/a&gt;，也可使用&lt;a href=&#34;http://ariang.mayswind.net/latest&#34;&gt;公开版本 demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://motrix.app&#34;&gt;Motrix&lt;/a&gt;：高颜值跨平台的下载工具，有漂亮的 GUI 界面，底层基于 aria2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tracker 列表：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;一个独立的收集 trackerlist 的页面：&lt;a href=&#34;https://trackerslist.com/#/zh&#34;&gt;https://trackerslist.com/#/zh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;通用 tracker list：&lt;a href=&#34;https://github.com/ngosang/trackerslist&#34;&gt;ngosang/trackerslist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;动漫资源 tracker list：&lt;a href=&#34;https://github.com/DeSireFire/animeTrackerList&#34;&gt;animeTrackerList&lt;/a&gt; (๑•̀ㅂ•́)و✧&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;热门站点普通视频资源下载&#34;&gt;热门站点普通视频资源下载&lt;/h2&gt;

&lt;p&gt;如果是 UGC 内容，比如 B 站用户上传的视频，那么 BT 通常是没有资源的，需要单独从源网站下载。不过既然是热门站点，都有很多人造过轮子了，这里推荐几个&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://github.com/ytdl-org/youtube-dl&#34;&gt;YouTube-DL&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;一款强大的命令行视频下载工具，别看人家名字只写了 youtube，但其实国内爱优腾都是支持的。命令行调用也非常简洁，&lt;a href=&#34;https://github.com/ytdl-org/youtube-dl&#34;&gt;知乎也有教程&lt;/a&gt;需要的话可以瞅瞅。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://github.com/yt-dlp/yt-dlp&#34;&gt;YT-DLP（YouTube DownLoader Plus）&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;YouTube-DL 的一个分支，包括一些 bug 修复和增强的特性&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://github.com/iawia002/lux&#34;&gt;Lux（原名 Annie）&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Golang 编写的一个视频下载工具，同样支持国内站点&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://www.flvcd.com/index.htm&#34;&gt;硕鼠&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;很早之前就出的一款免费视频下载合并工具，主要针对国内视频网站，但是像腾讯视频这种之前发过律师函，人家就迫不得已取消了支持。Windows 版，有界面，对于不是那么热门但是稍微又有点名气的网站支持较好&lt;/p&gt;

&lt;h2 id=&#34;冷门站点普通视频资源下载&#34;&gt;冷门站点普通视频资源下载&lt;/h2&gt;

&lt;p&gt;冷门站点的资源得我们自己动手了，不过利用浏览器的开发人员工具还是很容易获取的资源的。右键找到开发人员选项打开开发人员工具，可以点击左上角的按钮选择网页元素，找到&lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt;标签，里面一般会有一个链接地址，复制地址打开即可。&lt;/p&gt;

&lt;p&gt;这种简单的视频嵌入很容易下载，浏览器工具也很容易嗅探到。比如可以使用&lt;code&gt;专业视频下载工具&lt;/code&gt;插件，你可以&lt;a href=&#34;https://ext.chrome.360.cn/webstore/detail/noaehhegaeigebicejggjdecdkfphced&#34;&gt;访问 360 插件中心下载&lt;/a&gt;。这种工具很多，这里不再赘述&lt;/p&gt;

&lt;p&gt;链接后缀为&lt;code&gt;mp4&lt;/code&gt;的一般来说都是说明该网页上面的视频只是从那一个文件加载的，没有经过分片和其他处理。如果没有后缀名，或者是&lt;code&gt;flv&lt;/code&gt;、&lt;code&gt;ts&lt;/code&gt;或者链接含有&lt;code&gt;m3u8&lt;/code&gt;字样的，说明该网页的资源是经过分片的，需要我们动点手段。&lt;/p&gt;

&lt;h2 id=&#34;冷门站点-m3u8-动态分片视频资源下载&#34;&gt;冷门站点 m3u8 动态分片视频资源下载&lt;/h2&gt;

&lt;p&gt;以中国庭审网的庭审录像视频为例，打开开发者工具定位到视频的部分发现 video 标签里面的 url 很奇怪，访问该链接也并不能访问到有效的视频。这种网页一般都是通过 m3u8 来下发分片文件的信息&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205091548957.png&#34; alt=&#34;image-20220509151813071&#34; /&gt;&lt;/p&gt;

&lt;p&gt;打开开发者工具的网络选项卡，监听网络活动，点击播放视频，会多出来很多条目分别代表每一个网络请求。在搜索框输入 m3u8 来进行过滤。定位到该请求后可以在新标签页打开，保存这个 m3u8 文件。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205091548958.png&#34; alt=&#34;image-20220509144410278&#34; /&gt;&lt;/p&gt;

&lt;p&gt;之后我们可以利用 ffmpeg 载入这个 m3u8 文件并进行合并，如有需要可一并进行转码操作&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;ffmpeg -i xxxx.m3u8 -c xxxx.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果报错提示不支持的 protocol，那么需要再加个参数让 ffmpeg 使用 http 下载&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;ffmpeg -protocol_whitelist concat,file,http,https,tcp,tls,crypto -i xxxx.m3u8 -c copy xxxx.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;接下来等待命令跑完，我们就可以得到需要的视频文件了。&lt;/p&gt;

&lt;p&gt;其他常用处理命令&lt;/p&gt;

&lt;p&gt;使用&lt;code&gt;-i&lt;/code&gt;参数读取文件，查看详细参数&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;ffmpeg -i xxxx.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;使用 ffmepg 提取视频中的音频部分，方便后续处理。比如要生成字幕或是转写为文本，省的上传几百兆的视频文件。&lt;a href=&#34;https://jianwai.youdao.com/&#34;&gt;网易见外工作台&lt;/a&gt;做这些很方便，而且免费额度也很足，安利一波&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;ffmpeg -i xxxx.mp4 -vn -codec copy xxxx.aac
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205091548959.png&#34; alt=&#34;image-20220509153021601&#34; /&gt;&lt;/p&gt;

&lt;p&gt;解析并下载 m3u8 视频的其他方案&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;使用硕鼠解析：&lt;a href=&#34;https://www.flvcd.com/index.htm&#34;&gt;https://www.flvcd.com/index.htm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;使用 Chrome 插件：&lt;a href=&#34;https://chrome.google.com/webstore/detail/video-downloader-cococut/gddbgllpilhpnjpkdbopahnpealaklle&#34;&gt;CoCoCut&lt;/a&gt;，&lt;a href=&#34;https://github.com/xifangczy/cat-catch&#34;&gt;猫抓 (cat-catch)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;使用油猴脚本：&lt;a href=&#34;https://greasyfork.org/zh-CN/scripts/440577-m3u8-%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD-vip%E8%A7%A3%E6%9E%90%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD-%E7%BD%91%E7%AB%99%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD&#34;&gt;m3u8-downloader&lt;/a&gt;，配套工具&lt;a href=&#34;https://github.com/Momo707577045/m3u8-downloader&#34;&gt;地址&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;使用软件：&lt;a href=&#34;http://www.neatdownloadmanager.com/index.php/en/&#34;&gt;NeatDownloadManager&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;以上&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>Huginn 指南：为任意网站制作 RSS</title>
      <link>/posts/huginn%E6%8C%87%E5%8D%97%E4%B8%BA%E4%BB%BB%E6%84%8F%E7%BD%91%E7%AB%99%E5%88%B6%E4%BD%9Crss/</link>
      <pubDate>Sun, 08 May 2022 00:00:00 +0000</pubDate>
      
      <guid>/posts/huginn%E6%8C%87%E5%8D%97%E4%B8%BA%E4%BB%BB%E6%84%8F%E7%BD%91%E7%AB%99%E5%88%B6%E4%BD%9Crss/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # Huginn 指南：为任意网站制作 RSS --&gt;

&lt;p&gt;Huginn 使用多个不同功能的 Agent 组合搭配来实现一系列功能，一个 Agent 可以执行特定的操作，并产生一个 Event，你可以指定他产生的 Event 由哪个 Agent 接收处理。&lt;/p&gt;

&lt;p&gt;比如我们需要使用 WebSite Agent 来爬取某个网站上的列表内容，爬取后列表的每一项会生成一个 Event，我们可以指定一个 Output Agent 来接收这些 Event，并将其转换为 RSS 的格式进行输出，复制 Output Agent 返回给你的 URL 就可以进行订阅啦，Huginn 爬取网站生成 RSS 的基本原理就是这样。&lt;/p&gt;

&lt;h2 id=&#34;huginn-爬取普通网页制作-rss&#34;&gt;Huginn 爬取普通网页制作 RSS&lt;/h2&gt;

&lt;p&gt;右键网页打开开发者工具，屏幕会分出一部分空间显示开发者工具窗口，点击左上角的按钮再把鼠标移动到页面上可以选择页面的某一个元素，比如这里我们要爬取推荐文章列表，推荐文章列表的每一项都有同样的样式，我们可以使用 CSS 选择器来指定爬取该项&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207138.png&#34; alt=&#34;image-20220508160659378&#34; /&gt;&lt;/p&gt;

&lt;p&gt;该元素可以用 CSS 选择器&lt;code&gt;.meiwen&lt;/code&gt;选择到。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tips:&lt;/strong&gt; class=xxx 则使用&lt;code&gt;.xxx&lt;/code&gt;,如果为 id=xxx 则使用&lt;code&gt;#xxx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;该标签是 a 标签，我们可以继续限定一下条件，使用&lt;code&gt;a.meiwen&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;如果要限制必须是 h2 标签下的带有 meiwen 的 class 属性的 a 标签，可以使用&lt;code&gt;h2 a.meiwen&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;如果要再加一个限制，是列表元素 li 下面的 h2 标签里带有 meiwen 的 class 属性的 a 标签，可以使用&lt;code&gt;li h2 a.meiwen&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;添加其他附加限定条件以此类推&lt;/p&gt;

&lt;p&gt;你也可以在右侧 Style 面板里点击加号添加一个自定义样式，输入 CSS 选择器，浏览器会自动高亮符合条件的网页元素，你可以使用这个功能来检验你写的 CSS 选择器是否正确以及是不是提取的你想要的内容&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207716.png&#34; alt=&#34;image-20220508163359806&#34; /&gt;&lt;/p&gt;

&lt;p&gt;接下来在 Huginn 里创建一个 Scenario，然后点击新建一个 Agent，类型选择 WebSite Agent，填写一个名称，并在最下面的配置处指定你要爬取的网页元素&lt;/p&gt;

&lt;blockquote&gt;
&lt;h6 id=&#34;website-agent&#34;&gt;&lt;strong&gt;Website Agent&lt;/strong&gt;&lt;/h6&gt;

&lt;p&gt;The Website Agent scrapes a website, XML document, or JSON feed and creates Events based on the results.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;url: {
	css: li h2 a.meiwen
	value: @href
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;以爬取 url 为例，css 表示使用 css 选择器选择网页元素，value 表示从哪里获取对应的值，对于刚才我们选取的一个元素来说&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;a class=&amp;quot;meiwen&amp;quot; href=&amp;quot;/article/58030.html&amp;quot; title=&amp;quot;缘起则聚，缘灭则散&amp;quot;&amp;gt;缘起则聚，缘灭则散&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;href 属性里面的内容是他的链接，title 属性里面的内容则是他的标题。接下来在 value 中填写&lt;code&gt;@href&lt;/code&gt;指定从 href 属性提取内容，就可以取到链接地址了&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tips:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如果是纯文本节点或是想提取标签内嵌的文本，value 里可以填写&lt;code&gt;string(.)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;如果想删除多余的空格，可以使用&lt;code&gt;normalize-space(.)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro Tips 2:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;字符串处理函数和标签属性值变量可以一起使用，如&lt;code&gt;normalize-space(@title)&lt;/code&gt;可以获取该标签的 title 属性值并删除多余的空白字符&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207717.png&#34; alt=&#34;image-20220508163714342&#34; /&gt;&lt;/p&gt;

&lt;p&gt;接下来点击 Dry Run 按钮进行测试，不出意外我们会得到一个 json 的输出，里面包括我们爬取到的每一项他的 url 和 title。&lt;/p&gt;

&lt;p&gt;如果没有成功，你可能需要删掉上面没有使用到的 hovertext 节点，因为该项指定的内容在我们刚才的网页中并不存在。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207718.png&#34; alt=&#34;image-20220508164259295&#34; /&gt;&lt;/p&gt;

&lt;p&gt;点击 Save 保存，我们开始下一步输出 RSS。在刚才的 Scenario 中再新建一个 Agent，选择 Data Output Agent，并设置他的名字和 Source Agent&lt;/p&gt;

&lt;blockquote&gt;
&lt;h6 id=&#34;data-output-agent&#34;&gt;Data output Agent&lt;/h6&gt;

&lt;p&gt;The Data Output Agent outputs received events as either RSS or JSON. Use it to output a public or private stream of Huginn data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207719.png&#34; alt=&#34;image-20220508164941647&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Propagate immediately&lt;/strong&gt;是指即时处理来自 Source Agent 的 Event，启用他方便我们调试，但会略微增加服务器负载，你可以自行决定是否使用。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207720.png&#34; alt=&#34;image-20220508165345792&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在 secret 字段中为你的这个 RSS 标注一个英文的名字，修改 title 字段标注你的 RSS 的名字。item 字段是每条文章会有的属性，一般来说主要就 title 和 link，分别设置为上文我们提取的值的变量名。这里添加一个 guid 字段，这是一篇文章的唯一标识符，避免 RSS 阅读器读到的文章标题不同但是内容相同，常见于某篇文章的标题被修改，这会导致 RSS 阅读器内出现多篇重复文章。&lt;/p&gt;

&lt;p&gt;此外建议增加一个 link 字段，值设置为与爬取的网站的主域名一致，避免网站内使用相对链接开头的资源无法正常加载。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207721.png&#34; alt=&#34;image-20220508170038722&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207722.png&#34; alt=&#34;image-20220508170115192&#34; /&gt;&lt;/p&gt;

&lt;p&gt;点击 Save 保存，回到 Scenario 界面，第一次需要手动点击运行一下刚才的 Website Agent。稍等片刻后台会进行爬取，右上角会显示产生了多少个 Event。再点开刚才设置的 Data Output Agent 查看详情，vola！右侧就会显示生成的 RSS 链接了，复制以 xml 结尾的链接到 RSS 阅读器中就可以订阅啦🎉&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207723.png&#34; alt=&#34;image-20220508170212112&#34; /&gt;&lt;/p&gt;

&lt;p&gt;如果你的配置正确但是 WebSite Agent 又没有输出任何内容的话，那么你要爬取的站点的内容应该是通过 JavaScript 在你带开浏览器时动态生成的。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tips:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;你可以右键网页在开发人员菜单中点击显示源代码，然后用 Ctrl+F 搜索你在页面上见到的想爬取的某一条内容，如果有说明该网站的页面时静态的，否则说明你要爬取的内容并不是静态的。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;要爬取这样的站点，我们需要模拟浏览器操作，执行页面上的 JavaScript 脚本，待数据生成完毕后再使用上面的方法去爬取内容。要模拟浏览器操作，这里介绍两个方案：一个是利用 browserless 的无头浏览器，另一个是使用在线 PhatomJS 服务。&lt;/p&gt;

&lt;h2 id=&#34;使用-huginn-browserless-为动态网页生成-rss&#34;&gt;使用 Huginn+Browserless 为动态网页生成 RSS&lt;/h2&gt;

&lt;p&gt;部署了&lt;a href=&#34;https://github.com/Colin-XKL/RSSmanX&#34;&gt;RSS Man X&lt;/a&gt;的完整版的话默认已经包含 huginn 和 browserless 服务，无需重复安装。且 huginn 可以通过&lt;code&gt;service.browserless:3000&lt;/code&gt;访问到 browserless 服务。&lt;/p&gt;

&lt;p&gt;总体步骤与上文一样，不过因为被抓取的内容是通过 JavaScript 动态生成的，所以直接使用 WebSite Agent 是抓取不到东西的，我们需要先使用 Post Agent 向 browserless 服务发送指令，让他帮我们模拟浏览器操作，再将最终完整的网页返回给我们，再使用 WebSite Agent 进行后续处理。&lt;/p&gt;

&lt;blockquote&gt;
&lt;h6 id=&#34;post-agent&#34;&gt;&lt;strong&gt;Post Agent&lt;/strong&gt;&lt;/h6&gt;

&lt;p&gt;A Post Agent receives events from other agents (or runs periodically), merges those events with the Liquid-interpolated contents of payload, and sends the results as POST (or GET) requests to a specified url. To skip merging in the incoming event, but still send the interpolated payload, set no_merge to true.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;接下来以&lt;a href=&#34;https://pccz.court.gov.cn/pcajxxw/pcgg/ggdh?lx=0&#34;&gt;这个网站&lt;/a&gt;为例介绍一下，这个列表页的内容是由 JavaScript 动态生成的&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207724.png&#34; alt=&#34;image-20220508205159783&#34; /&gt;&lt;/p&gt;

&lt;p&gt;按照以下内容设置你的 Post Agent&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;quot;post_url&amp;quot;: &amp;quot;http://service.browserless:3000/content&amp;quot;,
  &amp;quot;expected_receive_period_in_days&amp;quot;: &amp;quot;1&amp;quot;,
  &amp;quot;content_type&amp;quot;: &amp;quot;json&amp;quot;,
  &amp;quot;method&amp;quot;: &amp;quot;post&amp;quot;,
  &amp;quot;payload&amp;quot;: {
    &amp;quot;url&amp;quot;: &amp;quot;https://pccz.court.gov.cn/pcajxxw/pcgg/ggdh?lx=0&amp;quot;
  },
  &amp;quot;headers&amp;quot;: {
    &amp;quot;Cache-Control&amp;quot;: &amp;quot;no-cache&amp;quot;,
    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/json&amp;quot;
  },
  &amp;quot;emit_events&amp;quot;: &amp;quot;true&amp;quot;,
  &amp;quot;no_merge&amp;quot;: &amp;quot;false&amp;quot;,
  &amp;quot;output_mode&amp;quot;: &amp;quot;clean&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其中&lt;code&gt;post_url&lt;/code&gt;为你的 browserless 实例地址，如果你使用了 RSS MAN X 里的 Huginn 可以直接向上面一样填写。&lt;code&gt;payload&lt;/code&gt;中的&lt;code&gt;url&lt;/code&gt;字段填写你需要的网页地址。注意 emit_events 要设置为&lt;code&gt;true&lt;/code&gt;，这样才方便我们后续使用 WebSite Agent 操作。&lt;/p&gt;

&lt;p&gt;点击 Dry Run，如果能返回一个带有&lt;code&gt;body&lt;/code&gt;字段且里面有文本内容说明调用成功。&lt;/p&gt;

&lt;p&gt;调用不成功检查一下配置，以及是不是我们的爬虫被目标网站拦截了。若是爬虫被拦截可参考文末的解决方案。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207725.png&#34; alt=&#34;image-20220508195731732&#34; /&gt;&lt;/p&gt;

&lt;p&gt;接下来点击 Save 保存，再新建一个 Website Agent，Source 设置为刚才的 Post Agent。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;quot;expected_update_period_in_days&amp;quot;: &amp;quot;2&amp;quot;,
  &amp;quot;data_from_event&amp;quot;: &amp;quot;{{ body }}&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;html&amp;quot;,
  &amp;quot;mode&amp;quot;: &amp;quot;on_change&amp;quot;,
  &amp;quot;extract&amp;quot;: {
    &amp;quot;url&amp;quot;: {
      &amp;quot;css&amp;quot;: &amp;quot;ul#wslb li a&amp;quot;,
      &amp;quot;value&amp;quot;: &amp;quot;normalize-space(@href)&amp;quot;
    },
    &amp;quot;title&amp;quot;: {
      &amp;quot;css&amp;quot;: &amp;quot;ul#wslb li a&amp;quot;,
      &amp;quot;value&amp;quot;: &amp;quot;@title&amp;quot;
    },
    &amp;quot;author&amp;quot;: {
      &amp;quot;css&amp;quot;: &amp;quot;ul#wslb li div.center&amp;quot;,
      &amp;quot;value&amp;quot;: &amp;quot;normalize-space(.)&amp;quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;注意修改&lt;code&gt;data_from_event&lt;/code&gt;的值，其他地方与爬取普通网站一样。再新建并配置一下 Output Agent，RSS 的链接就出来了&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207726.png&#34; alt=&#34;image-20220508205856407&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;使用-phantomjs-为动态页面生成-rss&#34;&gt;使用 PhantomJS 为动态页面生成 RSS&lt;/h2&gt;

&lt;p&gt;首先需要到&lt;a href=&#34;https://phantomjscloud.com&#34;&gt;Phantom Js Cloud 的官网&lt;/a&gt;注册一个账户，每个账户官方提供了一定的免费额度，每天大概可以爬取 500 个页面，对于做 RSS 来说妥妥的够用了。注册之后可以得到一个 API KEY，这个待会会使用到。&lt;/p&gt;

&lt;p&gt;接下来新建一个 Phantom JS Cloud Agent，填写基本的名称、API KEY 和目标 URL，render type 选择 html。底下 User Agent 建议改用真实的浏览器 UA，减少触发反爬虫的可能性。如果不知道自己的 UA 可以到这个网站查看当前浏览器的 UA，复制字符串即可。如果懒得查也可以用这个&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.81 Safari/537.36
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;h6 id=&#34;phantom-js-cloud-agent&#34;&gt;Phantom JS Cloud Agent&lt;/h6&gt;

&lt;p&gt;This Agent generates PhantomJs Cloud URLs that can be used to render JavaScript-heavy webpages for content extraction.&lt;/p&gt;

&lt;p&gt;URLs generated by this Agent are formulated in accordance with the PhantomJs Cloud API. The generated URLs can then be supplied to a Website Agent to fetch and parse the content. Sign up to get an api key, and add it in Huginn credentials.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;点击 Dry Run 后会返回一条 url，返回格式类似这样&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;[
  {
    &amp;quot;url&amp;quot;: &amp;quot;https://phantomjscloud.com/api/browser/xxxxxxx&amp;quot;
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后创建一个 WebSite Agent，Source Agent 设置为上面的 Phantom JS Cloud Agent，然后稍微改一下 url 的部分&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;quot;expected_update_period_in_days&amp;quot;: &amp;quot;2&amp;quot;,
  &amp;quot;url_from_event&amp;quot;: &amp;quot;{{url}}&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;html&amp;quot;,
  &amp;quot;mode&amp;quot;: &amp;quot;on_change&amp;quot;,
  &amp;quot;extract&amp;quot;: {...}
}  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;注意将原来的&lt;code&gt;url:??&lt;/code&gt;的部分更改为&lt;code&gt;&amp;quot;url_from_event&amp;quot;: &amp;quot;{{url}}&amp;quot;&lt;/code&gt;,这样就指定使用 Phantom JS Cloud 为我们获取的完整网页，接下来的操作就大同小异了。配置好要爬取的字段和规则后点击 Dry Run 就可以看到结果&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207727.png&#34; alt=&#34;image-20220508215636780&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这里是刚才的 Agent 产生的一个 Event。这里除了 url 和 title 我还提取了 date 字段。在 Output Agent 中，可以配置为每一条文章输出发布时间的信息。对于这种规整的日期字母串，可以使用&lt;code&gt;{{ date | date: %F }}&lt;/code&gt;进行解析并格式化输出为 rss 规范的时间格式如果没有配置的话，每篇文章的发布时间显示的都是一样的，为 Huginn 爬虫更新的时间。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;&amp;quot;item&amp;quot;: {
      &amp;quot;title&amp;quot;: &amp;quot;{{title}}&amp;quot;,
      &amp;quot;link&amp;quot;: &amp;quot;{{url}}&amp;quot;,
      &amp;quot;pubDate&amp;quot;: &amp;quot;{{ date | date: %F }}&amp;quot;
    },
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tips:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Huginn 解析日期&lt;/p&gt;

&lt;p&gt;注意&lt;code&gt;{{ date | date: %F }}&lt;/code&gt;里面，第一个&lt;code&gt;date&lt;/code&gt;是上面的 Website Agent 产生的 Event 里面的变量名，第二个&lt;code&gt;date&lt;/code&gt;是 Huginn 使用的 Liquid 模版引擎语法里内置的一个 filter，可以理解为有特定功能的函数&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205082207637.png&#34; alt=&#34;image-20220508220438696&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;faq&#34;&gt;FAQ&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;为什么启动 docker 容器后访问 Huginn 显示网络错误？&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Huignn 冷启动较慢，需要等待三五分钟。如果还是不行，检查端口映射和防火墙设置&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;为什么抓取到的包含相对路径的结果，网页上可以点击访问，但是生成的 RSS 不能正常使用？&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;检查 link 的设置，有些网站只是域名，有些网站有子目录，具体查看该网页源码中 head 节点里 base url 的设置&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;如何对爬取到的某一项的字符串做更高级更复杂的处理？&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;可以参考&lt;a href=&#34;https://github.com/huginn/huginn/wiki/Formatting-Events-using-Liquid&#34;&gt;Hugnn 官方对 Liquid 语法的文档&lt;/a&gt;以及&lt;a href=&#34;https://shopify.dev/api/liquid&#34;&gt;Shopify 官方关于 Liquid 模板的语法文档&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;为什么部署了 Huginn，等了很长时间都无法访问后台页面？&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;若部署后某个应用一直无法通过浏览器访问，请检查是否绑定到了 &lt;sup&gt;6000&lt;/sup&gt;&amp;frasl;&lt;sub&gt;6666&lt;/sub&gt; 等特殊端口，浏览器会拦截对这些端口的访问参见&lt;a href=&#34;https://blog.colinx.one/posts/docker-compose%E7%9A%84%E9%94%99%E8%AF%AF%E4%BD%BF%E7%94%A8%E5%A7%BF%E5%8A%BF/&#34;&gt;这里&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Huginn 爬虫访问目标网站被拦截了怎么解决&lt;/strong&gt;&lt;br /&gt;
介绍几个基本的反反爬虫策略：

&lt;ol&gt;
&lt;li&gt;带上 User Agent，要求是真实的浏览器 UA。&lt;/li&gt;
&lt;li&gt;Browserless 去掉默认会和请求一起发送的可以被识别为爬虫的特征参数，设置 browserless 的环境变量&lt;code&gt;DEFAULT_HEADLESS=false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用随机代理 IP，适用于因爬取频率达到爬虫阈值&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;扩展阅读&#34;&gt;扩展阅读&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/huginn/huginn/wiki/&#34;&gt;Huginn 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://shopify.dev/api/liquid/filters/&#34;&gt;Liquid 模板引擎语法官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.colinx.one/posts/rssmanx%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/&#34;&gt;RSS Man X 部署指南&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.colinx.one/posts/docker-compose%E7%9A%84%E9%94%99%E8%AF%AF%E4%BD%BF%E7%94%A8%E5%A7%BF%E5%8A%BF/&#34;&gt;docker compose 的错误使用姿势&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

        
        </description>
    </item>
    
    <item>
      <title>RSSManX 安装部署指南</title>
      <link>/posts/rssmanx%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/</link>
      <pubDate>Sat, 07 May 2022 00:00:00 +0000</pubDate>
      
      <guid>/posts/rssmanx%E5%AE%89%E8%A3%85%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # RSSManX 安装部署指南 --&gt;

&lt;p&gt;RSS Man X 是我两年前入坑 RSS 后，为了方便更多人更方便地使用 RSS 所发起的一个项目，主要是用 docker-compose 整合了一些常用的服务如 TTRSS、RSSHub、Huginn、OpenCC 等并进行了一些优化调整，如自动更新，反反爬虫等。这篇文章会尽可能详尽地讲解安装部署的步骤以及安装过程中可能会遇到的一些问题。&lt;/p&gt;

&lt;p&gt;RSS Man X 会利用到 docker 和 docker-compose，首先需要确保你的服务器正确安装了这些软件&lt;/p&gt;

&lt;h2 id=&#34;1-docker-环境准备&#34;&gt;1. Docker 环境准备&lt;/h2&gt;

&lt;p&gt;检查服务器中是否已经安装了 docker 和 docker-compose，并检查他们的版本是否太老。比如输入&lt;code&gt;docker --version&lt;/code&gt;来检查 docker 的版本&lt;/p&gt;

&lt;p&gt;docker 的版本建议不要低于 19，docker-compose 的版本建议不要低于 1.20&lt;br /&gt;
(注：Docker 新版本可使用&lt;code&gt;docker compose&lt;/code&gt; 替代 &lt;code&gt;docker-compose&lt;/code&gt;)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~ » docker --version
Docker version 20.10.12, build 20.10.12-0ubuntu2~20.04.1
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~ » docker-compose --version
docker-compose version 1.25.0, build unknown
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果上面命令执行后提示&lt;code&gt;command not found&lt;/code&gt;，那么说明并没有安装对应的软件包（或是安装的路径并不在当前用户的 PATH 变量中，尝试切换到 root 操作，详细的原因和解决方法见后文）&lt;/p&gt;

&lt;h3 id=&#34;1-1-ubuntu-debian-安装-docker&#34;&gt;1.1 Ubuntu/Debian 安装 Docker&lt;/h3&gt;

&lt;p&gt;ubuntu 和 debian 主要是用 apt 安装和管理软件包，可以使用以下命令来安装，根据实际情况选择是否要加 sudo。下面以 Ubuntu 为例。Debian 下的安装略有不同，可以参见&lt;a href=&#34;https://docs.docker.com/engine/install/debian/&#34;&gt;Docker 官方文档&lt;/a&gt;，以及&lt;a href=&#34;https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/&#34;&gt;清华镜像源&lt;/a&gt;。其中&lt;code&gt;download.docker.com&lt;/code&gt;连接不同的可以尝试讲域名部分更换为&lt;a href=&#34;https://mirrors.ustc.edu.cn/help/docker-ce.html&#34;&gt;中科大提供的镜像&lt;/a&gt;地址&lt;code&gt;mirrors.ustc.edu.cn/docker-ce&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;# 首先移除老旧的软件包
sudo apt-get remove docker docker-engine docker.io containerd runc

sudo apt-get update
# 安装一些必要的依赖
sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果你的服务器在墙外，可以直接使用 docker 官方的软件源&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

echo \
  &amp;quot;deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable&amp;quot; | sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果你的服务器在墙内，可以使用由中科大提供的镜像&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

echo \
  &amp;quot;deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \
  $(lsb_release -cs) stable&amp;quot; | sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;导入 docker 软件源后即可开始安装 docker，安装完成后可以输入&lt;code&gt;docker --version&lt;/code&gt;来检查 docker 的版本&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;1-2-centos-fedora-安装-docker&#34;&gt;1.2 CentOS/Fedora 安装 Docker&lt;/h3&gt;

&lt;p&gt;CentOS 和 Fedora 使用 yum 安装和管理软件包，新版本则是使用 dnf，不过两者功能一致且高度兼容。下面以 CentOS 为例，Fedora 可参见&lt;a href=&#34;https://docs.docker.com/engine/install/fedora/&#34;&gt;官方文档&lt;/a&gt;或&lt;a href=&#34;https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/&#34;&gt;清华镜像源&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;# 1. 首先移除老旧的软件包

sudo yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-latest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine
# 2.
sudo yum install -y yum-utils

# 3.A 之后使用官方docker软件库
sudo yum-config-manager \
   --add-repo \
   https://download.docker.com/linux/centos/docker-ce.repo

# 3.B 墙内方案
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo sed -i &#39;s+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+&#39; /etc/yum.repos.d/docker-ce.repo


# 4. 即可开始安装
sudo yum update
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;1-3-安装或更新-docker-compose&#34;&gt;1.3 安装或更新 docker-compose&lt;/h3&gt;

&lt;p&gt;docker-compose 目前有两个主要版本 V1 和 V2，都是可用的。V1 使用 Python 编写，使用时类似&lt;code&gt;sudo docker-compose up -d&lt;/code&gt;，V2 则是 Golang 编写，与前者高度兼容，但是是作为 docker 的插件安装的，使用时类似&lt;code&gt;sudo docker compose up -d&lt;/code&gt;，中间的短杠不需要了。&lt;/p&gt;

&lt;p&gt;如果是按照上文的步骤安装的 docker，那么默认已经安装了 docker compose v2，可以通过&lt;code&gt;docker compose version&lt;/code&gt;查看版本&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;~ » docker compose version
Docker Compose version v2.3.3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果需要是安装的比较老的 v1 版本的 docker-compose，想要单纯更新 docker-compose 而又不想动其他东西的话，可以更新安装 v1 版本的 docker-compose。&lt;/p&gt;

&lt;p&gt;首先删除老旧版本（如果有的话）&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;rm $DOCKER_CONFIG/cli-plugins/docker-compose
sudo rm /usr/local/lib/docker/cli-plugins/docker-compose
pip uninstall docker-compose
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然后使用 pip 来安装&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;pip3 install docker-compose
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;墙内也可以临时使用镜像源下载&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果提示 pip 命令不存在需要先安装一下&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;# Ubuntu/Debian
sudo apt install python3-pip

# CentOS/Fedora
sudo yum install python3-pip
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果 pip 报错试着升级一下 pip 的版本&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade pip
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;1-4-为-docker-配置镜像源&#34;&gt;1.4 为 Docker 配置镜像源&lt;/h3&gt;

&lt;p&gt;如果 Docker 下载镜像非常慢，你可能需要单独配置一下 Docker 的镜像源。==&lt;strong&gt;注意：Docker 安装软件源的镜像和 Docker 镜像或者说映像的国内源并不是同一个，英文表述可能更准确一些：&lt;/strong&gt;==&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;上文安装 docker 时配置的是 docker 的 repo，repo 里含有 docker 的软件包，&lt;a href=&#34;https://mirrors.ustc.edu.cn/help/docker-ce.html&#34;&gt;国内的镜像&lt;/a&gt;为 Docker CE 安装软件包的镜像&lt;/li&gt;
&lt;li&gt;现在我们要配置的是 Docker Hub 的 Mirror，Docker 里拉取 Image 默认会访问&lt;a href=&#34;https://hub.docker.com&#34;&gt;Docker Hub&lt;/a&gt;，国内有多个 Docker Hub 镜像或是 Docker 镜像加速器，如&lt;a href=&#34;https://mirrors.ustc.edu.cn/help/dockerhub.html&#34;&gt;中科大的源&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在&lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;文件中写入以下内容，如不存在可先行创建，注意 json 中列表的最后一项末尾是没有逗号的&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;quot;registry-mirrors&amp;quot;: [
    &amp;quot;https://hub-mirror.c.163.com&amp;quot;,
    &amp;quot;https://mirror.baidubce.com&amp;quot;,
    &amp;quot;https://docker.nju.edu.cn&amp;quot;,
    &amp;quot;https://docker.mirrors.sjtug.sjtu.edu.cn&amp;quot;,
    &amp;quot;https://dockerproxy.com&amp;quot;,
    &amp;quot;https://docker.m.daocloud.io&amp;quot;
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;update 20230720: 部分镜像源不再可用，更新镜像源配置。参考 &lt;a href=&#34;https://gist.github.com/y0ngb1n/7e8f16af3242c7815e7ca2f0833d3ea6&#34;&gt;https://gist.github.com/y0ngb1n/7e8f16af3242c7815e7ca2f0833d3ea6&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;配置完成后&lt;code&gt;sudo systemctl restart docker&lt;/code&gt;重启 docker 服务，然后输入&lt;code&gt;sudo docker info&lt;/code&gt;，在输出结果的末尾可以看到&lt;code&gt;Registry Mirrors&lt;/code&gt;里会出现我们刚刚配置的 Docker Hub 镜像&lt;/p&gt;

&lt;p&gt;群辉等 NAS 的系统并不是标准版 Linux，安装的也是魔改版 docker，上面的配置文件地址并不适用，建议自行搜索对应的文档或教程。&lt;/p&gt;

&lt;h2 id=&#34;2-安装-rss-man-x&#34;&gt;2. 安装 RSS Man X&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/Colin-XKL/RSSmanX&#34;&gt;RSS MAN X 项目&lt;/a&gt;旨在为 RSS 的同好提供一个方便地搭建自己的 RSS 服务的捷径，毕竟不是所有 RSS 爱好者都懂代码 😂。RSS Man X 能够有 RSS 订阅管理、RSS 在线阅读界面，进阶功能包括服务健康自检、海外站点 RSS 解锁等，提供不同的版本供选择，三个版本的 &lt;code&gt;docker-compose&lt;/code&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;th&gt;Lite 版&lt;/th&gt;
&lt;th&gt;Ultimate 版 ✨&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TTRSS&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;RSSHub&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;Huginn&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;Mercury&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;OpenCC&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;Redis&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;Browserless&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;/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;/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;/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;/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;/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;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&#34;2-1-安装流程&#34;&gt;2.1 安装流程&lt;/h3&gt;

&lt;p&gt;安装好了 &lt;code&gt;docker&lt;/code&gt; 和 &lt;code&gt;docker-compose&lt;/code&gt; 后，可以使用&lt;code&gt;git clone https://github.com/Colin-XKL/RSSmanX --depth=1&lt;/code&gt;快速克隆本仓库，也可以通过&lt;a href=&#34;https://archive.fastgit.org/Colin-XKL/RSSmanX/archive/refs/heads/master.zip&#34;&gt;这个镜像地址&lt;/a&gt;下载仓库 zip 文件，&lt;a href=&#34;https://gitee.com/colin-xkl/RSSmanX&#34;&gt;Gitee 上也有镜像&lt;/a&gt;不过不经常更新。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cd 进入文件夹，修改&lt;code&gt;.env&lt;/code&gt;中的值，如密码和 TTRSS 入口 URL 等&lt;/li&gt;
&lt;li&gt;运行 &lt;code&gt;sudo docker-compose up -d&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;等待程序跑完&lt;/li&gt;
&lt;li&gt;安装完成 ✅&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;2-2-相关事宜&#34;&gt;2.2 相关事宜&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;访问你设置的 &lt;code&gt;SELF_URL&lt;/code&gt; 即可看到 Tiny Tiny RSS 的登陆页面，使用默认账户 &lt;code&gt;admin&lt;/code&gt;，密码 &lt;code&gt;password&lt;/code&gt; 登陆即可开始使用&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;如开启海外站点解锁支持，第一次冷启动需要等待 3-5 分钟才能完全启动所有组件。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;数据默认保存位置&lt;code&gt;~/.docker/Database&lt;/code&gt;（注意以执行 docker 命令的用户为准，如使用 root 账户执行，则文件位于 root 用户 home 目录）&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;默认情况下只有 TTRSS 和 Huginn 可以从外部访问，其他组件互相可以访问但不能直接从外部访问以提高安全性。组件间互相访问可以使用&lt;code&gt;容器名+指定端口&lt;/code&gt;，端口默认为 80，如&lt;code&gt;http://rsshub/xxxxx&lt;/code&gt;即可访问到 RSS Man X 内的监听 80 端口的 rsshub 实例。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;在 TTRSS 中将原来订阅的 &lt;code&gt;https://rsshub.app/*&lt;/code&gt; 更改为 &lt;code&gt;http://rsshub/*&lt;/code&gt; 即可使用 RSS Man X 内的自建 RSSHub 实例，并激活反反爬虫和海外源加速等功能&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;如无法访问 rsshub 的官方文档站点，可以使用我维护的反代站点&lt;a href=&#34;https://rsshub-doc.azure.colinx.one/&#34;&gt;https://rsshub-doc.azure.colinx.one/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;关于 ARM 平台的支持可查阅&lt;a href=&#34;https://github.com/Colin-XKL/RSSmanX/issues/5&#34;&gt;置顶的 issue&lt;/a&gt;，替换部分不支持 arm 架构的 docker 镜像为支持 arm 的镜像即可。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;RSS Man X 的除 lite 以外的版本默认包含了自托管的 mercury 实例，你只需要在插件配置页面设置 mercury 实例地址为 &lt;code&gt;service.mercury:3000&lt;/code&gt; 即可，同理，OpenCC 实例地址为&lt;code&gt;service.opencc:3000&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;如果部分 RSS 源不能订阅，检查是否使用了非常规端口。在&lt;code&gt;.env&lt;/code&gt;文件中设置&lt;code&gt;RSS_ALLOW_PORTS&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;若部署后某个应用一直无法通过浏览器访问，请检查是否绑定到了&lt;code&gt;6000&lt;/code&gt;/&lt;code&gt;6666&lt;/code&gt;等特殊端口，浏览器会拦截对这些端口的访问参见&lt;a href=&#34;https://blog.colinx.one/posts/docker-compose%E7%9A%84%E9%94%99%E8%AF%AF%E4%BD%BF%E7%94%A8%E5%A7%BF%E5%8A%BF/&#34;&gt;这里&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;ls&lt;/code&gt;没有显示&lt;code&gt;.env&lt;/code&gt;文件是因为以点开头的文件在 Linux 中都是默认隐藏的，可以使用&lt;code&gt;ls -a&lt;/code&gt;查看到&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;vi/vim 编辑文本太麻烦可以尝试使用 nano&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;RSS Man 里所有容器绑定了服务器的/etc/localtime，使用&lt;code&gt;sudo timedatectl set-timezone Asia/Shanghai&lt;/code&gt; 设定系统的时区为上海后，容器里的时区也可以同步，这样日志里的时间就是东八区了&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;获取帮助&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;For Tiny tiny RSS problems:&lt;/strong&gt;
&lt;a href=&#34;https://tt-rss.org/wiki.php&#34;&gt;https://tt-rss.org/wiki.php&lt;/a&gt;
&lt;a href=&#34;http://ttrss.henry.wang/&#34;&gt;http://ttrss.henry.wang/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For RSSHub problems:&lt;/strong&gt;
&lt;a href=&#34;https://docs.rsshub.app/faq.html&#34;&gt;https://docs.rsshub.app/faq.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For Huginn problems:&lt;/strong&gt;
&lt;a href=&#34;https://github.com/huginn/huginn#readme&#34;&gt;https://github.com/huginn/huginn#readme&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;2-3-链接&#34;&gt;2.3 链接&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.colinx.one/posts/%E6%88%91%E7%9A%84rss%E6%96%B9%E6%A1%88%E4%B8%8E%E5%BF%83%E5%BE%97/&#34;&gt;我的 RSS 方案与心得&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Colin-XKL/RSSmanX&#34;&gt;RSS Man X GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.colinx.one/posts/huginn%E6%8C%87%E5%8D%97%E4%B8%BA%E4%BB%BB%E6%84%8F%E7%BD%91%E7%AB%99%E5%88%B6%E4%BD%9Crss/&#34;&gt;Huginn 指南：为任意网站制作 RSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.colinx.one/posts/docker-compose%E7%9A%84%E9%94%99%E8%AF%AF%E4%BD%BF%E7%94%A8%E5%A7%BF%E5%8A%BF/&#34;&gt;docker compose 的错误使用姿势&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

        
        </description>
    </item>
    
    <item>
      <title>前端静态资源加载的一些优化</title>
      <link>/posts/%E5%89%8D%E7%AB%AF%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E5%8A%A0%E8%BD%BD%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BC%98%E5%8C%96/</link>
      <pubDate>Fri, 06 May 2022 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E5%89%8D%E7%AB%AF%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E5%8A%A0%E8%BD%BD%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BC%98%E5%8C%96/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # 前端静态资源加载的一些优化 --&gt;

&lt;p&gt;最近在折腾优化博客，由于全站都是部署在 Netlify、Vercel 的 CDN 上，都是海外节点，国内访问延迟高，在想办法优化下访问速度和体验。线路部分的优化可以看另一篇文章&lt;a href=&#34;https://blog.colinx.one/posts/%E5%9B%BD%E5%A4%96%E9%9D%99%E6%80%81%E7%BD%91%E7%AB%99%E6%89%98%E7%AE%A1%E5%9C%A8%E5%9B%BD%E5%86%85%E9%80%9F%E5%BA%A6%E5%AF%B9%E6%AF%94%E5%8F%8A%E7%BA%BF%E8%B7%AF%E4%BC%98%E5%8C%96/&#34;&gt;国外静态网站托管服务商国内速度对比及线路优化&lt;/a&gt;。这篇文章来探讨下前端 CSS 和 JS 资源的加载。&lt;/p&gt;

&lt;p&gt;优化目标主要就两个：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;尽可能快，但是不希望我引入的辅助性第三方库影响到页面体验，不要阻塞主要内容渲染&lt;/li&gt;
&lt;li&gt;为了快第三方静态资源肯定是上 CDN，但是要有容灾，CDN 挂了要能 fallback 到其他 url&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;静态资源异步加载&#34;&gt;静态资源异步加载&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;prefetch&lt;/code&gt;、&lt;code&gt;preload&lt;/code&gt;这些预加载技术暂且不谈，博客站点没那么多资源。这里主要是用&lt;code&gt;async&lt;/code&gt;和&lt;code&gt;defer&lt;/code&gt;来控制脚本异步加载，以避免阻塞 DOM 解析和页面渲染。&lt;/p&gt;

&lt;p&gt;使用&lt;code&gt;async&lt;/code&gt;异步加载，对于&lt;a href=&#34;https://github.com/vinta/pangu.js/&#34;&gt;pangu&lt;/a&gt;这种会影响到内容呈现的使用&lt;code&gt;async&lt;/code&gt;，对于统计类第三方库使用&lt;code&gt;defer&lt;/code&gt;延迟加载，到 DOM 加载完再执行&lt;/p&gt;

&lt;p&gt;有些第三方库需要手动 init，这样就不能使用&lt;code&gt;defer&lt;/code&gt;、&lt;code&gt;async&lt;/code&gt;关键字加载资源了，&lt;strong&gt;&lt;code&gt;defer&lt;/code&gt;和&lt;code&gt;async&lt;/code&gt;关键字只适用于远程资源&lt;/strong&gt;，本以为把远程资源的&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;和内嵌在 HTML 里用来 init 的&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;都加上&lt;code&gt;defer&lt;/code&gt;就可以利用它顺序加载的特性解决这个问题，结果发现不是这样的。。。。异步打乱脚本执行顺序，init 脚本不等待资源下载完毕会先执行。利用好&lt;code&gt;onload&lt;/code&gt;事件可以解决这个问题。&lt;/p&gt;

&lt;p&gt;before&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;script src=&amp;quot;https://cdn.jsdelivr.net/npm/pangu@4/dist/browser/pangu.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
    pangu.spacingElementByClassName(&#39;post&#39;);
    pangu.spacingElementByTagName(&#39;p&#39;);

    document.addEventListener(&#39;DOMContentLoaded&#39;, () =&amp;gt; {
        pangu.autoSpacingPage();
    });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;after&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;script&amp;gt;
    function panguSpaing() {
        pangu.spacingElementByClassName(&#39;post&#39;);
        pangu.spacingElementByTagName(&#39;p&#39;);

        document.addEventListener(&#39;DOMContentLoaded&#39;, () =&amp;gt; {
            // listen to any DOM change and automatically perform spacing via MutationObserver()
            pangu.autoSpacingPage();
        });
    }
&amp;lt;/script&amp;gt;
&amp;lt;script async onload=&amp;quot;panguSpaing()&amp;quot; src=&amp;quot;https://cdn.jsdelivr.net/npm/pangu@4/dist/browser/pangu.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;除了&lt;code&gt;onload&lt;/code&gt;还有&lt;code&gt;onerror&lt;/code&gt;，还可以利用&lt;code&gt;onerror&lt;/code&gt;事件在资源加载失败时 fallback 到其他 CDN，详见下文&lt;/p&gt;

&lt;p&gt;这里跑了个测试看下优化前后的差距&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;优化前&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205062117479.png&#34; alt=&#34;image-20220506193639029&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205062117127.png&#34; alt=&#34;image-20220506193800266&#34; /&gt;&lt;/p&gt;

&lt;p&gt;First Contentful Pain Time 在 1.5s，整个页面到 1.5s 才能可见，DOM 加载总时间达到了 2.5s&lt;/p&gt;

&lt;p&gt;本来我都已经把首页不需要加载的三方库都拿走了，但是还剩下一个，这个用于前端性能监控的 js 阻塞了渲染，挂的是腾讯云的 CDN，国内快到飞起，国外就卡到不行（作为对比上图里从 jsdelivr 加载的 js 也是快到飞起，墙内就慢得一批）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;优化后&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205062117498.png&#34; alt=&#34;image-20220506193652188&#34; /&gt;&lt;/p&gt;

&lt;p&gt;优化后页面没有再阻塞，0.8s 页面就可用了，总 DOM 加载时间只有 1.5s，相较之前简直直接起飞。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205071426038.png&#34; alt=&#34;cn&#34; /&gt;&lt;/p&gt;

&lt;p&gt;国内某检测平台的结果也显示优化效果明显&lt;/p&gt;

&lt;h2 id=&#34;静态资源-fallback-加载&#34;&gt;静态资源 Fallback 加载&lt;/h2&gt;

&lt;p&gt;国内好用的静态资源 CDN 还真没有，新浪那种只提供那么几个热门的库完全不符合需求，BootCDN 炸了不是一次两次，字节 CDN 的资源 URL 有够 ugly，URL 里面还带节点信息多半后面会出问题。360 奇舞 CDN 之前也换过域名、备案出问题，感觉每一个能省心用。七牛的目前看上去还行，也不知道后面会不会出什么幺蛾子。。。为了稳妥起见 + 照顾全球的访客，还是优先使用的 cloudflare 和 jsdelivr 的 CDN&lt;/p&gt;

&lt;p&gt;网站主要三方库都是通过 jsdelivr 和 cloudflare 引入的，但是毕竟是海外的节点不知道哪一天就被墙了，所以还要为墙内的访客准备一个 fallback 方案。这里利用到&lt;code&gt;script&lt;/code&gt;标签的&lt;code&gt;onerror&lt;/code&gt;事件&lt;/p&gt;

&lt;p&gt;现代浏览器都支持&lt;code&gt;script&lt;/code&gt;和&lt;code&gt;link&lt;/code&gt;标签上的&lt;code&gt;onload&lt;/code&gt;和&lt;code&gt;onerror&lt;/code&gt;事件，详细支持情况可以查看这里&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://pie.gd/test/script-link-events/&#34;&gt;https://pie.gd/test/script-link-events/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;关于&lt;code&gt;onerror&lt;/code&gt;，中文互联网上有好几篇文章说他会捕获&lt;code&gt;script&lt;/code&gt;标签里的代码的执行错误。。。简直离谱。稍微查下 MDN 之类的文档就可以发现这玩意本来就是只捕获资源加载错误的&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The onerror event is triggered if an error occurs while loading an external file (e.g. a document or an image).&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://www.w3schools.com/jsref/event_onerror.asp&#34;&gt;https://www.w3schools.com/jsref/event_onerror.asp&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;利用好这个特性，就可以实现在资源加载失败时 fallback 从另一个 url 加载资源。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;script&amp;gt;
    function fallbackJSloader(url, loadedEvent) {
        console.log(&#39;Error loading asset, using fallback url&#39;);
        console.log(&#39;load asset from&#39;, url);

        let script = document.createElement(&amp;quot;script&amp;quot;);
        script.type = &amp;quot;text/javascript&amp;quot;;
        script.src = url;
        script.async = true;
        if (loadedEvent)
            script.setAttribute(&#39;onload&#39;, `${loadedEvent}()`)
        document.body.appendChild(script);
    }
&amp;lt;/script&amp;gt;

&amp;lt;script defer onload=&amp;quot;init_gitalk()&amp;quot;
onerror=&amp;quot;fallbackJSloader(&#39;https://cdn.staticfile.org/gitalk/1.7.2/gitalk.min.js&#39;,&#39;init_gitalk&#39;)&amp;quot;
src=&amp;quot;https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js&amp;quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;CSS 的 fallback 加载同理，此处不再赘述&lt;/p&gt;

&lt;p&gt;优化后如图，在开发者工具中手动 block 资源网站，可以自动 fallback 从另一个 url 加载资源，这下网站的可用性又提升了一点点🤏哈哈哈&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205062133393.png&#34; alt=&#34;66230832-3581-42DF-9F2F-B817E88DAF4D&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;扩展阅读&#34;&gt;扩展阅读&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.w3cplus.com/performance/remove-block-rendering.html&#34;&gt;消除阻塞页面渲染的资源&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://segmentfault.com/q/1010000000640869&#34;&gt;defer 和 async 的区别&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://lengyun.github.io/js/3-2-2dynamicAddCSS.html#%E4%B8%8E%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BDjs%E7%9A%84%E5%8C%BA%E5%88%AB&#34;&gt;动态加载 css&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;网站 profile&lt;/strong&gt;工具&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.webpagetest.org&#34;&gt;https://www.webpagetest.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

        
        </description>
    </item>
    
    <item>
      <title>国外静态网站托管服务商国内速度对比及线路优化</title>
      <link>/posts/%E5%9B%BD%E5%A4%96%E9%9D%99%E6%80%81%E7%BD%91%E7%AB%99%E6%89%98%E7%AE%A1%E5%9C%A8%E5%9B%BD%E5%86%85%E9%80%9F%E5%BA%A6%E5%AF%B9%E6%AF%94%E5%8F%8A%E7%BA%BF%E8%B7%AF%E4%BC%98%E5%8C%96/</link>
      <pubDate>Thu, 05 May 2022 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E5%9B%BD%E5%A4%96%E9%9D%99%E6%80%81%E7%BD%91%E7%AB%99%E6%89%98%E7%AE%A1%E5%9C%A8%E5%9B%BD%E5%86%85%E9%80%9F%E5%BA%A6%E5%AF%B9%E6%AF%94%E5%8F%8A%E7%BA%BF%E8%B7%AF%E4%BC%98%E5%8C%96/</guid>
      <description>
        
          
          
          
        
        
        

&lt;h1 id=&#34;国外静态网站托管服务商国内速度对比及线路优化&#34;&gt;国外静态网站托管服务商国内速度对比及线路优化&lt;/h1&gt;

&lt;p&gt;本文主要探讨 Netlify、Vercel、Cloudflare Pages、Azure Web Hosting 在国内的速度对比及线路优化&lt;/p&gt;

&lt;p&gt;以我的博客站点 blog.colinx.one 为例，使用 hugo 构建，选用的模板也很轻量没有太多奇奇怪怪的第三方组件，使用这些静态服务托管主要图个方便，不用备案而且基本流量不限。&lt;/p&gt;

&lt;p&gt;分别挂了四个服务商的 CI, 每次更新 Git 仓库都会自动触发构建。分别对四个默认分配的域名进行检测。&lt;/p&gt;

&lt;h2 id=&#34;四家服务商默认设置国内速度测试对比&#34;&gt;四家服务商默认设置国内速度测试对比&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Netlify&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://colins-blog.netlify.app&#34;&gt;colins-blog.netlify.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20220505191719.png&#34; alt=&#34;Netlify 在国内的速度检测&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vercel&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://colinx-blog.vercel.app&#34;&gt;colinx-blog.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20220505191728.png&#34; alt=&#34;Vercel 在国内的速度检测&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Azure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://nice-glacier-095b09e00.1.azurestaticapps.net&#34;&gt;nice-glacier-095b09e00.1.azurestaticapps.net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20220505191733.png&#34; alt=&#34;Azure 在国内的速度检测&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CloudFlare Pages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://colinx-blog.pages.dev&#34;&gt;colinx-blog.pages.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20220505191738.png&#34; alt=&#34;Cloudflare Pages 在国内的速度检测&#34; /&gt;&lt;/p&gt;

&lt;p&gt;emmm Cloudflare 这在国内的速度可太拉胯了，虽说可以通过自选节点的方式曲线救国，但想了想还是算了。利用好其他三家的节点应该足够国内大部分用户访问。&lt;/p&gt;

&lt;p&gt;&amp;mdash;Update on 2022-05-22&amp;mdash;&lt;/p&gt;

&lt;p&gt;又重新测了一下 cloudflare 的速度，这次倒是一片绿，看来还是要运气，不太稳定。电信和联通都嗖嗖的，移动基本上全挂了。。。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/202205221906656.png&#34; alt=&#34;image-20220522190417139&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这次能连接的节点主要就两个 172.66.45.34 和 172.66.46.222。&lt;/p&gt;

&lt;p&gt;&amp;mdash;end&amp;mdash;&lt;/p&gt;

&lt;p&gt;筛选后可用的节点&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Netlify
18.140.226.100 amazon SG
54.255.56.197 amazon SG
206.189.46.168 digital ocean SG

Vercel
显示caronet，据说为AWS节点 (76.76.21.21 Anycast)
76.76.21.241
76.76.21.98
76.76.21.93
76.76.21.142
76.76.21.22
76.76.21.61
76.76.21.164

Azure
52.175.64.109 US MS
13.70.37.114 HK MS
51.124.12.35 UK
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;优化前&#34;&gt;优化前&lt;/h2&gt;

&lt;p&gt;优化前使用了 dnspod 的解析服务做 4 个 A 记录的负载均衡，免费版套餐单记录单线路只能设置最多两个负载均衡记录，我这个是之前开通专业版套餐设置的，套餐到期了原有记录依旧保留，所以能设置四条同线路 A 记录负载均衡。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;before

206.189.46.168  digital ocean %netlify
76.223.126.88 %vercel
18.140.226.100 amazon  %netlify
18.139.201.98 amazon %netlify 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;检测一波，红了好几个省份&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20220505191745.png&#34; alt=&#34;image-20220504222718997&#34; /&gt;&lt;/p&gt;

&lt;p&gt;慢点可以接受，线路不通可不能忍。之前粗略筛的几个节点，如今过了快两年了，线路估计也发生了变化，简单跑了一下这几条，发现这个线路现在的状况实在不咋地&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20220505191749.png&#34; alt=&#34;trace&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这圈子兜的也太大了些。。。哦原来是 Digital Ocean 的节点啊，那没事了。&lt;/p&gt;

&lt;p&gt;亚马逊的节点稍微好些，没有绕道日本这么离谱的行为&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20220505191834.png&#34; alt=&#34;trace&#34; /&gt;&lt;/p&gt;

&lt;p&gt;再来看看 vercel 节点的表现&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20220505191933.png&#34; alt=&#34;trace2&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这里是自选的节点，直连东京节点，好评&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20220505192022.png&#34; alt=&#34;trace3&#34; /&gt;&lt;/p&gt;

&lt;p&gt;但是默认的 AnyCast 节点这个路由就稍微绕路了，看来大中华区还是得自己动手调整下线路&lt;/p&gt;

&lt;h2 id=&#34;优化后&#34;&gt;优化后&lt;/h2&gt;

&lt;p&gt;after&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20220505192417.png&#34; alt=&#34;image-20220505190011635&#34; /&gt;&lt;/p&gt;

&lt;p&gt;检测优化过程就不赘述了，都是拿几个基本的工具&lt;code&gt;ping&lt;/code&gt;、&lt;code&gt;tcping&lt;/code&gt;、&lt;code&gt;httping&lt;/code&gt;、&lt;code&gt;traceroute&lt;/code&gt;还有上文的全国网速检测网站对那几个节点挨个检测，直接上结论：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vercel 的 Anycast 基本上都是路由到日本，但是同一个地方可能会被路由到不同的路线，比如有些 IP 从上海出口转日本东京，有些是从广东出口转日本&lt;/li&gt;
&lt;li&gt;Netlify 的节点主要是在新加坡，提供商有 AWS 和 Digital Ocean，实测后者的节点经常性抽风，国内流量过去会绕个大圈子，还是 AWS 的靠谱些&lt;/li&gt;
&lt;li&gt;Azure 的静态网页托管服务现在是免费的，带宽和流量啥的妥妥够用，不过开账户有门槛，我是用 Github Education Pack 在 Azure 开了个 Azure for Students 订阅，每年 100 刀额度，到期可续&lt;/li&gt;
&lt;li&gt;Azure 能用的就香港节点，其他都是去往北美和欧洲的，直接 pass。对电信友好，移动和联通很不友好，饶了一大圈&lt;/li&gt;
&lt;li&gt;AWS 的节点对移动和联通挺友好，对电信支持略差&lt;/li&gt;
&lt;li&gt;Vercel 节点也是对移动和联通友好些&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;其他附加信息&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Netlify 可自定义证书，Vercel 不可以。所以要保证 vercel 的服务器可以把域名解析到自家服务器，不然没法续签 SSL 证书&lt;/li&gt;
&lt;li&gt;Cloudflare 的 CI 啥的做的挺垃圾，起步晚，很多东西不完善&lt;/li&gt;
&lt;li&gt;Netlify 可以安装插件，推送 sitemap 和网站安全性检测这些我感觉挺好使&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;最终线路设置&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;电信和其他走 Azure 与 Vercel&lt;/li&gt;
&lt;li&gt;移动联通走 Netlify 的 AWS 节点，以及 Vercel 在 JP 的节点&lt;/li&gt;
&lt;li&gt;海外走 Vercel 的 Anycast IP&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;常用线路检测与优化工具链接&#34;&gt;常用线路检测与优化工具链接&lt;/h2&gt;

&lt;p&gt;Best Trace&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://apps.apple.com/us/app/best-trace/id1037779758?l=zh&#34;&gt;https://apps.apple.com/us/app/best-trace/id1037779758?l=zh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;IP 批量查询&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://www.jsons.cn/ipbatch/&#34;&gt;http://www.jsons.cn/ipbatch/&lt;/a&gt;&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>我的 RSS 方案与心得</title>
      <link>/posts/%E6%88%91%E7%9A%84rss%E6%96%B9%E6%A1%88%E4%B8%8E%E5%BF%83%E5%BE%97/</link>
      <pubDate>Mon, 10 May 2021 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E6%88%91%E7%9A%84rss%E6%96%B9%E6%A1%88%E4%B8%8E%E5%BF%83%E5%BE%97/</guid>
      <description>
        
          &lt;img src=&#34;https://www.gethow.org/wp-content/uploads/2013/07/feed-297x140.jpg&#34;/&gt;
          
        
        
        

&lt;!-- # 我的 RSS 方案与心得 --&gt;

&lt;p&gt;使用 RSS 已经一年有余，这种对信息的主动掌握让我获取信息的质量和密度都上升了一个台阶。最早是使用 TTRSS 做服务端，安卓手机使用 &lt;a href=&#34;https://github.com/seazon/FeedMe&#34;&gt;FeedMe&lt;/a&gt; 订阅，主要订阅的是有源的商业内容站点、个人博客以及其他人分享的使用 Feed43 或 Feedburner 压制的源。随着我逐渐加大 RSS 阅读在我闲暇、琐碎时间内的比重，我对 RSS 有了更高的期望和要求，便开始了对如何构建更高效、更易用的 RSS 方案的探索。&lt;/p&gt;

&lt;h2 id=&#34;0x01-借助-rsshub-订阅各种热门冷门网站&#34;&gt;0x01 借助 RSSHub 订阅各种热门冷门网站&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://docs.rsshub.app/&#34;&gt;RSSHub&lt;/a&gt; 是个很赞的项目，它聚集了众多 RSS 爱好者来为现代的网站构建 RSS 订阅源。众所周知，网站提供 RSS 并不能为他的站点带来更高的收入，反而会减少主站的访客数。借助 RSSHub 可以方便地通过 RSS 订阅知乎、豆瓣、Facebook 等现代媒体社交平台。&lt;/p&gt;

&lt;h2 id=&#34;0x02-获取-feed-文章全文&#34;&gt;0x02 获取 Feed 文章全文&lt;/h2&gt;

&lt;p&gt;部分 RSS 源并不会在 xml 文件内提供文章全文，说白了是想让你点进他们的网站去浏览，这样网页上的广告才有可能被你点击。解决的方案有很多，方便起见我使用了 TTRSS 的插件 Readability 和 Mercury。两者都不能完美适配所有站点，同时启用这两者以实现互补。&lt;/p&gt;

&lt;h2 id=&#34;0x03-无障碍阅读繁体中文-feed&#34;&gt;0x03 无障碍阅读繁体中文 Feed&lt;/h2&gt;

&lt;p&gt;发现了几个质量不错的繁体中文信息源，主要是台湾的站点，如泛科学。由于文字和部分两岸文化差异，直接阅读繁体中文的文章有些困难。我的解决方案是使用 OpenCC 简繁转换服务，它能够对可映射的简繁汉字以及同一事物的两岸不同的表述进行翻译，输出的简体中文版文章基本可以无障碍阅读。Awesome-TTRSS 内有集成相应的插件和服务程序。&lt;/p&gt;

&lt;p&gt;不过原作者是使用 node.js 编写的服务端，翻译数据库得不到及时更新，如翻译后还是写的是&lt;code&gt;义大利&lt;/code&gt;而不是&lt;code&gt;意大利&lt;/code&gt;。而且 docker image 体积 100+M，内存占用也较大。我在考虑用 Go 语言重写 OpenCC 的服务端并兼容 TTRSS 的 OpenCC 插件，并加入 CI 自动从上游同步翻译数据库。&lt;/p&gt;

&lt;h2 id=&#34;0x04-为不支持-rss-的网站自制源&#34;&gt;0x04 为不支持 RSS 的网站自制源&lt;/h2&gt;

&lt;p&gt;繁茂如 RSSHub 也不能保证拥有所有站点的 RSS 源。对于自制源，网上的方案大多数为使用 Feed43 和 Feedburner，但是人家是商业服务，虽然使用确实方便，但说到底还是为了商业。白嫖用户限制多不说，天知道哪天会有 break change 或者直接被墙或者跑路。最稳妥的做法还是自建。&lt;/p&gt;

&lt;p&gt;手写爬虫程序简单灵活，不过后期维护难度较高而且难以复用。对于我想要订阅而有没有现成的源的网站，我的解决方案主要是两个：&lt;/p&gt;

&lt;h3 id=&#34;1-为-rsshub-编写目标站点的规则-并-pull-request-申请合并&#34;&gt;1. 为 RSSHub 编写目标站点的规则，并 Pull Request 申请合并&lt;/h3&gt;

&lt;p&gt;RSSHub 除了提供众多现成的各类站点的 RSS 规则之外，也提供了快速构建一个站点的 RSS 源的常用工具类和模板。需要对 JavaScript 和爬虫技术有一定了解。很荣幸能提交了几个 pr 并且已经合并进了主分支，如 CQUT 的教务处通知和&lt;a href=&#34;https://docs.rsshub.app/social-media.html#zhi-hu-yong-hu-wen-zhang&#34;&gt;知乎的用户文章列表&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&#34;2-使用-huginn-为目标站点自制源&#34;&gt;2. 使用 Huginn 为目标站点自制源&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/huginn/huginn&#34;&gt;Huginn&lt;/a&gt; 是一个强大的 &lt;a href=&#34;https://sspai.com/post/25270#!&#34;&gt;IFTTT&lt;/a&gt; 应用，用它来生成 RSS 源简直是大材小用（主要是他动辄 200M 的内存占用）。不过某些情况下我需要监视特定站点并在内容变化时得到通知，个人向为主，这类就不适合写 RSSHub 的规则。&lt;/p&gt;

&lt;p&gt;使用门槛比 RSSHub 略低，可视化界面还是比较友好的，不过新手上手还是会有点困难，了解了 Huginn 的工作原理和基本的 Liquid 语法之后就手到擒来了。&lt;/p&gt;

&lt;h3 id=&#34;3-使用-feed43-和-rss-proxy-这类可视化工具自助生成-rss-链接&#34;&gt;3. 使用 feed43 和 rss-proxy 这类可视化工具自助生成 RSS 链接&lt;/h3&gt;

&lt;p&gt;手写解析规则还是太麻烦，很多网页结构很简单根本没必要单独花时间写一堆解析规则，而且有些时候只是想临时订阅一段时间或是订阅个很小的网站，不想大费周章，选择 feed43 这类工具不失为一个轻量又便捷的选择。不过&lt;a href=&#34;https://feed43.com/&#34;&gt;feed43&lt;/a&gt;对免费账户创建的 RSS 并不保证稳定，时常无法连接甚至直接失效。在 Github 上发现一个不错的替代品&lt;a href=&#34;https://github.com/damoeb/rss-proxy/&#34;&gt;rss-proxy&lt;/a&gt;，一个可视化的，快速自助生成站点 RSS 链接的工具。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://cdn.jsdelivr.net/gh/damoeb/rss-proxy/docs/rssproxy-candidates.png&#34; alt=&#34;rss-proxy screenshot&#34; /&gt;&lt;/p&gt;

&lt;p&gt;填入目标网址就可以自动解析目标网页，程序会自动检测网页上的列表内容，可以自己选择要订阅哪个列表，然后就可以生成一个 RSS 链接。生成的 RSS 链接包括的信息有目标网址、要订阅的目标列表的节点信息和输出格式（RSS/ATOM）等，也就是说，rss-proxy 并不像 feed43 会把解析的规则存储在服务端，它是直接编码在 url 里面的！rss-proxy 开源支持自部署，不想用它提供的公用实例也可以自建，迁移零门槛。rss-proxy 也支持调用无头浏览器渲染异步获取数据的网页，可玩性很高。&lt;/p&gt;

&lt;p&gt;-&amp;gt;&amp;gt;&amp;gt;&amp;gt; &lt;a href=&#34;https://rssproxy-v1.migor.org/&#34;&gt;rss-proxy 公用实例&lt;/a&gt;，可以点击体验下，还是很方便的&lt;/p&gt;

&lt;p&gt;使用了一段时间体验挺不错，有个小问题就是对 UTF-8 以外的编码不太友好。&lt;/p&gt;

&lt;h2 id=&#34;0x05-解锁海外-rss-源&#34;&gt;0x05 解锁海外 RSS 源&lt;/h2&gt;

&lt;p&gt;由于众所周知的原因，我国的互联网是不「互联」的。rsshub.app 部署在国外，现已基本无法直接访问。国内服务器上自建的 RSSHub 订阅如 Facebook 等国外站点更是不可行。为此我使用了 Clash 代理，并添加了一些公开的机场订阅，虽然速度和稳定性不是很高，但对于 RSS 这种需求还是绰绰有余的。又完善了一些爬墙的规则，比如对 google、facebook，rsshub.app 走代理，内网地址和 CN 的 IP 直连，反爬严格的网站完全走随机节点。一番操作下来，基本可以实现全球 RSS 订阅自由了 😁&lt;/p&gt;

&lt;h2 id=&#34;0x06-rss-订阅破-cloudflare-五秒盾&#34;&gt;0x06 RSS 订阅破 CloudFlare 五秒盾&lt;/h2&gt;

&lt;p&gt;如上所述，海外 RSS 源走公用机场可以解决国内的网络问题。但是很多站点会使用 CloudFlare 做 CDN 和防火墙，我们使用的公用机场其实一大半都是被用作非法用途的，IP 很多都在人家的黑名单里面，但凡通过那个节点访问 CloudFlare 保护的网站都会触发五秒盾防御，浏览器访问倒是没什么，但是可苦了 RSS。&lt;/p&gt;

&lt;p&gt;google 了一番，没人写过我这个问题。。。人家都是爬虫绕过五秒盾，调包实现的破解。不过好在最终还是有了可行的解决方案：&lt;strong&gt;Clash 识别 CloudFlare 节点 IP 段，对于他家的节点，使用 Round-Robin 算法的 Load-Balance 策略走海内外随机节点，包括本机直连。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;上面一句话有三个技术要点：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;识别 CF 节点&lt;/strong&gt;：CF 的节点遍布全球，把 IP 列表加到 Clash 规则集里面肯定是不现实的。不过好在人家家大业大都是买的 IP 段，官网也给出了所有节点的 IP 段，也就十个左右。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Round-Robin&lt;/strong&gt;：一种常见的负载均衡算法，简单来说就是把所有节点组成一个圆环，每次访问选择一个环上的节点，之后沿环方向移动一个特定步长，作为下一个要使用的节点，每次访问所使用的节点都不一样。另一种常用的算法是 Consist-Hashing，一致性哈希，相同的 url 拥有相同的哈希值，根据哈希值来选择的节点是一样的，同一个 url 会使用同一个节点。对于上文提到的场景，要实现反反爬虫，那必须选择 Round-Robin 算法。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;包括本机节点&lt;/strong&gt;：如上文所述，触发五秒盾的原因是那些公用机场的 IP 都不大干净，但是我用来部署 RSS 这些东西的自用的服务器没有这个问题，只有网络问题 😂。使用本机作为随机节点的兜底，即便特殊情况下所有的公共机场都是脏 IP，但是本机能直连东亚和美西的 CF 节点，还是可以保证 RSS 的可用性。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;可能的改进：匹配到 CF 节点，选择从本机连接东亚的连接较好的 CF 节点来请求目标站点的内容，可以一次解决那两个问题&lt;/p&gt;

&lt;p&gt;以上都被我整合进了我的 Github 项目 &lt;a href=&#34;https://github.com/Colin-XKL/RSSmanX&#34;&gt;RSSman X&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/Colin-XKL/RSSmanX&#34;&gt;RSSman X&lt;/a&gt; 基于 docker-compsoe 提供容器化 TTRSS 与 RSSHUB 等组件的一键部署，整合实用组件为你带来最佳 RSS 体验&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feature：简单一键部署，常用组件整合，自动更新支持，服务健康自检支持，海外站点 RSS 解锁&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210512190819.png&#34; alt=&#34;image-20210512190732383&#34; /&gt;&lt;/p&gt;

&lt;p&gt;感兴趣的朋友可以关注一下 🍺&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>RSSManX - 一套 RSS 综合解决方案</title>
      <link>/posts/rssmanx/</link>
      <pubDate>Sat, 08 May 2021 00:00:00 +0000</pubDate>
      
      <guid>/posts/rssmanx/</guid>
      <description>
        
          
          
          
        
        
        

&lt;p&gt;&lt;img src=&#34;https://cdn.jsdelivr.net/gh/Colin-XKL/RSSmanX/.github/logo.png&#34; alt=&#34;logo&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://img.shields.io/github/license/Colin-XKL/RSSmanX&#34; alt=&#34;license&#34; /&gt;&lt;br /&gt;
&lt;img src=&#34;https://img.shields.io/github/v/release/Colin-XKL/RSSmanX&#34; alt=&#34;release&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/Colin-XKL/RSSmanX/blob/master/README-zh_cn.md&#34;&gt;中文说明&lt;/a&gt; ｜ &lt;a href=&#34;https://github.com/Colin-XKL/RSSmanX/&#34;&gt;English&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RSSman X is a project that composed several useful services to help you build an excellent RSS experience.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/Colin-XKL/RSSmanX&#34;&gt;RSSman X&lt;/a&gt; 基于 docker-compsoe 提供容器化 TTRSS 与 RSSHUB 等组件的一键部署，整合实用组件为你带来最佳 RSS 体验&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feature：简单一键部署，常用组件支持，自动更新支持，服务健康自检支持，海外站点 RSS 解锁&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&#34;快速开始&#34;&gt;快速开始&lt;/h3&gt;

&lt;p&gt;(若已安装 &lt;code&gt;docker&lt;/code&gt; 和 &lt;code&gt;docker-compose&lt;/code&gt;)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;mkdir RSSmanX &amp;amp;&amp;amp; cd $_ &amp;amp;&amp;amp; wget https://cdn.jsdelivr.net/gh/Colin-XKL/RSSmanX/docker-compose.yml &amp;amp;&amp;amp; sudo docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;说明&#34;&gt;说明&lt;/h2&gt;

&lt;p&gt;本项目旨在为 RSS 的同好提供一个方便地搭建自己的 RSS 服务的捷径。毕竟不是所有 RSS 爱好者都懂代码 😂。如果你想快速地搭建自己的 RSS 服务，能够有 RSS 订阅管理、RSS 在线阅读界面，进阶功能包括服务健康自检、海外站点 RSS 解锁等。希望订阅国内外的各大网站的 RSS 信息源又不想跟着网上漫天飞的教程瞎折腾的话，那么你可以使用本仓库的脚本快速完成安装部署。&lt;/p&gt;

&lt;h3 id=&#34;不同版本中包含的组件说明&#34;&gt;不同版本中包含的组件说明&lt;/h3&gt;

&lt;p&gt;三个版本的&lt;code&gt;docker-compose&lt;/code&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;th&gt;Lite 版&lt;/th&gt;
&lt;th&gt;Ultimate 版 ✨&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TTRSS&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;RSSHub&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;Huginn&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;Mercury&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;OpenCC&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;Redis&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;Browserless&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;/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;/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;/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;/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;/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;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;不同组件的功能描述见文末。不同版本对应的配置文件如下：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;标准版&lt;/strong&gt;：&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lite 版&lt;/strong&gt;：&lt;code&gt;docker-compose-lite.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ultimate 版&lt;/strong&gt;：&lt;code&gt;docker-compose-ultimate.yml&lt;/code&gt;和&lt;code&gt;config.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;选择对应版本下载到本地后都 compose 文件需要重命名为标准的&lt;code&gt;docker-compose.yml&lt;/code&gt;才可使用&lt;/p&gt;

&lt;h2 id=&#34;安装说明&#34;&gt;安装说明&lt;/h2&gt;

&lt;h3 id=&#34;需求&#34;&gt;需求&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;一台 Linux 系统的服务器&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;本文以腾讯云 Ubuntu 18.04 系统的服务器为例，其他云服务商的没差，系统为 CentOS 的会有点差异&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;依赖项&#34;&gt;依赖项&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;docker&lt;/li&gt;
&lt;li&gt;docker-compose&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;安装 Docker&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;sudo apt-get update

sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo
sudo add-apt-repository \
   &amp;quot;deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable&amp;quot;
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;安装 docker-compose&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;sudo apt install docker-compose
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;完整文档参见 📕&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/engine/install/&#34;&gt;https://docs.docker.com/engine/install/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/compose/install/&#34;&gt;https://docs.docker.com/compose/install/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;如何安装&#34;&gt;如何安装&lt;/h3&gt;

&lt;p&gt;安装好了 &lt;code&gt;docker&lt;/code&gt; 和 &lt;code&gt;docker-compose&lt;/code&gt; 后可以执行文章开头的快速开始的指令。或者可以按照下面的步骤手动操作：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;确定安装好了 &lt;code&gt;docker&lt;/code&gt; 和 &lt;code&gt;docker-compose&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;克隆本仓库/下载你所需要的版本的 compose 文件，注意修改文件名&lt;/li&gt;
&lt;li&gt;cd 进入文件夹，编辑&lt;code&gt;docker-compose&lt;/code&gt;文件，修改密码及 ttrss 的&lt;code&gt;SELF_URL&lt;/code&gt;处的值&lt;/li&gt;
&lt;li&gt;运行 &lt;code&gt;sudo docker-compose up -d&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;等待程序跑完&lt;/li&gt;
&lt;li&gt;安装完成 ✅&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&#34;使用相关事宜&#34;&gt;使用相关事宜：&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;访问你设置的&lt;code&gt;SELF_URL&lt;/code&gt;即可看到 Tiny Tiny RSS 的登陆页面，使用默认账户&lt;code&gt;admin&lt;/code&gt;，密码&lt;code&gt;password&lt;/code&gt;登陆即可开始使用。&lt;/li&gt;
&lt;li&gt;如开启海外站点解锁支持，第一次冷启动需要等待 3-5 分钟才能完全启动所有组件。&lt;/li&gt;
&lt;li&gt;数据保存位置 ~/.dockerData/Database/&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;详细配置和使用事宜请参考对应应用的文档说明。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TTRSS 相关文档 &lt;a href=&#34;https://ttrss.henry.wang/&#34;&gt;https://ttrss.henry.wang/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RSSHub 相关文档 &lt;a href=&#34;https://docs.rsshub.app/&#34;&gt;https://docs.rsshub.app/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;功能模块介绍&#34;&gt;功能模块介绍&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Tiny Tiny RSS&lt;/strong&gt;
RSS 订阅管理与在线阅读工具&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RSShub&lt;/strong&gt;
生成国内大部分网站的 RSS 信息源，同时自部署可以访问到那些严格防爬的站点的源（知乎、微博等）&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Huginn&lt;/strong&gt;
高级 IFTTT 工具，你可以用生成任何 RSS 源，但使用门槛略高&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Postgres&lt;/strong&gt;
数据库，用于存储 RSS 文章数据等。比 MySQL 更轻，性能更好&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenCC&lt;/strong&gt;
简繁体转换，如果你订阅了一些繁体的 RSS 源，可以用它来将文章转为简体&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mercury&lt;/strong&gt;
用于获取 RSS 全文&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browserless&lt;/strong&gt;
用于获取常规方式无法获取的网站 RSS，为 RSSHub 的可选组件&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redis&lt;/strong&gt;
提供缓存，提升性能，为 RSSHub 的可选组件&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WatchTower&lt;/strong&gt;
用于自动更新 RSShub 等组件，可以更好地支持新添加的源以及更快的获得 bug 修复&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clash&lt;/strong&gt;
智能路由与正向代理工具，用于解锁海外站点及提供海外 RSS 源的加速&lt;/p&gt;

&lt;h2 id=&#34;acknowledgement&#34;&gt;Acknowledgement&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://tt-rss.org/&#34;&gt;Tiny tiny RSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/BYVoid/OpenCC&#34;&gt;OpenCC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/postlight/mercury-parser&#34;&gt;Mercury&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/huginn/huginn&#34;&gt;Huginn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/DIYgod/RSSHub&#34;&gt;RSShub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/HenryQW/Awesome-TTRSS&#34;&gt;Awesome TTRSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;license&#34;&gt;License&lt;/h2&gt;

&lt;p&gt;GPL-3.0&lt;/p&gt;

&lt;h2 id=&#34;changelogs&#34;&gt;Changelogs&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;2020-07-07 v1.0 First release&lt;/li&gt;
&lt;li&gt;2020-07-14 v1.1 Update quick start shell script&lt;/li&gt;
&lt;li&gt;2020-10-05 v1.2 Fix wrong environment variable.&lt;/li&gt;
&lt;li&gt;2020-11-08 v1.3 TTRSS now can update feeds with ports except &lt;sup&gt;80&lt;/sup&gt;&amp;frasl;&lt;sub&gt;443&lt;/sub&gt;, and our self-hosted rsshub works again.&lt;/li&gt;
&lt;li&gt;2020-11-13 v1.4 Several updates includes security and performance enhancements.&lt;/li&gt;
&lt;li&gt;2020-11-24 v1.5 Lock the docker image version of some services to avoid unexpected errors.&lt;/li&gt;
&lt;li&gt;2021-05-08 v2.0 Add container network isolation, health check, global proxy, smart routing etc.&lt;/li&gt;
&lt;/ul&gt;

        
        </description>
    </item>
    
    <item>
      <title>Flutter 拖动排序列表与跨平台优化实践</title>
      <link>/posts/flutter-%E6%8B%96%E5%8A%A8%E6%8E%92%E5%BA%8F%E5%88%97%E8%A1%A8%E4%B8%8E%E8%B7%A8%E5%B9%B3%E5%8F%B0%E4%BC%98%E5%8C%96%E5%AE%9E%E8%B7%B5/</link>
      <pubDate>Tue, 30 Mar 2021 00:00:00 +0000</pubDate>
      
      <guid>/posts/flutter-%E6%8B%96%E5%8A%A8%E6%8E%92%E5%BA%8F%E5%88%97%E8%A1%A8%E4%B8%8E%E8%B7%A8%E5%B9%B3%E5%8F%B0%E4%BC%98%E5%8C%96%E5%AE%9E%E8%B7%B5/</guid>
      <description>
        
          
          
          
        
        
        &lt;!-- # Flutter 拖动排序列表与跨平台优化实践 --&gt;

&lt;p&gt;Flutter 中实现拖动排序的列表非常简单，使用官方的&lt;code&gt;ReorderableListView&lt;/code&gt;替代原本的&lt;code&gt;ListView&lt;/code&gt;即可，&lt;code&gt;ListView.builder&lt;/code&gt;同理。&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dart&#34;&gt;  return ReorderableListView(
    // padding: const EdgeInsets.symmetric(horizontal: 40),
    children: &amp;lt;Widget&amp;gt;[
      for (int index = 0; index &amp;lt; _items.length; index++)
        ListTile(
          key: Key(&#39;$index&#39;),
          tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
          title: Text(&#39;Item ${_items[index]}&#39;),
        ),
    ],
    onReorder: (int oldIndex, int newIndex) {
      setState(() {
        if (oldIndex &amp;lt; newIndex) {
          newIndex -= 1;
        }
        final int item = _items.removeAt(oldIndex);
        _items.insert(newIndex, item);
      });
    },
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;上面是官方给的 demo，简洁明了。&lt;a href=&#34;https://www.youtube.com/watch?v=yll3SNXvQCw&#34;&gt;官方介绍视频&lt;/a&gt;下面的评论里，人家直呼比原生 Android 写的过瘾的多。阅读文档后我给我的 App 的界面也加上了可拖动排序的功能。效果如下图&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20210330234001.png&#34; alt=&#34;截屏 2021-03-30 23.04.59&#34; /&gt;&lt;/p&gt;

&lt;p&gt;虽然可以实现拖动了，但是右边有一个按钮很碍眼。不过这个是用来控制拖动的，鼠标移上去才能触发拖动。&lt;/p&gt;

&lt;p&gt;翻了翻文档发现，这个地方&lt;code&gt;ReorderableListView&lt;/code&gt;在移动端和桌面端的处理是不一样的，上图（桌面 macos）右边会出现一个 dragHandler，而移动端则是靠长按列表项触发拖动。&lt;/p&gt;

&lt;p&gt;要把这个碍眼的图标去掉，有两个方案：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;找到定义这个图标的地方，更换一个合适的图标，并在外面包裹一层，仅在鼠标 hover 时将图标显示以进行拖动，其他情况下隐藏&lt;/li&gt;
&lt;li&gt;将拖动的实现定义为和移动端相同，即都通过长按列表项触发拖动&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;针对方案一，以&lt;code&gt;ReorderableListView&lt;/code&gt; 和&lt;code&gt;Icon&lt;/code&gt;为关键词搜索，很遗憾的是并没有这方面的资料，又翻了翻源码，并没有找到可以自定义右边这个拖拽按钮的实现。&lt;/p&gt;

&lt;p&gt;在 Flutter 官方的 Github 仓库的 issue 中，&lt;a href=&#34;https://github.com/flutter/flutter/issues/66080#issuecomment-771123430&#34;&gt;https://github.com/flutter/flutter/issues/66080#issuecomment-771123430&lt;/a&gt;   对相关问题做了阐述，并有提案对&lt;code&gt;ReorderableListView&lt;/code&gt;进行了改进。该 issue 对应的 pr 已经被合并到 stable channel，查阅相关 API 后了解到可以使用&lt;code&gt;buildDefaultDragHandles: false&lt;/code&gt;，关闭默认的拖拽触发实现，再使用&lt;code&gt;ReorderableDelayedDragStartListener&lt;/code&gt;包裹原先的&lt;code&gt;ListTile&lt;/code&gt;即可实现桌面端和移动端都通过长按列表项触发拖拽排序。&lt;/p&gt;

&lt;p&gt;不过相应的，ListTile 的&lt;code&gt;onLongPress&lt;/code&gt;就不能再有响应了。刚好今天完成了滑动删除的实现，现在列表也的删除、排序已经高度可用且多平台统一了。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20210330233350.png&#34; alt=&#34;截屏 2021-03-30 23.21.32&#34; /&gt;&lt;/p&gt;

&lt;p&gt;附相关代码实现：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-dart&#34;&gt;body: ReorderableListView.builder(
  buildDefaultDragHandles: false,
  onReorder: (int oldIndex, int newIndex) {
    setState(() {
      if (oldIndex &amp;lt; newIndex) newIndex -= 1;
      var temp = l.removeAt(oldIndex);
      l.insert(newIndex, temp);
    });
  },
  itemCount: l.length,
  itemBuilder: (context, index) {
    final item = l[index];
    return Dismissible(
        key: item.key,
        background: listTileBackground(),
        onDismissed: (direction) {
          setState(() {
            lastDeleted = item;
            l.removeAt(index);
          });
          ScaffoldMessenger.of(context).showSnackBar(msgDeleted);
        },
        child: ReorderableDelayedDragStartListener(
            key: item.key,
            index: index,
            child: ListTile(
              title: Text(item.title),
              subtitle: Text(item.content),
              contentPadding: EdgeInsets.fromLTRB(16, 8, 16, 8),
              onTap: () {
                //your function here
              },
              // onLongPress: () {
              //   lastDeleted = item;
              //   l.removeAt(index);
              //   setState(() {});
              //   ScaffoldMessenger.of(context)
              //       .showSnackBar(msgDeleted);
              // },
            )));
  })));
&lt;/code&gt;&lt;/pre&gt;

        
        </description>
    </item>
    
    <item>
      <title>Colin&#39;s 实验室 - 2021 春</title>
      <link>/posts/colins-%E5%AE%9E%E9%AA%8C%E5%AE%A4-2021%E6%98%A5/</link>
      <pubDate>Thu, 25 Feb 2021 00:00:00 +0000</pubDate>
      
      <guid>/posts/colins-%E5%AE%9E%E9%AA%8C%E5%AE%A4-2021%E6%98%A5/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # Colin&#39;s 实验室  - 2021 春 --&gt;

&lt;blockquote&gt;
&lt;p&gt;小玩具及他们的 demo&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;英语文本智能查词-project-sweeper&#34;&gt;英语文本智能查词（Project Sweeper）&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;自动分割给定的英文文本，提取词元后在数据库中搜索，根据给定的词汇量和难度等级进行筛选，只能提取阅读障碍词汇并高亮当前备考项目（如四级）的重点单词&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20210330233722.jpg&#34; alt=&#34;360 截图 20210206210445677&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;知乎爬虫及-js-逆向&#34;&gt;知乎爬虫及 JS 逆向&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;日常用 RSS 订阅知乎的一些高质量专栏。但由于知乎本事并不支持 RSS，内容大多通过 RSShub 来的，其本质是个爬虫，经常会受到前端页面结构变更的影响。为了应对这个变化，RSShub 中对于知乎相关页面的爬取规则必须得重写。&lt;/p&gt;

&lt;p&gt;分析了一通知乎的页面，发现有个接口可以直接请求，但是会检验 header。header 里面有几项特殊的自定义参数，&lt;code&gt;x-zse-83&lt;/code&gt;  和 &lt;code&gt;x-zse-86&lt;/code&gt;等。为了搞清楚这里面的数值怎么来的，就必须对知乎前端页面资源中的一个 js 文件进行逆向分析。&lt;/p&gt;

&lt;p&gt;逆向折腾了大半天，就快要成功提取核心加密函数的时候，发现知乎的前端页面为了 SEO 有加入一页的文章列表数据，可以直接用上。考虑到逆向的工作量和潜在的法律问题，遂放弃原本的方案。&lt;/p&gt;

&lt;p&gt;新的方案完成后，已向 RSShub 提交 PR 并已被合并。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;mc-服务器搭建与极限优化&#34;&gt;MC 服务器搭建与极限优化&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;1 核 2G 学生机，从 2 人联机频频崩溃到 8 人挖矿毫无压力，学习了 JVM GC 种种，对服务端程序的一些参数也渐渐熟悉。优化效果喜人，总有还能压榨的性能，就像资本家看手下的骡子一样 hhh&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205949.png&#34; alt=&#34;屏幕截图 (12)&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;洞洞板-冰箱贴-cvpro-没想好名字&#34;&gt;洞洞板/冰箱贴/CVPRO/（&amp;hellip;没想好名字）&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;一款跨平台的灵感素材收集与简易管理 App，基于 Flutter 构建，跨平台，颜值在线。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20210330233350.png&#34; alt=&#34;截屏 2021-03-30 23.21.32&#34; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;持续开发中，附 roadmap&lt;/p&gt;

&lt;p&gt;version 1.0&lt;/p&gt;

&lt;p&gt;[x] Text support&lt;br /&gt;
[x] Key shortcut support&lt;br /&gt;
[x] About Page&lt;br /&gt;
[ ] Content editing&lt;br /&gt;
[x] List item dismiss
[x] List Sorting&lt;/p&gt;

&lt;p&gt;Future - Key functions&lt;/p&gt;

&lt;p&gt;[ ] Data Storage&lt;br /&gt;
[ ] Pic support&lt;br /&gt;
[ ] Trashbin&lt;br /&gt;
[ ] File support&lt;br /&gt;
[ ] Multiple List&lt;/p&gt;

&lt;p&gt;Future - Key features&lt;/p&gt;

&lt;p&gt;[ ] Grid view&lt;br /&gt;
[ ] Drag and Drop support&lt;br /&gt;
[ ] Card resize&lt;/p&gt;

&lt;p&gt;Future - Extra&lt;/p&gt;

&lt;p&gt;[ ] Text reformat, delete useless spaces etc.&lt;br /&gt;
[ ] Pic OCR support&lt;br /&gt;
[ ] WebDav support and automatically upload files&amp;lt;10M&lt;/p&gt;
&lt;/blockquote&gt;

        
        </description>
    </item>
    
    <item>
      <title>Minecraft 上云笔记 - MC 自定义皮肤并支持联机</title>
      <link>/posts/minecraft%E4%B8%8A%E4%BA%91%E7%AC%94%E8%AE%B0-mc%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%AE%E8%82%A4%E5%B9%B6%E6%94%AF%E6%8C%81%E8%81%94%E6%9C%BA/</link>
      <pubDate>Mon, 22 Feb 2021 00:00:00 +0000</pubDate>
      
      <guid>/posts/minecraft%E4%B8%8A%E4%BA%91%E7%AC%94%E8%AE%B0-mc%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%AE%E8%82%A4%E5%B9%B6%E6%94%AF%E6%8C%81%E8%81%94%E6%9C%BA/</guid>
      <description>
        
          
          
          
        
        
        &lt;!-- # Minecraft 上云笔记 - MC 自定义皮肤并支持联机 --&gt;

&lt;p&gt;方案概述：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;仪表盘 - 红石皮肤站
&lt;a href=&#34;https://mcskin.cn/user&#34;&gt;https://mcskin.cn/user&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[CSL] 万用皮肤补丁 (CustomSkinLoader) - MC 百科 | 最大的 Minecraft 中文 MOD 百科
&lt;a href=&#34;https://www.mcmod.cn/class/883.html&#34;&gt;https://www.mcmod.cn/class/883.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;全员安装皮肤 mod，即可保证所有人都可以看见对方的皮肤&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;使用：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;安装好 forge&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;安装好皮肤补丁的 mod&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;启动一次 MC，让他自动生成配置文件&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;code&gt;&amp;quot;.minecraft\CustomSkinLoader\CustomSkinLoader.json&amp;quot;&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
 &amp;quot;version&amp;quot;: &amp;quot;14.12&amp;quot;,
 &amp;quot;loadlist&amp;quot;: [
   {
     &amp;quot;name&amp;quot;: &amp;quot;红石皮肤站&amp;quot;,
     &amp;quot;root&amp;quot;: &amp;quot;https://mcskin.cn/csl/&amp;quot;,
     &amp;quot;type&amp;quot;: &amp;quot;CustomSkinAPI&amp;quot;
   },
   {
     &amp;quot;name&amp;quot;: &amp;quot;Mojang&amp;quot;,
     &amp;quot;type&amp;quot;: &amp;quot;MojangAPI&amp;quot;
   },
......
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：&lt;/p&gt;

&lt;p&gt;自定义皮肤站最好排在 Mojang API 的前面，不然的话如果有正版用户起的角色名字和你的一样，就会默认载入他的皮肤（巨坑 +1）&lt;/p&gt;
&lt;/blockquote&gt;

        
        </description>
    </item>
    
    <item>
      <title>Minecraft 上云笔记 - MC 服务器快速搭建&amp;MOD 推荐&amp;性能优化</title>
      <link>/posts/minecraft%E4%B8%8A%E4%BA%91%E7%AC%94%E8%AE%B0-mc%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%BF%AB%E9%80%9F%E6%90%AD%E5%BB%BAmod%E6%8E%A8%E8%8D%90%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/</link>
      <pubDate>Sun, 07 Feb 2021 00:00:00 +0000</pubDate>
      
      <guid>/posts/minecraft%E4%B8%8A%E4%BA%91%E7%AC%94%E8%AE%B0-mc%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%BF%AB%E9%80%9F%E6%90%AD%E5%BB%BAmod%E6%8E%A8%E8%8D%90%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # Minecraft 上云笔记 - MC 服务器快速搭建&amp;MOD 推荐&amp;性能优化 --&gt;

&lt;blockquote&gt;
&lt;p&gt;MC 快速上云，学生机轻松带动，三五好友，畅快联机&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;前言-踩坑&#34;&gt;前言&amp;amp;踩坑&lt;/h2&gt;

&lt;p&gt;距离上一次玩 MC 已有四年之久，上次玩的时候还用的是家里的老爷机，连独显都没有，玩个整合包都费劲。如今设备早已更新换代，B 站不少做 MC 的 UP 主的内容挺有趣，于是尝试重新拾起 MC。&lt;/p&gt;

&lt;p&gt;手机端国内只有网易代理，APP 卡顿严重，生态封闭，体验奇差。安卓下载的国际服倒是还不错，不过身为基岩版，与 Java 版的生态并不相通。Github 上找到了可以让基岩版进 Java 版服务器的轮子，不过手机端连接服务器又是一个麻烦事。连接远程服务器又需要登录 Xbox，但是登上了连接的时候又出现奇怪的问题。&lt;/p&gt;

&lt;p&gt;贴吧有人给出解决方案，搭建 VPN，形成局域网，那样服务器会被视为局域网内开放的 MC 服务端。但天朝政策收紧，搭建 PPTP、L2TP 等隧道均未果，严重怀疑云服务商干扰了对应服务的端口。几番权衡决定投归 PC 端的 Java 版，生态丰富而且可以充分利用好硬件性能。&lt;/p&gt;

&lt;h2 id=&#34;mc-服务器快速搭建&#34;&gt;MC 服务器快速搭建&lt;/h2&gt;

&lt;h3 id=&#34;mc-服务端选择&#34;&gt;MC 服务端选择&lt;/h3&gt;

&lt;p&gt;物色了很多 MC 服务端，但看了下主要可用且被应用广泛的就两类，&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Spigot、PaperSpigot 这类加装插件的&lt;/li&gt;
&lt;li&gt;SpongeForge 这类可以加装 Mod 的&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;前者生态目测更丰富些，MCBBS 上的开服板块大部分都是 PaperSpigot 搭建的。但是好像都是那种几十上百人的公用服务器，什么权限控制、小游戏、防作弊的插件居多，而我只是想要一个能够装 Mod 的可以供三五好友方便联机的服务器。我的选择是后者&lt;/p&gt;

&lt;h3 id=&#34;mc-服务器快速搭建-1&#34;&gt;MC 服务器快速搭建&lt;/h3&gt;

&lt;p&gt;搭建方案千千万，不过 Docker 来的最实在。Github 找到一个非常方便的镜像，&lt;a href=&#34;https://github.com/itzg/docker-minecraft-server&#34;&gt;itzg/minecraft-server&lt;/a&gt;。这个镜像是运行时构建的，会根据指定的环境变量下载和安装对应的 MC 服务端程序。支持的服务端有 Bukkit、Spigot、PaperSpigot、SpongeForge 等等，MC 的版本和各项参数均支持通过环境变量自定义，非常方便。而且可以通过更换不同的 Tag 来使用不同的 JDK 版本，从 8 到 15，Hotspot 和 OpenJ9 都有，可以按需选用。有 arm 版本，树莓派也可食用。&lt;/p&gt;

&lt;p&gt;安装 Docker 和 docker-compose 后，可以方便地编写脚本来快速启动一个 MC 服务器。这里放上我的&lt;code&gt;docker-compose.yml&lt;/code&gt;文件&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;version: &amp;quot;3&amp;quot;
# Forge with Sponge API support. THIS REQUIRES DOWNLOADING SPONGEFORGE.
# Place the SpongeForge jar file in /data/mods. Other Forge mods go here as well.
# Place Sponge mods in /data/mods/plugins. Yes, this is a directory inside the Forge mod directory. Do NOT use /data/plugins.

services:
  minecraft:
    image: itzg/minecraft-server
    container_name: &amp;quot;MCServer&amp;quot;
    ports:
      - &amp;quot;25565:25565&amp;quot;
    volumes:
      - &amp;quot;mc:/data&amp;quot; # 主要数据，包括存档数据等
      - &amp;quot;~/.minecraft/forgemods/:/data/mods/&amp;quot; #Forge Mod 位置
      # - &amp;quot;~/.minecraft/sponegemods/:/data/mods/plugins&amp;quot;
      - &amp;quot;~/.minecraft/tmp/:/tmp&amp;quot; # Forge 下载失败可以自己放进去
      - /etc/timezone:/etc/timezone:ro #绑定本机的时区，方便看日志
    environment:
      SERVER_NAME: &amp;quot;MCServer&amp;quot;
      EULA: &amp;quot;TRUE&amp;quot;
      VERSION: &amp;quot;1.12.2&amp;quot; #(Ensure this is compatbile with the version of SpongeForge you are using!)
      TYPE: &amp;quot;FORGE&amp;quot; # 这里以 SpongeForge 的服务端为例，其他服务端也支持
      FORGEVERSION: &amp;quot;RECOMMENDED&amp;quot;
      # FORGEVERSION: &amp;quot;14.23.5.2854&amp;quot;
      CONSOLE: &amp;quot;false&amp;quot;
      ENABLE_RCON: &amp;quot;true&amp;quot;
      RCON_PASSWORD: &amp;quot;mcserver&amp;quot;
      RCON_PORT: 28016
      INIT_MEMORY: 512M
      MAX_MEMORY: 1536M # 内存根据实际需要修改
      OVERRIDE_SERVER_PROPERTIES: &amp;quot;true&amp;quot; 
      SNOOPER_ENABLED: &amp;quot;false&amp;quot; # 统计数据
      VIEW_DISTANCE: 8 #加载区块范围，默认 10，建议 4~8
      SEED: &amp;quot;-505794890&amp;quot; # 初始生成世界的种子
      PVP: &amp;quot;true&amp;quot;
      ONLINE_MODE: &amp;quot;FALSE&amp;quot; #正版校验开关
      ALLOW_FLIGHT: &amp;quot;FALSE&amp;quot; 
      USE_AIKAR_FLAGS: &amp;quot;false&amp;quot; # 一些优化
      RESOURCE_PACK: &amp;quot;https://blog-1301127393.file.myqcloud.com/MC/Distribution/VNR-1.0.1.zip&amp;quot; # 我自己会用的资源包，这里填 url
      NETWORK_COMPRESSION_THRESHOLD: 512 # 网络优化
    restart: unless-stopped
  rcon:
    image: itzg/rcon  # 服务器远程管理面板，具体使用自行百度
    container_name: &amp;quot;RCON&amp;quot;
    depends_on:
      - minecraft
    ports: #这两个端口都需要防火墙放行
      - &amp;quot;3000:4326&amp;quot; # Web UI
      - &amp;quot;4327:4327&amp;quot; # Connection from Web UI
    volumes:
      - &amp;quot;rcon:/opt/rcon-web-admin/db&amp;quot;
      - /etc/timezone:/etc/timezone:ro
    environment:
      RWA_ENV: &amp;quot;TRUE&amp;quot;
      RWA_ADMIN: &amp;quot;TRUE&amp;quot;
      RWA_PASSWORD: &amp;quot;mcadmin&amp;quot;
      RWA_RCON_HOST: &amp;quot;MCServer&amp;quot;
      RWA_RCON_PASSWORD: &amp;quot;mcserver&amp;quot; # RCON server to control
      RWA_RCON_PORT: 28016
    restart: unless-stopped

volumes:
  mc:
  rcon:

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;环境变量可以设置的地方非常多，可以到项目主页的 README 查看。&lt;a href=&#34;https://github.com/itzg/docker-minecraft-server&#34;&gt;https://github.com/itzg/docker-minecraft-server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose up -d&lt;/code&gt; 启动，第一次启动他会下载 MC、下载 MC 服务端、初始化世界。之后就可以在 MC 客户端连接了。（启动完毕就测试一下，测试没问题再进行后面安装 mod、服务器调优（按需）的步骤！）&lt;/p&gt;

&lt;h2 id=&#34;mc-客户端安装&#34;&gt;MC 客户端安装&lt;/h2&gt;

&lt;h3 id=&#34;mc-启动器选择&#34;&gt;MC 启动器选择&lt;/h3&gt;

&lt;p&gt;（正版玩家略过，现在貌似正版购买的只支持官方启动器）&lt;/p&gt;

&lt;p&gt;对于服务器选择，MCBBS 有一篇讲的挺详细，可以到这里挑选：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;我的世界 Minecraft Java 版 下载指南 | 文件结构说明 | 推荐启动器 - 软件资源 - Minecraft(我的世界) 中文论坛 -
&lt;a href=&#34;https://www.mcbbs.net/forum.php?mod=viewthread&amp;amp;tid=38297&amp;amp;page=1#pid547821&#34;&gt;https://www.mcbbs.net/forum.php?mod=viewthread&amp;amp;tid=38297&amp;amp;page=1#pid547821&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我推荐的启动器：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HMCL&lt;/strong&gt;（力荐！跨平台、颜值高、功能完备，不过需要先装 Java)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BMCL&lt;/strong&gt;（次推荐，颜值略低，基于.Net，功能完备）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我不推荐的启动器：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nsiso&lt;/strong&gt; （页面倒是做的漂亮，但是我装完 mod 启动竟然启动不了，兼容性或者说功能完备性欠缺，不知道后续版本如何。当时出问题之后我换 HMCL 就可以完美启动）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;上一张 HMCL 的主页的图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205913.png&#34; alt=&#34;image-20210129172401421&#34; /&gt;&lt;/p&gt;

&lt;p&gt;其他没有使用过的启动器暂时不予评价。&lt;/p&gt;

&lt;h3 id=&#34;mc-本体安装&#34;&gt;MC 本体安装&lt;/h3&gt;

&lt;p&gt;（正版玩家略过、整合包玩家略过）&lt;/p&gt;

&lt;p&gt;推荐方式为启动器内安装，还可以顺带把 Forge 和 OptiFine 也安装了。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forge：安装第三方 Mod 需要&lt;/li&gt;
&lt;li&gt;OptiFine：游戏显示调优，有些光影会需要。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;版本选择的话，我的选择是 1.12.2。目前 Mod 支持比较完备，生态也很丰富。很多 Mod 最高只支持 1.12.2，目测是后面官方更新了 API 啥的。当然倾向于原版的同学可以选择更新的 1.16，后面的版本有很多有意思的更新。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;踩坑笔记&lt;/strong&gt;：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;这些启动器大多带有三个下载源：官方服务器、MCBBS 镜像和 BMCL 镜像。不过我当时安装的时候 BMCL 的镜像抽风了，下载一直没进度。建议选择 MCBBS 的源（虽然可能部分内容更新没有很勤）&lt;/li&gt;
&lt;li&gt;通过启动器自动安装 OptiFine 的时候一直报错，换版本也是一样。后来的解决方案是选择窗口上方的【从本地文件安装/升级】&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;mod-推荐&#34;&gt;Mod 推荐&lt;/h2&gt;

&lt;p&gt;针对我实际使用和测试的情况做一些推荐。下文所有 Mod 均在 1.12.2 下测试并实际使用过，兼容性良好。&lt;/p&gt;

&lt;h3 id=&#34;功能增强型-mod-客户端必装&#34;&gt;功能增强型 Mod（客户端必装）&lt;/h3&gt;

&lt;p&gt;这部分 Mod 主要是部分音效和部分不涉及多人游戏的功能的增强，可以随意安装，装不装都不影响好友联机与进服务器。&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mod 名称&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DynamicSurroundings&lt;/td&gt;
&lt;td&gt;动态环境音效，比如草地有蟋蟀的声音，夜晚有狼的声音，使游戏很有沉浸感&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;SoundFilters&lt;/td&gt;
&lt;td&gt;环绕音效，使得 MC 里所有的声音更真实，比如矿洞里的脚步声会有回音，房子里面听外面的声音会更小等等&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;BetterHUD&lt;/td&gt;
&lt;td&gt;加强版的 HUD 信息显示，比如方位信息、坐标信息、时间信息、人物护甲、健康状态信息等等很多功能，而且可自定义程度也很高。&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;JEI&lt;/td&gt;
&lt;td&gt;可以方便地查看物品的合成表，一般整合包必备的插件&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;JustEnoughCharacters&lt;/td&gt;
&lt;td&gt;JEI 的扩展，支持按拼音、简拼搜索物品&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Journeymap&lt;/td&gt;
&lt;td&gt;旅行地图，貌似已经停更，但是功能上没有什么欠缺。支持小地图显示、快速传送等。也是一般整合包必备的插件&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;InventoryTweaks&lt;/td&gt;
&lt;td&gt;按 R 键整理背包&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&#34;功能增强型-mod-服务端-客户端都必装&#34;&gt;功能增强型 Mod（服务端&amp;amp;客户端都必装）&lt;/h3&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mod 名称&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FTB-Ultimine&lt;/td&gt;
&lt;td&gt;超级挖掘，挖矿、清理场地好帮手&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Doubledoors&lt;/td&gt;
&lt;td&gt;双开门可以一键开关，不用挨个点击开关啦&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;OpenGlider&lt;/td&gt;
&lt;td&gt;滑翔翼，经济实用的交通工具&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Quark&lt;/td&gt;
&lt;td&gt;对原版 MC 的很多地方进行了一些加强，我最喜欢的是他增加了纸墙和纸灯笼这类物品，可以建造一些日系的建筑（文末有图）&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;KeepingInventory&lt;/td&gt;
&lt;td&gt;死亡不掉落，不解释，小白福音&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&#34;内容增强型-mod-服务端-客户端都必装&#34;&gt;内容增强型 Mod（服务端&amp;amp;客户端都必装）&lt;/h3&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mod 名称&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Natura&lt;/td&gt;
&lt;td&gt;添加了很多有意思的植物，整个世界变得生机勃勃，可以种樱花树，初期没食物还可以野外采蓝莓吃&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;MrCrayfish`s Vehicle Mod&lt;/td&gt;
&lt;td&gt;载具 Mod，可以在 MC 开车哦&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Animania&lt;/td&gt;
&lt;td&gt;动物谷，更多的小动物、更加真实的动物喂养与繁殖&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Twilightforest&lt;/td&gt;
&lt;td&gt;鼎鼎有名的暮色森林，不解释&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&#34;谨慎选用的-mod&#34;&gt;谨慎选用的 Mod&lt;/h3&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mod 名称&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LootBags&lt;/td&gt;
&lt;td&gt;击杀怪物得到战利品带，随机开出各种物品。不过你的箱子很快就会被一堆奇奇怪怪的东西堆满（比如我有一大箱无用的钻石马铠）&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Cuisine&lt;/td&gt;
&lt;td&gt;中文名烹饪工艺，国人作者开发的 Mod，挺有趣，很好地还原了做菜的过程，做完之后的菜会获得药水一样的效果。不过目测已经停更，而且没有很好的教程&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：上面列举的所有 Mod 都是 Mod 本体，有些 Mod 的功能还依赖于其他 Mod，在安装时必须同时安装 Mod 本体和他依赖的 Mod。具体的依赖关系可以参考 mcmod.cn 上对 Mod 介绍页的 Mod 关系选项卡，CurseForge 的 Mod 介绍页的 Relation 选项卡。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;踩坑笔记&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;R 键整理的快捷键与 JEI 的部分功能冲突，可自行修改快捷键&lt;/li&gt;
&lt;li&gt;R 键整理对烹饪工艺中生产出来的菜品没辙&lt;/li&gt;
&lt;li&gt;推荐仅将 FTB-Ultimine 用于挖泥巴和挖沙，实际使用时可能会出现挖了矿不掉东西的情况┭┮﹏┭┮&lt;/li&gt;
&lt;li&gt;不要用铁镐、钻石镐开 FTB-Ultimine 挖东西！耐久掉的飞快&lt;/li&gt;
&lt;li&gt;DynamicSurroundings 可以在设置里按需屏蔽特定的声音，比如装上后发现我家所在的地形会有乌鸦叫，就很烦。屏蔽之后整个世界都好起来了&lt;/li&gt;
&lt;li&gt;DynamicSurroundings 与 Animania 有 bug，对 Animania 的某些特有生物进行交互时会触发找不到特定媒体资源的 bug，导致游戏崩溃，重新进入又会触发这个 bug，只有在进去的一瞬间用指令将玩家杀死才能勉强逃离这个无尽的循环（血泪的教训）（最新版本已修复）&lt;/li&gt;
&lt;li&gt;Animania 会对每个维度的世界进行注入，比较耗费资源。在同时安装虚无世界 AoA 的情况下，每次服务器启动 Animania 需要对其包含的二十多的世界维度进行注入，严重拖慢启动速度&lt;/li&gt;
&lt;li&gt;Quark 模组对 1.12 的 MC 只有 1.6 版本而没有后续版本的内容更新和 bug 修复。实际使用中有点吃性能&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;mc-服务器优化&#34;&gt;MC 服务器优化&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;我使用的是 SpongeForge，因此只对一些通用的优化手段和原版服务器的一些参数做介绍。使用 Spigot 等的可以参考 MCBBS 的帖子进行更加深入的调优：&lt;/p&gt;

&lt;p&gt;Minecraft 服务器优化教程 —— 让多带 50% 的玩家不再是梦 - 联机教程 - Minecraft(我的世界) 中文论坛
&lt;a href=&#34;https://www.mcbbs.net/forum.php?mod=viewthread&amp;amp;tid=478126&#34;&gt;https://www.mcbbs.net/forum.php?mod=viewthread&amp;amp;tid=478126&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;对于一台长期运行的 MC 服务器，我们需要关注的主要是下面几点&lt;/p&gt;

&lt;h3 id=&#34;1-稳定性&#34;&gt;1. 稳定性&lt;/h3&gt;

&lt;p&gt;要保证服务的稳定，我们需要防范的是&lt;strong&gt;内在的崩溃&lt;/strong&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;尽量使用稳定版的 MC 和稳定版的 Forge&lt;/li&gt;
&lt;li&gt;避免使用评分较低的 Mod&lt;/li&gt;
&lt;li&gt;加载大量 Mod 前先在本地做好测试，避免冲突，同时保障所有依赖项已安装好&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;避免外在影响致 MC 服务器崩溃&lt;/strong&gt;的方法有：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;为 JVM 设置合适的内存限制，避免因&lt;code&gt;OutOfMemory&lt;/code&gt;导致 MC 服务端进程被系统杀掉&lt;/li&gt;
&lt;li&gt;开放的服务器最好限制下权限并封堵一些游戏内的漏洞，避免熊孩子炸服&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;2-可维护性&#34;&gt;2. 可维护性&lt;/h3&gt;

&lt;p&gt;这一项的话其实见仁见智，有些人可能只会开个服务器玩几个星期，有些人会开几年。如果只是短期玩的话麻烦点就麻烦点咯，但是要长期玩的话，注意一下服务器的可维护性后面可以减少很多时间和精力。&lt;/p&gt;

&lt;p&gt;我的建议有以下几点：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;使用 Docker&lt;/strong&gt;。这样可以方便地进行服务的停启与迁移、升级。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用 Docker-Compose&lt;/strong&gt;并保存&lt;code&gt;docker-coompose.yml&lt;/code&gt;文件，这样你可以方便地更改一些参数而不用每次都输入一串长长的&lt;code&gt;docker run&lt;/code&gt;指令。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;经常备份&lt;/strong&gt;。数据无价。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;尽量避免使用已经停止维护的 Mod&lt;/strong&gt;。到时候要是出了奇怪的 Bug，你就只能含泪把这个 Mod 所有相关的内容从你的世界剥离。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;3-响应及时性&#34;&gt;3. 响应及时性&lt;/h3&gt;

&lt;p&gt;响应及时性也体现在几个方面：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU 运算能力够强，复杂的时间（战斗、爆炸）等能很快地处理过来&lt;/li&gt;
&lt;li&gt;存储设备 IO 速度快，服务启动、区块加载可以非常迅速&lt;/li&gt;
&lt;li&gt;网络连接稳定、延迟低，波动小&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;上面三点可以通过堆硬件来实现。不过有没有不辛苦钱包又能提高游戏体验的方法呢？&lt;/p&gt;

&lt;p&gt;自然是有的。我们可以通过修改服务端程序的部分配置来实现。不过本质上是牺牲一小部分游戏体验换取一大部分游戏体验，就看你能忍受的牺牲的部分能有多少咯。&lt;/p&gt;

&lt;p&gt;MC 服务器的优化主要聚焦在两个地方&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;MC 服务端程序的参数优化&lt;/li&gt;
&lt;li&gt;JVM 参数调优&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&#34;mc-服务端优化&#34;&gt;MC 服务端优化&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;VIEW_DISTANCE: 8&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这一项可以更改加载的&lt;strong&gt;区块&lt;/strong&gt;的数量。这个数值越大，就会加载更多的区块，占用的内存和 CPU 就会更多。这个数值过小可能会导致你家的作物不长以及怪物刷不出来，会显著影响游戏体验。减小这一项的数值可以显著减少内存和 CPU 占用。&lt;/p&gt;

&lt;p&gt;默认值 10，建议值 4~8。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：1 个&lt;strong&gt;&lt;em&gt;区块&lt;/em&gt;&lt;/strong&gt;并不是指一个方块，而是指一个&lt;code&gt;16*16&lt;/code&gt;的区域。这个数值对可视区域的影响并不会很大，你可以放心地减小这个数值。这一项的值每减小 1，你的服务器每次就可以少计算​&lt;code&gt;16*16*256&lt;/code&gt;个方块&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;NETWORK_COMPRESSION_THRESHOLD: 512&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这一项的含义是对大于特定大小的数据包进行压缩。压缩会消耗一定量的 CPU 资源，不过可以减缓网络的压力。如果你的网络条件较差，可以减小这一项的数值。&lt;/p&gt;

&lt;p&gt;默认值：256&lt;/p&gt;

&lt;h4 id=&#34;jvm-调优&#34;&gt;JVM 调优&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;首先需要声明的是，我不是 JVM 调参专业户，下文的数据也并不是严格的评测。结论并不严谨，仅仅从一个技术人员的视角出发，结合我实际的使用体验，给出的一些建议，供大家参考。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5 id=&#34;当我们在讨论-jvm-调优时-我们在谈论什么&#34;&gt;当我们在讨论 JVM 调优时，我们在谈论什么？&lt;/h5&gt;

&lt;p&gt;&lt;strong&gt;垃圾回收&lt;/strong&gt;（&lt;strong&gt;G&lt;/strong&gt;arbage &lt;strong&gt;C&lt;/strong&gt;ollection）一直以来都是众多 JVM 调优教程的核心所在。Java 运行于 VM 上，运行过程中不可避免的垃圾回收是最影响应用整体性能的存在。&lt;/p&gt;

&lt;p&gt;这里我们不去纠结那些新生代、老年代的划分、各种比率、各种单元的大小，我们只需要明白几点：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;不要觉得你比 JVM 的开发人员牛 X&lt;/li&gt;
&lt;li&gt;不要觉得网上各路 JVM 调参大神的方法就适用于你&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;众多顶级公司都在使用 Java，其母公司 Oracle 自然会招聘全球最优秀的一批开发人员去开发，所以&lt;strong&gt;JVM 的大部分设置都是开箱即用的，默认最佳的。&lt;/strong&gt;在你不了解某一项参数的含义、不知道更改某一项配置的目的时，最好是不要做改动。&lt;/p&gt;

&lt;p&gt;其次，网络上大部分 JVM 的调优教程都是应对“面试造火箭”的，即便是以实际应用为主的 JVM 优化教程，人家那都是几十核几百 G 内存的机器，一秒钟要承担几百万的访问量，他们做优化的出发点、目标都&lt;strong&gt;不一定适用于你。&lt;/strong&gt;&lt;/p&gt;

&lt;h5 id=&#34;明确优化目标&#34;&gt;明确优化目标&lt;/h5&gt;

&lt;p&gt;明确了上面两点我们可以开始着手进行优化了。&lt;/p&gt;

&lt;p&gt;首先需要明确你开 MC 服务器的机器是什么配置。以我的为例，我使用的是腾讯云的&lt;strong&gt;1 核 2G 的云服务器&lt;/strong&gt;，&lt;strong&gt;带宽 2M&lt;/strong&gt;，即峰值速度为 256k/s。&lt;/p&gt;

&lt;p&gt;其次需要知道你的优化目标。网络上大多数 JVM 的优化教程都是追求更低的响应时间，以便能够承载更多的并发访问。&lt;/p&gt;

&lt;p&gt;以我的情况为例：我开这个 MC 服务器的目的，只是希望能够与&lt;strong&gt;不超过 5 个好友&lt;/strong&gt;联机，玩带一些暮色森林这样的&lt;strong&gt;Mod&lt;/strong&gt;的 MC。&lt;/p&gt;

&lt;p&gt;搭建完服务器后，观察了了一段时间后发现，&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;只有在 MC 服务器刚启动的时候 CPU 占用率会达到 100%，空载（没有玩家在线，后台没有高负荷任务）只有 2% 左右，两人联机时 CPU 平均负载在 30% 左右。&lt;/li&gt;
&lt;li&gt;加装了十几个 Mod 的情况下，空载占用 CPU 资源在 1G 左右，两人联机 1.4G 左右。&lt;/li&gt;
&lt;li&gt;只有在客户端刚进入的时候会跑满带宽，之后正常游戏时，每台客户端需要占用 10K/s 左右的带宽。&lt;/li&gt;
&lt;li&gt;联机游戏间或卡顿，但很快恢复&lt;/li&gt;
&lt;li&gt;查看日志发现空载时时竟然仍会&lt;code&gt;can&#39;t keep up&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205922.png&#34; alt=&#34;服务器在空载&#34; /&gt;&lt;/p&gt;

&lt;p&gt;那么以我的情况来看&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU 性能富余&lt;/li&gt;
&lt;li&gt;内存吃紧&lt;/li&gt;
&lt;li&gt;带宽够用&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;那么&lt;strong&gt;我的优化目标&lt;/strong&gt;就是：利用好 CPU 资源，尽力减少内存占用，以便为其他程序让路，并且为未来可能要添加的新 Mod 留出空间。&lt;/p&gt;

&lt;h5 id=&#34;优化&#34;&gt;优化&lt;/h5&gt;

&lt;p&gt;JVM 优化的大头是 GC。网上吹的漫天飞的 G1GC 的确有他的可取之处，一些腐竹的测试数据也表明其实际效果优秀。但是在我的案例中，使用 G1GC 是有问题的：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;G1GC 天生是为了现代互联网应用环境而设计的&lt;/strong&gt;，需要开很多个线程协同来完成垃圾回收工作。他适用于多核处理器 + 大内存机器上的高负荷运算。而我的服务器是单核，内存也并不富裕。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多线程的 GC 模式跑在单核机器上&lt;/strong&gt;时出现的问题就是：单核机器无法并行处理多个任务，其本质上只是在多个任务之间快速切换，来实现各个任务基本“实时”“并行”运行。但是线程之间的切换是有代价的，&lt;strong&gt;性能损耗积少成多&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;G1GC 追求在延迟可控的情况下达到更高的吞吐量&lt;/strong&gt;。但他的&lt;strong&gt;代价是&lt;a href=&#34;https://segmentfault.com/q/1010000021658061&#34;&gt;更多的内存占用&lt;/a&gt;。&lt;/strong&gt;小内存机器并不适合使用 G1GC。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;物色了一番，我最终选择换用 Serial GC 代替原本的 G1GC。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Serial（-XX:+UseSerialGC）&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;从名字我们可以看出，这是一个串行收集器。&lt;/p&gt;

&lt;p&gt;Serial 收集器是 Java 虚拟机中最基本、历史最悠久的收集器。在 JDK1.3 之前是 Java 虚拟机新生代收集器的唯一选择。目前也是 ClientVM、ServerVM 4 核 4GB 以下机器默认垃圾回收器。Serial 收集器并不是只能使用一个 CPU 进行收集，而是当 JVM 需要进行垃圾回收的时候，需暂停所有的用户线程，直到回收结束。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5 id=&#34;优化前后对比&#34;&gt;优化前后对比&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;优化前 MC 服务器的资源占用情况&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205932.jpg&#34; alt=&#34;360 截图 20210129163301881&#34; /&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SERIAL GC (1 ONLINE)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205936.png&#34; alt=&#34;image-20210202194034351&#34; /&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;进一步对 mod 优化后，2 online&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205939.png&#34; alt=&#34;image-20210202221554906&#34; /&gt;&lt;/p&gt;

&lt;h5 id=&#34;其他优化方法&#34;&gt;其他优化方法&lt;/h5&gt;

&lt;p&gt;更换 GC 只是众多优化方法中的一种，其他的诸如换用 OpenJ9 虚拟机也可以有不错的效果，可惜的是 Forge 对其的支持并不友好，只得作罢。还有启用指针压缩也可以获得不错的性能提升，不过 JDK6_u23 之后 &lt;code&gt;UseCompressedOops&lt;/code&gt; 就已经被默认启用了，使用新版本 Java 基本不用关注这方面的优化了。&lt;/p&gt;

&lt;h2 id=&#34;写在最后&#34;&gt;写在最后&lt;/h2&gt;

&lt;p&gt;晒几张图&lt;/p&gt;

&lt;p&gt;我家：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205942.png&#34; alt=&#34;屏幕截图 (13)&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205946.png&#34; alt=&#34;屏幕截图 (16)&#34; /&gt;&lt;/p&gt;

&lt;p&gt;我安装的光影 Sildurs Vibrant Shaders v1.281 High 效果图&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205949.png&#34; alt=&#34;屏幕截图 (12)&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Better HUD + 旅行地图效果图&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205953.png&#34; alt=&#34;屏幕截图 (17)&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;参考-推荐阅读&#34;&gt;参考&amp;amp;推荐阅读&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;大家最推荐用哪种联机方式玩 Minecraft？ - 知乎
&lt;a href=&#34;https://www.zhihu.com/question/54048310&#34;&gt;https://www.zhihu.com/question/54048310&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;View Distance: optimize your Minecraft server
&lt;a href=&#34;https://mtxserv.com/article/12535/view_distance_optimize_your_minecraft_server&#34;&gt;https://mtxserv.com/article/12535/view_distance_optimize_your_minecraft_server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Minecraft 服务器优化教程 —— 让多带 50% 的玩家不再是梦 - 联机教程 - Minecraft(我的世界) 中文论坛
&lt;a href=&#34;https://www.mcbbs.net/forum.php?mod=viewthread&amp;amp;tid=478126&#34;&gt;https://www.mcbbs.net/forum.php?mod=viewthread&amp;amp;tid=478126&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;itzg/docker-minecraft-server: Docker image that provides a Minecraft Server that will automatically download selected version at startup
&lt;a href=&#34;https://github.com/itzg/docker-minecraft-server&#34;&gt;https://github.com/itzg/docker-minecraft-server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;jvm G1 垃圾收集器有什么缺点？ - SegmentFault 思否
&lt;a href=&#34;https://segmentfault.com/q/1010000021658061&#34;&gt;https://segmentfault.com/q/1010000021658061&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

        
        </description>
    </item>
    
    <item>
      <title>JAMStack 初体验 - 基于 Pocket 和 Gatsby 构建你的「网络日志」</title>
      <link>/posts/jamstack%E5%88%9D%E4%BD%93%E9%AA%8C-%E5%9F%BA%E4%BA%8Epocket-%E5%92%8C-gatsby-%E6%9E%84%E5%BB%BA%E4%BD%A0%E7%9A%84%E7%BD%91%E7%BB%9C%E6%97%A5%E5%BF%97/</link>
      <pubDate>Sat, 09 Jan 2021 00:00:00 +0000</pubDate>
      
      <guid>/posts/jamstack%E5%88%9D%E4%BD%93%E9%AA%8C-%E5%9F%BA%E4%BA%8Epocket-%E5%92%8C-gatsby-%E6%9E%84%E5%BB%BA%E4%BD%A0%E7%9A%84%E7%BD%91%E7%BB%9C%E6%97%A5%E5%BF%97/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # JAMStack 初体验 - 基于 Pocket 和 Gatsby 构建你的「网络日志」 --&gt;

&lt;p&gt;折腾了自己的专属 RSS 信息流，每天都能从那些高质量的信息源中获得不少干货知识，一般就会顺手收藏一下。有一天突然想起自己收藏的那些文章，本身不就是经过二次筛选的高质量文章吗？于是便在构想能不能通过某种方式将这个信息源也公开出来，一方面是记录，另一方面也是间接地展示自己。恰逢遇见&lt;strong&gt;JAMStack&lt;/strong&gt;，最近在国外非常火，国内的阿里和腾讯也在跟进，搞静态托管那一套。经多方物色，最终确定基于&lt;code&gt;Pocket API&lt;/code&gt;+&lt;code&gt;Gatsby&lt;/code&gt;来构建这样一个自己的「网络日志」。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are what you read.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;简谈-jamstack&#34;&gt;简谈 JAMStack&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;JAMStack 即基于客户端 &lt;strong&gt;J&lt;/strong&gt;avaScript，可重用 &lt;strong&gt;A&lt;/strong&gt;PI 和预先构建 &lt;strong&gt;M&lt;/strong&gt;arkup 的现代 Web 开发架构。当我们谈论“堆栈”时，我们不再谈论操作系统，特定 Web JAMStack 与特定技术无关。这是一种构建网站和应用程序的新方法，可提供更好的性能，更高的安全性，更低的扩展成本以及更好的开发人员体验。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;JAMStack 是一种新颖的网站架构，与传统的服务端渲染和近些年国内流行的前后端分离等架构不同的是，他的网页是静态的，可以托管在 CDN 上，内容是动态的，可以方便地进行修改。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JAMStack 几个显著的优势&lt;/strong&gt;：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;页面为静态，TTFT（TimeToFirstByte）的时间可以降到非常低&lt;/li&gt;
&lt;li&gt;页面为静态，服务器遭受的安全风险要低得多&lt;/li&gt;
&lt;li&gt;不同于客户端渲染，JAMStack 对 SEO 会非常友好&lt;/li&gt;
&lt;li&gt;不同于传统纯静态网站，内容可以方便地动态更新&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;为什么选择-gatsby&#34;&gt;为什么选择 Gatsby&lt;/h2&gt;

&lt;p&gt;作为一个网站生成器 Site Generator，Gastby 的入门门槛其实是较高的，相对于 Hexo、Hugo 那种简简单单配置下就是一个站点，Gatsby 的难度要更高，因为其灵活度更大，所有的配置、页面都是 Javascript 来配置的，当然你也可以使用 Typescript。其基于 React，生态丰富且灵活度高，天生&lt;code&gt;GarphQL&lt;/code&gt;是选择它的主要原因。&lt;/p&gt;

&lt;h2 id=&#34;网站架构及效果&#34;&gt;网站架构及效果&lt;/h2&gt;

&lt;p&gt;流程：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;我在其他地方看到不错的文章，将其收藏到 Pocket&lt;/li&gt;
&lt;li&gt;定时任务，从&lt;code&gt;Pocket API&lt;/code&gt;获取文章数据，交给 Gatsby 生成站点&lt;/li&gt;
&lt;li&gt;自动部署，将生成的静态文件部署到 CDN&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://reading.colinx.one&#34;&gt;reading.colinx.one&lt;/a&gt;站点主页就会出现我收藏的文章啦&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这其中，Gastby 充当的是&lt;strong&gt;Site Generator&lt;/strong&gt;的角色，而数据来源为我的&lt;code&gt;Pocket API&lt;/code&gt;，也就是我把 Pocket 作为&lt;strong&gt;Headless CMS&lt;/strong&gt;来管理我的数据，可以方便地进行更新和管理。&lt;/p&gt;

&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;

&lt;p&gt;项目已经开源，地址在&lt;a href=&#34;https://github.com/Colin-XKL/Colinx-Reading&#34;&gt;https://github.com/Colin-XKL/Colinx-Reading.git&lt;/a&gt;。你也可以去申请自己的 Pocket API 然后部署你自己的站点。&lt;/p&gt;

&lt;p&gt;初始尝试 JAMStack，感觉对于博客、文档这类的站点会非常友好，国外比较火的像 Shopify 这种的无头电商也不错，国内的碍于国情应该不大可能了。&lt;/p&gt;

&lt;h2 id=&#34;链接&#34;&gt;链接&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Welcome to the Gatsby Way of Building | Gatsby
&lt;a href=&#34;https://www.gatsbyjs.com/docs/&#34;&gt;https://www.gatsbyjs.com/docs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;For fast and secure sites | Jamstack
&lt;a href=&#34;https://jamstack.org/&#34;&gt;https://jamstack.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

        
        </description>
    </item>
    
    <item>
      <title>Win 10 配置 C 语言环境的正确姿势</title>
      <link>/posts/win-10%E9%85%8D%E7%BD%AEc%E8%AF%AD%E8%A8%80%E7%8E%AF%E5%A2%83%E7%9A%84%E6%AD%A3%E7%A1%AE%E5%A7%BF%E5%8A%BF/</link>
      <pubDate>Sun, 27 Dec 2020 00:00:00 +0000</pubDate>
      
      <guid>/posts/win-10%E9%85%8D%E7%BD%AEc%E8%AF%AD%E8%A8%80%E7%8E%AF%E5%A2%83%E7%9A%84%E6%AD%A3%E7%A1%AE%E5%A7%BF%E5%8A%BF/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # Win 10 配置 C 语言环境的正确姿势 --&gt;

&lt;blockquote&gt;
&lt;p&gt;本系列教程旨在为刚入门的编程语言学习者做好指南工作，开始编码，本应很简单&lt;/p&gt;

&lt;p&gt;The PAINLESS way to start coding!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;VC6.0 太古老，Dev C++ 没补全不友好，MinGW 安装太烦恼？&lt;/p&gt;

&lt;p&gt;你用着最新的电脑，最新的系统，却在用着上个世纪的软件开始你人生第一门编程课？&lt;/p&gt;

&lt;p&gt;你需要这篇指南：&lt;strong&gt;在现代化的硬件和平台上使用现代化工具学习 C 语言&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;*aka*：&lt;strong&gt;Win10 配置 C 语言环境的正确姿势&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;截止 2020 年末，Win10 配置 C 语言环境的常见方案有：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;使用 scoop 来便捷地安装所需的环境&lt;/li&gt;
&lt;li&gt;使用 Winget 来安装所需的环境 &lt;em&gt;[不成熟]&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;使用国内镜像 Cygwin+VSCode 配置 C 语言环境【快速】&lt;/li&gt;
&lt;li&gt;使用 WSL+VSCode&lt;/li&gt;
&lt;li&gt;使用 WSL+Clion&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;综合考虑可行性与小白友好性，我们推荐的方案是：&lt;/p&gt;

&lt;h2 id=&#34;使用国内镜像-cygwin-vscode-快速配置-c-语言环境&#34;&gt;使用国内镜像 Cygwin+VSCode 快速配置 C 语言环境&lt;/h2&gt;

&lt;p&gt;C 语言编写的&lt;code&gt;.c&lt;/code&gt;源代码文件需要通过编译器编译生成可执行文件&lt;code&gt;.exe&lt;/code&gt;后才能运行。Windows 系统默认没有自带 C 语言的编译器，这里我们需要手动下载配置才行。&lt;/p&gt;

&lt;p&gt;C 语言编译器在 Win 平台下的选择多种多样，但要么配置麻烦，使用门槛高；要么就是下载源在国外，国内下载慢如龟，甚至直接下不成。这里给出基于国内镜像 Cygwin+VSCode 配置 C 语言环境的方案，&lt;strong&gt;实测可用，步骤清晰易懂，国内网络也可在几分钟内配置好！&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&#34;编译器的下载与配置&#34;&gt;编译器的下载与配置&lt;/h3&gt;

&lt;p&gt;Cygwin 的下载安装分为两个部分：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cygwin 安装程序的下载（～1MB）&lt;/li&gt;
&lt;li&gt;安装器来完整后续的编译器核心部分的安装（～100MB）&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&#34;cygwin-的下载安装&#34;&gt;Cygwin 的下载安装&lt;/h4&gt;

&lt;p&gt;Cygwin 的安装程序可以&lt;a href=&#34;https://cygwin.com/install.html&#34;&gt;从其官方站点下载&lt;/a&gt;。不过站点为全英文且国内访问速度堪忧，这里给出快速下载链接&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cygwin 安装程序&lt;strong&gt;快速下载&lt;/strong&gt;（不限速，免登陆）&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://wws.lanzous.com/iUpUKjojq5i&#34;&gt;https://wws.lanzous.com/iUpUKjojq5i&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;下载完以后，双击打开，进入下图的界面&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164821.png&#34; alt=&#34;image-20201224235413884&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;点击下一步，选择第一项，从网络下载并安装&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164829.png&#34; alt=&#34;image-20201224235436360&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;如果让你选择安装路径的话，可以不用改，不过默认在 C 盘。自己改的话，一个尽量避免使用中文路径，还有一个就是要记住你自己自定义的路径，后面会用到。&lt;/p&gt;

&lt;p&gt;网络好的话，点击下一步会出来一个可用的国内镜像列表，那样的话随便选一个都可以直接进行后面的步骤。&lt;/p&gt;

&lt;p&gt;网络条件不好的情况下，半分钟以内就会报错说网络连接失败。不过不用担心，接下来可以自己填写国内镜像地址。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164833.png&#34; alt=&#34;image-20201224235644342&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在 User URL 的输入框输入&lt;code&gt;https://mirrors.tuna.tsinghua.edu.cn/cygwin/&lt;/code&gt;并点击 Add 添加。之后点击下一步继续。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164836.png&#34; alt=&#34;image-20201224235719679&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;之后会进入一个选择界面。这里选择要安装的组件。我们只需要 C 语言的编译器，这里在搜索框内输入&lt;code&gt;gcc&lt;/code&gt;，然后在下方找到&lt;code&gt;gcc-core&lt;/code&gt;  和   &lt;code&gt;gcc-g++&lt;/code&gt;，点击右侧的三角形打开下拉菜单，选择 9 开头的版本。如下图所示。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164839.png&#34; alt=&#34;image-20201225000518139&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;选择完成后，一路点击下一步安装。如果出现如下的警告信息，直接用默认的设置，点下一步继续就可以了。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164842.png&#34; alt=&#34;image-20201225000604625&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;一般一到两分钟之内就可以下载完毕。如果过了很久还没有装完，要么是网络太垃圾，要么就是不小心勾了其他的软件，一直在安装。。。&lt;/p&gt;

&lt;h4 id=&#34;配置-cygwin&#34;&gt;配置 Cygwin&lt;/h4&gt;

&lt;p&gt;下面要更改环境变量。如果你之前没有自定义安装目录的话，默认路径&lt;code&gt;C:\cygwin64\bin&lt;/code&gt;。否则下文对应的地方使用你自定义的目录。&lt;/p&gt;

&lt;p&gt;在开始菜单中找到&lt;code&gt;Windows系统&lt;/code&gt; - 控制面板。如果这里没有的话，按&lt;code&gt;Windows徽标键&lt;/code&gt;+&lt;code&gt;S&lt;/code&gt;可以呼出搜索面板，可以在此搜索控制面板菜单项。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164856.png&#34; alt=&#34;image-20201227152139118&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在控制面板主页找到系统与安全。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164859.png&#34; alt=&#34;image-20201227152347064&#34; /&gt;&lt;/p&gt;

&lt;p&gt;或者如果你的控制面板打开不是上面的布局而是下面这种布局的话，找到系统菜单。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164903.png&#34; alt=&#34;image-20201227152420458&#34; /&gt;&lt;/p&gt;

&lt;p&gt;进入如下的页面，点击高级系统设置。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164910.png&#34; alt=&#34;image-20201225001127874&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;切换到高级选项卡，点击下方的环境变量菜单&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164913.png&#34; alt=&#34;image-20201225000925342&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在用户变量中，点击&lt;code&gt;Path&lt;/code&gt;，点击下方编辑按钮进行编辑&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164916.png&#34; alt=&#34;image-20201225000949291&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;输入 Cygwin 安装路径下的 bin 目录。如果你之前没有自定义安装路径，直接设置如图即可。否则设置为你自定义的路径。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;注意：这一步只要添加这一个就好&lt;/strong&gt;，不要看我截图里面的很干净，就把其他的都删了&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164919.png&#34; alt=&#34;image-20201225001045854&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;一路点击确定。修改完之后重启下电脑确保改动生效。&lt;/p&gt;

&lt;p&gt;在 PowerShell 中或者命令提示符中输入 gcc 并回车。如果显示 no input files 则表示安装成功。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164921.png&#34; alt=&#34;image-20201225001234917&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;配置编辑器&#34;&gt;配置编辑器&lt;/h3&gt;

&lt;p&gt;安装完了编译器，可以先来 Hello world 了&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164924.png&#34; alt=&#34;image-20201225001723920&#34; /&gt;&lt;/p&gt;

&lt;p&gt;按住 Shift 键，右键点击文件夹空白处，会出现在此处打开 Powershell 窗口的选项。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164932.png&#34; alt=&#34;image-20201225001744160&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gcc hello.c&lt;/code&gt; 命令就会在当前目录下生成一个 exe 可执行文件。如果要指定文件名，可以&lt;code&gt;gcc hello.c -o hello.exe&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;输入&lt;code&gt;./hello.exe&lt;/code&gt;即可执行该 exe 文件。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227164937.png&#34; alt=&#34;image-20201225002338213&#34; /&gt;&lt;/p&gt;

&lt;p&gt;如果直接双击 exe 也可以，不过运行窗口会一闪而过，解决方案是在 main 函数末尾，return 语句前，加一句 getchar()。&lt;/p&gt;

&lt;h2 id=&#34;配置-vscode-的作为-c-语言学习环境&#34;&gt;配置 VSCode 的作为 C 语言学习环境&lt;/h2&gt;

&lt;p&gt;VSCode 是由微软主导开发的一款开源免费、轻巧简单、功能强大的代码编辑器。配合各式各样的插件可以方便地实现各种你想得到和你想不到的功能。&lt;/p&gt;

&lt;p&gt;前往&lt;a href=&#34;https://code.visualstudio.com/&#34;&gt;VSCode 官网&lt;/a&gt;下载 Windows 版 VScode。并按照安装程序的指引进行安装。&lt;/p&gt;

&lt;p&gt;直接下载链接&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://code.visualstudio.com/sha/download?build=stable&amp;amp;os=win32-x64-user&#34;&gt;https://code.visualstudio.com/sha/download?build=stable&amp;amp;os=win32-x64-user&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;如果下载速度太慢可以考虑如下方案。&lt;/p&gt;

&lt;p&gt;原下载链接：&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://az764295.vo.msecnd.net/stable/ea3859d4ba2f3e577a159bc91e3074c5d85c0523/VSCodeUserSetup-x64-1.52.1.exe&#34;&gt;https://az764295.vo.msecnd.net/stable/ea3859d4ba2f3e577a159bc91e3074c5d85c0523/VSCodeUserSetup-x64-1.52.1.exe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;将开头的 az764295.vo.msecnd.net 替换掉，如下。&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://vscode.cdn.azure.cn/stable/ea3859d4ba2f3e577a159bc91e3074c5d85c0523/VSCodeUserSetup-x64-1.52.1.exe&#34;&gt;https://vscode.cdn.azure.cn/stable/ea3859d4ba2f3e577a159bc91e3074c5d85c0523/VSCodeUserSetup-x64-1.52.1.exe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;速度直接起飞！&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;打开安装包进行安装，无脑下一步即可。不顾最后的页面可以考虑全部钩上。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165016.png&#34; alt=&#34;image-20201227155805507&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165019.png&#34; alt=&#34;image-20201227155937465&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165022.png&#34; alt=&#34;image-20201227160036085&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165026.png&#34; alt=&#34;image-20201227160129001&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165029.png&#34; alt=&#34;image-20201227160209263&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165032.png&#34; alt=&#34;image-20201227160939375&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165035.png&#34; alt=&#34;image-20201227161003478&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在输入栏中，在当前选项卡为&lt;strong&gt;用户&lt;/strong&gt;的情况下，输入&lt;code&gt;run&lt;/code&gt;并按回车进行搜索。修改&lt;code&gt;Run in Terminal&lt;/code&gt;和 &lt;code&gt;Save File Before Run&lt;/code&gt;的设置项。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165038.png&#34; alt=&#34;image-20201227161205762&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;完成了上述的设置，我们就可以来编写 C 语言的程序了。&lt;/p&gt;

&lt;h3 id=&#34;hello-c&#34;&gt;Hello，C！&lt;/h3&gt;

&lt;p&gt;点击左侧第一个按钮，来到文件管理面板。点击打开文件夹按钮，打开一个空白的文件夹（任意文件夹都可以，只是保存你代码的地方，一般一个干净整洁的新文件夹为宜）&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165059.png&#34; alt=&#34;image-20201227163528187&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;打开文件夹后，在空白处单击右键，新建一个文件，文件名输入为&lt;code&gt;hello.c&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165107.png&#34; alt=&#34;image-20201227164010460&#34; /&gt;&lt;/p&gt;

&lt;p&gt;点击右上角的三角形按钮即可自动编译运行你的 C 语言代码。在窗口下方的终端即可看到输出的&lt;code&gt;Hello,C!&lt;/code&gt;字样。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201227165112.png&#34; alt=&#34;image-20201227164041803&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;完成&#34;&gt;完成✅&lt;/h3&gt;

&lt;p&gt;现在，开始你的 C 语言学习之旅吧！&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>Mac 平台配置 C/Python/Java 学习环境</title>
      <link>/posts/mac%E5%B9%B3%E5%8F%B0%E9%85%8D%E7%BD%AE%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83/</link>
      <pubDate>Fri, 18 Dec 2020 00:00:00 +0000</pubDate>
      
      <guid>/posts/mac%E5%B9%B3%E5%8F%B0%E9%85%8D%E7%BD%AE%E5%AD%A6%E4%B9%A0%E7%8E%AF%E5%A2%83/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # Mac 平台配置 C/Python/Java 学习环境 --&gt;

&lt;blockquote&gt;
&lt;p&gt;本系列教程旨在为刚入门的编程语言学习者做好指南工作，开始编码，本应很简单&lt;/p&gt;

&lt;p&gt;The PAINLESS way to start coding!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;配置-c-语言环境&#34;&gt;配置 C 语言环境&lt;/h2&gt;

&lt;p&gt;下面以 clang+VSCode+CodeRunner 为例，搭建一个简单的 C 语言学习环境。&lt;/p&gt;

&lt;h3 id=&#34;检查编译器支持&#34;&gt;检查编译器支持&lt;/h3&gt;

&lt;p&gt;C 语言的编译需要编译器，一般可以选择 gcc 或是 clang。Mac 系统默认安装了 clang 同时兼容了 gcc 的指令。在终端中进行查看：&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015258.png&#34; alt=&#34;screenshot&#34; /&gt;&lt;/p&gt;

&lt;p&gt;输入&lt;code&gt;gcc -v&lt;/code&gt;指令测试 gcc 命令是否可用并查看其版本，由上图输出可以看到，该命令可用，版本信息显示的则是 clang 的信息。一般来说，刚学习 C 语言无需关注两者的异同。&lt;/p&gt;

&lt;h3 id=&#34;配置-vscode&#34;&gt;配置 VSCode&lt;/h3&gt;

&lt;p&gt;&lt;span id=&#34;vscode&#34;&gt;VSCode&lt;/span&gt;是由微软主导开发的一款开源免费、轻巧简单、功能强大的代码编辑器。配合各式各样的插件可以方便地实现各种你想得到和你想不到的功能。&lt;/p&gt;

&lt;p&gt;前往&lt;a href=&#34;https://code.visualstudio.com/&#34;&gt;VSCode 官网&lt;/a&gt;下载 Mac 版 VScode。并按照安装程序的指引进行安装。&lt;/p&gt;

&lt;p&gt;如果下载速度太慢，可以参考&lt;a href=&#34;https://zhuanlan.zhihu.com/p/112215618&#34;&gt;这篇文章&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015416.png&#34; alt=&#34;截屏 2020-12-18 22.20.00&#34; /&gt;&lt;/p&gt;

&lt;p&gt;安装完毕后，打开会看到如下图所示的界面。默认界面为英文，下面对其进行汉化并安装一些必要的插件。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015546.png&#34; alt=&#34;截屏 2020-12-18 22.21.59&#34; /&gt;&lt;/p&gt;

&lt;p&gt;单击方形图标，打开扩展面板。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015621.png&#34; alt=&#34;image-20201218223234296&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;搜索&lt;code&gt;chinese&lt;/code&gt;安装汉化插件。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015622.png&#34; alt=&#34;image-20201218222747511&#34; /&gt;&lt;/p&gt;

&lt;p&gt;搜索&lt;code&gt;code runner&lt;/code&gt;安装 Code Runner 插件。并按指示重启应用（Reload 字样）&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015620.png&#34; alt=&#34;image-20201218222511011&#34; style=&#34;zoom:50%;&#34; /&gt;（截图中因为本地已安装故只显示了 Uninstall 卸载按钮。未安装的情况下会显示 Install 按钮可点击安装）&lt;/p&gt;

&lt;p&gt;其他插件可根据需要安装。此处推荐安装 C/C++ 插件以实现 C 代码的高亮和补全等功能。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015624.png&#34; alt=&#34;image-20201218223432859&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;重启后进入应用，界面自动切换到中文。再点击扩展图标，展开扩展列表，在已安装扩展中找到&lt;strong&gt;Code Runner&lt;/strong&gt;，点击齿轮图标展开菜单，点击进入扩展设置。&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015627.png&#34; alt=&#34;image-20201218224215676&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;在输入栏中，在当前选项卡为&lt;strong&gt;用户&lt;/strong&gt;的情况下，输入&lt;code&gt;run&lt;/code&gt;并按回车进行搜索。修改&lt;code&gt;Run in Terminal&lt;/code&gt;和 &lt;code&gt;Save File Before Run&lt;/code&gt;的设置项。&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015626.png&#34; alt=&#34;image-20201218224059150&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;完成了上述的设置，我们就可以来编写 C 语言的程序了。&lt;/p&gt;

&lt;h3 id=&#34;hello-c&#34;&gt;Hello，C！&lt;/h3&gt;

&lt;p&gt;点击左侧第一个按钮，来到文件管理面板。点击打开文件夹按钮，打开一个空白的文件夹（任意文件夹都可以，只是保存你代码的地方，一般一个干净整洁的新文件夹为宜）&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015623.png&#34; alt=&#34;image-20201218230901008&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;打开文件夹后，在空白处单击右键，新建一个文件，文件名输入为&lt;code&gt;hello.c&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015629.png&#34; alt=&#34;image-20201218224536077&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;键入代码。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015628.png&#34; alt=&#34;image-20201218224343393&#34; /&gt;&lt;/p&gt;

&lt;p&gt;点击右上角的三角形按钮即可自动编译运行你的 C 语言代码。在窗口下方的终端即可看到输出的&lt;code&gt;Hello,C!&lt;/code&gt;字样。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219021631.png&#34; alt=&#34;image-20201219021624927&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;完成&#34;&gt;完成✅&lt;/h3&gt;

&lt;p&gt;现在，开始你的 C 语言学习之旅吧！&lt;/p&gt;

&lt;h2 id=&#34;配置-python-语言学习环境&#34;&gt;配置 Python 语言学习环境&lt;/h2&gt;

&lt;h3 id=&#34;检查-python-环境&#34;&gt;检查 Python 环境&lt;/h3&gt;

&lt;p&gt;Mac 系统会自带有 Python 环境。在终端中输入 python 并回车。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015630.png&#34; alt=&#34;截屏 2020-12-18 22.54.54&#34; /&gt;&lt;/p&gt;

&lt;p&gt;可以看到系统已经安装有 Python，但是显示版本为 2.7。现在的主流版本是 Python3，Python2 与 Python3 的语法并不兼容。&lt;/p&gt;

&lt;p&gt;在&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;后面键入&lt;code&gt;exit()&lt;/code&gt;退出 python2 的交互程序。再次在终端输入&lt;code&gt;python3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015634.png&#34; alt=&#34;image-20201218231954777&#34; /&gt;&lt;/p&gt;

&lt;p&gt;此时显示的版本为 3.8.6。&lt;/p&gt;

&lt;h3 id=&#34;hello-python&#34;&gt;Hello, Python!&lt;/h3&gt;

&lt;p&gt;在交互式命令行界面，我们可以直接输入 python 语句并执行。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219021016.png&#34; alt=&#34;截屏 2020-12-18 23.00.54&#34; /&gt;&lt;/p&gt;

&lt;p&gt;一句一句地输入代码再执行显然太低效了。我们需要一个趁手的代码编辑器。&lt;/p&gt;

&lt;p&gt;下面以 VSCode 为例。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VSCode 的下载和基本配置&lt;/strong&gt;请参考上文 C 语言环境配置中 VSCode 的配置环节。&lt;/p&gt;

&lt;p&gt;完成基本的设置后，来安装 Python 的专属插件，以实现 Python 代码的高亮、补全等功能。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015633.png&#34; alt=&#34;image-20201218230442930&#34; /&gt;&lt;/p&gt;

&lt;p&gt;点击左侧第一个按钮，来到文件管理面板。点击打开文件夹按钮，打开一个空白的文件夹（任意文件夹都可以，只是保存你代码的地方，一般一个干净整洁的新文件夹为宜）&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015623.png&#34; alt=&#34;image-20201218230901008&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;打开文件夹后，在空白处单击右键，新建一个文件，文件名输入为&lt;code&gt;hello.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015629.png&#34; alt=&#34;image-20201218224536077&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;键入代码。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015631.png&#34; alt=&#34;截屏 2020-12-18 22.58.44&#34; /&gt;&lt;/p&gt;

&lt;p&gt;点击右上角的三角形按钮开始运行我们编写的代码&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015632.png&#34; alt=&#34;截屏 2020-12-18 23.00.54&#34; /&gt;&lt;/p&gt;

&lt;p&gt;可以看到，窗口下方的终端中已经出现了&lt;code&gt;Hello,Python!&lt;/code&gt;字样。代码运行成功。&lt;/p&gt;

&lt;h3 id=&#34;完成-1&#34;&gt;完成✅&lt;/h3&gt;

&lt;p&gt;现在，开始你的 Python 语言学习之旅吧！&lt;/p&gt;

&lt;h2 id=&#34;配置-java-语言学习环境&#34;&gt;配置 Java 语言学习环境&lt;/h2&gt;

&lt;h3 id=&#34;安装-jdk&#34;&gt;安装 JDK&lt;/h3&gt;

&lt;p&gt;Mac OS 并没有内置 Java 语言的支持，需要我们另外安装。&lt;/p&gt;

&lt;p&gt;直接在终端输入&lt;code&gt;java&lt;/code&gt;，系统会提示 Java 未安装并跳转到 Oracle 官方的下载页面。在官网下载会强制要求你注册并登陆 Oracle 账户，网站连接缓慢且步骤繁琐。此处我们到清华大学的 TUNA 开源软件镜像站下载相关软件。&lt;/p&gt;

&lt;p&gt;首先到 TUNA 开源软件镜像站，来到&lt;a href=&#34;https://mirrors.tuna.tsinghua.edu.cn/AdoptOpenJDK/&#34;&gt;AdoptOpenJDK 的下载页面&lt;/a&gt;。在列表中找到你需要的版本，点击进入后依次选择处理器架构和平台。&lt;/p&gt;

&lt;p&gt;此处以 Java 11 为例，其 Mac OS 下安装程序的下载地址为&lt;a href=&#34;https://mirrors.tuna.tsinghua.edu.cn/AdoptOpenJDK/11/jdk/x64/mac/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9.1_1.pkg&#34;&gt;https://mirrors.tuna.tsinghua.edu.cn/AdoptOpenJDK/11/jdk/x64/mac/OpenJDK11U-jdk_x64_mac_hotspot_11.0.9.1_1.pkg&lt;/a&gt;。需要其他版本的也可以自行选择。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;自行选择时请注意：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;jre 只是 java 运行环境，并不包括对 java 代码的编译功能。下载时请认准&lt;strong&gt;jdk&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;选择处理器架构时，传统 Intel 内核 Mac 请选择&lt;strong&gt;x86&lt;/strong&gt;，对于 M1 内核的 Mac，截止本文写作，暂无相关支持，请关注后续更新。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;最内层下载资源的列表中，jdk 的资源文件名会有&lt;code&gt;hotspot&lt;/code&gt;和 &lt;code&gt;openj9&lt;/code&gt;两种字样。Java 入门请选择&lt;code&gt;hotspot&lt;/code&gt;，文件后缀名请选择&lt;code&gt;.pkg&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;下载完成后点击打开，出现如下的安装界面。根据指引完成安装。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015635.png&#34; alt=&#34;image-20201218232011039&#34; /&gt;&lt;/p&gt;

&lt;p&gt;安装完成后，在终端中输入&lt;code&gt;java -version&lt;/code&gt;并回车确认。看到如下输出说明已经正确安装且 Java 的版本为&lt;code&gt;11.0.9.1&lt;/code&gt;即 Java 11.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015640.png&#34; alt=&#34;image-20201218235233365&#34; /&gt;&lt;/p&gt;

&lt;p&gt;下面来为 Java 的学习配置一个趁手的代码编辑器，以 VSCode 为例。&lt;/p&gt;

&lt;h3 id=&#34;为-java-语言学习配置-vscode&#34;&gt;为 Java 语言学习配置 VSCode&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;VSCode 的下载和基本配置&lt;/strong&gt;请参考上文 C 语言环境配置中 VSCode 的配置环节。&lt;/p&gt;

&lt;p&gt;完成基本的设置后，来安装 Java 的专属插件，以实现 Java 代码的高亮、补全等功能。&lt;/p&gt;

&lt;p&gt;在左侧扩展面板的搜索栏中搜索&lt;code&gt;java&lt;/code&gt;，选择&lt;code&gt;Language Support for Java&lt;/code&gt;并安装。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015641.png&#34; alt=&#34;image-20201218235514041&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;点击左侧第一个按钮，来到文件管理面板。点击打开文件夹按钮，打开一个空白的文件夹（任意文件夹都可以，只是保存你代码的地方，一般一个干净整洁的新文件夹为宜）&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015623.png&#34; alt=&#34;image-20201218230901008&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;打开文件夹后，在空白处单击右键，新建一个文件，文件名输入为&lt;code&gt;hello.java&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015629.png&#34; alt=&#34;image-20201218224536077&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;键入代码。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015639.png&#34; alt=&#34;image-20201218235213233&#34; /&gt;&lt;/p&gt;

&lt;p&gt;可以看到，在窗口下方的终端面板中，已经成功出现了&lt;strong&gt;Hello, Java!&lt;/strong&gt;字样，代码运行成功。&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015637.png&#34; alt=&#34;截屏 2020-12-19 00.05.33&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;完成-2&#34;&gt;完成✅&lt;/h3&gt;

&lt;p&gt;至此，Mac 平台下的 Java 语言学习环境配置完毕，开始你的 Java 学习之旅吧！&lt;/p&gt;

&lt;h2 id=&#34;常见问题&#34;&gt;常见问题&lt;/h2&gt;

&lt;h3 id=&#34;1-java-扩展安装弹出提示-jdk-版本过低&#34;&gt;1. Java 扩展安装弹出提示 JDK 版本过低&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20201219015638.png&#34; alt=&#34;image-20201218234917588&#34; style=&#34;zoom:50%;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这是因为插件内置的一些功能需要 Java 来运行，而这些功能又依赖于一些较新的特性，这些特性最早出现在 Java 11 中。为了更好地学习和使用 Java，这里推荐安装 Java 11 或 Java 12。网站教程或学校授课常常以 Java 8 为例，但对于初学者来说，几者无太大区别，Java 8 的代码都可以被很好地支持。&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>云服务器入门指南</title>
      <link>/posts/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/</link>
      <pubDate>Sun, 15 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/</guid>
      <description>
        
          
          
          
        
        
        

&lt;!-- # 云服务器入门指南 --&gt;

&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;

&lt;p&gt;各大厂商持续发力云计算，上云的门槛也越来越低。获取云服务器的门槛越来越低，但是真正使用好云服务器的难度一直都很高。本文旨在为新上云的小白提供方向性的指引并引导入坑  : )&lt;/p&gt;

&lt;h2 id=&#34;云服务器相关的几个概念&#34;&gt;云服务器相关的几个概念&lt;/h2&gt;

&lt;h3 id=&#34;服务器的操作系统&#34;&gt;服务器的操作系统&lt;/h3&gt;

&lt;p&gt;主要分为两大阵营：Windows Server 和 Linux Server。前者一般自带可视化界面，基本兼容平时使用的 exe 程序，某种程度上也可以作为“云电脑”使用。后者一般不自带图形化界面，操作都通过特定命令完成，上手难度较高，但配置各种开发环境、安装各类高级工具比 win 平台更容易。没有 Linux 基础的用户建议先在本地建立虚拟机练习。&lt;/p&gt;

&lt;p&gt;Linux Server 主要的两个阵营为 Debian 系、RedHat 系。主要的发行版&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debian 系：Debian, Ubuntu&lt;/li&gt;
&lt;li&gt;RedHat 系：RedHat, CentOS, Fedora&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;对于初学者来说，最明显的区别在于前者使用 &lt;code&gt;apt install xxx&lt;/code&gt;  来安装软件，而后者是通过 &lt;code&gt;yum install xxx&lt;/code&gt;  来安装。&lt;/p&gt;

&lt;h3 id=&#34;公网-ip&#34;&gt;公网 IP&lt;/h3&gt;

&lt;p&gt;IP 可以理解为一台设备在互联网世界中的门牌号和地址，相当于知道某个具体的地址就能发快递包裹。IP 分为公网 IP 和内网 IP。顾名思义，内网 IP 一般用于公司或学校内部。一般来说，只知道一台设备的内网 IP 的情况下并不能准确定位这台设备，就类似于只知道你的朋友的名字，并不能直接给他寄快递，你必须要知道他学校/单位/家的地址才行。&lt;/p&gt;

&lt;p&gt;服务器拥有公网 IP 的好处在于，你可以直接通过这个 IP 定位到你的服务器，相当于你的服务器在互联网世界中拥有了响当当的名号，只要说出这个名号，互联网世界的公民都能知道他，给他发消息。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*此处公网内网 IP 的叙述仅适用于 IPv4 地址。更多关于 IPv4 地址和 IPv6 地址的相关信息参见文末扩展阅读。&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&#34;端口&#34;&gt;端口 &lt;/h3&gt;

&lt;p&gt;端口的英文为 port，有港口的意思。一般来说，一台设备不同的端口运行着不同的服务，我们可以很好的控制特定端口的开放与关闭，从而控制不同的服务是否对外开放，正如开放一个通商口岸。常见的服务端口有 &lt;code&gt;HTTP  80&lt;/code&gt;   &lt;code&gt;HTTPS  443&lt;/code&gt;   &lt;code&gt;DNS  53&lt;/code&gt;   &lt;code&gt;SSH 22&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;一个服务也可能不是仅仅通过一个端口提供服务，他可能会将一个大的功能拆分为几个子功能，通过不同的端口与外界通讯。如 FTP，SMB 等。你可以通过关闭指定端口来详细控制特定服务。当然如果你想想外面提供像 FTP 这样通过多个端口与外界通讯的端口，就要注意要确保他使用的所有端口都要设置为开放才能保证外界的正常访问。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*FTP 是一种文件传输协议，你可以在某些电影资源的下载链接里看见以 &lt;code&gt;ftp://&lt;/code&gt;  开头的链接。这说明这个电影资源是存放在某个 FTP 服务器上。&lt;/em&gt;
&lt;em&gt;*关于 FTP、SMB 的端口使用及配置参见文末扩展阅读&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&#34;防火墙&#34;&gt;防火墙&lt;/h3&gt;

&lt;p&gt;防火墙（Firewall）某种程度上是控制本机与外界通讯的工具。下面以几个具体的实例来介绍下防火墙：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;你的服务器建了个网站，需要向外提供 HTTP 服务，那么你需要在防火墙中设置开放 80 端口，允许其他所有 IP 访问。&lt;/li&gt;
&lt;li&gt;公司有一台服务器搭载了一个仅面向公司员工的网站，希望仅允许公司内的员工访问。而公司内员工的内网 IP 个格式为 192.168.*.&lt;em&gt;，那么就可以在防火墙中设置，仅允许来自 IP 为 192.168.&lt;/em&gt;.*的设备访问这台服务器的 80 端口，其他一律禁止&lt;/li&gt;
&lt;li&gt;近期互联网上流行一种病毒 X 通过计算机的 1234 端口感染其他机器。那么为了保护本机不受病毒影响，你可以在防火墙中设置关闭 1234 端口，禁止任何来源访问 1234 端口，从而将病毒 X 阻挡在防火墙外。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;注意：对于云服务器来说，可能会存在多重防火墙。一般 Linux 系统自身会有一套防火墙（firewalld/ufw 等），云服务商会有一套网络防火墙（一般为网络安全组/网络访问控制等）&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&#34;几种远程连接方式对比&#34;&gt;几种远程连接方式对比&lt;/h3&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&#34;center&#34;&gt;&lt;strong&gt;连接方式&lt;/strong&gt;&lt;/th&gt;
&lt;th align=&#34;center&#34;&gt;SSH&lt;/th&gt;
&lt;th align=&#34;center&#34;&gt;VNC&lt;/th&gt;
&lt;th align=&#34;center&#34;&gt;RDP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&#34;center&#34;&gt;&lt;strong&gt;支援平台&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;Linux，Mac OS，BSD&amp;hellip;，Win 需额外安装软件&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;Linux,Win,Mac OS,iOS,Android 等，基本所有都需额外软件 *&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;Win 自带，其他需额外安装软件&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&#34;center&#34;&gt;&lt;strong&gt;易用性&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;★&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;★★★&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;★★★*&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&#34;center&#34;&gt;&lt;strong&gt;可视化界面&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;否&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;是&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;是&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&#34;center&#34;&gt;&lt;strong&gt;网络要求&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;极低&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;高&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;较高&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td align=&#34;center&#34;&gt;&lt;strong&gt;配置难度&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;★&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;★★★&lt;/td&gt;
&lt;td align=&#34;center&#34;&gt;★★&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;ul&gt;
&lt;li&gt;1 部分 Linux 发行版自带 VNC 连接，不过大部分需手动启用&lt;/li&gt;
&lt;li&gt;2 RDP 连接对于同为 Win 的机器更为容易，对于平台不一样的情况，配置比较麻烦&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;快速入门须知&#34;&gt;快速入门须知&lt;/h2&gt;

&lt;p&gt;当你拥有了一台属于自己的云服务器，你发现面对复杂的控制台手足无措，不知道怎么连接，不知道能拿来干什么。那么你可以参考一下的步骤。&lt;strong&gt;下文仅适用于 Linux Server &amp;amp; 有一点点 Linux 操作经验的选手&lt;/strong&gt;。&lt;/p&gt;

&lt;h3 id=&#34;开启-ssh-远程连接&#34;&gt;开启 SSH 远程连接&lt;/h3&gt;

&lt;h4 id=&#34;服务器端设置&#34;&gt;服务器端设置&lt;/h4&gt;

&lt;p&gt;1.首先，登陆你的账户，打开云服务器的控制台，开机（不解释）  
2.定位到你的云服务器，一般新的账户只有一台云服务器实例，点击其菜单，找到远程连接选项  
3.接下来会打开一个网页端的黑框，根据其提示，设置实例密码等等。这里记录你的系统用户名和密码。
4.一般网页端会有提示，根据具体情况开启 SSH 服务，设置允许 root 权限远程登录。具体的操作因平台和操作系统不同而不同，此处不再赘述。
5.现在到服务器菜单里找到网络设置/防火墙设置/网络安全组设置，点击进入，&lt;strong&gt;开启服务器 22 端口的访问权限&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;接下来在你的电脑上配置 SSH 远程访问。 &lt;/p&gt;

&lt;h4 id=&#34;本地电脑设置&#34;&gt;本地电脑设置&lt;/h4&gt;

&lt;p&gt;1.1 Win10 用户和 Linux 用户、Mac OS 用户一般系统会预装 ssh 客户端。打开 CMD 命令控制符/PowerShell，输入 ssh 回车看是否有反应。&lt;strong&gt;如果没有提示 xxx 找不到，可以直接到步骤 2.1&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;1.2 如果没有反应，你需要到 设置 - 应用 - 可选功能 中，安装 SSH 客户端。&lt;/p&gt;

&lt;p&gt;1.3 Windows 其他版本用户需要安装第三方 SSH 客户端。这里推荐使用 Putty。&lt;/p&gt;

&lt;p&gt;2.1 接下来使用 &lt;code&gt;ssh 你的用户名@你的服务器IP&lt;/code&gt; 来连接到你的服务器。注意&lt;strong&gt;At 符号@前后没有空格，输完回车确认&lt;/strong&gt;。正常情况下可以成功连接到。&lt;/p&gt;

&lt;p&gt;2.2 如果出现 Permission denied，可能的原因有&lt;code&gt;用户名密码错误&lt;/code&gt; / &lt;code&gt;未开启root账户远程登录&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;2.3 如果出现 Connection time out，则大概率是你&lt;code&gt;IP地址填写错误&lt;/code&gt;，也有可能是你的&lt;code&gt;服务器没开机&lt;/code&gt;/ &lt;code&gt;你的服务器系统没有默认开启ssh服务&lt;/code&gt;/ &lt;code&gt;防火墙未放行22端口&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;排查相关问题请带上相关关键字去搜索引擎搜索。&lt;/p&gt;

&lt;h3 id=&#34;安装软件&#34;&gt;安装软件&lt;/h3&gt;

&lt;h4 id=&#34;安装软件的命令及常见问题&#34;&gt;安装软件的命令及常见问题&lt;/h4&gt;

&lt;p&gt;参见上文介绍操作系统的部分。不过具体安装的时候，经常会遇到的问题为安装需要 root 权限。一般来说，日常使用时为了安全期间，我们不会直接用 root 账户进行操作。通常的做法为创建一个普通的账户，当执行需要高权限的指令时在命令前加上 sudo，或是使用 &lt;code&gt;su root&lt;/code&gt;  来临时切换为 root 用户*，并输入密码来进行二次确认，以确保安全性。此处涉及到的操作有：  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;添加一个普通用户 ( &lt;code&gt;useradd NEWUSERNAME&lt;/code&gt;  /  &lt;code&gt;adduser NEWUSERNAME&lt;/code&gt;  )&lt;/li&gt;
&lt;li&gt;设置新用户的密码  ( &lt;code&gt;passwd USERNAME&lt;/code&gt;  )&lt;/li&gt;
&lt;li&gt;将新用户添加到 sudoers 的列表中  ( 修改 &lt;code&gt;/etc/sudoers&lt;/code&gt;  ) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;具体操作可以以  &lt;code&gt;操作系统名称+操作关键字&lt;/code&gt;  为关键字在搜索引擎中自行搜索详细教程。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*临时切换为 root 用户，执行完命令后，记得用 exit 命令退出 root 账户&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&#34;镜像源的设置&#34;&gt;镜像源的设置&lt;/h4&gt;

&lt;p&gt;执行完上述命令，当你尝试安装一个软件时，如果你云服务器提供商没有为你的系统进行“优化”的话，你会发现安装软件的速度非常慢。这是因为这些 Linux 系统基本都是由国外的厂商/组织进行开发，安装软件时需要到位于国外的服务器获取数据，你的网络请求可能会跨越大半个地球，网络速度也随着传输距离的增加不断减小*。国内有很多组织建立了公益性质的镜像站点，我们可以将安装程序的软件源设置为位于国内的镜像站点以大大提高软件安装下载的速度。
国内的镜像站点有&lt;strong&gt;阿里云镜像站&lt;/strong&gt;、&lt;strong&gt;清华大学 tuna 镜像站&lt;/strong&gt;、&lt;strong&gt;中国科学技术大学开源镜像站&lt;/strong&gt;等。这些站点提供多种主流 Linux 发行版的软件安装源的镜像。不同操作系统更换软件源的操作有所不同，可以到以上镜像站点中查找特定系统更换软件源的详细步骤。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*请注意此处叙述并不准确，与一个站点通信的速度取决于很多因素。&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&#34;常用工具的安装&#34;&gt;常用工具的安装&lt;/h4&gt;

&lt;p&gt;更换好了软件源后，我们就可以愉快的安装软件了。你可以尝试安装一下 &lt;code&gt;screenfetch&lt;/code&gt;  的软件包进行测试，安装完成后输入 &lt;code&gt;screenfetch&lt;/code&gt;  命令，他会在你的屏幕上输出字符画形式的系统图标和系统配置信息。&lt;/p&gt;

&lt;p&gt;部分 Linux 发行版可能并没有预置很多的软件包，你可以根据自己的需要进行安装，如文本编辑工具 &lt;code&gt;nano&lt;/code&gt;  &lt;code&gt;vim&lt;/code&gt;  等*。C 编译工具 &lt;code&gt;gcc&lt;/code&gt;  ,C++ 编译工具 &lt;code&gt;g++&lt;/code&gt;  ，Java 开发组件 &lt;code&gt;openjdk&lt;/code&gt;  等。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*推荐初学者使用易于上手的 &lt;code&gt;nano&lt;/code&gt;  文本编辑器。大部分 Linux 发行版都有预置。&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&#34;初级玩法&#34;&gt;初级玩法&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;搭建 Wordpress 网站&lt;/strong&gt;：为服务器安装好基础设施，部署 wordpress 服务。参见 &lt;a href=&#34;https://help.aliyun.com/document_detail/50774.html?spm=a2c4g.11186623.6.1134.26fc7ed9zbIv5a&#34;&gt;服务器 LAMP 部署&lt;/a&gt;，&lt;a href=&#34;https://segmentfault.com/a/1190000013035065&#34;&gt;Wordpress 搭建&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;作为远程开发环境&lt;/strong&gt;：  &lt;a href=&#34;https://www.jianshu.com/p/0f2fb935a9a1&#34;&gt;VSCode 进行远程开发&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;其他高级玩法&#34;&gt;其他高级玩法&lt;/h2&gt;

&lt;p&gt;参见：&lt;a href=&#34;https://www.zhihu.com/question/40854395&#34;&gt;知乎问答：自己拥有一台服务器可以做哪些很酷的事情？&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;扩展阅读&#34;&gt;扩展阅读&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/36542469&#34;&gt;IPv6 是什么？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.jianshu.com/p/016ee3b7ff97&#34;&gt;CentOS7 firewall 开放服务 / 端口&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://linux.cn/article-8087-1.html&#34;&gt;在 Ubuntu 中用 UFW 配置防火墙&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.wpdaxue.com/make-your-wordpress-site-faster.html&#34;&gt;让你的 WordPress 网站更快的 16 条建议&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cnblogs.com/xiaohh/p/4789813.html&#34;&gt;FTP 主动模式和被动模式的区别&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.5yun.org/15466.html&#34;&gt;Samba 服务使用的端口和协议&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

        
        </description>
    </item>
    
    <item>
      <title>坑爹的阿里云 &amp; Swap 的重要性</title>
      <link>/posts/%E6%A0%91%E8%8E%93%E6%B4%BE-apache2-%E8%AE%BE%E7%BD%AE%E7%89%B9%E5%AE%9A%E5%9F%9F%E5%90%8D%E8%BD%AC%E5%8F%91%E5%88%B0%E7%89%B9%E5%AE%9A%E7%AB%AF%E5%8F%A3/</link>
      <pubDate>Tue, 10 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E6%A0%91%E8%8E%93%E6%B4%BE-apache2-%E8%AE%BE%E7%BD%AE%E7%89%B9%E5%AE%9A%E5%9F%9F%E5%90%8D%E8%BD%AC%E5%8F%91%E5%88%B0%E7%89%B9%E5%AE%9A%E7%AB%AF%E5%8F%A3/</guid>
      <description>
        
          
          
          
        
        
        &lt;p&gt;随着树莓派上部署的项目越来越多，每次使用 &lt;strong&gt;IP + 端口&lt;/strong&gt;访问也越来越不方便。考虑使用 Apache 来特定子域名跳转到不同端口对应的不同应用。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;树莓派 3B+  Raspbian 系统&lt;/li&gt;
&lt;li&gt;Apache2&lt;/li&gt;
&lt;li&gt;自己的域名&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在 Apache2 的配置文件（路径 /etc/Apache2/Apache2.conf ) 文件末尾加上以下配置：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
  ServerName YOUR_DOMAIN.COM #此处为本条规则绑定的域名，下同
  ServerAlias YOUR_DOMAIN.COM
  ProxyPreserveHost On
  ProxyRequests Off
  ProxyPass / http://localhost:8080/ #修改此处的端口号为实际所需，下同
  ProxyPassReverse / http://localhost:8080/
&amp;lt;/VirtualHost&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;之后开启 Apache2 的相关模块&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;a2enmod rewrite
a2enmod proxy
a2enmod proxy_http


&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;最后重启 Apache2 即可 sudo systemctl restart Apache2&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>打造沉浸式互联网体验「广告篇 - 上」</title>
      <link>/posts/%E6%89%93%E9%80%A0%E6%B2%89%E6%B5%B8%E5%BC%8F%E4%BA%92%E8%81%94%E7%BD%91%E4%BD%93%E9%AA%8C%E5%B9%BF%E5%91%8A%E7%AF%87-%E4%B8%8A/</link>
      <pubDate>Tue, 18 Feb 2020 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E6%89%93%E9%80%A0%E6%B2%89%E6%B5%B8%E5%BC%8F%E4%BA%92%E8%81%94%E7%BD%91%E4%BD%93%E9%AA%8C%E5%B9%BF%E5%91%8A%E7%AF%87-%E4%B8%8A/</guid>
      <description>
        
          
          
          
        
        
        

&lt;h2 id=&#34;序&#34;&gt;序&lt;/h2&gt;

&lt;p&gt;继机械化、电气化、自动化的三次工业革命后，人类正迎来以互联网为载体的智能化时代。互联网与我们的生活结合得越来越紧密。除了装修房子，购置服装，优化家庭互联网体验也是提升生活质量的一个良好途径。本篇中我们将聚焦网页浏览来优化我们的互联网体验。&lt;/p&gt;

&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;

&lt;p&gt;“上网冲浪”这样的词已经淡出公众的视野，身边的 10 后甚至 00 后都鲜有人熟悉这个词了。也许我们现在与互联网的交互并不局限于网页交互了，但我想，你也肯定不希望被自己偶然上某度查资料的时候被漫天的广告破坏了一天的心情。&lt;/p&gt;

&lt;p&gt;本系列将从以下几点从易到难，逐步优化日常的网页体验。无需任何代码基础，使用文中推荐的工具，小白亦可轻松上手！&lt;/p&gt;

&lt;ul&gt;
&lt;li&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;通过 Hosts 屏蔽广告联盟 *&lt;/li&gt;
&lt;li&gt;借助 AdGuardHome 打造局域网统一去广告方案 **&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;网络篇&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2020/01/20/tDZ9kw68rAajWVy.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2020/01/20/vAqHRYSNfl9PdTZ.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2020/01/20/JgRAjFCdDpwreBU.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20200120213009.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20200121223647.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;这样的广告呢，虽然他的侵略性或许比以往更小了，不过还是有点碍眼。而且在某种程度上，依然可能会误导家里的老人或是小孩。为了统一家庭的互联网体验，减少不必要的麻烦，这个广告也是我们的 target。由于这个广告是嵌入搜索结果中的，如果你用之前的小伎俩，打算单独屏蔽这个广告对应的元素的话，你就要失望了。因为他会连带着屏蔽所有的搜索结果。这显然是不可取的。下面我们要介绍另外两个工具。&lt;/p&gt;

&lt;h3 id=&#34;tampermonkey-油猴&#34;&gt;Tampermonkey 油猴&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2020/01/21/Jo4BkYaf3K58DmW.png&#34; alt=&#34;&#34; /&gt;&lt;br /&gt;
这是一个非常强大的浏览器插件，可以在特定的页面插入特定的 js 脚本，从而实现非常强大的功能。比如，音乐网站 VIP 资源下载，百度云盘下载加速，视频网站 VIP 资源在线观看，以及我们今天的的男二号：&lt;/p&gt;

&lt;h3 id=&#34;ac-搜索引擎优化脚本&#34;&gt;AC - 搜索引擎优化脚本&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2020/01/21/ZYhCx2Xzd9yABcI.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;安装好油猴插件后，你可以在 &lt;a href=&#34;https://greasyfork.org/zh-CN/&#34;&gt;Greasyfork.org&lt;/a&gt; 上下载各种黑科技般的脚本。安装成功后，油猴会在你进入符合条件的网页时自动启用对应的脚本。比如，你安装了 AC 的这个脚本，而这个网页是适配了某度的，那么当你进入某度的网页时，油猴就会自动启用这个脚本。快来领取属于你的纯净版度度吧。&lt;br /&gt;
&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20200121231059.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;前面介绍的几个，都只是借助第三方工具来屏蔽网页上特定的碍眼的元素。如果我们要阅读来自不同网站的新闻，为了获得机制纯净的阅读体验，难道要用 AdBlock 一个一个选中页面中除文章主体文字以外其他所有元素？对于这种页面结构非常固定的一类网站，我们是否可以通过某种方式，来只提取页面主体的文字，以优化我们的阅读体验呢？&lt;/p&gt;

&lt;h3 id=&#34;使用浏览器自带的阅读工具&#34;&gt;使用浏览器自带的阅读工具&lt;/h3&gt;

&lt;p&gt;苹果很早就想到了这一点，Safari 浏览器可以识别当前的的页面是否是一个结构简单，文字为主题的页面。在符合条件的网页上，Safari 会提示你使用阅读工具来优化页面，以获得更好的阅读体验。当然，你也可以手动启用他。&lt;br /&gt;
&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20200121233256.png&#34; alt=&#34;&#34; /&gt;&lt;br /&gt;
微软也不甘示弱，在随 Win10 推出的 Microsoft Edge 上，也内置了阅读工具。你可以在地址栏的右边找到他。&lt;br /&gt;
&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20200121233739.png&#34; alt=&#34;&#34; /&gt;&lt;br /&gt;
&lt;em&gt;[注：区别与 2020 年新的基于 Chromium 内核的新 Edge 浏览器，此处指的是老版 Edge HTML 内核的 Microsoft Edge 浏览器]&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&#34;使用第三方阅读工具-简阅-simpread-http-ksria-com-simpread&#34;&gt;使用第三方阅读工具 - &lt;a href=&#34;http://ksria.com/simpread/&#34;&gt;简阅 SimpRead&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2020/01/21/ZcsEIv8wBfjOmVa.png&#34; alt=&#34;&#34; /&gt;&lt;br /&gt;
也许你买不起苹果，受不了 Win10，你依然可以通过安装第三方工具的方式享受纯净的阅读体验。简阅，正如他的名字，旨在为你提供简约的阅读视图。作者为了实现“简单阅读”这个小目标，主动适配了数百个常见的文字为主体的网站，并设计为可以自动检测网页结构，对于漫天飞舞的各类热门冷门的小说网站、新闻网站，都可以自动识别并优化为适合阅读的页面。&lt;/p&gt;

&lt;p&gt;恭喜你！利用上面介绍的几个工具，你已经可以在国内互联网环境中求的一份净土了。如果你感兴趣或是强迫症患者，欢迎前往 &lt;strong&gt;打造沉浸式互联网体验【广告篇 - 下】&lt;/strong&gt;&lt;br /&gt;
温馨提示：下篇介绍的内容的内容将略有一点偏硬核，需要一点点的动手能力哦~&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>从一次异常断网谈防火墙配置</title>
      <link>/posts/%E4%BB%8E%E4%B8%80%E6%AC%A1%E5%BC%82%E5%B8%B8%E6%96%AD%E7%BD%91%E8%B0%88%E9%98%B2%E7%81%AB%E5%A2%99%E9%85%8D%E7%BD%AE/</link>
      <pubDate>Sat, 08 Feb 2020 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E4%BB%8E%E4%B8%80%E6%AC%A1%E5%BC%82%E5%B8%B8%E6%96%AD%E7%BD%91%E8%B0%88%E9%98%B2%E7%81%AB%E5%A2%99%E9%85%8D%E7%BD%AE/</guid>
      <description>
        
          
          
          
        
        
        

&lt;h2 id=&#34;序&#34;&gt;序&lt;/h2&gt;

&lt;p&gt;十分钟前，突然发现手边的电脑上的 QQ 突然变灰，多次重新登陆均失败。而当前打开几个百度的网页均未出现异常。但点击几个搜索结果均显示打不开网页。一分钟后，iPad 播放的音乐也突然停止。尝试 Ping 局域网的网关和树莓派均失败。而路由器仍然显示网络连接正常，手机端仍可以正常上网，断网前半个小时内我是没有对路由器和承载着众多服务的树莓派进行任何改动的。初步查看，发现电脑网卡的 ip 变为&lt;code&gt;169.254&lt;/code&gt;开头的 IP，而内网 IP 之前一直用的是&lt;code&gt;192.168.1.\*&lt;/code&gt;。现在电脑和路由器&lt;code&gt;192.168.1.1&lt;/code&gt;以及绑定了这个网段静态 IP 的树莓派都不在同一个网段内，自然是无法访问的。那么为什么会分配到这样的 IP 地址呢？&lt;br /&gt;
简单查询得知，这样的 IP 属于保留的 IP 地址段，用于在无法 DHCP 获取 IP 时自己给自己分配一个 IP。这样分配得来的 IP 自然是不能正常使用的。而此前局域网的 DHCP 被我的树莓派承包了，那么首要任务是查看树莓派的 DHCP 服务是否正常运行。&lt;/p&gt;

&lt;h2 id=&#34;排错三步走&#34;&gt;排错三步走&lt;/h2&gt;

&lt;p&gt;虽然树莓派之前绑定的 IP 地址无法 ping 通，但庆幸的是，通过主机名依然可以访问到局域网内树莓派，不过此时链接的是 IPv6。IPv6 作为 IPv4 的升级版，在很多方面都有所不同，局域网 IP 地址的分配和 IPv4 的 DHCP 走的并不是同一个路子。之前为了将树莓派的 DNS 用于家庭局域网，而家里的移动光猫上并不能修改 IPv4 DHCP 的 DNS 信息，无奈只能禁用路由器的 IPv4 DHCP 转而使用 AdGuardHome 内置的 DHCP 服务器。而 IPv6 的 DHCP 分为两个部分：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;内网的，分配的 IPv6 地址一般以&lt;code&gt;fe80&lt;/code&gt;开头，这种地址仅用于内网访问。&lt;/li&gt;
&lt;li&gt;公网的，IPv6 的地址容量之大足以为地球上的每一粒沙子分配一个独一无二的 IPv6 地址，而这对于现今地址池即将枯竭的 IPv4 是根本无法想象的。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;由于要分配的公网 IPv6 地址是要由路由器从公网获取一个前缀然后再为局域网的每个支持 IPv6 的设备分配地址，这一项任务不能由内网的树莓派代劳，所以当时就没有改动，没想到现在竟然成了救命稻草。&lt;br /&gt;
通过 IPv6 的方式，成功连接上了树莓派。查看了 AdGuardHome 的 DNS 服务以及 DHCP 服务，并没有发现任何异常。&lt;br /&gt;
例行 SSH 连上查看日志。&lt;code&gt;sudo systemctl status AdGuardHome.service&lt;/code&gt;，果然，发现了端倪。&lt;br /&gt;
&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20200121221431.png&#34; alt=&#34;&#34; /&gt;&lt;br /&gt;
原来！DHCP 服务！是要单独监听 67 端口的！&lt;br /&gt;
而一个小时之前，为了防止暴露在公网上的树莓派遭到攻击，我特地启用了防火墙，并设置规则为，除了放行的 DNS 53 等端口，其他默认屏蔽。想来应该是误伤了 DHCP 的 67 端口。而之前 DHCP 设置每个 IP 地址的租约为一个小时，即，每间隔一个小时才会重新进行一次 DHCP 请求。于是&lt;code&gt;sudo ufw allow 67/tcp&lt;/code&gt;端口放行 DHCP 服务信息。win10 断网重连以令其重新获取 IP 地址。&lt;br /&gt;
没想到还是不成功。AdGuardHome 的 DHCP 租约面板，依然显示没有任何设备连接。依据以往的经验，乖乖去查了 DHCP 所使用的端口信息，发现 DHCP 需要&lt;code&gt;67/udp&lt;/code&gt;和&lt;code&gt;68/udp&lt;/code&gt;两个端口，且还是使用 udp 连接。&lt;br /&gt;
接下来问题就好办了，重复上面的操作。查看本机的 IP 地址已经恢复正常。&lt;/p&gt;

&lt;h2 id=&#34;谈防火墙&#34;&gt;谈防火墙&lt;/h2&gt;

&lt;p&gt;在树莓派未暴露在公网上之前，我对防火墙的理解仅限于早些年 360 卫士花里胡哨的网络安全服务。在这次事件之前，我也只是以为防火墙只是防范来自公网的不友善的访问的工具。今天才发现，防火墙除了字面上的意思，防范风险之外，他也是网络数据进出主机的安检。什么样的请求是允许的，什么样的是屏蔽的，这些都需要认真考虑，仔细配置。对于我那配置了众多服务的树莓派来说，我应当在没添加一个新的服务时，查询其使用的端口信息，并更新防火墙配置，我之前却大大忽视了这一点，直到出了事故才意识到。也希望给后来者提供一个减少犯错的机会，毕竟要是实际生产环境出了事故，可就不是十几分钟断网的事了。&lt;/p&gt;

&lt;h2 id=&#34;防火墙设置&#34;&gt;防火墙设置&lt;/h2&gt;

&lt;p&gt;防火墙抵挡了来自外部的威胁，也会对现有的服务造成影响。除了网页访问的 80 和 443 端口，其他有固定端口的特定服务要手动在防火墙中添加规则。对于像 BT 下载这种没有固定端口的，需要根据实际设定来更新防火墙规则。&lt;br /&gt;
&lt;img src=&#34;https://blog-1301127393.file.myqcloud.com/BlogImgs/20200122140951.png&#34; alt=&#34;&#34; /&gt;&lt;br /&gt;
图中为 Aria2 的默认监听端口，为了保证正常的 BT 下载，需要保证这个范围的端口也添加进防火墙允许通过的规则。&lt;br /&gt;
最简单有效的办法是，将所有出站的请求默认允许，对于外部传入的请求，除了必要的几个服务，其他一概默认禁止。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo ufw default allow outgoing
sudo ufw default deny incoming


&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这样设置可以保证我们能够正常访问互联网上的绝大多数服务，且阻挡大部分外部的攻击。不过这种情况下，如果你的系统被植入了后门，那么这台机器依然可以向外发送请求。如之前爆发的“永恒之蓝”，如果你的机器被感染了，那么他依然可以经由特定的端口，向外传送数据，从而感染局域网中的其他设备。防火墙的规则就要根据实际的情况来进行设置了。&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>一次成功的网络优化 &amp; 吐槽国内糟糕的网络环境</title>
      <link>/posts/%E4%B8%80%E6%AC%A1%E6%88%90%E5%8A%9F%E7%9A%84%E7%BD%91%E7%BB%9C%E4%BC%98%E5%8C%96-%E5%90%90%E6%A7%BD%E5%9B%BD%E5%86%85%E7%B3%9F%E7%B3%95%E7%9A%84%E7%BD%91%E7%BB%9C%E7%8E%AF%E5%A2%83/</link>
      <pubDate>Thu, 10 Oct 2019 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E4%B8%80%E6%AC%A1%E6%88%90%E5%8A%9F%E7%9A%84%E7%BD%91%E7%BB%9C%E4%BC%98%E5%8C%96-%E5%90%90%E6%A7%BD%E5%9B%BD%E5%86%85%E7%B3%9F%E7%B3%95%E7%9A%84%E7%BD%91%E7%BB%9C%E7%8E%AF%E5%A2%83/</guid>
      <description>
        
          
          
          
        
        
        &lt;p&gt;在内网的树莓派上部署了 AdGuardHome，做 DNS 服务器的同时，也可以为内网所有设备过滤广告。本来嘛拦截了广告理应网络加载会更快，然而实际体验却很糟糕。网页加载要比之前慢得多。AdGuardHome 的面板显示的平均反应时间一度达到了 1000ms。1s 的延时还是会非常影响网络体验的。用 dig 命令看了下 DNS 查询的情况。不看不知道一看吓一跳，随便查询一个域名竟然废了四秒多！这怎么能忍受！&lt;/p&gt;

&lt;p&gt;[图片已丢失]
&lt;!-- ![](http://192.168.1.200/wp-content/uploads/2019/12/image-1-1280x784.png) --&gt;&lt;/p&gt;

&lt;p&gt;看网上其他人的评价，并没有我这种龟速的情况。况且我的上游 DNS 已经更换为了国内几个大厂的 DNS 比如阿里的腾讯的，测试查询一般反应时间也才 50ms。本地这个结果肯定是不能接受的。最开始还想过要根据常用域名手动制作 hosts 直接重定向。但是 dnspython 这个库不好直接指定 dns 查询，adguardhome 的 query 日志又经过特殊加密，这条路困难重重。决定将其作为备用方案。接下来进入漫长的排雷环节。&lt;/p&gt;

&lt;p&gt;首先考虑上游 DNS 中设置了谷歌等国外的 DNS，某些情况下会比国内的 DNS 慢。但是即便只留了一个阿里的 DNS，反应速度还是在秒级。&lt;/p&gt;

&lt;p&gt;接下来定位过滤器，开了五六个过滤器，按理说查询 DNS 前会先读取本地的过滤器以寻找匹配项，过滤规则一多自然会反应迟钝。禁用了一个默认的 30k 条规则的配置，速度有那么一点提升，但还是在 1s 以上，完全不能接收。这跟平时用阿里 DNS 差了几个数量级啊。&lt;/p&gt;

&lt;p&gt;后来发现了这货：&lt;/p&gt;

&lt;p&gt;[图片已丢失]&lt;/p&gt;

&lt;!-- ![](http://192.168.1.200/wp-content/uploads/2019/12/image-1280x191.png) --&gt;

&lt;p&gt;原来，他会把每次查询的域名先交给他服务器做安全性检查，这在国内的互联网环境中完全是鸡肋，而且因为每次都要连接境外服务器，其延迟可想而知。果然禁用了这一项，速度嗖嗖的就起来了：&lt;/p&gt;

&lt;!-- ![](http://192.168.1.200/wp-content/uploads/2019/12/image-2-1280x708.png) --&gt;

&lt;p&gt;[图片已丢失]&lt;/p&gt;

&lt;p&gt;即便是冷门的实验室官网的域名，也在 100ms 内解决了，对于常见的热门网站由于多设备频繁访问，会直接查询本地缓存。虽然基本只有可怜的差不多 60s 的缓存时间，但是一旦命中，就可以在 &amp;lt; 10ms 的时间响应。如果是过滤器中的域名，更是可以达到 &amp;lt; 5ms。终于，这个 AdGuard Home DNS 可以正式投入使用了。&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>坑爹的阿里云 &amp; Swap 的重要性</title>
      <link>/posts/%E5%9D%91%E7%88%B9%E7%9A%84%E9%98%BF%E9%87%8C%E4%BA%91-swap-%E7%9A%84%E9%87%8D%E8%A6%81%E6%80%A7/</link>
      <pubDate>Thu, 12 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E5%9D%91%E7%88%B9%E7%9A%84%E9%98%BF%E9%87%8C%E4%BA%91-swap-%E7%9A%84%E9%87%8D%E8%A6%81%E6%80%A7/</guid>
      <description>
        
          
          
          
        
        
        &lt;p&gt;在一次编译 VSCode 的项目中，跨越千山万水，解决重重依赖后，终于来到了编译环节。然而才开始没多久，就出现了一个匪夷所思的报错。&lt;/p&gt;

&lt;p&gt;谷歌一番，又到 /var/log/message 里查看了一番系统日志，竟然说是内存爆满，进程被 kill 了。想来我阿里云的那台服务器内存的统计曲线基本就没超过一半，今儿个怎么会出现内存爆掉的情况。又是一顿折腾发现这台阿里云的机子 Swap 大小竟然为 0？？Swap 为物理内存达到一定临界值之后，系统将磁盘的一部分空间作内存使用，一般在 Windows 系统上都是由系统自动管控，新安装的 Linux 桌面发行版也会在安装时提醒用户设置，这坑爹的阿里云在安装的时候没给我分配 Swap 分区？&lt;/p&gt;

&lt;p&gt;吐槽归吐槽，问题还是要自己解决。网上各种 swap 分区的设置教程大部分都比较模糊，代码的参数及命令都没有解释清楚，给人一种看不懂的感觉～对于操作磁盘这种敏感操作，还是要尽量避免在半懂不懂的情况下进行这种高危操作，毕竟数据无价嘛。最后找到了一篇靠谱的教程，并在服务器端和树莓派端进行实践。&lt;/p&gt;

&lt;p&gt;参考：&lt;em&gt;&lt;a href=&#34;https://linux.cn/article-9238-1.html&#34;&gt;https://linux.cn/article-9238-1.html&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;使用 fallocate 创建交换空间，我们首先在 / 目录下创建一个名为 swap_space 的文件。然后分配 4GB 到 swap_space 文件：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;fallocate -l 4G /swap_space
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;我们运行下面命令来验证文件大小：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ls -lh /swap_space
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然后更改文件权限，让 /swap_space 更安全：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;chmod 600 /swap_space
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这样只有 root 可以读写该文件了。我们再来格式化交换分区（LCTT 译注：虽然这个 swap_space 是个文件，但是我们把它当成是分区来挂载）：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mkswap /swap_space
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然后启用交换空间：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;swapon -s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;每次重启后都要重新挂载磁盘分区。因此为了使之持久化，就像上面一样，我们编辑 /etc/fstab 并输入下面行：&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/swap_space swap swap defaults 0 0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;保存并退出文件。现在我们的交换分区会一直被挂载了。我们重启后可以在终端运行 &lt;code&gt;free -m&lt;/code&gt;来检查交换分区是否生效。&lt;/p&gt;

&lt;p&gt;修改后 Swap 分区大小变为 4G，编译终于可以跑起来了～&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>Colin&#39;s Blog 1.0 构建心得</title>
      <link>/posts/colins-blog-1.0-%E6%9E%84%E5%BB%BA%E5%BF%83%E5%BE%97/</link>
      <pubDate>Mon, 08 Apr 2019 00:00:00 +0000</pubDate>
      
      <guid>/posts/colins-blog-1.0-%E6%9E%84%E5%BB%BA%E5%BF%83%E5%BE%97/</guid>
      <description>
        
          
          
          
        
        
        

&lt;p&gt;经过两三天的折腾，从 Linux 结构及指令，到 LNMP 框架搭建，再到数据库的配置，最后端口转发 + 内网穿透，博客终于成功上线！在此将部署过程及踩过的坑记录下来，一方面是纪念，另一方面希望能够后来人提供一点帮助。&lt;/p&gt;

&lt;h2 id=&#34;从想法到实现&#34;&gt;从想法到实现&lt;/h2&gt;

&lt;p&gt;第一代博客采用树莓派 3B + 构建。当初作为寒假的练手项目，入手了树莓派 3B + 以及智能小车所需的配件。由于时间没有规划好，最后在寒假前匆匆完成了小车硬件的组装，智能控制部分（wifi 遥控、红外循迹等）没能够完成。开学只带了树莓派的板子。闲置良久，想利用起来，刚好又有搭建大学生竞赛信息服务网站及公众号的想法，就开始着手构建基于树莓派的服务器，先从 Wordpress 搭建博客开始。&lt;/p&gt;

&lt;h2 id=&#34;lnmp-wordpress-框架搭建&#34;&gt;LNMP+Wordpress 框架搭建&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;L=Linux&lt;br /&gt;
N=Nginx&lt;br /&gt;
M=MySQL&lt;br /&gt;
P=PHP&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;LNMP 架构是广泛使用的服务器架构。与此类似的还有 LAMP，A=Apache。Nginx 与 Apache 作为目前市场上高度流行的两种服务器程序，网络上已经有非常多的相关的文档和教程。&lt;br /&gt;
关于 Nginx 与 Apache 的选择，这里只简单做个介绍：&lt;br /&gt;
&lt;strong&gt;Nginx&lt;/strong&gt;：资源占用低，性能好，配置简洁，功能有限。&lt;br /&gt;
&lt;strong&gt;Apache&lt;/strong&gt;：相对 Nginx 占用资源要多一点，不过插件和文档更丰富，设置某些功能的时候会方便一点。&lt;br /&gt;
具体两者的区别和测试可自行百度。刚开始考虑到树莓派的配置以及访问量，我选择使用 Nginx。具体部署过程此处不再赘述。&lt;br /&gt;
设置好 Nginx，开始配置 MySQL 和 PHP。安装 php 的时候开始遇到了一些小波折：网络上大部分教程都是基于 php5.0，安装包的时候都是类似于&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo apt-get install php5-fpm

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这样的，但在实际安装过程中会报错，说找不到这个名字的包。这个还算好解决，又搜索了几个教程，发现最新的版本为 php7.0，根据新版本 php 的教程按部就班做就基本 OK 了。&lt;/p&gt;

&lt;p&gt;WordPress 部署比较简单，但是对于新手而言，需要熟悉 Linux 基本指令：cd 目录切换，wget 文件下载，tar\zip 解压等。但是相对于有很多依赖项的或者配置繁琐的程序，Wordpress 安装其实已经算很简单了。&lt;/p&gt;

&lt;h3 id=&#34;第一个大坑-mysql&#34;&gt;第一个大坑：MySQL&lt;/h3&gt;

&lt;p&gt;安装 MySQL 一马平川，配置数据库，创建账户的时候也没有任何问题。然而第二次开始使用时，却发现刚刚设置的账户登不上去了？!! 翻来覆去又重装了几遍 MySQL，排除了账户密码错误、屏蔽了远程连接等可能性。最后一直停留在报错说登陆失败。无论是测试用户还是 root，有密码还是无密码，统统失败。Wordpress 里面连接数据库也一直失败&lt;/p&gt;

&lt;p&gt;这时怀疑不是数据库的问题，开始怀疑是 Nginx 或者 php。简单看了一下 Nginx 竟然无法启动？根据报错查了下日志发现与 php 的什么 fpm 和 fastcgi 通信有问题，又百度来百度去，改了下配置文件，把 fastcgi 通信的问题解决了。重启 nginx 服务又发现 80 端口被占用，又是一通百度。。。网上的解决方案无非两种：一种是 nginx 服务已经启动，直接另外用命令启动 nginx 服务必然会导致上述的问题。另外一种就是其他程序占用 80 端口，找到进程 kill 掉即可。然而我的问题并不是上面两种，无限郁闷 ing。。。&lt;/p&gt;

&lt;p&gt;但是测试网页的时候却发现网页可以正常显示？？? 又细查了一遍发现不知道什么时候又装了 Apache。。。又比 Nginx 先启动，自然会占用做网络服务器会用到的 80 端口。突然想起来安装 MYSQL 的时候好像弹出了个窗口。。。一阵哭笑不得。&lt;/p&gt;

&lt;p&gt;然而经过一晚上折腾，MySQL 这个问题依然没有解决。迫不得已，决定第二天尝试 SQlite。&lt;/p&gt;

&lt;h3 id=&#34;第二个大坑-pdo-driver&#34;&gt;第二个大坑：PDO Driver&lt;/h3&gt;

&lt;p&gt;在决定弃用 MySQL 后，毅然卸载了 MySQL 并删除了残留，全新安装 SQLite。这里简单介绍一下两者的区别：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;MySQL：功能强，效率高，支持多用户，安全性好，但是占用资源较多&lt;/p&gt;

&lt;p&gt;SQLite：精简版的 SQL，没有多用户概念，文件方式存储，方便迁移，占用资源少，运行快。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;满怀期待装好了 Sqlite，配置好了数据库，以及 Wordpress 配置文件 wp-config.php，没想到进去 Wordpress 报错。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PHP PDO Extension is missing

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;百度了下，说是 php 对 sqlite 的支持没有打开。需要到 php.ini 把对应属于 sqlite 的扩展启用，把被注释的部分提出来。&lt;/p&gt;

&lt;p&gt;一顿操作过后，进 Wordpress，又报&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PHP PDO Extension is not loaded

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;又是一顿猛肝，身心俱疲（无限查百度，查必应，查 StackOverflow，查官方文档）。一开始是看到有人说 php 扩展的目录默认是被注释的，看了下的却如此，就把改掉了。没想还是出错&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;;extension path= ../

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;当时的代码大致如此。改了之后还是没效果，又继续查。查到晚上两点困了累了，遂罢。&lt;/p&gt;

&lt;p&gt;第二天起床继续肝。早上起来和熬夜的效果就是不一样，没两下就突然想起来，被我解除注释的，php 扩展路径的那一行，它代表的是配置文件所在目录的父文件夹。但是他那个父文件夹底下根本就！！没有！！扩展名为 so 的扩展库文件！！！&lt;/p&gt;

&lt;p&gt;所以！是扩展目录问题了。&lt;/p&gt;

&lt;p&gt;但是他的扩展目录又到底在哪儿呢？百度的结果是说不同机子不一样。采用源代码编译安装的时候可以指定路径，但是我是用 apt 安装的。接下来是疯狂的找 php 扩展所在目录了。把百度的几个目录找了一遍，，又在其他地方又 php 字样的目录找了一遍，可算给我找到了。回去把 php.ini 一改，重启。哈！终于成了！&lt;/p&gt;

&lt;p&gt;第三个大坑：外网访问&lt;/p&gt;

&lt;p&gt;博客能够在内网正常访问了，折腾了两天总算有了成果。但是作为一个服务器只能在内网访问就没多大意思了。最终要做成的网站是要给人看的嘛。于是开始找树莓派外网访问的方案。大概有四种：&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&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;使用 frp 内网穿透。但是需要有另外一台有公网 IP 的 VPS。这还不如直接买一台阿里云的服务器呢。放弃。&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;使用 Ngrok 做内网转发。Ngrok 免费且评价还不错，就决定是你了！&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ngrok 的安装部署不难，简单来说就是注册账号，树莓派上安装 Ngrok，然后在树莓派上启动，与账号绑定。他会给你分配一个二级域名，打开这个域名，虽然有点慢，因为服务器在美国，但是成功地跳转到了我的博客主页！&lt;/p&gt;

&lt;p&gt;但是接下来的测试中发现，通过那个二级域名会指向我博客的主页，这时候点击页面上的任何连接都会跳转到我的树莓派的内网 IP。很明显，网站的博客的页面上的链接都是绝对地址，这也是为什么 Wordpress 的设置里面有一项是让你填写自己的网站的域名。这个比较好办，用相对路径就可以了。Wordpress 插搜索 Relative URL，就可以找到将全站链接转换为相对链接的插件。&lt;/p&gt;

&lt;p&gt;考虑到树莓派性能有限，网站在内网访问已经有点慢了，通过外网访问会更慢。于是就对站点进行了一些优化，速度大幅提升，外网访问的速度也可以接受了。具体教程可参见另一篇博文。&lt;/p&gt;

&lt;h2 id=&#34;大功告成&#34;&gt;大功告成&lt;/h2&gt;

&lt;p&gt;至此，FXZ‘s Blog 部署完成，正式上线！&lt;/p&gt;

&lt;p&gt;所谓努力与收获成正比自有它的道理，非常庆幸，也非常感谢自己坚持了下来。在这短短的两三天时间里，克服了众多困难，拒绝了数次开黑邀请。所幸结果是令人欣慰的，特此写下这第一篇博文。&lt;em&gt;2019 年 4 月 8 日晚于重庆&lt;/em&gt;&lt;/p&gt;

        
        </description>
    </item>
    
    <item>
      <title>黑苹果笔记</title>
      <link>/posts/%E9%BB%91%E8%8B%B9%E6%9E%9C%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Tue, 12 Mar 2019 00:00:00 +0000</pubDate>
      
      <guid>/posts/%E9%BB%91%E8%8B%B9%E6%9E%9C%E7%AC%94%E8%AE%B0/</guid>
      <description>
        
          
          
          
        
        
        

&lt;p&gt;从两年前第一次听说黑苹果，到暑假第一次装黑苹果，再到几个月前成功装上黑苹果，一路走来，收获颇丰。在这里将 Dell G3 大致安装过程记录下来。&lt;/p&gt;

&lt;p&gt;配置：Dell G3 3579 Intel i5-8300H UHD630 GTX1050Ti&lt;/p&gt;

&lt;h2 id=&#34;v1-0-千辛万苦从国外网站上淘来个-efi&#34;&gt;V1.0 千辛万苦从国外网站上淘来个 EFI&lt;/h2&gt;

&lt;p&gt;一开始想走捷径，爬国内外各种论坛找现成的 EFI。最后在 InsanelyMac 上找到一位老哥的 EFI，不料链接挂了。又注册论坛账号然后给他留言说能不能补发一次。这位小哥倒是挺热情的，不仅给了 EFI，还把安装中踩过的坑也一并列出来，以帮助后来者。没想到因为墙 + 移动的渣渣网络，补发的链接打不开。。。又到处 找梯子然而不好使。最后 还是借朋友的电信网成功下载下来了。（电信在宽带业务上深耕十几年了，移动才两三年怎么比得上）&lt;/p&gt;

&lt;p&gt;满怀欣喜的用上了这个 EFI。本来我是用黑果小兵的带 Clover 的镜像安装好了的，替换一下 EFI 就可以了。没想到装上去没用，没驱动的还是没驱动。可能是版本的原因吧，我当时装的是 10.14.2，而论坛里面大多是 10.13.6（截止本文写作时，GTX 系列显卡 驱动支持只到 10.13，10.14 的还没出）。没办法了，自己来吧。之前怕爬了那么多帖子，对黑苹果驱动优化也有了些了解。&lt;/p&gt;

&lt;h2 id=&#34;v1-2-2019-3-14-声卡-键盘-触控板&#34;&gt;V1.2 @2019.3.14 声卡 + 键盘 + 触控板&lt;/h2&gt;

&lt;p&gt;根据黑果小兵的帖子，对声卡进行了注入。&lt;/p&gt;

&lt;p&gt;这里要注意，一定要按照黑果小兵的帖子的步骤一步一步来，有些先决条件没有处理好，后续怎么折腾都是白搭。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ALC236 LayoutID：13+Hackintool 处理 = 声音播放 + 麦克风&lt;br /&gt;
笔记本键盘 OK&lt;br /&gt;
触控板 -&amp;gt; 鼠标&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;v1-3-2019-3-14-rndis-连接网络&#34;&gt;V1.3 @2019.3.14 RNDIS 连接网络&lt;/h2&gt;

&lt;p&gt;Dell G3 的有线网卡是非常好驱动的，但是自带的 Intel 无线网卡全球无解，只有 更换。考虑到目前没有用有线网，手头也没有小螺丝刀来拆机，于是选择通过共享手机网路。这里使用 HoRNDIS 驱动实现手机电脑 USB 网络共享。反正平时不是经常用，这样用够用了。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;RNDIS OK&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;v2-0-2019-3-14-驱动核显-uhd630&#34;&gt;V2.0 @2019.3.14 驱动核显 UHD630&lt;/h2&gt;

&lt;p&gt;照着黑果小兵的教程，使用 Hackintool 进行修补，最终成功实现了 UHD630 的驱动，显存显示 2048M，特效开启，丝滑顺畅。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;UHD630 OK&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;v2-1-2019-3-15-显示器-edid-修补-cpu-变频&#34;&gt;V2.1 @2019.3.15 显示器 EDID 修补 + CPU 变频&lt;/h2&gt;

&lt;p&gt;同样照着黑果小兵的教程，进行了 EDID 修补，使得 3 苹果系统可以正常识别我的显示器。感觉差别不是很明显啊，唯一的区别好像是之前一直都是显示的 21 寸外接显示器，现在显示的是 15.5′ 内建显示器。&lt;/p&gt;

&lt;p&gt;CPU 变频对平时的体验还是很重要的，多任务时自动升频，闲置自动降频，一方面保证日常体验，另一方面风扇不会 一直狂转。不过好像 10.14 默认支持 8 代 U，检测结果是可以正常变频，那就不用再处理了。就算不能，CPU-S 里面一件生成 SSDT 也是很方便的。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;EDID 修补&lt;br /&gt;
CPU 变频正常，无需处理&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;v2-2-2019-3-15-usb-端口修补&#34;&gt;V2.2 @2019.3.15 USB 端口修补&lt;/h2&gt;

&lt;p&gt;同样的根据黑果小兵的教程，使用 Hackintoool 进行 USB 修补。刚开始 也不知道这是干啥用的，我的所有 USB 端口都工作正常。后来知道屏蔽无效的端口可以避免一些很奇怪的坑，比如睡眠唤醒问题。那就做一下吧&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意：使用 hackintool 修补 usb 时导出 kext 和 dsdt 补丁前会要求修改 config.plist, 修改会导致异常，应略过此步骤&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;问题&lt;/strong&gt;：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;靠下的 USB3.0 无法使用 USB 2.0&lt;br /&gt;
Hub 需接上部的 USB3.0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;说明&lt;/strong&gt;：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;更正此问题只需更新 USBPort.kext&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;改动&lt;/strong&gt;：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;+XHCI-unsupported.kext&lt;br /&gt;
+USBPort.kext&lt;br /&gt;
-USBInjectAll.kext&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;v2-3-2019-3-15-修补声卡&#34;&gt;V2.3 @2019.3.15 修补声卡&lt;/h2&gt;

&lt;p&gt;用了一段时间发现之前弄好的声卡驱动只能外放，插上耳机就没声音了。经过一番探索，大致了解到 Layout-id 是布局文件，记录了不同的端口之间的映射关系。我这种情况是属于端口映射不当，耳机孔的输入与输出没能够正确映射。改了下声卡注入的 Platform-ID，解决了问题。当晚就用黑苹果看了个电影。Mac 的音效比较 清亮，也没有什么破音的现象，声卡驱动的很好。接下来可以放心的耍 Logic Pro X 了哈哈（当初想装黑苹果就是冲着 Logic Pro X 和 XCode 来的）&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;声卡 platform-id 修改为 15，外放 OK 麦克风 OK 耳机 OK&lt;br /&gt;
耳机麦克风 Failed&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;暂告一段落&#34;&gt;暂告一段落&lt;/h2&gt;

&lt;p&gt;黑苹果的显示 + 声音 + 网络等基本问题已经解决，虽然还 不是很完美，但是用 Logic 和 Xcode 已经没问题了，后续有时间 有需要 再继续折腾。&lt;/p&gt;

&lt;p&gt;Logic Pro X +USB 连接 iPad 上 Logic Remote 爽到飞起！看来不需要买 MIDI 键盘了，准备把资金换个大点的、更快的固态，把黑苹果装上去～&lt;/p&gt;

&lt;p&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;li&gt;文件名乱码&lt;/li&gt;
&lt;li&gt;重启后才能使用声卡&lt;/li&gt;
&lt;/ul&gt;

        
        </description>
    </item>
    
  </channel>
</rss>