guanghulab/server/nginx/novel-mirror-shield.conf
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

207 lines
9.4 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ═══════════════════════════════════════════════════════════
# 语言保护罩 · Novel智库节点入站保护配置
# ═══════════════════════════════════════════════════════════
#
# 编号: ZY-SVR-NGX-006-SHIELD
# 服务器: ZY-SVR-006 (43.153.203.105 · 新加坡 · 智库节点)
# 守护: 铸渊 · ICE-GL-ZY001
# 版权: 国作登字-2026-A-00037559
#
# 语言保护罩三层架构 (L2 + L3 由本配置实现):
#
# L1 · 出站伪装层 — 由 novel-api 的代理池模块负责
# L2 · 入站蜜罐层 — 本配置: 扫描者看到自己的镜像
# L3 · 自动封禁层 — fail2ban 监控 nginx 日志自动 ban
#
# 蜜罐原理:
# 未授权访问 → 返回 JSON 镜像,把扫描者的信息原样反射
# 服务器伪装为 CDN 静态节点,不暴露任何技术栈
# 真实应用 (4000/4001/4002) 只绑定 127.0.0.1,不直接暴露
#
# ═══════════════════════════════════════════════════════════
# ─── 全局:隐藏 Nginx 版本,伪装为 CDN ───
# 在 nginx.conf 主配置 http{} 块内设置:
# server_tokens off;
# more_set_headers 'Server: cloudfront'; # 需要 headers_more 模块
# 本配置通过 add_header 覆盖实现类似效果
# ─── 速率限制区域 (在 http{} 块定义,此处注释说明) ───
# limit_req_zone $binary_remote_addr zone=shield_limit:10m rate=10r/m;
# limit_conn_zone $binary_remote_addr zone=shield_conn:10m;
# ─── GeoIP 封锁区 (可选,需 ngx_http_geoip2_module) ───
# geo $blocked_country {
# default 0;
# # 如需按国家封锁,在此添加
# }
# ═══════════════════════════════════════════════════════════
# HTTP → HTTPS 重定向 · novel.guanghuyaoming.com
# ───────────────────────────────────────────────────────────
# 必须在 default_server (蜜罐) 之前定义,让合法域名流量
# 在到达蜜罐之前先被这个 server block 捕获并重定向到 HTTPS。
# Let's Encrypt ACME 挑战也在此处处理。
# ═══════════════════════════════════════════════════════════
server {
listen 80;
listen [::]:80;
server_name novel.guanghuyaoming.com;
server_tokens off;
# Let's Encrypt ACME 验证路径certbot 申请证书时需要)
location /.well-known/acme-challenge/ {
root /var/www/certbot;
try_files $uri =404;
}
# 所有其他请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# ═══════════════════════════════════════════════════════════
# 蜜罐 · 80 端口 — HTTP 入站捕获
# ═══════════════════════════════════════════════════════════
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
# 隐藏服务器信息,伪装为静态 CDN 节点
server_tokens off;
add_header Server "AmazonS3" always;
add_header X-Cache "Miss from cloudfront" always;
add_header Via "1.1 cloudfront.net (CloudFront)" always;
# 访问日志fail2ban 监控此日志)
access_log /var/log/nginx/shield-access.log;
error_log /var/log/nginx/shield-error.log warn;
# ─── 蜜罐路由:所有未知路径 ───
# 将扫描者的信息原样镜像反射回去
location / {
# 速率限制每分钟10次超出返回 429
limit_req zone=shield_limit burst=5 nodelay;
# 返回镜像响应 (纯静态 HTML不暴露后端)
default_type text/html;
return 200 '<!DOCTYPE html>
<html><head><meta charset="utf-8">
<title>Amazon S3</title>
<style>body{font-family:Arial,sans-serif;background:#f0f0f0;margin:40px;color:#333}
.container{max-width:600px;margin:0 auto;background:#fff;padding:40px;border-radius:4px;box-shadow:0 1px 3px rgba(0,0,0,.1)}
h1{color:#e47911;font-size:24px}p{line-height:1.6;color:#555}
.code{font-family:monospace;background:#f8f8f8;padding:12px;border-radius:3px;border-left:3px solid #e47911;font-size:13px}
</style></head>
<body><div class="container">
<h1>AccessDenied</h1>
<p>Access Denied</p>
<div class="code">RequestId: $request_id<br>
HostId: novel.guanghuyaoming.com</div>
</div></body></html>';
}
# ─── 健康检查(内部监控用,外部不知道此路径)───
location = /_shield_health {
allow 127.0.0.1;
deny all;
default_type application/json;
return 200 '{"status":"alive","shield":"active","layer":"L2"}';
}
}
# ═══════════════════════════════════════════════════════════
# 正式入口 · 443 端口 — HTTPSSSL 由 certbot 配置)
# ═══════════════════════════════════════════════════════════
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name novel.guanghuyaoming.com;
# SSL 证书certbot --nginx 自动填写)
ssl_certificate /etc/letsencrypt/live/novel.guanghuyaoming.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/novel.guanghuyaoming.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# 强化 SSL隐藏版本伪装 CDN
server_tokens off;
add_header Server "cloudfront" always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 不暴露后端 IP
add_header X-Powered-By "" always;
# 访问日志
access_log /var/log/nginx/novel-access.log;
error_log /var/log/nginx/novel-error.log warn;
# ─── 小说 API 后端 (:4000) ───
location /api/ {
proxy_pass http://127.0.0.1:4000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 不向后端暴露真实连接信息头
proxy_hide_header X-Powered-By;
proxy_hide_header Server;
proxy_read_timeout 120s;
}
# ─── Phase 1: 阅读器静态入口Phase 2 替换为 Node.js 阅读器)───
location / {
root /opt/novel-db/app/public;
try_files $uri $uri/ /index.html;
}
# ─── 成员 Agent API (:4002) ───
location /agent/ {
proxy_pass http://127.0.0.1:4002;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_hide_header X-Powered-By;
proxy_hide_header Server;
# Agent 长连接支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
}
# ─── 保护罩状态 API供面板拉取仅已认证用户可访问───
location /shield/ {
proxy_pass http://127.0.0.1:4000/shield/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# ─── 蜜罐:未知路径扫描捕获 ───
location @honeypot {
default_type application/json;
add_header Server "cloudfront" always;
add_header X-Cache "Hit" always;
return 403 '{"error":"AccessDenied","requestId":"$request_id","message":"Access Denied"}';
}
}
# ═══════════════════════════════════════════════════════════
# 扫描捕获 · 非标准端口蜜罐(需 iptables 引流)
# ═══════════════════════════════════════════════════════════
# 在 stream{} 块配置(须在 nginx.conf 引入 stream 模块)
# 将常见扫描端口(8080/8443/3000/3001/3002)流量引入蜜罐
# 可通过 iptables REDIRECT 规则实现:
# iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80
# iptables -t nat -A PREROUTING -p tcp --dport 8443 -j REDIRECT --to-port 80
# iptables -t nat -A PREROUTING -p tcp --dport 3000 -j REDIRECT --to-port 80
# 这样所有扫描常用端口的流量都被引导到蜜罐 80 端口