fix: 添加自动创建/更新 webroot 路由功能,修复证书申请时的路由匹配问题
- 新增 ensure_webroot_route 方法,自动创建或更新 APISIX webroot 路由 - 支持为指定域名创建带 host 字段的路由,确保正确匹配 - 在申请证书前自动确保 webroot 路由存在并配置正确 - 设置路由优先级为 99999,确保优先匹配 /.well-known/acme-challenge/* 路径 - 使用 serverless-pre-function 插件从 /var/www/certbot 目录读取验证文件 - 修复了证书申请时因路由匹配问题导致的 404 错误
This commit is contained in:
parent
3478db383e
commit
db30f3d7f1
@ -295,6 +295,78 @@ class APISIXSSLManager:
|
||||
logger.error(f"上传证书到 APISIX 失败: {e}")
|
||||
return False
|
||||
|
||||
def ensure_webroot_route(self, domain: str = None) -> bool:
|
||||
"""确保 webroot 路由存在并正确配置
|
||||
|
||||
Args:
|
||||
domain: 域名,如果提供则创建针对该域名的路由,否则创建通用路由
|
||||
"""
|
||||
if domain:
|
||||
route_id = f"certbot-webroot-{domain.replace('.', '-')}"
|
||||
else:
|
||||
route_id = "certbot-webroot"
|
||||
|
||||
route_url = f"{self.apisix_admin_url}/apisix/admin/routes/{route_id}"
|
||||
|
||||
try:
|
||||
# 检查路由是否存在
|
||||
response = self.session.get(route_url, timeout=10)
|
||||
|
||||
route_config = {
|
||||
"uri": "/.well-known/acme-challenge/*",
|
||||
"name": route_id,
|
||||
"priority": 99999,
|
||||
"plugins": {
|
||||
"serverless-pre-function": {
|
||||
"phase": "rewrite",
|
||||
"functions": [
|
||||
"return function(conf, ctx) local uri = ngx.var.uri; if not uri then uri = ctx.var.uri; end local token = string.match(uri, \"^/%.well%-known/acme%-challenge/(.+)$\"); if not token then ngx.status = 404; ngx.say(\"Token not found. URI: \" .. (uri or \"nil\")); return; end; local path = \"/var/www/certbot/.well-known/acme-challenge/\" .. token; local file = io.open(path, \"r\"); if file then local content = file:read(\"*all\"); file:close(); ngx.header.content_type = \"text/plain\"; ngx.say(content); else ngx.status = 404; ngx.say(\"File not found: \" .. path); end end"
|
||||
]
|
||||
}
|
||||
},
|
||||
"status": 1
|
||||
}
|
||||
|
||||
# 如果指定了域名,设置 host 字段以确保正确匹配
|
||||
if domain:
|
||||
route_config["host"] = domain
|
||||
|
||||
if response.status_code == 200:
|
||||
# 路由存在,检查是否需要更新
|
||||
existing_route = response.json().get('value', {})
|
||||
existing_priority = existing_route.get('priority', 0)
|
||||
existing_host = existing_route.get('host')
|
||||
|
||||
# 检查是否需要更新(优先级或 host 不匹配)
|
||||
needs_update = (existing_priority < 99999) or (domain and existing_host != domain)
|
||||
|
||||
if needs_update:
|
||||
logger.info(f"更新 webroot 路由: {route_id}")
|
||||
response = self.session.put(route_url, json=route_config, timeout=10)
|
||||
if response.status_code in [200, 201]:
|
||||
logger.info("Webroot 路由更新成功")
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"Webroot 路由更新失败: {response.status_code} - {response.text}")
|
||||
return False
|
||||
else:
|
||||
logger.debug(f"Webroot 路由已存在且配置正确: {route_id}")
|
||||
return True
|
||||
else:
|
||||
# 路由不存在,创建它
|
||||
logger.info(f"创建 webroot 路由: {route_id}")
|
||||
response = self.session.put(route_url, json=route_config, timeout=10)
|
||||
if response.status_code in [200, 201]:
|
||||
logger.info("Webroot 路由创建成功")
|
||||
return True
|
||||
else:
|
||||
logger.error(f"Webroot 路由创建失败: {response.status_code} - {response.text}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"确保 webroot 路由时出错: {e}")
|
||||
return False
|
||||
|
||||
def request_certificate(self, domain: str, additional_domains: List[str] = None, max_retries: int = 3) -> bool:
|
||||
"""申请 Let's Encrypt 证书
|
||||
|
||||
@ -303,6 +375,9 @@ class APISIXSSLManager:
|
||||
additional_domains: 额外域名列表
|
||||
max_retries: 最大重试次数(默认3次)
|
||||
"""
|
||||
# 确保 webroot 路由存在(为当前域名创建)
|
||||
self.ensure_webroot_route(domain)
|
||||
|
||||
domains = [domain]
|
||||
if additional_domains:
|
||||
domains.extend(additional_domains)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user