Skip to content

Instantly share code, notes, and snippets.

@br41n10
Created April 12, 2024 04:50
Show Gist options
  • Save br41n10/e2d378c7a04d4861b2f0cbf4d2476d71 to your computer and use it in GitHub Desktop.
Save br41n10/e2d378c7a04d4861b2f0cbf4d2476d71 to your computer and use it in GitHub Desktop.
An Apisix plugin to dynamically set upstream host:port based on URI, or Header or whatever. Very basic implementation, modify on your needs.
local upstream = require("apisix.upstream")
local core = require("apisix.core")
local ipmatcher = require("resty.ipmatcher")
local ngx = ngx
local schema = {
type = "object",
properties = {
},
additionalProperties = true,
}
local _M = {
version = 0.1,
priority = 80,
name = 'dynamic_uri_upstream',
schema = schema,
}
local function parse_domain(host)
local ip = ""
if not ipmatcher.parse_ipv4(host) and not ipmatcher.parse_ipv6(host)
then
local ip, err = core.resolver.parse_domain(host)
if ip then
return ip
end
if err then
core.log.error("dns resolver domain: ", host, " error: ", err)
end
end
return host
end
function _M.check_schema(conf)
return core.schema.check(schema, conf)
end
function _M.access(conf, ctx)
-- Get the request URI
local uri = ngx.var.uri
local args = ngx.var.args
-- get upstream hostport and path based on uri
local upstream_hostport, path = string.match(uri, "^/proxy/([^/]+)/?(.*)") -- change here on your needs !!!!!
if not path then
path = ""
end
local upstream_host, upstream_port = string.match(upstream_hostport, "([^:]+):?(%d*)")
if upstream_port == "" then
upstream_port = "80"
end
upstream_port = tonumber(upstream_port)
-- core.log.warn("hostport: ", upstream_hostport)
-- core.log.warn("path: ", path)
-- set path
ngx.req.set_uri("/" .. path)
-- set upstream
-- some params can be set from existing upstream config
-- or can be set by plugin conf
local up_conf = {
timeout = {
connect = 6,
send = 300,
read = 300
},
scheme = "http",
type = "roundrobin",
pass_host = "pass",
keepalive_pool = {
idle_timeout = 60,
requests = 1000,
size = 320
},
hash_on = "vars",
nodes = {
{
priority = 0,
port = upstream_port,
host = parse_domain(upstream_host),
weight = 1
}
}
}
local ok, err = upstream.check_schema(up_conf)
if not ok then
core.log.error("failed to validate generated upstream: ", err)
return 500, err
end
local matched_route = ctx.matched_route
up_conf.parent = matched_route
local upstream_key = up_conf.type .. "#route_" .. matched_route.value.id
core.log.info("upstream_key: ", upstream_key)
upstream.set(ctx, upstream_key, ctx.conf_version, up_conf)
end
return _M
@br41n10
Copy link
Author

br41n10 commented Apr 12, 2024

Note: in nginx, this can be done very simple

    location ~ /proxy\/(.*) {
        proxy_pass  http://$1?$args

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment