Using Templates


For config file generation, we provide a backend service which can bind config.xml data to templates written in Jinja2 (

All available templates should be installed at the following location on the OPNsense system:

  1. /usr/local/opnsense/service/templates/

Naming convention

All templates should be put into a directory structure containing the vendor and package/application name, our sample application is placed inside the directory:


Template package content

Every template directory should contain at least 2 files:

  1. a content descriptor, containing the actual targets, named +TARGETS

  2. one or more template(s)


The +TARGETS file contains the source template name inside the template directory and the (dynamic) target filename divided by a colon (:) multiple lines may be inserted per file.

For example :


Will create a file /tmp/template_sample/simple_page.txt using the template example_simple_page.txt.


Optionally you can specify which file or files to remove on call of “template cleanup”, which can be specified by using an extra tag next to the target, such as: example_simple_page.txt:/tmp/template_sample/simple_page.txt:/tmp/template_sample/simple_page.*

By default all targets will be removed when calling cleanup.

If you want to use information from within the config.xml file as output filename, you can use tags to address the content, like [version] to input the tag version from the xml file. When generating multiple files from 1 template, you can use one wildcard (%) to address a section of the config file, for example [interfaces.%.if] loops over the interfaces and outputs the value of if.

Target overwrites

Every template package can specify overwrites, which can be used by vendors who implement and maintain their own templates for features in OPNsense.

Simply add files using the target definition in the +TARGETS.D directory of the templates folder using as extension .TARGET.

For example an overwrite for OPNsense/Sample can use the following name and location /usr/local/opnsense/service/templates/OPNsense/Sample/+TARGETS.D/custom.TARGET


Be vey careful using this feature, you need to maintain these templates yourself and features may break after upgrades of OPNsense.


For more information of the template language itself, please look at and the examples installed in /usr/local/opnsense/service/templates/OPNsense/Sample.

There’s one special case when using the template engine, every wildcard used for the output file generation is also provided to the template, so you are able to determine which filter let to this output.

Those filters are stored in the variable TARGET_FILTERS.

{% if TARGET_FILTERS['interfaces.wan'] %}
{% endif %}

Test usage

The templates can be rendered via the backend service (configd), to test this functionality on a running OPNsense system, use:

# generate template package
configctl template reload OPNsense/Sample
# cleanup files
configctl template cleanup OPNsense/Sample

Python template usage example

The template system itself is a separate module which is used by configd, to use (or test) the system without the daemon, use:

# import template system and config.xml handling
from modules import template
from modules import config

# construct a new template object, set root to /tmp/
tmpl = template.Template(target_root_directory='/tmp/')
# open the config.xml and bind to template object
conf = config.Config('/config.xml')

# generate output for OPNsense/Sample
generated_filenames = tmpl.generate('OPNsense/Sample')

# print results
for filename in generated_filenames:
  print ('.. generated : %s'%filename)