Templates for Config Generation¶
What You'll Learn¶
- The
templatemodule and.j2file convention - Loops and conditionals inside a template file, not just in a task
- When
templateis the right tool, and whenlineinfileis better instead
Minimal Example¶
templates/nginx.conf.j2
server {
listen {{ http_port }};
server_name {{ server_name }};
root {{ document_root }};
}
- name: Deploy nginx configuration
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/app.conf
notify: Restart nginx
Practical Example — Loops and Conditionals Inside a Template¶
templates/nginx.conf.j2
{% for upstream in upstream_servers %}
upstream backend_{{ loop.index }} {
server {{ upstream.host }}:{{ upstream.port }};
}
{% endfor %}
server {
listen {{ http_port }};
{% if ssl_enabled %}
listen 443 ssl;
ssl_certificate {{ ssl_cert_path }};
{% endif %}
location / {
proxy_pass http://backend_1;
}
}
vars:
http_port: 80
ssl_enabled: true
ssl_cert_path: /etc/ssl/certs/app.pem
upstream_servers:
- { host: 10.0.1.10, port: 8080 }
- { host: 10.0.1.11, port: 8080 }
{% for %}/{% if %} (statement tags, not expression tags) work inside any file the template module renders — the whole file is one Jinja2 document, not just the parts that look like variables.
Why template, Not lineinfile, for Whole Files¶
# Fragile — depends on the file already existing in a specific shape,
# and can't express "regenerate this file's structure from variables"
- ansible.builtin.lineinfile:
path: /etc/nginx/nginx.conf
regexp: "^worker_connections"
line: "worker_connections 1024;"
# Correct for files you own outright — one template, fully regenerated
- ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
lineinfile/blockinfile are the right tool for surgically editing part of a file you don't fully own (a system file another process also writes to). template is right when Ansible owns the entire file's content — it's simpler to reason about, and a diff of the template source shows the whole intended config, not scattered regex patches. See Copy vs. Template for the fuller decision guide.
Common Mistakes¶
- Using
lineinfileto build up an entire config file line by line instead of onetemplate— harder to review, and eachlineinfiletask is a separate idempotency check instead of one coherent render. - Forgetting
notify:on atemplatetask that changes a service's config — the service never picks up the new config until restarted; see Handlers. - Hardcoding environment-specific values directly in the
.j2file instead of passing them as variables — defeats the entire point of templating.
Interview Questions¶
- Why would you choose
templateoverlineinfilefor a config file, and vice versa? - Can a Jinja2 template file contain loops and conditionals, not just variable substitution?
Next¶
Continue to Advanced Jinja2.