{"id":13776240,"url":"https://github.com/jkeys089/lua-resty-resolver","last_synced_at":"2025-12-30T00:31:17.896Z","repository":{"id":22209559,"uuid":"95603815","full_name":"jkeys089/lua-resty-resolver","owner":"jkeys089","description":"Caching DNS resolver for ngx_lua and LuaJIT","archived":false,"fork":false,"pushed_at":"2022-02-23T20:00:44.000Z","size":35,"stargazers_count":27,"open_issues_count":4,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-02-13T20:30:27.177Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jkeys089.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-27T21:50:26.000Z","updated_at":"2022-08-21T13:44:03.000Z","dependencies_parsed_at":"2022-08-03T08:00:46.844Z","dependency_job_id":null,"html_url":"https://github.com/jkeys089/lua-resty-resolver","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkeys089%2Flua-resty-resolver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkeys089%2Flua-resty-resolver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkeys089%2Flua-resty-resolver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jkeys089%2Flua-resty-resolver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jkeys089","download_url":"https://codeload.github.com/jkeys089/lua-resty-resolver/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253551495,"owners_count":21926303,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T18:00:20.148Z","updated_at":"2025-12-30T00:31:17.890Z","avatar_url":"https://github.com/jkeys089.png","language":"Perl","readme":"Name\n====\n\nlua-resty-resolver - Caching DNS resolver for ngx_lua and LuaJIT\n\n\nTable of Contents\n=================\n\n* [Name](#name)\n* [Status](#status)\n* [Description](#description)\n* [Motivation](#motivation)\n* [Synopsis](#synopsis)\n* [Master Methods](#master-methods)\n    * [new](#master-new)\n    * [init](#master-init)\n    * [set](#master-set)\n    * [client](#master-client)\n* [Client Methods](#client-methods)\n    * [new](#client-new)\n    * [get](#client-get)\n* [Prerequisites](#prerequisites)\n* [Installation](#installation)\n* [Demo](#demo)\n* [Copyright and License](#copyright-and-license)\n* [See Also](#see-also)\n\n\nStatus\n======\n\nThis library is still under active development and is considered production ready.\n\n\nDescription\n===========\n\nA pure lua DNS resolver that supports:\n\n*   Caching DNS lookups according to upstream TTL values\n*   Caching DNS lookups directly from the master (i.e. don't replicate DNS queries per worker thread)\n*   Support for DNS-based round-robin load balancing (e.g. multiple A records for a single domain)\n*   Low cache contention via local worker cache (i.e. workers sync from the master using a randomized delay to avoid contention)\n*   Optional stale results to smooth over DNS availability issues\n*   Configurable min / max TTL values\n*   Sensible security (e.g. don't allow potentially harmful results such as `127.0.0.1`)\n\n\nMotivation\n==========\n\nQ: Why would you want to use this library?\n\nA: You want dynamic DNS resolution [like they have in Nginx Plus](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#resolve)\n\nAs of nginx v1.9.x you'll need a commercial license to dynamically resolve upstream server names. The opensource version doesn't support this feature and will simply resolve each domain once and cache it forever (i.e. until nginx restart).\nThere are [workarounds](https://forum.nginx.org/read.php?2,248924,248924#msg-248924) but they are less than ideal (e.g. don't support [keepalive](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive)).\n\nThis module allows us to use the standard, open source [OpenResty bundle](https://openresty.org) _and_ get the benefits of dynamic upstream name resolution without sacrificing features like keepalive.\n\n\nSynopsis\n========\n\n```lua\n    # nginx.conf:\n\n    http {\n        lua_package_path \"/path/to/lua-resty-resolver/lib/?.lua;;\";\n\n        # global dns cache (may be shared for multiple domains but for best perf use separate zone per domain)\n        lua_shared_dict dns_cache 1m;\n\n        # create a global master which caches DNS answers according to upstream TTL\n        init_by_lua_block {\n            local err\n            cdnjs_master, err = require(\"resolver.master\"):new(\"dns_cache\", \"cdnjs.cloudflare.com\", {\"8.8.8.8\"})\n            if not cdnjs_master then\n                error(\"failed to create cdnjs resolver master: \" .. err)\n            end\n        }\n\n        # create a per-worker client that periodically syncs from the master cache (again, according to TTL values)\n        init_worker_by_lua_block {\n            cdnjs_master:init() -- master `init` must be called from a worker since it uses `ngx.timer.at`, it is ok to call multiple times\n            local err\n            cdnjs_client, err = cdnjs_master:client()\n            if not cdnjs_client then\n                error(\"failed to create cdnjs resolver client: \" .. err)\n            end\n        }\n\n        # use per-worker client to lookup host address\n        upstream cdnjs_backend {\n            server 0.0.0.1;   # just an invalid address as a place holder\n\n            balancer_by_lua_block {\n                -- note: if `lua_code_cache` is `off` then you'll need to uncomment the next line\n                -- local cdnjs_client = require(\"resolver.client\"):new(\"dns_cache\", \"cdnjs.cloudflare.com\")\n                local address, err = cdnjs_client:get(true)\n                if not address then\n                    ngx.log(ngx.ERR, \"failed to lookup address for cdnjs: \", err)\n                    return ngx.exit(500)\n                end\n\n                local ok, err = require(\"ngx.balancer\").set_current_peer(address, 80)\n                if not ok then\n                    ngx.log(ngx.ERR, \"failed to set the current peer for cdnjs: \", err)\n                    return ngx.exit(500)\n                end\n            }\n\n            keepalive 10;     # connection pool MUST come after balancer_by_lua_block\n        }\n\n        server {\n            location =/status {\n                content_by_lua_block {\n                    local address, err = cdnjs_client:get()\n                    if address then\n                        ngx.say(\"OK\")\n                    else\n                        ngx.say(err)\n                        ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)\n                    end\n                }\n            }\n\n            location = /js {\n                proxy_pass http://cdnjs_backend/;\n                proxy_pass_header Server;\n                proxy_http_version 1.1;\n                proxy_set_header Connection \"\";\n                proxy_set_header Host cdnjs.cloudflare.com;\n            }\n        }\n    }\n```\n\n[Back to TOC](#table-of-contents)\n\n\nMaster Methods\n==============\n\nTo load the master library,\n\n1. you need to specify this library's path in ngx_lua's [lua_package_path](https://github.com/openresty/lua-nginx-module#lua_package_path) directive. For example, `lua_package_path \"/path/to/lua-resty-resolver/lib/?.lua;;\";`.\n2. you use `require` to load the library into a local Lua variable:\n\n```lua\n    local resolver_master = require \"resolver.master\"\n```\n\n\nmaster new\n----------\n`syntax: local master, err = resolver_master:new(shared_dict_key, domain, nameservers [, min_ttl, max_ttl, dns_timeout, blacklist])`\n\nCreates a new master instance. Returns the instance and an error string.\nIf successful the error string will be `nil`.\nIf failed, the the instance will be `nil` and the error string will be populated.\n\nThe `shared_dict_key` argument specifies the [ngx.shared](https://github.com/openresty/lua-nginx-module#ngxshareddict) key to use for cached DNS values.\nIt is OK to use the same shared dict for multiple domains (i.e. masters are careful not to interfere with other masters resolving other domains).\nHowever, for best performance it is recommended to use a different shared dict for each domain.\n\nThe `domain` argument specifies the fully qualified domain name to resolve.\n\nThe `nameservers` argument specifies the list of nameservers to query (see the `nameservers` param in of [resty.dns.resolver:new](https://github.com/openresty/lua-resty-dns#new).\n\nThe `min_ttl` argument specifies the minimum allowable time in seconds to cache the results of a DNS query.\nThe default value is `10`.\n\nThe `max_ttl` argument specifies the maximum allowable time in seconds to cache the results of a DNS query.\nThe default value is `3600` (1 hour).\n\nThe `dns_timeout` argument determines the maximum amount of time in seconds to wait for DNS results.\nWe also use this value to schedule future DNS queries (i.e. query a bit earlier than the TTL suggests to allow for potential lag up to the `dns_timeout` value when receiving the results).\n**Note:** this is _NOT_ the total timeout for all nameservers. The total time is calculated as `dns_timeout * 5` since we use the default `retrans` value in [resty.dns.resolver:new](https://github.com/openresty/lua-resty-dns#new).\nThe default value is `2`.\n\nThe `blacklist` argument specifies table of banned IP addresses which are ignored if included in DNS server response.\nThe default value is `{\"127.0.0.1\"}`.\n\nThe master instance is thread safe and can be safely shared globally (typically declared as a global in a [init_by_lua_block](https://github.com/openresty/lua-nginx-module#init_by_lua_block)).\n\n[Back to TOC](#table-of-contents)\n\n\nmaster init\n-----------\n`syntax: local ok, err = master:init()`\n\nInitializes a master instance and causes the master to populate the cache ASAP. Returns a success indicator and an error string.\nIf successful the success indicator will be truthy and the error string will be `nil`.\nIf failed, the success indicator will be falsy and the error string will be populated.\n\nThe `init` method **MUST** be called in a context that supports the use of [ngx.timer.at](https://github.com/openresty/lua-nginx-module#ngxtimerat) (e.g. the first usable entrypoint is [init_worker_by_lua_block](https://github.com/openresty/lua-nginx-module#init_worker_by_lua_block)).\nThis method is idempotent and can be safely called any number of times without any impact.\n\n[Back to TOC](#table-of-contents)\n\n\nmaster set\n----------\n`syntax: local next_query_delay = master:set(lookup_result [, exp_offset])`\n\nCaches the DNS query results. Returns the amount of time in seconds to delay before querying again.\n\nThe `lookup_result` argument is a table containing successful query results (i.e. each entry is a table with IPv4 `address` and `ttl` seconds keys).\n\nThe `exp_offset` argument is the expiration offset to use with each record's TTL (useful for testing).\nThe default value is the current timestamp determined by [ngx.now](https://github.com/openresty/lua-nginx-module#ngxnow)\n\nThis method should not be used in normal operation and is only really useful for testing.\n\n[Back to TOC](#table-of-contents)\n\n\nmaster client\n----------\n`syntax: local client, err = master:client()`\n\nConvenience method for creating a new client.\nExactly the same as calling [resolver_client:new](#client-new) with the same `shared_dict_key` and `domain` used by the master instance.\n\n[Back to TOC](#table-of-contents)\n\n\nClient Methods\n==============\n\nTo load the client library,\n\n1. you need to specify this library's path in ngx_lua's [lua_package_path](https://github.com/openresty/lua-nginx-module#lua_package_path) directive. For example, `lua_package_path \"/path/to/lua-resty-resolver/lib/?.lua;;\";`.\n2. you use `require` to load the library into a local Lua variable:\n\n```lua\n    local resolver_client = require \"resolver.client\"\n```\n\n[Back to TOC](#table-of-contents)\n\n\nclient new\n----------\n`syntax: local client, err = resolver_client:new(shared_dict_key, domain)`\n\nCreates a new client instance. Returns the instance and an error string.\nIf successful the error string will be `nil`.\nIf failed, the the instance will be `nil` and the error string will be populated.\n\nThe `shared_dict_key` argument specifies the [ngx.shared](https://github.com/openresty/lua-nginx-module#ngxshareddict) key to use for cached DNS values and should be the same value used when creating the master instance.\n\nThe `domain` argument specifies the fully qualified domain name to resolve and should be the same value used when creating the master instance.\n\nClient instances are _NOT_ thread safe and should be shared only at the worker level (typically declared as a global in a [init_worker_by_lua_block](https://github.com/openresty/lua-nginx-module#init_worker_by_lua_block)).\n**Note:** when [lua_code_cache](https://github.com/openresty/lua-nginx-module#lua_code_cache) is `off` (e.g. during development) it is not possible to use a global, per-worker client due to the new lua VM per-request model.\n\n[Back to TOC](#table-of-contents)\n\n\nclient get\n----------\n`syntax: local address, err = client:get([exp_fallback_ok])`\n\nRetrieve the next cached address using a simple round-robin algorithm to choose when multiple addresses are available. Returns an IPv4 address string and an error string.\nIf successful the error string will be `nil`.\nIf failed, the the address will be `nil` and the error string will be populated.\n\nThe `exp_fallback_ok` argument is a boolean which determines if it is OK to return a stale value (`true` when a stale value is allowable, `false` when it is NOT ok to return a stale value).\nA stale value is one that has been cached longer than the TTL duration. If there is even one fresh record it will always be returned, even when `exp_fallback_ok` is `true`.\nThe default value is `false`.\n\nClients will automatically sync from the master cache as needed.\nUnder normal conditions there should never be a situation where the client has no fresh records. However, if the upstream nameserver becomes unavailable the local cache may expire while the master continues to retry.\nThe client will always retain at least one stale record so that it may continue to service requests until the upstream nameserver becomes available.\nIt may be preferable to return an error rather than use stale results which is why the `exp_fallback_ok` option defaults to `false`.\n\n[Back to TOC](#table-of-contents)\n\n\nPrerequisites\n=============\n\n* [LuaJIT](http://luajit.org) 2.0+\n* [ngx_lua module](http://wiki.nginx.org/HttpLuaModule)\n* [lua-resty-dns](https://github.com/openresty/lua-resty-dns)\n\nThese all come with the standard [OpenResty bundle](http://openresty.org).\n\n[Back to TOC](#table-of-contents)\n\n\nInstallation\n============\n\nIt is recommended to use the latest [OpenResty bundle](http://openresty.org) directly. You'll need to enable LuaJIT when building your ngx_openresty\nbundle by passing the `--with-luajit` option to its `./configure` script.\n\nAlso, you'll need to configure the [lua_package_path](https://github.com/openresty/lua-nginx-module#lua_package_path) directive to\nadd the path of your lua-resty-resolver source tree to ngx_lua's Lua module search path, as in\n\n```nginx\n    # nginx.conf\n    http {\n        lua_package_path \"/path/to/lua-resty-resolver/lib/?.lua;;\";\n        ...\n    }\n```\n\nand then load the library in Lua:\n\n```lua\n    local resolver_master = require \"resolver.master\"\n```\n\nDemo\n====\n\nA demo app is provided through [this repository](https://github.com/mauricioabreu/dynamic-dns-resolver-demo)\n\nWith this app you can test all features provided by this library without having to integrate it in your real project.\n\n[Back to TOC](#table-of-contents)\n\n\nCopyright and License\n=====================\n\nThis module is licensed under the BSD license.\n\nCopyright (C) 2012-2025, Thought Foundry Inc.\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n[Back to TOC](#table-of-contents)\n\n\nSee Also\n========\n* the ngx_lua module: http://wiki.nginx.org/HttpLuaModule\n\n[Back to TOC](#table-of-contents)\n","funding_links":[],"categories":["Libraries"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjkeys089%2Flua-resty-resolver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjkeys089%2Flua-resty-resolver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjkeys089%2Flua-resty-resolver/lists"}