Render configuration files with Ansible templates

Use Jinja2 variables, conditions, and loops, then validate generated configuration and protect rendered secrets.

Best practices
Illustration of software development and testing

Ansible templates use Jinja2 to insert variables and evaluate conditions, loops, and filters. Rendering happens on the control node; the template module transfers the resulting file to the managed host. This lets one configuration structure serve several environments while keeping host-specific values in variables.

Jinja2 syntax in context

These Nginx-oriented fragments demonstrate the syntax:

# A value with a default.
listen {{ http_port | default(80) }};

# A condition.
{% if env == "production" %}
worker_processes {{ ansible_processor_vcpus }};
{% else %}
worker_processes 2;
{% endif %}

# Build an upstream from inventory hosts.
upstream backend {
{% for host in groups['appservers'] %}
    server {{ hostvars[host]['ansible_host'] }}:{{ app_port }};
{% endfor %}
}

{{ }} produces output, {% %} controls template logic, and | applies a filter such as default, join, or upper. Required inventory variables must exist. Host facts need to be gathered with gather_facts or setup; the top-level fact alias in this example also depends on fact injection being enabled. Explicit ansible_facts access can avoid that alias dependency.

The Nginx directives above belong in different configuration contexts. They are syntax fragments, not a complete nginx.conf to copy into production.

Validate a complete configuration before installing it

- name: Render the Nginx configuration
  ansible.builtin.template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    validate: '/usr/sbin/nginx -t -c %s'
    backup: true
    owner: root
    group: root
    mode: '0644'
  notify: reload nginx

Run this task with appropriate privileges and define a reload nginx handler in the playbook. src must be a complete, valid configuration, not the earlier collection of syntax fragments. The validation command checks a temporary candidate before the destination is replaced; a failed check prevents installation. The handler is notified when the task changes the file.

If the rendered file contains secrets, tighten its permissions and set the task's no_log: true and diff: false. Consider whether backups should be created and who can read them.

A syntax check is only one stage of verification. Reload a small group of hosts, request important endpoints, and check status codes and response content before expanding the rollout. Retain a rollback copy. If Guance HTTP synthetic tests already cover those endpoints, review their response assertions and results during the same deployment window.

Organize templates and protect sensitive values

  • Put role templates in templates/, with defaults and variables at the appropriate precedence levels.
  • Reference Vault-encrypted variables instead of embedding secrets in template source. The rendered file is still plaintext; protect its permissions and any backups.
  • Prepare complex data in tasks or variables so the template remains easy to review.

Frequently asked questions

What if the target file also uses template delimiters?

Ordinary Nginx braces do not conflict with Jinja2, but systems that use {{ }} can. Emit literal delimiters with {{ '{{' }} raw {{ '}}' }} or wrap the relevant content in a {% raw %} block.

How can I preview the rendered file?

For nonsensitive configuration, use --check --diff. Disable diffs for secrets. You can also target a local test inventory and render to a temporary path with ansible-playbook -c local, ensuring the task does not write to a real system configuration path.

How do template, copy, and lineinfile differ?

Use copy for a static file, lineinfile for a small targeted change to a shared file, and template when automation owns the whole file and its content varies by host or environment.

References

Related reading

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting