You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache在请求到达HTTPS端口前实现URL过滤/白名单配置的方案咨询

Apache在请求到达HTTPS端口前实现URL过滤/白名单配置的方案咨询

首先得明确:单纯靠Apache本身没法实现你要的效果,为啥呢?因为HTTPS的握手流程是先协商SSL证书,等握手完成之后,Apache才会收到请求里的Host头(也就是子域名)。这时候如果没有对应子域名的虚拟主机配置,Apache已经把默认证书发出去了,浏览器自然会弹出SSL错误——这步流程Apache没法跳过,所以必须在它前面加一层能提前解析SNI(SSL握手时客户端发送的服务器名称指示)的工具来过滤请求。

下面给你两个靠谱的实现方案,都是我实际用过的:

方案一:用Nginx做前置反向代理

Nginx可以在SSL握手阶段解析SNI,直接拒绝不在白名单里的请求,连证书都不用发,浏览器就会显示“连接超时”。

步骤很简单:

  1. 先装Nginx:sudo apt install nginx
  2. 修改Apache的监听端口,把443改成8080(或者其他没被占用的端口),这样Apache就不再直接对外暴露HTTPS端口了
  3. 配置Nginx的/etc/nginx/sites-available/default(或者新建一个配置文件):
# 处理所有无效子域名的请求,直接断开连接
server {
    listen 443 ssl;
    server_name _;
    # 随便整个无效证书就行,反正我们直接拒绝,不会用到它
    ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
    ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
    return 444; # Nginx的特殊返回码,直接关闭连接,不发任何响应
}

# 处理合法的app1子域名
server {
    listen 443 ssl;
    server_name app1.example.com;
    ssl_certificate /path/to/your/app1-cert.pem;
    ssl_certificate_key /path/to/your/app1-key.pem;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# 处理合法的app2子域名
server {
    listen 443 ssl;
    server_name app2.example.com;
    ssl_certificate /path/to/your/app2-cert.pem;
    ssl_certificate_key /path/to/your/app2-key.pem;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
  1. 重启Nginx和Apache:sudo systemctl restart nginx apache2

至于HTTP(80端口)的过滤,直接在Apache里配置就行:

<VirtualHost *:80>
    ServerName _
    RewriteEngine On
    RewriteRule ^ - [R=444,L] # 直接关闭连接
</VirtualHost>

<VirtualHost *:80>
    ServerName app1.example.com
    Redirect permanent / https://app1.example.com/
</VirtualHost>

<VirtualHost *:80>
    ServerName app2.example.com
    Redirect permanent / https://app2.example.com/
</VirtualHost>

方案二:修正HAProxy的配置(你之前可能配错了)

HAProxy同样支持基于SNI的ACL过滤,之前没成功大概率是没用到正确的SNI匹配规则。给你一个可行的配置示例:

修改HAProxy的主配置文件(比如/etc/haproxy/haproxy.cfg):

frontend https-in
    bind *:443 ssl crt /path/to/your/certs/ # 这里放所有合法子域名的证书,HAProxy会自动根据SNI选择
    # 定义白名单ACL,匹配合法的子域名
    acl valid_subdomain req.ssl_sni -i app1.example.com app2.example.com
    # 不在白名单里的请求直接拒绝
    tcp-request content reject unless valid_subdomain
    # 合法请求转发给Apache
    use_backend apache_backend if valid_subdomain

backend apache_backend
    server apache_localhost 127.0.0.1:8080 check # Apache监听8080端口

然后重启HAProxy:sudo systemctl restart haproxy,同时记得把Apache的443端口改成8080。

为啥Apache本身不行?

再啰嗦一句:Apache的mod_ssl是先完成SSL握手(发送证书),再处理虚拟主机和Host头。也就是说,当Apache知道用户访问的是哪个子域名时,已经把默认证书发出去了,这时候再拒绝也晚了,浏览器已经拿到无效证书,必然弹出SSL错误。所以必须用前置工具在握手阶段就把无效请求拦下来。

备注:内容来源于stack exchange,提问作者root

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 10:07:59