How to Dynamically Load Nginx Variables from External Files: A Practical Guide


2 views

Nginx doesn't natively support reading file contents into variables during configuration parsing. The example you provided:

server {
    set $serverNames /www/test.txt;
    server_name $serverNames;
    ...
}

simply assigns the file path string to the variable rather than reading its content. This is a common pain point when trying to implement dynamic configuration.

Using include Directives

For static configurations that change infrequently:

# /etc/nginx/server_names.conf
server_name example.com test.example.com;

# main config
server {
    include /etc/nginx/server_names.conf;
    ...
}

Lua Module Approach

For dynamic content loading with OpenResty or nginx+lua:

http {
    lua_shared_dict server_names 1m;
    
    init_by_lua_block {
        local file = io.open("/www/test.txt", "r")
        ngx.shared.server_names:set("names", file:read("*a"))
        file:close()
    }
}

server {
    server_name $server_names;
    
    set_by_lua_block $server_names {
        return ngx.shared.server_names:get("names")
    }
}

Using Environment Variables

For containerized deployments:

server {
    server_name $SERVER_NAMES;
    ...
}

Then start nginx with:

SERVER_NAMES=$(cat /www/test.txt) nginx

Whichever method you choose, remember:

  • File read operations should be cached when possible
  • Implement proper error handling for missing files
  • Consider performance impact during reloads
  • For clustered environments, ensure synchronization

Many developers need to dynamically configure Nginx server names or other variables from external files, whether for multi-environment deployments or centralized configuration management. While Nginx doesn't natively support direct file reading in variable assignment, several effective workarounds exist.

The code snippet:

server {
    set $serverNames /www/test.txt;
    server_name $serverNames;
    ...
}

fails because Nginx treats the file path as a literal string value rather than reading its contents. The set directive doesn't have file reading capability.

1. Using include + map Combo

http {
    map $host $dynamic_server_name {
        include /www/test.map;
    }

    server {
        server_name $dynamic_server_name;
        ...
    }
}

Where test.map contains key-value pairs:

example.com example.com;
*.test.dev test.dev;

2. Lua Module Approach

For OpenResty or Nginx with Lua module:

server {
    access_by_lua_block {
        local file = io.open("/www/test.txt", "r")
        ngx.var.server_name = file:read("*a")
        file:close()
    }
    ...
}

3. Environment Variables via OS

env SERVER_NAMES_FILE=/www/test.txt;

http {
    server {
        server_name $SERVER_NAMES_FILE;
        ...
    }
}

Then populate via shell script:

export SERVER_NAMES=$(cat /www/test.txt)

For enterprise deployments:

  • Implement file change monitoring to reload Nginx when the source file updates
  • Add proper file permission controls
  • Consider using consul-template for distributed systems
  • Benchmark performance impact for high-traffic sites

For complex scenarios, consider:

# Docker-compose example
version: '3'
services:
  nginx:
    image: nginx
    volumes:
      - ./config:/dynamic_config
    command: /bin/bash -c "envsubst < /dynamic_config/template.conf > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"