How to Use the envsubst Command in Linux to Substitute Environment Variables into Configuration Templates

Modern DevOps workflows, Docker container deployments, and CI/CD automation pipelines rely on parameterized configuration files. For example, an Nginx reverse proxy configuration, Kubernetes deployment manifest, or database connection file often needs to ingest dynamic hostnames, port numbers, API tokens, and environment identifiers at deploy time without hardcoding credentials into Git repositories.

While complex templating engines like Jinja2, Helm, or custom Python scripts can handle variable substitution, Linux includes a blazingly fast, lightweight, and native command-line utility built specifically for this purpose: envsubst. Part of the standard GNU gettext utilities suite, envsubst reads a template from standard input, substitutes occurrences of shell environment variables with their active values, and streams the rendered result to standard output.

This guide explains how envsubst operates, its syntax nuances, how to avoid accidentally overwriting unintended variables, and how to integrate it into real-world Linux container workflows.

How envsubst Works

The basic execution model of envsubst follows standard Unix stream processing:

envsubst < template.conf > output.conf

Whenever envsubst encounters an environment variable written in standard shell syntax—such as $VARIABLE_NAME or ${VARIABLE_NAME}—it replaces that token with the current value of the exported environment variable. If an environment variable is unset or empty, envsubst replaces it with an empty string.

Installing envsubst on Linux

envsubst is distributed as part of the gettext package. It is pre-installed on most standard Linux distributions, but can be added to minimal container images easily:

On Debian / Ubuntu:

sudo apt update && sudo apt install -y gettext-base

On Alpine Linux (Common for Docker):

apk add --no-cache gettext

On RHEL / Rocky Linux / Fedora:

sudo dnf install -y gettext

The Critical Pitfall: Overwriting Unintended Variables

By default, if you run raw envsubst on a configuration file, it replaces every single string that looks like a shell variable ($var). In configuration files that use dollar signs for internal application syntax—such as Nginx (which uses $host, $uri, $remote_addr) or shell scripts—raw envsubst will strip and erase all those internal variables, breaking your configuration completely!

The Solution: Variable Whitelisting

To substitute only specific variables while leaving all other dollar-sign variables intact, pass a comma- or space-separated list of target variable names as a command argument:

envsubst '$PORT,$BACKEND_URL' < nginx.conf.template > nginx.conf

Notice the single quotes and backslashes: escaping the dollar signs prevents your active interactive shell from expanding the variable names before passing them to envsubst.

Real-World Example: Parameterizing an Nginx Configuration

1. Create the Template File (nginx.conf.template)

server {
    listen ${SERVER_PORT};
    server_name ${DOMAIN_NAME};

    location / {
        proxy_pass http://${BACKEND_HOST}:${BACKEND_PORT};
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

2. Define Environment Variables

export SERVER_PORT="80"
export DOMAIN_NAME="api.example.com"
export BACKEND_HOST="127.0.0.1"
export BACKEND_PORT="8080"

3. Render with Targeted Substitution

Execute envsubst, specifying strictly the variables you want replaced:

envsubst '$SERVER_PORT $DOMAIN_NAME $BACKEND_HOST $BACKEND_PORT'   < nginx.conf.template > /etc/nginx/conf.d/default.conf

4. Review the Rendered Output

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Notice that while ${SERVER_PORT} and ${BACKEND_HOST} were replaced with their environment values, Nginx’s internal $host, $remote_addr, and $proxy_add_x_forwarded_for were perfectly preserved.

Advanced Techniques: Dynamic Whitelisting in Shell Scripts

If your template contains dozens of environment variables, manually typing every variable into the whitelist argument is tedious. You can combine envsubst with its -v (variables) flag to automatically extract and whitelist all variables defined in the template:

# Automatically substitute only variables that are actually defined in the current shell environment
DEFINED_ENVS=$(printf '${%s} ' $(env | cut -d= -f1))
envsubst "$DEFINED_ENVS" < template.yaml > output.yaml

Command Reference Summary

Syntax Pattern Behavior Best Used For
envsubst < in > out Replaces all $VAR strings globally Plain text files, SQL scripts, YAML without native $ syntax
envsubst '$VAR1,$VAR2' < in > out Replaces strictly VAR1 and VAR2 Nginx configurations, Apache configs, Bash scripts
envsubst -v < in Lists all variable names found in the template Auditing required variables before deployment

By incorporating envsubst into your container startup entrypoint scripts (e.g., /docker-entrypoint.d/), developers achieve elegant, zero-overhead configuration management across all Linux environments.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.