SSL 证书过期会导致网站无法访问,用 CertMonitor 可以监控证书有效期并邮件通知。
快速开始
- 注册账号:访问 certmonitor.xyz
- 添加域名:输入要监控的域名
- 配置通知:设置邮件接收地址
为什么需要
- Let’s Encrypt 证书 90 天到期,容易忘记续期
- 自动续期失败时能及时发现
Stuff I learned recently.
SSL 证书过期会导致网站无法访问,用 CertMonitor 可以监控证书有效期并邮件通知。
市售的食用鸡蛋几乎都是未受精的,无法孵化出小鸡。
超市买的鸡蛋放多久都孵不出小鸡,只会变质。
GitHub token 校验不要依赖固定长度,尤其不要写类似 ghs_[A-Za-z0-9]{36} 的正则。
GitHub 官方文档列出的 token 前缀包括:
ghp_: classic personal access tokengithub_pat_: fine-grained personal access tokengho_: OAuth access tokenghu_: GitHub App user access tokenghs_: GitHub App installation access tokenghr_: GitHub App refresh token2026-04-27 起,GitHub App installation token 会逐步切到 stateless 格式,ghs_ token 会变成类似 ghs_APPID_JWT 的结构,长度约 520 字符且会变化。JWT 部分也不应该由客户端解析或校验语义。
如果业务只是想拦住明显错误的输入,可以只做轻量格式检查:
const githubTokenRe = /^(?:(?:ghp|gho|ghu|ghs|ghr)_|github_pat_)[A-Za-z0-9_.-]+$/;
这个校验只确认是 GitHub 已知 token 前缀,并允许 JWT 常见的 . 和 -。真正有效性仍然应该交给 GitHub API 返回 401 Bad credentials 之类的结果判断。
更稳的原则:
GITHUB_TOKEN,跨 repo 或特殊权限才使用 PAT 或 GitHub App参考:
Workflowy 早期的 inline editing 不是直接用 contenteditable,而是把一个透明的 textarea 精确覆盖在当前 hover 的文本上,点击后再切换可见层。
实现思路:
opacity: 0 的 textarea 移动到这段文本上方。textarea,把 textarea 设为 opacity: 1,同时把底层文本设为 opacity: 0。textarea.value 到底层渲染节点。这样做的好处是输入、选区、键盘行为都交给原生 textarea 处理,同时显示层仍可以自己控制高亮、链接、tag 等富文本效果。
<!doctype html>
<meta charset="utf-8" />
<style>
.item {
position: relative;
padding: 4px 8px;
font: 16px/1.5 system-ui, sans-serif;
white-space: pre-wrap;
}
#editor {
position: absolute;
z-index: 10;
opacity: 0;
resize: none;
overflow: hidden;
border: 0;
padding: 4px 8px;
margin: 0;
font: 16px/1.5 system-ui, sans-serif;
background: transparent;
outline: none;
}
</style>
<div class="item">Buy milk #todo</div>
<div class="item">Read https://example.com</div>
<textarea id="editor"></textarea>
<script>
const editor = document.querySelector('#editor');
let currentItem = null;
document.querySelectorAll('.item').forEach((item) => {
item.addEventListener('mouseenter', () => {
if (document.activeElement === editor) return;
moveEditorOver(item);
});
});
function moveEditorOver(item) {
currentItem = item;
const rect = item.getBoundingClientRect();
editor.value = item.textContent;
editor.style.left = `${rect.left + window.scrollX}px`;
editor.style.top = `${rect.top + window.scrollY}px`;
editor.style.width = `${rect.width}px`;
editor.style.height = `${rect.height}px`;
editor.style.opacity = 0;
}
editor.addEventListener('mousedown', () => {
if (!currentItem) return;
currentItem.style.opacity = 0;
editor.style.opacity = 1;
});
editor.addEventListener('input', () => {
if (!currentItem) return;
currentItem.textContent = editor.value;
});
editor.addEventListener('blur', () => {
if (!currentItem) return;
currentItem.style.opacity = 1;
editor.style.opacity = 0;
});
</script>
想让 AI 在不熟悉的领域里产出更好,先学那个领域的 glossary。
很多 vibecoding 前端看起来差,不一定是模型不会写,而是 prompt 里只有「菜单」「按钮」「页面」这种粗粒度词。换成更准确的 UI component 名称,模型会更容易命中它内部已经学过的 pattern。
例如不要只说:
做一个有菜单和按钮的设置页。
先补一点 domain knowledge,再说:
做一个 settings surface:
- 左侧用 sidebar navigation
- 顶部用 toolbar,包含 segmented control 和 search field
- 主区域用 form section、field group、select、switch、slider
- 危险操作放到 destructive action zone
- 保存状态用 inline validation 和 toast feedback
这不是堆术语,而是在给 LLM 更精确的索引词。对任何陌生领域都一样:先问 AI 或文档要一份 glossary,掌握关键概念和对象名,再开始让它做事。磨刀不误砍柴工。
可以先看这些网站补词汇:
docker-compose.yml 中 tty: true 和 stdin_open: true 这两个配置项分别对应 docker run 的 -t 和 -i 参数。
分配虚拟终端(Pseudo-TTY),让程序输出像在普通命令行中运行,保留颜色和交互式输出。
保持标准输入开启,即使没有 attach 到容器也能接收指令。
Minecraft 服务器等需要交互式控制台的服务。
Minecraft 服务器有交互式控制台,可以:
/op yourname 给自己管理员权限,或 /stop 安全关闭服务器docker attach 进入游戏控制台直接输入指令如果没开这两个选项,docker attach 只能看输出,无法输入命令。
services:
mc:
image: itzg/minecraft-server
tty: true
stdin_open: true
总结:
tty负责输出,stdin_open负责输入。
公司网络能审计 HTTPS 访问记录,并非”破解了加密”,而是利用了 TLS 握手阶段明文传输的 SNI(Server Name Indication)。
在 HTTPS(即 TLS)连接中,代理/防火墙无需解密流量,也无需建立 CONNECT 隧道,只需旁路观察 TLS 握手的第一个 ClientHello 报文。
ClientHello 是未加密的明文数据,其中包含扩展字段。SNI 格式如下:
Extension: server_name
Hostname: example.com
代理/防火墙只需解析这个明文握手包,即可获取目标域名,无需:
SNI 是 TLS 扩展,用于解决单 IP 多域名场景。客户端必须在
ClientHello中明文告诉服务器想访问的域名,否则服务器无法选择正确证书。
HTTPS(TLS)保护的只是 HTTP 请求内容(路径、Header、Body),但不会隐藏目标域名和 IP 等元数据。
企业可在终端安装根证书,代理动态生成假证书解密流量。但已不属于纯 CONNECT 透传。
根据 2026 年最新实测数据,简单有效的 email 地址防爬虫方法:
| 方法 | 阻止率 |
|---|---|
| 无保护 | 0% |
| HTML Entities | 95% |
| HTML 注释 | 98% |
| HTML SVG | 100% |
| CSS display: none | 100% |
| JS 拼接 | 100% |
| JS 转换 (自定义函数) | 100% |
| JS AES 加密 | 100% |
| 方法 | 阻止率 |
|---|---|
| 无保护 | 0% |
| HTML Entities | 100% |
| URL 编码 | 96% |
| HTTP 重定向 | 100% |
| HTML SVG | 100% |
| JS 拼接 | 100% |
| JS 转换 | 100% |
| JS AES 加密 | 100% |
最简单且有效:CSS display: none + 变化诱饵标签
<div class="email">ad@<span>email.</span>spencermortensen.<span>example.</span>com</div>
div.email > span:nth-child(2) { display: none; }
无 JS 依赖,完全无障碍可用。
推荐方案:JS 转换(自定义函数)
<span id="email">zibby example com</span>
const map = { zibby: 'hello', example: 'gmail', com: 'com' };
// 自定义转换逻辑
原理:HTML 源码只有乱码,需要在浏览器端用 JS 转换才能得到真实 email。
最强方案:JS AES 加密(需 HTTPS)
<span class="email">Kreuz2xa6xB8Fpjaa0lFgACNLO6n_Auu1CGjcG8z_Ec</span>
使用浏览器内置 SubtleCrypto 进行 AES-256 加密。
关键发现:大多数爬虫很简单,即使最基础的混淆技术也能阻止 95% 以上的爬虫。建议组合使用多种技术。
Docker Compose 默认会给卷名加上项目前缀(目录名),使用 name 属性可自定义卷名。
services:
db:
image: postgres
volumes:
- my_custom_volume:/var/lib/postgresql/data
volumes:
my_custom_volume:
name: "production_db_volume"
运行 docker compose up 后,docker volume ls 会显示 production_db_volume,而非 my-app_my_custom_volume。
适用场景:
Docker Compose 中的 healthcheck 配置会覆盖 Dockerfile 中的 HEALTHCHECK 指令。
# docker-compose.yml
services:
web:
image: myapp
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
优先级:Dockerfile < Docker Compose。
为什么 Compose 优先?
遵循”运行时配置优于镜像构建配置”原则。Compose 覆盖 Dockerfile 的优势:
depends_on 的 condition: service_healthy 控制容器启动顺序AI 时代 LLM 经常需要读取 git diff,默认行为不要用 delta 修改。
Delta 安装时可能会自动添加配置:
[core]
pager = delta
需要先移除这个配置,然后在 .gitconfig 中添加:
[alias]
ds = -c pager.diff=delta diff
git diff 保持原生格式,便于 LLM 读取git ds 查看带 delta 的漂亮 diff 效果Bitwarden SSH Agent 默认会暴露所有可用密钥给 SSH 客户端,可能导致 Too many authentication failures 错误。通过 SSH Config 指定特定密钥解决。
# ~/.ssh/config
Host vps1
HostName domain.com
StrictHostKeyChecking no
User root
Port 26456
IdentityFile ~/.ssh/bw_keys/vps-auth.pub
IdentitiesOnly yes
Host vps2
HostName 1.1.1.1
StrictHostKeyChecking no
User root
Port 27644
IdentityFile ~/.ssh/bw_keys/vps-auth.pub
IdentitiesOnly yes
IdentitiesOnly yes 强制 SSH 只使用指定的密钥,跳过 Agent 中的其他密钥。
/usr/bin/env 是 Unix/Linux 系统中用于查找并运行程序的工具,主要用于 Shebang 中以提高脚本可移植性。
#!/usr/bin/python3 - 直接指定路径,跨系统兼容性差。
#!/usr/bin/env python3 - 在 $PATH 中搜索,兼容性极佳。
envenv 查看 $PATH 环境变量python3| 特性 | 直接路径 | 使用 env |
|---|---|---|
| 可移植性 | 差 | 极佳 |
| 虚拟环境支持 | 不支持 | 完美支持 |
| 灵活性 | 低 | 高 |
# 临时设置语言
env LANG=en_US.UTF-8 check_system_status
# 查看所有环境变量
env
env 不支持传递多个参数,如 #!/usr/bin/env python3 -u 在旧系统上可能失效。
使用 brew install 命令安装某些 cask 软件时,可以省略 cask 关键字,直接 brew install yaak 也能安装成功。
但在使用 brew bundle 命令时,必须在 Brewfile 中明确指定 cask 关键字:
# 正确写法
cask "yaak"
# 错误写法,会报错
brew "yaak"
原因:brew bundle 解析 Brewfile 时需要明确区分安装类型,而命令行 brew install 有自动检测能力。
测试覆盖率报告是构建产物,可以在本地或 CI 环境中随时重新生成,不应提交到 Git 仓库。
将 Git 仓库的默认分支从 master 修改为 main。
# 重命名本地分支
git branch -m master main
# 获取远程更新
git fetch origin
# 设置本地 main 分支跟踪远程 main 分支
git branch -u origin/main main
# 设置远程仓库的默认分支
git remote set-head origin -a 在 macOS 下配置如下参数,可以使用快捷键 ctrl+cmd来在任意位置拖拽窗口,而不是仅仅通过标题栏。
defaults write -g NSWindowShouldDragOnGesture YES

参考链接:https://www.reddit.com/r/MacOS/comments/k6hiwk/keyboard_modifier_to_simplify_click_drag_of/
Formula 用于从源码编译,Cask 用于分发预编译二进制。
Homebrew 团队希望统一 CLI 和 GUI 的安装体验,推动 brew install 作为唯一入口。因此 GoReleaser 官方推荐使用 Cask:
何时用 Cask:Go CLI 工具官方通常提供预编译二进制。
何时用 Formula:上游只提供源码、需要编译定制、或依赖本地库的软件。
自定义 tap 可同时包含两者:
# Formula
brew install zhaochunqi/homebrew-tap/<tool>
# Cask
brew install --cask zhaochunqi/homebrew-tap/<tool>
通过 homebrew-tap,可以让自己的项目通过 brew install 直接安装。
brew install zhaochunqi/tap/git-open
homebrew-<tap-name>,例如 homebrew-tapFormula/<formula-name>.rb 文件⚠️ 注意: Homebrew 官方不提倡在 Formula 中分发预编译二进制,这被认为是不好的实践。对于 Go CLI 工具等提供预编译二进制的项目,推荐使用 Homebrew Cask 进行分发。参考 Go CLI 工具更适合通过 Homebrew Cask 分发预编译二进制。
class GitOpen < Formula
desc "Open your git repo in browser using one command"
homepage "https://github.com/zhaochunqi/git-open"
version "2.2.1"
on_macos do
on_arm do
url "https://github.com/zhaochunqi/git-open/releases/download/v2.2.1/git-open_Darwin_arm64.tar.gz"
sha256 "9b653ba97f5095e8764f43eeb9ab0e46d01f4bbd14eadd51760b636512812a8c"
end
on_intel do
url "https://github.com/zhaochunqi/git-open/releases/download/v2.2.1/git-open_Darwin_x86_64.tar.gz"
sha256 "ab24e6fe8a49b6f526a785a94a10b56a139430f795346d30f8a5a5db1387223d"
end
end
on_linux do
on_arm64 do
url "https://github.com/zhaochunqi/git-open/releases/download/v2.2.1/git-open_Linux_arm64.tar.gz"
sha256 "8776da29b63a21f0949cda1814e30cc2c926bb6dee4199a9f7f0684486671c70"
end
on_x86_64 do
url "https://github.com/zhaochunqi/git-open/releases/download/v2.2.1/git-open_Linux_x86_64.tar.gz"
sha256 "cf91815149c341d718ea7b26d5d671e261bb8a5701e2de2da803d9a5a6c278c4"
end
end
def install
bin.install "git-open"
end
test do
system "#{bin}/git-open", "--version"
end
end
查看 ctrl + r绑定的键位::
❯ bindkey '^r'
"^R" history-incremental-search-backward
比如绑定 fzf-ghq-widget方法:
zle -N fzf-ghq-widget
# 1. 绑定默认 (Emacs) 模式
bindkey '^g' fzf-ghq-widget
# 2. 绑定 Vi 插入模式 (防止使用 Vi 模式时失效)
bindkey -M viins '^g' fzf-ghq-widget
解析: