跳到主要内容

Caddy2插件Geocn

· 阅读需 3 分钟

为什么要Geocn

大部分场景下,我们网站允许任何人访问, 某些特殊场景下我们需要限制大陆ip访问。 但是已有插件caddy-maxmind-geolocation为啥不用。

默认使用的 GeoIP2 数据库是来自于 MaxMind 的 GeoLite2 免费数据库。这个数据库目前存在一下几个问题:

  • 获取不便:从 2019 年 12 月 30 日起,必须注册后才能下载
  • 数据量大:数据库庞大,包含全球的 IP 地址段,约 4 MB
  • 准确度低:对中国大陆的 IP 地址判定不准,如:香港阿里云的 IP 被判定为新加坡、中国大陆等

新的政策要求注册才能下载会增加时间成本,而且会让自动化下载的难度大大增加。庞大的数据量无可厚非,但是对于大多数中国大陆的用户来说,仅需要去判断 IP 的地理位置是否属于中国大陆境内,其他国家的 IP 一律代理。过多的数据量会增加载入时间,降低查询效率。

基于上述考虑, 结合caddy-maxmind-geolocationHackl0us/GeoIP2-CN两者, 只有判断ip是否是中国大陆ip即可。

核心设计

  • 使用Hackl0us/GeoIP2-CN提供的准确度高、用户使用体验好的仅含有中国大陆 IP 信息的 GeoIP2 数据库
  • 使用caddyhttp.RequestMatcher, 不得不说 Request Matchers
    • 获取request.RemoteAddr地址, 优先级最高
    • request.Header获取X-Forwarded-For地址, 如果RemoteAddr为内网地址,才考虑

使用caddy

编译caddy2

可以参考 ysicing/caddy2

默认情况下, 直接使用提供的二进制即可。不过我们需要集成第三方插件,需要使用xcaddy自行编译

# 本地安装xcaddy
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
# github action安装
- name: Install Go
uses: actions/setup-go@v1
with:
go-version: 1.17.x
- name: install xcaddy
run: |
echo "install xcaddy"
go get -u github.com/caddyserver/xcaddy/cmd/xcaddy@latest
- name: build bin
run: |
export TZ='Asia/Shanghai'
export PATH=$PATH:$(go env GOPATH)/bin
xcaddy build --with github.com/ysicing/caddy2-geocn

构建caddy二进制

# 使用remote code
xcaddy build --with github.com/ysicing/caddy2-geocn
# 使用local code
xcaddy build --with github.com/ysicing/caddy2-geocn=../caddy2-geocn

插件本地化测试

cd go/src/github.com/ysicing/
git clone https://github.com/ysicing/caddy2-geocn.git
cd caddy2-geocn
# 二进制
make build
make run
# docker
GOOS=linux xcaddy build --with github.com/ysicing/caddy2-geocn=../caddy2-geocn
rm -rf Country.mmdb
wget https://github.com/Hackl0us/GeoIP2-CN/raw/release/Country.mmdb
docker build -t ghcr.io/ysicing/caddy2-geocn -f example/Dockerfile .

docker-compose.yaml示例如下:

version: '2'
services:
caddy2-geocn:
image: ghcr-proxy.hk1.godu.dev/ysicing/caddy2-geocn
container_name: caddy2-geocn
ports:
- '80:80'
volumes:
- './Caddyfile:/etc/caddy/Caddyfile'

Caddyfile示例如下:

(LOG) {
log {
output file /var/log/caddy.log {
roll_size 1mb
roll_keep 5
roll_keep_for 1h
}
format console {
time_format "iso8601"
}
}
}

(COMCFG) {
encode zstd gzip
}

{
debug
}

:80 {
import COMCFG
import LOG
metrics /metrics
@geofilter {
not geocn {
db_file "/etc/caddy/Country.mmdb"
}
}
# file_server @geofilter {
# root /etc/caddy/example/deny
#}
redir @geofilter https://www.baidu.com{uri} permanent
file_server {
root /etc/caddy/example/allow
}
}
EOF
docker-compose up -d

云环境

docker run -itd 80:80 ghcr.io/ysicing/caddy2-geocn:latest

应用场景

我的博客 就是很好的示例, 分别使用代理和非代理方式访问

致谢