{"id":15068,"date":"2025-08-04T04:01:41","date_gmt":"2025-08-04T04:01:41","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=15068"},"modified":"2025-08-04T04:01:41","modified_gmt":"2025-08-04T04:01:41","slug":"deep-dive-into-jinja2-ansible-template-with-example","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/deep-dive-into-jinja2-ansible-template-with-example\/","title":{"rendered":"Ansible: Deep Dive into Jinja2 Ansible Template with example"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><\/h2>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Introduction to Ansible Templates and Jinja2<\/strong><\/h2>\n\n\n\n<p>Ansible templates are powerful tools for creating dynamic configuration files and scripts based on variables and logic. Templates in Ansible use the Jinja2 templating engine, which enables you to programmatically control the contents of files generated during playbook runs. Jinja2 allows you to access variables, use conditional statements, loops, and filters, making your automation flexible and reusable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What is Jinja2?<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Jinja2<\/strong> is a modern, designer-friendly templating language for Python. In Ansible, it empowers the creation of files that can adapt based on the current data (like host variables or facts), supporting variables, logic, and complex data structures.<\/li>\n\n\n\n<li><strong>Key Syntax<\/strong>:\n<ul class=\"wp-block-list\">\n<li><code>{{ variable }}<\/code> for variable interpolation<\/li>\n\n\n\n<li><code>{% control structures %}<\/code> for logic (if, for, etc.)<\/li>\n\n\n\n<li>Filters (e.g., <code>{{ my_var | upper }}<\/code>)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Concepts and Features of Jinja2 in Ansible<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Variables:<\/strong> Insert values dynamically: text<code>Hello, {{ username }}!<\/code><\/li>\n\n\n\n<li><strong>Expressions and Filters:<\/strong> Use built-in or custom filters to modify data: text<code>{{ mylist | join(', ') }}<\/code><\/li>\n\n\n\n<li><strong>Conditionals:<\/strong> text<code>{% if is_admin %} You are an admin. {% else %} You are a user. {% endif %}<\/code><\/li>\n\n\n\n<li><strong>Loops:<\/strong> text<code>{% for item in items %} - {{ item }} {% endfor %}<\/code><\/li>\n\n\n\n<li><strong>Includes and Macros:<\/strong> Reuse chunks of templates.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Using Templates in Ansible<\/strong><\/h2>\n\n\n\n<p>Templates in Ansible are typically stored as <code>.j2<\/code> (Jinja2) files. The <code>template<\/code> module copies these files to managed nodes, rendering them with variables and logic.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Basic Workflow<\/strong><\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Create the Template File<\/strong>\n<ul class=\"wp-block-list\">\n<li>Example: <code>templates\/config.j2<\/code> text<code>user={{ app_user }} path={{ app_path }}<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Reference in Playbook<\/strong>\n<ul class=\"wp-block-list\">\n<li>Use the <code>template<\/code> module: text<code>- name: Copy app config template: src: config.j2 dest: \/etc\/myapp\/config.cfg<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Define Variables<\/strong>\n<ul class=\"wp-block-list\">\n<li>In inventory, playbook, or host\/group vars: text<code>vars: app_user: alice app_path: \/opt\/myapp<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Practical Examples<\/strong><\/h2>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>1. Dynamic HTML Page<\/strong><\/h2>\n\n\n\n<p><strong>Template: <code>templates\/landing-page.html.j2<\/code><\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">text<code>&lt;!doctype html&gt;\n&lt;html lang=\"en\"&gt;\n&lt;head&gt;\n  &lt;meta charset=\"utf-8\"&gt;\n  &lt;title&gt;{{ page_title }}&lt;\/title&gt;\n  &lt;meta name=\"description\" content=\"Created with Ansible\"&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;h1&gt;{{ page_title }}&lt;\/h1&gt;\n  &lt;p&gt;{{ page_description }}&lt;\/p&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n\n\n\n<p><strong>Playbook:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">text<code>- name: Configure landing page\n  hosts: web\n  vars:\n    page_title: \"Welcome\"\n    page_description: \"This is an Ansible-generated page\"\n  tasks:\n    - name: Deploy HTML page\n      template:\n        src: landing-page.html.j2\n        dest: \/var\/www\/html\/index.html\n<\/code><\/pre>\n\n\n\n<p>Result: The <code>index.html<\/code> on the target server will be customized per the defined vars.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>2. Configuring Nginx Virtual Host with Logic and Loops<\/strong><\/h2>\n\n\n\n<p><strong>Template: <code>templates\/nginx_vhost.conf.j2<\/code><\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">text<code>server {\n  listen {{ nginx_port }} default_server;\n  server_name {{ domain_name }};\n  root {{ document_root }};\n  index index.html index.htm;\n  access_log \/var\/log\/nginx\/{{ domain_name }}_access.log;\n  error_log \/var\/log\/nginx\/{{ domain_name }}_error.log;\n  location \/ {\n    try_files $uri $uri\/ =404;\n    {% if enable_php %}\n    location ~ \\.php$ {\n      include snippets\/fastcgi-php.conf;\n      fastcgi_pass unix:\/var\/run\/php\/php7.4-fpm.sock;\n    }\n    {% endif %}\n  }\n}\n<\/code><\/pre>\n\n\n\n<p><strong>Playbook:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">text<code>- name: Configure nginx virtual host\n  hosts: web_servers\n  vars:\n    nginx_port: 80\n    domain_name: \"example.com\"\n    document_root: \"\/var\/www\/html\"\n    enable_php: true\n  tasks:\n    - name: Create Nginx configuration\n      template:\n        src: nginx_vhost.conf.j2\n        dest: \/etc\/nginx\/sites-available\/{{ domain_name }}.conf\n<\/code><\/pre>\n\n\n\n<p>Result: Nginx configs will dynamically adapt to each server or environment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Advanced Jinja2 Usage in Ansible<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Facts<\/strong>: Use system facts collected by Ansible, e.g., <code>{{ ansible_facts['os_family'] }}<\/code><\/li>\n\n\n\n<li><strong>Dictionaries\/Loops<\/strong>: Render configuration options dynamically: text<code>{% for opt in floaterm_options %} let g:{{ opt }} = {{ floaterm_options[opt] }} {% endfor %}<\/code><\/li>\n\n\n\n<li><strong>Macros<\/strong>: Reuse complex snippets within templates.<\/li>\n\n\n\n<li><strong>Includes\/Extends<\/strong>: Organize and reuse base templates for consistency.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Best Practices<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Use clear variable names<\/strong> and document their purpose.<\/li>\n\n\n\n<li><strong>Version control your templates<\/strong> for traceability.<\/li>\n\n\n\n<li><strong>Leverage roles for reusability<\/strong>\u2014combine variables, templates, and logic.<\/li>\n\n\n\n<li><strong>Test templates locally<\/strong> using <code>ansible-playbook<\/code> in check mode or via dry runs.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Summary Table: Jinja2 Features in Ansible Templates<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Jinja2 Feature<\/th><th>Example Syntax<\/th><th>Use-Case<\/th><\/tr><\/thead><tbody><tr><td>Variables<\/td><td><code>{{ variable }}<\/code><\/td><td>Insert dynamic values<\/td><\/tr><tr><td>Conditionals<\/td><td><code>{% if cond %}...{% endif %}<\/code><\/td><td>Show\/hide content<\/td><\/tr><tr><td>Loops<\/td><td><code>{% for item in items %}...{% endfor %}<\/code><\/td><td>Repeat content for lists<\/td><\/tr><tr><td>Filters<\/td><td>`{{ var<\/td><td>upper }}`<\/td><\/tr><tr><td>Includes<\/td><td><code>{% include \"file.j2\" %}<\/code><\/td><td>Code reuse within templates<\/td><\/tr><tr><td>Macros<\/td><td><code>{% macro name(args) %}...{% endmacro %}<\/code><\/td><td>Reusable snippets<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Conclusion<\/strong><\/h2>\n\n\n\n<p>Ansible templates powered by Jinja2 make configuration management <strong>dynamic, flexible, and adaptable<\/strong>. Mastering their syntax\u2014along with how to combine variables, logic, loops, and facts\u2014enables DevOps teams to automate at scale, reduce errors, and manage highly customizable infrastructure.<\/p>\n\n\n\n<p>If you&#8217;re new, start with simple templates and gradually incorporate more advanced Jinja2 logic for maximum automation efficiency!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/devops-school\/c88f531ec63aed887b32444e641c9f53.js\"><\/script>\n\n\n\n<h3 class=\"wp-block-heading\">Refernece<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>https:\/\/jinja.palletsprojects.com\/en\/2.11.x\/<\/li>\n\n\n\n<li>https:\/\/codeburst.io\/jinja-2-explained-in-5-minutes-88548486834e<\/li>\n\n\n\n<li>https:\/\/mydbops.wordpress.com\/2019\/04\/17\/jinja2-for-better-ansible\/<\/li>\n<\/ul>\n\n\n<div class=\"epyt-gallery\" data-currpage=\"1\" id=\"epyt_gallery_31069\"><iframe loading=\"lazy\"  id=\"_ytid_10727\"  width=\"760\" height=\"427\"  data-origwidth=\"760\" data-origheight=\"427\" src=\"https:\/\/www.youtube.com\/embed\/?enablejsapi=1&#038;autoplay=0&#038;cc_load_policy=0&#038;cc_lang_pref=&#038;iv_load_policy=1&#038;loop=0&#038;rel=1&#038;fs=1&#038;playsinline=0&#038;autohide=2&#038;theme=dark&#038;color=red&#038;controls=1&#038;disablekb=0&#038;\" class=\"__youtube_prefs__  no-lazyload\" title=\"YouTube player\"  data-epytgalleryid=\"epyt_gallery_31069\"  allow=\"fullscreen; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen data-no-lazy=\"1\" data-skipgform_ajax_framebjll=\"\"><\/iframe><div class=\"epyt-gallery-list\"><div>Sorry, there was a YouTube error.<\/div><\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>Introduction to Ansible Templates and Jinja2 Ansible templates are powerful tools for creating dynamic configuration files and scripts based on variables and logic. Templates in Ansible use the Jinja2 templating&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[1],"tags":[],"class_list":["post-15068","post","type-post","status-publish","format-standard","hentry","category-sql"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/15068","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=15068"}],"version-history":[{"count":8,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/15068\/revisions"}],"predecessor-version":[{"id":51176,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/15068\/revisions\/51176"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=15068"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=15068"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=15068"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}