How to Auto‑Update Nginx Upstreams with Nacos Service Discovery (Lua & Java Agents)
Learn how to replace manual Nginx upstream configuration with automatic service discovery using Nacos, by either writing Lua scripts with the nginx‑lua‑module or building a Java/Golang agent that fetches instance lists via the Nacos API, updates upstream blocks, and triggers hot reloads.
Background
Traditionally, Nginx load‑balancing is configured manually by defining an
upstreamblock with static server IP:PORT entries and reloading Nginx whenever the service list changes.
<code>upstream serverList {
server 172.17.0.111:9999;
server 172.17.0.110:9999;
}
server {
location / {
proxy_pass http://serverList;
}
}
</code>In a micro‑service architecture, instances are registered in a service registry such as Nacos or Eureka, which already maintains the IP:PORT list. The goal is to let Nginx obtain this list automatically and update its
upstreamdefinition with hot reload.
Two Implementation Approaches
Use the
nginx‑lua‑moduleto write a Lua script that calls the registry’s HTTP API, generates the
upstreamconfiguration, and triggers a timed
reloadfor hot updates.
Write a separate agent in Java or Golang that uses the Nacos SDK to subscribe to service changes, generates the
upstreamblock, and invokes
nginx -s reloadwhen instances appear or disappear.
nacos‑nginx‑template
The second approach is packaged as the
nacos‑nginx‑templateproject, which runs an agent that watches Nacos and rewrites Nginx configuration.
Download binary
Configure config.toml
The configuration file uses TOML syntax. Example:
<code>nginx_cmd = "/usr/sbin/nginx" # full path to nginx binary
nacos_addr = "172.16.0.100:8848" # Nacos address
reload_interval = 1000 # refresh interval in ms
[discover_config1]
nginx_config = "/etc/nginx/nginx.conf"
nginx_upstream = "upsteam1"
nacos_service_name = "service1"
[discover_config2]
nginx_config = "/etc/nginx/nginx.conf"
nginx_upstream = "upsteam2"
nacos_service_name = "service2"
</code>Start the agent
<code>sh bin/startup.sh</code>Core Java Code
Read
config.toml, subscribe to Nacos services, and refresh upstream blocks.
<code>for (DiscoverConfigBO configBO : list) {
namingService.subscribe(configBO.getServiceName(),
event -> {
List<Instance> instances = namingService.getAllInstances(configBO.getServiceName());
// update nginx upstream
refreshUpstream(instances, configBO.getUpstream(), configBO.getConfigPath());
});
}
</code> <code>private boolean refreshUpstream(List<Instance> instances, String nginxUpstream, String nginxConfigPath) {
Pattern pattern = Pattern.compile(UPSTREAM_REG.replace(PLACEHOLDER, nginxUpstream));
String conf = FileUtl.readStr(nginxConfigPath);
String newUpstream = UPSTREAM_FOMAT.replace(PLACEHOLDER, nginxUpstream);
StringBuffer servers = new StringBuffer();
if (instances.size() > 0) {
for (Instance instance : instances) {
if (!instance.isHealthy() || !instance.isEnabled()) {
continue;
}
servers.append(formatSymbol + " server " + instance.getIp() + ":" + instance.getPort() + ";\n");
}
}
servers.append(formatSymbol);
newUpstream = newUpstream.replace(PLACEHOLDER_SERVER, servers.toString());
conf = matcher.replaceAll(newUpstream);
return true;
}
</code>Reload Nginx from Java:
<code>Runtime.getRuntime().exec("nginx -s reload");</code>Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.