# =============================================================================
# 企微智能IT支持服务台 — Nginx 配置（公司内网服务器版）
# =============================================================================
# 适用场景：独立域名 itsupport.servyou.com.cn，公司内网 DNS 解析
# 与 NAS 版的区别：
#   1. 移除 Cloudflare 相关头（X-Forwarded-Proto https 等）
#   2. server_name 改为正式域名
#   3. 真实 IP 直接从 $remote_addr 获取（无 CF 代理层）
#   4. 预留 HTTPS 配置注释（如公司有统一 SSL 终端）
# =============================================================================

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # ------------------------------------------------------------------
    # 日志格式
    # ------------------------------------------------------------------
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent"';

    access_log /var/log/nginx/access.log main;
    error_log  /var/log/nginx/error.log warn;

    # ------------------------------------------------------------------
    # 真实 IP 还原(2026-06-15 v0.5.1 修复)
    # ------------------------------------------------------------------
    # 问题:公司有 WAF/堡垒机/反向代理,nginx 看到的 $remote_addr
    #       是代理 IP(不在白名单),allow/deny 因此误判 403
    # 修法:信任内网段代理透传的 X-Forwarded-For 头,用真实 IP 做白名单
    # 注意:set_real_ip_from 是"我信任的代理",不是"我允许的客户端"
    #       必须精确,否则攻击者可伪造 X-Forwarded-For 绕过白名单
    set_real_ip_from 10.0.0.0/8;          # 内网 A 类(代理/WAF 出口)
    set_real_ip_from 172.16.0.0/12;       # 内网 B 类
    set_real_ip_from 192.168.0.0/16;      # 内网 C 类
    set_real_ip_from 10.212.0.0/16;       # VPN 网段
    real_ip_header    X-Forwarded-For;    # 从 X-Forwarded-For 取最后一个非信任 IP
    real_ip_recursive on;                 # 递归剥离已信任代理 IP

    # ------------------------------------------------------------------
    # 基础配置
    # ------------------------------------------------------------------
    sendfile           on;
    tcp_nopush        on;
    tcp_nodelay       on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    client_max_body_size 50m;   # 支持文件上传（企微媒体文件）

    # ------------------------------------------------------------------
    # Gzip 压缩（前端静态资源）
    # ------------------------------------------------------------------
    gzip            on;
    gzip_vary      on;
    gzip_min_length 1024;
    gzip_types      text/plain text/css text/xml text/javascript
                   application/javascript application/xml+rss
                   application/json application/ld+json;

    # =================================================================
    # 上游服务定义（Docker 内部网络）
    # =================================================================
    upstream backend_api {
        server backend:8000;
    }

    # =================================================================
    # HTTP 服务（监听 80 端口）
    # =================================================================
    # 如果公司有统一 SSL 终端（如 F5/Nginx 反代），此服务器只需监听 80
    # 如果需要本机 HTTPS，取消下方 server 块注释，并配置证书路径
    # =================================================================
    # HTTP — 80 端口强制 301 跳 HTTPS
    # =================================================================
    server {
        listen 80;
        server_name itsupport.servyou.com.cn;

        # ACME http-01 验证用（如果以后用 Let's Encrypt）
        location /.well-known/acme-challenge/ {
            root /usr/share/nginx/html;
        }

        # 其他全部 301 跳 https
        location / {
            return 301 https://$host$request_uri;
        }
    }

    # =================================================================
    # HTTPS — 443 端口(主服务)
    # =================================================================
    server {
        listen 443 ssl;
        http2 on;
        server_name itsupport.servyou.com.cn;

        # SSL 证书(通配符 *.servyou.com.cn,fullchain 含 leaf+intermediate+root)
        ssl_certificate     /etc/nginx/ssl/itsupport.servyou.com.cn.crt;
        ssl_certificate_key /etc/nginx/ssl/itsupport.servyou.com.cn.key;
        ssl_protocols       TLSv1.2 TLSv1.3;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
        ssl_session_cache   shared:SSL:10m;
        ssl_session_timeout 1d;

        # ------------------------------------------------------------------
        # 安全头
        # ------------------------------------------------------------------
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;

        # CSP 收紧: 去掉 unsafe-inline(生产不需要,只有 dev HMR 需要)
        add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-eval' https://res.wx.qq.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https: http:; connect-src 'self' https://qyapi.weixin.qq.com wss://*; font-src 'self' data:;" always;

        # 隐私与跨域控制
        add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
        add_header Cross-Origin-Opener-Policy "same-origin" always;
        add_header Cross-Origin-Embedder-Policy "require-corp" always;
        add_header Cross-Origin-Resource-Policy "same-origin" always;

        # 隐藏服务器版本
        server_tokens off;

        # ------------------------------------------------------------------
        # 健康检查端点
        # ------------------------------------------------------------------
        location = /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }

        # ------------------------------------------------------------------
        # H5 员工端 — /itdesk/
        # ------------------------------------------------------------------
        location /itdesk/ {
            alias /usr/share/nginx/html/itdesk/;
            index index.html;
            try_files $uri /itdesk/index.html;
        }

        # ------------------------------------------------------------------
        # 坐席工作台 — /itagent/
        # ------------------------------------------------------------------
        location /itagent/ {
            alias /usr/share/nginx/html/itagent/;
            index index.html;
            try_files $uri /itagent/index.html;
        }

        # ------------------------------------------------------------------
        # 管理后台 — /itadmin/（仅限内网/VPN 访问）
        # ------------------------------------------------------------------
        location /itadmin/ {
            # IP 白名单：仅允许内网网段
            allow 10.0.0.0/8;
            allow 172.16.0.0/12;
            allow 192.168.0.0/16;
            allow 10.212.0.0/16;  # VPN 网段
            deny all;

            alias /usr/share/nginx/html/itadmin/;
            index index.html;
            try_files $uri /itadmin/index.html;
        }

        # ------------------------------------------------------------------
        # 统一入口 Portal — /itportal/
        # ------------------------------------------------------------------
        location /itportal/ {
            alias /usr/share/nginx/html/itportal/;
            index index.html;
            try_files $uri /itportal/index.html;
        }

        # ------------------------------------------------------------------
        # 后端 API — /api/（管理端 API 仅限内网/VPN）
        # ------------------------------------------------------------------
        location /api/ {
            # 管理端 API 路径需要 IP 白名单
            location ~ ^/api/admin/ {
                allow 10.0.0.0/8;
                allow 172.16.0.0/12;
                allow 192.168.0.0/16;
                allow 10.212.0.0/16;
                deny all;

                proxy_pass http://backend_api;
                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_connect_timeout 60s;
                proxy_send_timeout    300s;
                proxy_read_timeout    300s;
            }

            # 其他 API 路径
            proxy_pass http://backend_api/;
            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;

            # 超时设置（AI 回复可能较慢）
            proxy_connect_timeout 60s;
            proxy_send_timeout    300s;
            proxy_read_timeout    300s;
        }

        # ------------------------------------------------------------------
        # WebSocket — /ws/（坐席端实时通信）
        # ------------------------------------------------------------------
        location /ws/ {
            access_log off;  # P0-#4: 关闭 WS 路径日志，避免 token 泄露
            proxy_pass http://backend_api;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            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_read_timeout 86400s;  # WebSocket 长连接
        }

        # ------------------------------------------------------------------
        # 企微回调 — /api/wecom/callback（接收企微消息推送）
        # ------------------------------------------------------------------
        # 企微验证回调 URL 时使用 GET，后续消息推送使用 POST
        # 此路径已包含在 /api/ 的代理规则中，无需单独配置

        # ------------------------------------------------------------------
        # 默认路径 — 重定向到统一入口
        # ------------------------------------------------------------------
        location = / {
            return 302 /itportal/;
        }
    }
}
