Appearance
HTTPS 与反向代理
端口
- 对外只有 nginx 的端口(
GEOBRIDGE_HTTP_PORT,默认 80;启用 HTTPS 后另有 443)。app 只发布在127.0.0.1:9086,worker、数据库、Redis、对象存储都不发布端口。云服务器的安全组只需放行 nginx 的端口。 - 不要把应用端口改成对外发布。 应用信任 nginx 传来的客户端地址;应用端口能被直接访问时,客户端可以伪造地址,绕过登录失败锁定与 API Key 的 IP 白名单。
- 部署目录的
nginx/geobridge.conf对应用之外的路径一律返回 404。 - nginx 的
server块是默认主机,按客户端带来的Host转发;同一个 nginx 还要服务其他站点时,把server_name改为本站域名。 - SELinux 强制模式的主机(RHEL、Rocky 等)上,
nginx/geobridge.conf与备份目录的绑定挂载需要标签:在compose.yml的挂载后加:z(如./nginx/geobridge.conf:/etc/nginx/conf.d/default.conf:ro,z),备份前对备份目录执行chcon -Rt container_file_t <目录>。
启用 HTTPS
- 把证书放到部署目录的
certs/:certs/fullchain.pem、certs/privkey.pem。 - 编辑
compose.yml的nginx服务,取消两行注释:端口"${GEOBRIDGE_HTTPS_PORT:-443}:443"与挂载./certs:/etc/nginx/certs:ro。 - 编辑
nginx/geobridge.conf:取消文末 443server块的注释,把 80 的server块中从proxy_set_header Host到最后一个location的内容原样复制到标记处,填写server_name。80 的server块只保留listen、server_name、absolute_redirect off;、access_log /dev/stdout geobridge;与return 301 https://$host$request_uri;(文件中的注释给出了完整写法;需要同时保留 HTTP 访问时可以不改)。access_log /dev/stdout geobridge;这一行不能删:删掉后访问日志退回 nginx 默认格式,会把带?token=的请求连同 API Key 记进日志。
- 编辑
.env:GEOBRIDGE_WEB_BASE_URL=https://<域名>/geobridge-mapserver(对外端口不是 443 时带上端口)。 - 执行
docker compose up -d,再执行docker compose restart nginx(配置文件以只读方式挂载,修改后需要重启 nginx)。
日志与 API Key
- nginx 与应用的访问日志都不记录查询串与 Referer,所以经
?token=传入的 API Key 不会写进访问日志。自己新增server块时同样写上access_log /dev/stdout geobridge;。 - nginx 的错误日志格式不能自定义:应用停止、重启或超时期间,带
?token=的请求会以完整的请求行写进错误日志。所以docker compose logs nginx的输出应与.env一样限制访问。第三方程序尽量用请求头X-GeoBridge-Token传 Key。不能接受时,可在server块中写error_log /dev/stderr crit;,代价是看不到上游错误。
前面另有反向代理或负载均衡
部署目录的 nginx 已按要求配置好。如果在它前面再加一层反向代理、负载均衡或 CDN,或者不用自带的 nginx 而改用自己的代理,必须满足:
覆盖而不是追加客户端地址:
nginxproxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host;- 不要用
$proxy_add_x_forwarded_for:平台取X-Forwarded-For最左边的值,追加时最左边是客户端自己写的值,可以绕过登录锁定与 IP 白名单。 - 同时清空客户端可能自带的
Forwarded、X-Forwarded-Host等请求头,完整写法见部署目录的nginx/geobridge.conf。 - 用
Host $http_host保留客户端带来的端口(对外端口不是 80、443 时$host会丢掉端口)。 - nginx 的
location中只要写了一条proxy_set_header,就不再继承server级的全部proxy_set_header,需要整组重写。 - 多级代理时,只有最外层用
$remote_addr,内层原样转发外层设置的值。
- 不要用
应用端口只能由代理访问:自带的 Compose 部署已只发布在
127.0.0.1;代理与应用不在同一台机器时,用防火墙或内网隔离只放行代理。上下文路径保持
/geobridge-mapserver:代理把/geobridge-mapserver/原样转发给应用,不要改写路径前缀。对外地址变化后按修改访问地址更新GEOBRIDGE_WEB_BASE_URL。请求体大小:上传接口
/geobridge-mapserver/api/需要允许 130 MB 以上的请求体(分片上传每片最大 128 MiB),/geobridge-mapserver/rest/允许 20 MB。WebSocket(可选):平台的实时数据推送默认关闭;开启后
/geobridge-mapserver/rest/需要支持 WebSocket 升级(转发Upgrade、Connection请求头)。
配置不对的后果:
- 没有正确传递客户端地址:登录失败锁定变成全站锁定(任意 30 次失败让所有人 15 分钟无法登录);API Key 的 IP 白名单失效;地图方案的公开样式地址被改写成内网地址。
- 应用端口仍对外开放,或代理「追加」了客户端地址:客户端可以伪造地址绕过登录锁定与 IP 白名单。
CDN
- 公开服务的瓦片与样式可以放在 CDN 之后,按平台返回的
Cache-Control缓存即可,各地址的缓存时长见缓存与性能。 - 「API Key」与「私有」级别服务的响应带
Cache-Control: private,CDN 必须遵守。不确定 CDN 是否遵守时,不要缓存/rest/geodata/services/下的响应,或只缓存公开服务的地址。 - 服务从公开改为非公开后,在 CDN 上清除该服务的地址前缀,见访问级别。
- CDN 回源时同样要按上一节传递客户端地址,否则 IP 白名单与登录锁定按 CDN 节点的地址计算。
在线系统安全清单
把平台对公网开放之前,逐项确认:
GEOBRIDGE_OUTBOUND_BLOCK_PRIVATE=true(安装默认):数据源的新建、修改、连接测试与健康检查不允许连接内网地址,否则有写权限的用户可以让数据源访问内网主机或云厂商的元数据服务。这项检查不覆盖发布与出图时按已保存参数发起的连接、HTTP 跟随的重定向,也不防 DNS 重绑定,所以云服务器上还要在主机层拦截元数据服务:阿里云 ECS 把实例元数据访问设为「仅加固模式」(控制台 → 实例 → 修改实例元数据访问信息);
在宿主上禁止容器访问元数据地址(
DOCKER-USER链只作用于容器流量):bashiptables -I DOCKER-USER -d 100.100.100.200 -j DROP iptables -I DOCKER-USER -d 169.254.169.254 -j DROP # 其他云厂商该规则重启后失效,请用
iptables-persistent(Debian/Ubuntu)或iptables-services(RHEL 系)保存。连接云数据库(如阿里云 RDS)等内网地址:不要关闭限制,而是在
.env中设GEOBRIDGE_OUTBOUND_ALLOW,优先写数据库的内网连接地址(主机名,如pgm-xxxx.pg.rds.aliyuncs.com)或它的 IP,其次是只含数据库的网段;多个用逗号分隔。不要写172.16.0.0/12、10.0.0.0/8这样的大网段:Compose 内部网络通常也在其中,等于放行了 Redis、对象存储与应用自身。修改后执行docker compose up -d。
- 不配置
GEOBRIDGE_SERVER_DATA_ROOTS:「服务器目录」数据源的目录浏览对所有登录用户开放。 - 应用端口不对外发布,安全组只放行 nginx 的端口。
- 修改
admin的初始密码;.env与备份分开、妥善保管。 - 服务与地图方案默认私有:需要公开的逐个设置访问级别,第三方程序使用 API Key。
- 启用 HTTPS,并确认
GEOBRIDGE_WEB_BASE_URL是https://的对外地址。