文章851
标签121
分类10

如何在 Linux 上生成 PGP 公钥(支持老版本 GnuPG)


PGP(Pretty Good Privacy)是一种广泛使用的加密技术,常用于邮件加密、签名以及身份认证等安全场景。  
本文介绍如何在 Linux 系统中使用 `gpg` 命令生成并导出 PGP 公钥,兼顾 **老版本 GnuPG** 与 **新版本 GnuPG(2.1+)**。

---

## 一、环境准备

首先确认系统已安装 GnuPG:

```bash
gpg --version

输出类似:

gpg (GnuPG) 2.0.22

如果你看到 gpg: invalid option "--quick-gen-key" 这样的报错,说明你用的是 老版本 GnuPG(如 2.0 / 1.x),该版本不支持 --quick-gen-key
本文将分别介绍两种版本的密钥生成方法。


二、老版本 GnuPG(无 --quick-gen-key

老版本(如 GnuPG 2.0 / 1.x)必须使用交互式命令:

1. 生成密钥对

gpg --gen-key

然后按提示依次输入:

  • 密钥类型:选择 1(RSA and RSA)
  • 密钥长度:建议输入 4096
  • 有效期:输入 0 表示永不过期,或 1y 表示一年
  • 姓名 / 邮箱:任意填写
  • 口令:用于保护私钥

完成后 GPG 会在本地生成一对密钥(私钥 + 公钥)。

2. 查看已生成的密钥

gpg --list-keys

输出示例:

/root/.gnupg/pubring.gpg
------------------------
pub   4096R/2C09D88D 2025-08-21
uid                  <你的名字与邮箱>
sub   4096R/CBF9B651 2025-08-21

其中:

  • 2C09D88D 是主公钥的 KEYID
  • CBF9B651 是加密子钥的 KEYID

3. 导出公钥(ASCII 装甲)

gpg --armor --export 2C09D88D > public.asc

也可以用邮箱导出:

gpg --armor --export "yourname@example.com" > public.asc

public.asc 内容如下:

-----BEGIN PGP PUBLIC KEY BLOCK-----
...
-----END PGP PUBLIC KEY BLOCK-----

此文件即可安全地发给他人,用于加密或验证签名。


三、新版本 GnuPG(2.1+)

GnuPG 2.1 及以上版本支持 --quick-gen-key 命令,一条命令即可生成密钥对。

1. 一条命令生成密钥

gpg --quick-gen-key "Your Name <yourname@example.com>" default default 0

参数说明:

  • default 表示使用默认算法(ed25519 签名 + cv25519 加密)
  • 最后一个 0 表示永不过期(也可以写成 1y 表示一年)

2. 导出公钥

gpg --armor --export yourname@example.com > public.asc

或用 --list-keys 查出 KEYID 后用 KEYID 导出:

gpg --list-keys
gpg --armor --export <KEYID> > public.asc

四、导出私钥(仅限备份)

警告:私钥必须妥善保管,绝不能泄露!

gpg --armor --export-secret-keys 2C09D88D > private.asc

private.asc 文件建议离线保存,切勿上传或发送给他人。


五、常用命令速查表

功能命令示例
生成密钥(老版本)gpg --gen-key
生成密钥(新版本)gpg --quick-gen-key "Name <Email>" default default 0
查看密钥列表gpg --list-keys
导出公钥gpg --armor --export <KEYID> > public.asc
导出私钥gpg --armor --export-secret-keys <KEYID> > private.asc
查看指纹gpg --fingerprint <KEYID>

六、结语

无论你使用的是老版本 GnuPG 还是新版本,只要掌握了 gpg --gen-keygpg --armor --export 这两步,就能顺利生成并导出符合 PGP 标准的公钥。
如果你看到 gpg: WARNING: nothing exported,说明你导出命令中用的邮箱或 KEYID 不存在,先用 --list-keys 查出正确的 KEYID 即可。

掌握这些基础命令,你就可以安全地进行邮件加密、文件签名与身份认证等操作了。

Nginx 镜像流量:低成本实现流量复用

在微服务架构和持续交付的背景下,如何在不影响线上用户的前提下验证新功能、监控服务稳定性或分析流量特征?Nginx 的 镜像流量(Traffic Mirroring) 技术提供了一种轻量级解决方案——将生产环境的真实请求实时复制到测试/监控环境,主请求正常响应,镜像请求独立处理。本文将详细介绍基于 Nginx 内置模块 ngx_http_mirror_module 的配置方法与实践技巧。

一、什么是 Nginx 镜像流量?

镜像流量是指将客户端发送到 Nginx 的原始请求(包括请求方法、Header、Body 等),在完成主业务逻辑响应的同时,额外复制一份发送到指定的镜像后端服务器。其核心特点包括:
• 无侵入性:主请求不受镜像过程影响,用户无感知。

• 实时性:镜像流量与主请求同步触发,接近真实线上环境。

• 灵活性:可针对全量或部分流量(如特定接口、用户群体)进行镜像。

典型应用场景:
• 预发布验证:将生产流量镜像到预发布环境,验证新版本兼容性。

• 安全监控:复制流量到 WAF 或日志分析平台,检测异常行为(如 SQL 注入)。

• 数据分析:将流量同步到大数据平台,统计用户行为或接口性能。

二、核心模块与关键指令

Nginx 通过内置模块 ngx_http_mirror_module 实现镜像功能(默认编译进主线版本,无需额外安装)。主要指令如下:

指令 作用 示例

mirror 指定镜像请求的目标 URI(通常指向一个内部 location) mirror /mirror;

mirror_request_body on|off 是否镜像原始请求的 Body(POST/PUT 等需设为 on) mirror_request_body on;

internal 标记 location 为内部访问(仅允许 Nginx 内部转发,禁止外部直接调用) location = /mirror { internal; ... }

三、基础配置示例

场景假设

• 主业务后端:http://primary_backend:8000(处理真实用户请求)

• 镜像后端:http://mirror_backend:8080(接收复制的流量,如测试环境)

Nginx 配置代码

定义上游服务器(可选,便于管理)

upstream primary_backend {

server 192.168.1.10:8000;  # 主业务服务器

}

upstream mirror_backend {

server 192.168.1.20:8080;  # 镜像环境服务器

}

server {

listen 80;
server_name example.com;

location / {
    # 启用镜像,并指定镜像请求的 URI(/mirror)
    mirror /mirror;
    # 允许镜像请求携带 Body(POST/PUT 等接口必须开启)
    mirror_request_body on;

    # 主请求代理到生产后端
    proxy_pass http://primary_backend;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

# 镜像请求的处理 location(内部访问,禁止外部直接调用)
location = /mirror {
    internal;  # 关键!标记为内部 location
    # 将镜像请求代理到镜像后端,保留原始请求的 URI
    proxy_pass http://mirror_backend$request_uri;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

}

配置解析

  1. 主请求流程:用户访问 example.com/xxx 时,Nginx 先将请求代理到 primary_backend(主业务服务器),保证用户正常响应。
  2. 镜像流程:同时,Nginx 会根据 mirror /mirror 指令,将相同的请求(包括 Method、Headers、Body)复制一份,转发到本地的 /mirror location。
  3. 内部转发:/mirror location 通过 internal 限制仅允许 Nginx 内部访问,再通过 proxy_pass 将镜像请求发送到 mirror_backend:8080(镜像环境),且保留原始请求的 URI(如 /api/user)。

四、进阶功能:按条件镜像部分流量

若需仅镜像特定流量(如仅测试接口或特定用户),可通过 Nginx 的变量控制 mirror 指令的生效范围。

示例:仅镜像 /api/test 接口的流量

location / {

# 仅当请求 URI 是 /api/test 时启用镜像
if ($request_uri ~ ^/api/test) {
    mirror /mirror;
    mirror_request_body on;
}

proxy_pass http://primary_backend;
proxy_set_header Host $host;

}

location = /mirror {

internal;
proxy_pass http://mirror_backend$request_uri;

}

示例:按用户 ID 镜像(需请求头传递用户标识)

假设请求头中包含 X-User-ID,仅镜像用户 ID 为 1001 的流量:
map $http_x_user_id $should_mirror {

default 0;
"1001"  1;

}

server {

location / {
    if ($should_mirror) {
        mirror /mirror;
        mirror_request_body on;
    }
    proxy_pass http://primary_backend;
}

location = /mirror {
    internal;
    proxy_pass http://mirror_backend$request_uri;
}

}

五、注意事项与优化建议

  1. 性能与资源消耗

• 带宽与连接数:镜像流量会额外占用网络带宽和后端连接池,需确保镜像后端服务器具备足够的处理能力。

• 超时控制:镜像请求可能因后端延迟导致 Nginx 阻塞(尽管不影响主请求),建议调整以下参数:
location = /mirror {

  internal;
  proxy_pass http://mirror_backend$request_uri;
  proxy_connect_timeout 2s;  # 连接超时 2 秒
  proxy_read_timeout 5s;     # 读取响应超时 5 秒

}

  1. 敏感信息处理

镜像流量包含原始请求的所有内容(如 Cookie、Authorization 头),需在镜像后端或传输过程中对敏感数据(如用户密码、Token)进行脱敏或过滤,避免泄露。

  1. 监控与告警

建议对镜像后端的请求量、响应状态码(如 5xx 错误率)进行监控,及时发现镜像环境异常(避免误判为主业务问题)。

六、总结

Nginx 镜像流量是一种简单高效的流量复用方案,通过 ngx_http_mirror_module 模块,开发者可以零成本实现生产环境流量的实时复制,为测试验证、安全监控和数据分析提供真实数据支撑。实际使用时,需根据业务需求调整镜像范围、优化性能参数,并严格注意敏感信息保护。

动手试试吧! 通过简单的 Nginx 配置,你就能为团队搭建一个可靠的流量镜像环境,提升系统的稳定性和迭代效率。

参考资料:
http://nginx.org/en/docs/http/ngx_http_mirror_module.html

https://example.com/nginx-book(示例书籍,需替换为实际参考)

HTTP 499 状态码详解:客户端断开连接的背后真相

在日常开发与运维中,我们经常会关注 HTTP 返回码,如 200 表示成功,500 表示服务器异常等。但你是否在某些场景下遇到过一个非标准状态码 —— 499

这并不是一个出现在官方 HTTP 规范中的状态码,但它却频繁出现在 Nginx 的访问日志、API 网关、反向代理等场景中,很多开发者对它感到疑惑。今天我们就来深入解读一下 HTTP 499 状态码。


什么是 HTTP 499?

499 是 Nginx 自定义的非标准状态码,表示:

客户端主动关闭连接(Client Closed Request)而导致服务器未能完成处理。

换句话说,请求发出后,客户端在服务器处理完成之前就中断了连接,服务器虽然开始了处理,但结果还没来得及返回给客户端。


499 的典型触发场景

1. 用户主动取消请求

例如前端页面快速切换、刷新、关闭标签页等:

const controller = new AbortController();
fetch('/api/heavy-task', { signal: controller.signal });
controller.abort(); // 主动取消请求

2. 浏览器超时或重定向

浏览器在等待响应时超时,或中间请求被重定向、打断。

3. 反向代理/负载均衡器中断连接

在 Nginx 代理场景下,如果客户端断连,Nginx 就会记录该请求为 499。

4. 移动网络/弱网环境

网络不稳定时,TCP 连接断开,但服务器不知情,仍在继续处理。


与其他状态码的区别

状态码来源含义
408标准 HTTP请求超时,客户端太慢导致服务器主动断开
499Nginx 私有客户端主动断开连接(用户取消、页面关闭等
502网关/代理服务器网关错误
504网关超时后端服务响应超时

499 不属于 HTTP 官方规范(RFC),但在使用 Nginx、Traefik、Kong 等网关中非常常见。


如何排查 499 问题?

✅ 步骤一:确认日志来源

在 Nginx 的 access.log 中可能会看到如下记录:

192.168.1.100 - - [04/Aug/2025:10:32:12 +0800] "GET /api/data HTTP/1.1" 499 0 "-" "Mozilla/5.0 ..."

表示客户端断连,返回码为 499。

✅ 步骤二:排查耗时请求

查看该请求是否涉及长时间处理或慢查询,如数据库查询、文件上传、图像处理等。

✅ 步骤三:确认是否客户端取消

  • 前端是否使用了 AbortController 或 Axios 的 cancelToken
  • 移动端是否存在频繁切换网络、App 后台等情况。

✅ 步骤四:检查网关/代理配置

如:

proxy_read_timeout 60s;
proxy_connect_timeout 10s;

设置过短,可能导致连接被提前关闭。


如何避免或优化 499?

1. 优化后端处理性能

确保接口响应时间足够快,避免长耗时处理阻塞。

2. 前端增加 loading/防抖

防止用户频繁切换页面或发起重复请求。

3. 合理设置超时时间

后端超时时间建议略短于 Nginx 的 proxy_read_timeout,避免 Nginx 认为后端卡死。

4. 使用异步任务/排队机制

对于可能超过 10 秒的大任务,考虑使用任务队列 + 轮询/通知机制。


实战举例

某系统中 /api/export 接口导出数据体积较大,响应时间超过 20 秒。用户频繁点击导出后关闭页面,Nginx 日志中记录大量 499 请求。最终优化方案:

  • 将导出任务异步处理,返回任务 ID
  • 用户前端轮询任务状态,完成后再下载
  • 结果:导出成功率显著提升,499 错误大幅减少

总结

  • 499 是 Nginx 自定义的 HTTP 状态码,表示客户端主动断开连接
  • 常见于用户取消请求、页面刷新、代理连接断开等场景
  • 不属于 HTTP 官方状态码,但对线上排查性能问题非常有价值
  • 优化建议:前端请求管理、后端性能优化、合理超时设置

📌 参考资料

【踩坑】 Swoole 定时 Kill Worker 导致 TCP 粘包问题分析与解决

在高性能服务中,Swoole 常被用于构建 TCP/HTTP 长连接服务。但最近我们在实际业务(撮合引擎)运行中,遇到一个隐蔽但影响极大的问题:客户端 TCP 请求出现粘包/串包现象,导致撮合逻辑异常

经过多轮排查,最终定位到问题根因竟是我们为了防止内存泄漏设置的一个“自杀式”机制——worker 每 6 小时定时 kill 重启。以下是详细的分析过程与解决方案。


背景

在撮合系统中,核心引擎是一个基于 Swoole 的 TCP 长连接服务。由于部分逻辑存在小量内存泄漏,为防止单个 worker 长时间运行导致内存持续膨胀,我们在 worker 中加入了定时 kill 逻辑:

\Swoole\Timer::after(6 * 3600 * 1000, function () use ($pid) {
    \swoole_process::kill($pid, SIGKILL);
});

每 6 小时主动结束进程,由主进程重新拉起新 worker。

">