Exciting news! TCMS official website is live! Offering full-stack software services including enterprise-level custom R&D, App and mini-program development, multi-system integration, AI, blockchain, and embedded development, empowering digital-intelligent transformation across industries. Visit dev.tekin.cn to discuss cooperation!

envsubst: Production-Grade Secure Environment Variable Substitution Tool Built for Nginx/Docker/K8s

2026-04-19 16 mins read

This article introduces an enhanced version of the envsubst tool that solves security issues of the native tool in Nginx configuration substitution. It supports advanced features like wildcard whitelists, default value syntax, and debug mode, with zero dependencies—perfect for containerized deployment scenarios.

envsubst-secure-environment-variable-substitution-nginx-docker-k8s
 

1. Background & Pain Points

1.1 Why envsubst?

In containerized and microservice architectures, we often need to dynamically generate configuration files based on environment variables. Typical scenarios include:

  • Nginx configuration: Set listening ports and backend addresses via environment variables
  • Docker containers: Inject configuration at startup
  • Kubernetes: ConfigMap template rendering
  • CI/CD pipelines: Multi-environment configuration management

    The native envsubst (from GNU gettext) is simple but has critical flaws in production.

1.2 Three Major Pain Points of Native envsubst

Pain Point 1: Breaks Nginx Built-in Variables

# Template file
server {
    listen ${PORT};
    server_name ${HOST};
    
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;        # ← Nginx built-in variable
        proxy_set_header X-Real-IP $remote_addr;  # ← Nginx built-in variable
    }
}

# Using native envsubst
envsubst < nginx.conf.template > nginx.conf

Result: $host and $remote_addr are incorrectly replaced with empty strings → Nginx config failure!

Pain Point 2: Lack of Fine-Grained Control Native envsubst either replaces all variables or lists every variable explicitly:

# Method 1: Replace all (DANGEROUS)
envsubst < config.tpl

# Method 2: List one by one (cumbersome)
envsubst '$DB_HOST $DB_PORT $REDIS_URL $API_ENDPOINT ...' < config.tpl

No wildcard support → high maintenance cost with dozens of variables.

Pain Point 3: Poor Undefined Variable Handling

echo '${UNDEFINED_VAR}' | envsubst
# Output: empty string (variable deleted)

In many cases, we want to keep undefined variables as-is, not erase them.


2. Solution: Enhanced envsubst

2.1 Core Feature Comparison

FeatureNative envsubstEnhanced envsubst
${VAR} substitution
$VAR substitution⚠️ Requires --all
Protect Nginx variables✅ Enabled by default
Wildcard whitelist✅ Supported
Preserve undefined vars-k flag
Default value support${VAR:-default}
Invalid variable handlingDelete/blank✅ Preserve as-is
Debug mode--debug
Statistics--stats/--json-stats
Whitelist file--whitelist-file
Binary size~17KB~50KB
Dependenciesgettext (libintl)None (zero dependency)

2.2 Technical Highlights

  • Pure C implementation, zero dependencies: No external libraries, ~50KB static binary
  • POSIX-compliant: Follows bash variable substitution semantics
  • Streaming processing: Handles large files with minimal memory footprint
  • Cross-platform: Runs perfectly on Linux/macOS/Alpine

3. Core Features Explained

3.1 Safe Default Behavior

Enhanced envsubst only replaces ${VAR} by default and leaves $VAR untouched:

# Template
echo 'Host: $host, Port: ${PORT}' | PORT=8080 ./envsubst

# Output
Host: $host, Port: 8080

$host preserved (Nginx built-in variable) ✅ ${PORT} correctly substituted

3.2 Powerful Wildcard Whitelist

Supports three wildcard patterns:

# Prefix match
./envsubst 'REST_*' < config.tpl
# Matches: REST_HOST, REST_PORT, REST_TOKEN

# Suffix match
./envsubst '*_PROD' < config.tpl
# Matches: DB_HOST_PROD, API_URL_PROD

# Middle match
./envsubst 'APP_*_API' < config.tpl
# Matches: APP_USER_API, APP_ORDER_API

# Multiple rules (space/comma separated)
./envsubst 'REST_* WAF_* CONFIG_*' < config.tpl
./envsubst 'REST_*,WAF_*,CONFIG_*' < config.tpl

Real‑world Example: Nginx + WAF Config

# Only replace variables starting with REST_* and WAF_*
./envsubst 'REST_* WAF_*' < nginx.conf.template > nginx.conf

# Result:
# - ${REST_HOST} → api.example.com ✅
# - ${WAF_CACHE_SIZE} → 5m ✅
# - $host → $host (unchanged) ✅
# - $remote_addr → $remote_addr (unchanged) ✅

3.3 Bash-Style Default Values

Supports ${VAR:-default} syntax:

# Variable unset → use default
echo '${PORT:-80}' | ./envsubst
# Output: 80

# Variable set → prefer environment value
echo '${PORT:-80}' | PORT=8080 ./envsubst
# Output: 8080

# Nginx config in action
cat > nginx.tpl << 'EOF'
server {
    listen ${PORT:-80};
    server_name ${HOST:-localhost};
    
    location / {
        proxy_pass http://${BACKEND:-127.0.0.1:8080};
    }
}
EOF

./envsubst < nginx.tpl

3.4 Debug Mode

Use --debug to trace substitution:

echo '${HOST} ${PORT} ${UNDEF}' | HOST=localhost PORT=80 ./envsubst --debug 2>&1

3.5 Statistics

Human‑readable:

echo '${A} ${B} ${C}' | A=1 B=2 ./envsubst --stats 2>&1

JSON format (machine‑readable):

echo '${A} ${B}' | A=1 ./envsubst --json-stats 2>stats.json

3.6 Whitelist File

Store rules in a file for maintainability:

# rules.txt
# Comments start with #
REST_*
WAF_*
APP_*
CONFIG_*

# Usage
./envsubst --whitelist-file rules.txt < config.tpl > output.conf

4. Real‑World Use Cases

4.1 Nginx in Docker Containers

Dockerfile

FROM openresty/openresty:alpine
COPY envsubst /usr/local/bin/
COPY nginx.conf.template /etc/nginx/
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

docker-entrypoint.sh

#!/bin/sh
set -e
echo "🔧 Generating nginx configuration..."
envsubst 'NGINX_* WAF_* APP_*' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
echo "✅ Configuration generated successfully"
exec "$@"

4.2 Kubernetes ConfigMap

Use initContainer to render templates safely with envsubst.

4.3 CI/CD Multi‑Environment Config

GitHub Actions / GitLab CI examples with validation and stats checks.


5. Performance & Benchmark

  • 100 variables: < 1ms
  • 1000‑line config: < 10ms
  • 1MB file: < 100ms
  • Memory usage: < 100KB
  • Zero dependencies, ~50KB static binary

6. Comparison with Similar Tools

Featureenvsubst (GNU)Enhanced envsubstgomplateconfd
LanguageCCGoGo
Binary Size~17KB~50KB~15MB~20MB
DependencieslibintlNoneNoneNone
Nginx Safe⚠️⚠️
Wildcards
Default Values
Learning CurveLowLowMediumHigh
Best ForGeneralNginx/ContainersComplex templatesDynamic config

7. Best Practices

  • Use prefixed variable names: DB_HOST, REDIS_URL, API_ENDPOINT
  • Add comments in templates
  • Use least‑privilege whitelists
  • Add error handling and validation in scripts

8. FAQ

  • Q: Why isn’t my variable replaced?
    Check: exported as env var, in whitelist, use --debug
  • Q: How to protect Nginx variables?
    Default mode (no --all), use whitelist, or escape \$host
  • Q: Why don’t defaults work?
    Variable must be in whitelist
  • Q: Special character support?
    Full support for URLs, spaces, symbols
  • Q: Performance for large files?
    Excellent: streaming, low memory

9. Project Info

git clone https://github.com/tekintian/envsubst.git
cd envsubst
make
make test
sudo make install

10. Summary

The enhanced envsubst solves critical production pain points: ✅ Security: Protects Nginx variables by default
✅ Flexibility: Wildcard whitelists
✅ Usability: Default values + debug mode
✅ Reliability: 70+ test cases, 100% coverage
✅ Lightweight: 50KB, zero dependencies
✅ Cross‑platform: Linux/macOS/Alpine

Ideal for:

  • Docker container configuration
  • Kubernetes ConfigMap rendering
  • Nginx/OpenResty setups
  • CI/CD multi‑env management
  • Any environment variable substitution workflow

    If you need a secure, fast, production‑ready env substitution tool—try enhanced envsubst today!

    #env #envsubst #Docker #K8s #Nginx #DevOps """

显示为Markdown

display(Markdown(english_content)) print("\n✅ Full English translation completed (SEO‑optimized, tech‑blog style)")

envsubst: Production-Grade Secure Environment Variable Substitution Tool Built for Nginx/Docker/K8s

This article introduces an enhanced version of the envsubst tool that resolves critical security flaws of the native implementation in Nginx configuration substitution. It supports advanced features including wildcard whitelists, bash-style default values, and debug mode, with zero dependencies—making it ideal for containerized deployment in Docker and Kubernetes.


1. Background & Pain Points

1.1 Why envsubst?

In containerized and microservice architectures, dynamic configuration generation from environment variables is essential for:

  • Nginx: Setting listening ports and backend service addresses
  • Docker: Injecting runtime configuration
  • Kubernetes: Rendering ConfigMap templates
  • CI/CD pipelines: Managing multi-environment configurations

    The native envsubst (from GNU gettext) works for basic cases but fails in production environments.

1.2 Three Critical Flaws of Native envsubst

Pain Point 1: Breaks Nginx Built-in Variables

# Template file
server {
    listen ${PORT};
    server_name ${HOST};
    
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;        # ← Nginx built-in variable
        proxy_set_header X-Real-IP $remote_addr;  # ← Nginx built-in variable
    }
}

# Run native envsubst
envsubst < nginx.conf.template > nginx.conf

Result: $host and $remote_addr are incorrectly replaced with empty strings → Nginx configuration failure.

Pain Point 2: No Fine-Grained Control

Native envsubst only supports two modes:

  1. Replace all variables (unsafe)
  2. List every variable explicitly (cumbersome for many variables) No wildcard support → high maintenance overhead.

Pain Point 3: Poor Undefined Variable Handling

echo '${UNDEFINED_VAR}' | envsubst
# Output: empty string (variable erased)

Production workflows often require preserving undefined variables instead of deleting them.


2. Solution: Enhanced envsubst

2.1 Core Feature Comparison

FeatureNative envsubstEnhanced envsubst
${VAR} substitution
$VAR substitution⚠️ Requires --all
Protect Nginx variables✅ Enabled by default
Wildcard whitelist✅ Supported
Preserve undefined vars-k flag
Default value support${VAR:-default}
Invalid variable handlingDelete/blank✅ Preserve as-is
Debug mode--debug
Statistics--stats/--json-stats
Whitelist file--whitelist-file
Binary size~17KB~50KB
Dependenciesgettext (libintl)None (zero dependency)

2.2 Technical Highlights

  • Pure C99 implementation, zero external dependencies
  • POSIX-compliant bash variable substitution semantics
  • Streaming I/O: Handles large files with minimal memory
  • Cross-platform: Linux / macOS / Alpine fully supported

3. Core Features Explained

3.1 Safe Default Behavior

Enhanced envsubst only replaces ${VAR} syntax by default, leaving $VAR (Nginx variables) untouched:

echo 'Host: $host, Port: ${PORT}' | PORT=8080 ./envsubst
# Output: Host: $host, Port: 8080

✅ Protects Nginx built-in variables
✅ Safely substitutes user-defined variables

3.2 Wildcard Whitelist

Supports flexible pattern matching:

# Prefix match
./envsubst 'REST_*' < config.tpl

# Suffix match
./envsubst '*_PROD' < config.tpl

# Middle match
./envsubst 'APP_*_API' < config.tpl

# Multiple rules
./envsubst 'REST_* WAF_* CONFIG_*' < config.tpl

3.3 Bash-Style Default Values

# Use default if variable is unset
echo '${PORT:-80}' | ./envsubst
# Output: 80

# Override with environment variable
echo '${PORT:-80}' | PORT=8080 ./envsubst
# Output: 8080

3.4 Debug & Statistics

  • --debug: Trace every substitution step
  • --stats: Human-readable substitution summary
  • --json-stats: Machine-readable JSON for CI/CD validation

3.5 Whitelist File

Manage large rule sets via external file:

# rules.txt
REST_*
WAF_*
APP_*
CONFIG_*
./envsubst --whitelist-file rules.txt < config.tpl

4. Real-World Use Cases

4.1 Docker + Nginx

FROM openresty/openresty:alpine
COPY envsubst /usr/local/bin/
COPY nginx.conf.template /etc/nginx/
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

Entrypoint Script

#!/bin/sh
set -e
envsubst 'NGINX_* WAF_* APP_*' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
exec "$@"

4.2 Kubernetes ConfigMap

Render templates safely via initContainer using envsubst.

4.3 CI/CD Pipelines

Validate substitutions in GitHub Actions / GitLab CI with JSON statistics.


5. Performance & Benchmark

  • 100 variables: < 1ms
  • 1000-line config: < 10ms
  • 1MB file: < 100ms
  • Memory usage: < 100KB
  • Binary size: ~50KB

6. Comparison with Similar Tools

Featureenvsubst (GNU)Enhanced envsubstgomplateconfd
LanguageCCGoGo
Binary Size~17KB~50KB~15MB~20MB
DependencieslibintlNoneNoneNone
Nginx Safe⚠️⚠️
Wildcards
Default Values
Learning CurveLowLowMediumHigh
Best ForGeneralNginx/ContainersComplex templatesDynamic config

7. Best Practices

  1. Use prefixed variables: DB_HOST, REDIS_URL, API_ENDPOINT
  2. Add clear comments in templates
  3. Apply least-privilege whitelists
  4. Add error handling and substitution validation

8. FAQ

Q: Why is my variable not replaced?
Check: exported as environment variable, included in whitelist, use --debug to diagnose.

Q: How to protect Nginx variables?
Use default mode (no --all), apply whitelist, or escape: \$host.

Q: Why don’t default values work?
Variables must be in the whitelist to evaluate defaults.

Q: Does it support special characters?
Yes: URLs, spaces, symbols, and passwords are fully supported.


9. Project Information

git clone https://github.com/tekintian/envsubst.git
cd envsubst
make
make test
sudo make install

10. Summary

Enhanced envsubst solves production-critical problems of the native tool: ✅ Security: Protects Nginx variables by default
✅ Flexibility: Wildcard whitelists for fine-grained control
✅ Usability: Default values + debug + statistics
✅ Reliability: 70+ test cases, full coverage
✅ Lightweight: 50KB, zero dependencies
✅ Cross-platform: Linux/macOS/Alpine

Perfect for:

  • Docker container configuration
  • Kubernetes ConfigMap rendering
  • Nginx/OpenResty deployments
  • CI/CD multi-environment management
  • Any environment variable substitution workflow

    If you need a secure, fast, production-grade environment variable substitution tool, try enhanced envsubst today.

    #env #envsubst #Docker #K8s #Nginx #DevOps

Image NewsLetter
Icon primary
Newsletter

Subscribe our newsletter

Please enter your email address below and click the subscribe button. By doing so, you agree to our Terms and Conditions.

Your experience on this site will be improved by allowing cookies Cookie Policy