Ansible Environment Variables — Set and Use env vars in Playbooks

Introduction

Ansible's environment keyword sets environment variables for task execution on remote hosts. This is essential for commands that need PATH modifications, proxy settings, API tokens, database connection strings, or any application that reads configuration from the environment.

Setting Environment Variables

Per Task

---
- name: Environment variable examples
  hosts: all
  tasks:
    - name: Run with custom environment
      ansible.builtin.command:
        cmd: /opt/app/bin/migrate
      environment:
        DATABASE_URL: "postgresql://db.example.com:5432/myapp"
        RAILS_ENV: production
        SECRET_KEY_BASE: "{{ vault_secret_key }}"

Per Play

- name: Deploy application
  hosts: webservers
  environment:
    HTTP_PROXY: "http://proxy.example.com:3128"
    HTTPS_PROXY: "http://proxy.example.com:3128"
    NO_PROXY: "localhost,127.0.0.1,.example.com"

  tasks:
    - name: Install packages (uses proxy)
      ansible.builtin.apt:
        name: nginx
        state: present

    - name: Download file (uses proxy)
      ansible.builtin.get_url:
        url: https://releases.example.com/app-2.0.tar.gz
        dest: /tmp/app-2.0.tar.gz

Per Role

- name: Deploy with role
  hosts: all
  roles:
    - role: deploy_app
      environment:
        APP_ENV: production
        LOG_LEVEL: warn

From Variables

  vars:
    proxy_env:
      HTTP_PROXY: "http://proxy.example.com:3128"
      HTTPS_PROXY: "http://proxy.example.com:3128"
      NO_PROXY: "localhost,127.0.0.1"
    app_env:
      DATABASE_URL: "{{ vault_db_url }}"
      REDIS_URL: "redis://cache.example.com:6379"

  tasks:
    - name: Install with proxy
      ansible.builtin.apt:
        name: curl
        state: present
      environment: "{{ proxy_env }}"

    - name: Run application command
      ansible.builtin.command:
        cmd: /opt/app/bin/setup
      environment: "{{ proxy_env | combine(app_env) }}"

Reading Environment Variables

From the Controller

    # Read env vars from the machine running ansible-playbook
    - name: Use controller environment variable
      ansible.builtin.debug:
        msg: "Home dir: {{ lookup('env', 'HOME') }}"

    - name: Deploy with controller's AWS credentials
      amazon.aws.ec2_instance:
        name: webserver
        instance_type: t3.micro
      environment:
        AWS_ACCESS_KEY_ID: "{{ lookup('env', 'AWS_ACCESS_KEY_ID') }}"
        AWS_SECRET_ACCESS_KEY: "{{ lookup('env', 'AWS_SECRET_ACCESS_KEY') }}"

From the Remote Host

    # Read env vars from the remote host via facts
    - name: Show remote PATH
      ansible.builtin.debug:
        msg: "Remote PATH: {{ ansible_env.PATH }}"

    - name: Check if variable is set on remote
      ansible.builtin.debug:
        msg: "JAVA_HOME is {{ ansible_env.JAVA_HOME | default('not set') }}"

Playbook workflow

Generate a complete playbook from this tutorial

Use Ansible Environment Variables Guide as the starting context and generate an editable Ansible playbook in the playground.

One anonymous generation is available. Do not paste passwords, private keys, tokens, or customer secrets.

Generate a playbook

Common Use Cases

PATH Modification

    - name: Run command with custom PATH
      ansible.builtin.command:
        cmd: my-custom-tool --version
      environment:
        PATH: "/opt/custom/bin:{{ ansible_env.PATH }}"

Python Virtual Environments

    - name: Install Python packages in virtualenv
      ansible.builtin.pip:
        name: django
        virtualenv: /opt/app/venv
      environment:
        VIRTUAL_ENV: /opt/app/venv
        PATH: "/opt/app/venv/bin:{{ ansible_env.PATH }}"

Java Applications

    - name: Run Java application
      ansible.builtin.command:
        cmd: java -jar /opt/app/app.jar
      environment:
        JAVA_HOME: /usr/lib/jvm/java-17
        JAVA_OPTS: "-Xms512m -Xmx2048m -Djava.io.tmpdir=/opt/tmp"
        SPRING_PROFILES_ACTIVE: production

Persistent Environment Variables

    # Set env vars permanently on remote host
    - name: Set system-wide environment variable
      ansible.builtin.lineinfile:
        path: /etc/environment
        regexp: '^APP_ENV='
        line: 'APP_ENV=production'

    - name: Set user environment variable
      ansible.builtin.lineinfile:
        path: "/home/{{ app_user }}/.bashrc"
        regexp: '^export DATABASE_URL='
        line: 'export DATABASE_URL="{{ vault_db_url }}"'

    - name: Create environment file for systemd service
      ansible.builtin.template:
        src: app.env.j2
        dest: /etc/myapp/environment
        mode: '0600'
      notify: Restart myapp

Systemd Environment Files

    # Template: app.env.j2
    # DATABASE_URL={{ db_url }}
    # REDIS_URL={{ redis_url }}
    # SECRET_KEY={{ vault_secret_key }}

    - name: Configure systemd service with env file
      ansible.builtin.template:
        src: myapp.service.j2
        dest: /etc/systemd/system/myapp.service
      notify: Reload systemd
# myapp.service.j2
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=myapp
EnvironmentFile=/etc/myapp/environment
ExecStart=/opt/app/bin/start
Restart=always

[Install]
WantedBy=multi-user.target

Proxy Configuration

# group_vars/all.yml — apply proxy to all hosts behind corporate firewall
proxy_env:
  HTTP_PROXY: "http://proxy.corp.example.com:8080"
  HTTPS_PROXY: "http://proxy.corp.example.com:8080"
  NO_PROXY: "localhost,127.0.0.1,10.0.0.0/8,.corp.example.com"
  http_proxy: "{{ HTTP_PROXY }}"   # Some tools use lowercase
  https_proxy: "{{ HTTPS_PROXY }}"
  no_proxy: "{{ NO_PROXY }}"

Troubleshooting

IssueSolution
Environment not appliedenvironment only affects that task, not the session
lookup('env') returns emptyVariable not set on controller; check with echo $VAR
ansible_env missing variableRun gather_facts: true; variable must be in remote shell
Proxy not workingSet both uppercase AND lowercase variants
PATH not foundPrepend to existing: "/new/path:{{ ansible_env.PATH }}"

Best Practices

  1. Use environment keyword, not shell: export — cleaner and scoped
  2. Store env vars in group_vars — define proxy_env once, use everywhere
  3. Secrets via Vault — DATABASE_URL: "{{ vault_db_url }}"
  4. Use combine() to merge — environment: "{{ base_env | combine(app_env) }}"
  5. Persistent vars via files — use /etc/environment, .bashrc, or systemd EnvironmentFile
  6. Don't leak secrets in logs — use no_log: true on tasks with sensitive env vars

Conclusion

The environment keyword gives you precise control over task execution context — proxy settings, API keys, PATH modifications, and application configuration. Define environment dictionaries in group_vars, combine them with | combine(), and keep secrets in Vault. For persistent environment changes, use lineinfile on shell profiles or systemd EnvironmentFile.