Learn Using SaltStack With Pillars on Ubuntu 17.04

March 28, 2019

Table of Contents

While SaltStack is a great tool for running operations on many servers simultaneously, it also supports per-host defined configuration presets stored in an unique file which are further called “pillar”. In this guide, we will write a small SaltStack formula for installing Nginx and automating the deployment of virtual hosts using pillars.


  • IT Web Services instance running Ubuntu 17.04 ( master )
  • Two IT Web Services instances running Ubuntu 17.04 ( minions )

Setting up master

https://www.itweb.services/tutorials/linux-guides/getting-started-with-saltstack-on-ubuntu-17-04″>this article which explains how to get started with SaltStack.


We start with creating the folder for our formula which further holds the files required for SaltStack’s operations on our minions.

mkdir -p /srv/salt/nginx

After creating the folder, we can continue with writing up the init.sls file which is an essential part of every formula:

    - installed
        - source: salt://nginx/files/virtualhosts.jinja
        - template: jinja
        - user: root
        - group: root
        - mode: 655
    - run
    - names:
        - service nginx restart

As you have probably noticed, SaltStack uses the Jinja templating engine for generating dynamic configuration files. This provides a broad range of possibilities within our configuration template files, such as accessing native Python code or setting variables and similar. The next step consists of creating the template for our virtualhosts.conf file, whereas we need to create the folder first:

mkdir -p /srv/salt/nginx/files

Once the folder is created, we can continue with writing up the virtualhosts.jinja file:

{% for vhost in pillar['vhosts'] %}
server {
    listen {{ vhost['listenPort'] }};
    server_name {{ vhost['serverName'] }};
    root {{ vhost['documentRoot'] }};
    index {%- for index in vhost['indexFiles'] -%}{{ index }}{%- endfor -%};
    location / {
        try_files $uri $uri/ =404;
{% endfor %}


After creating the formula, we can go ahead and setup our Pillar base:

mkdir -p /srv/pillar/

Any references for hosts matching a particular pillar file are written into the top.sls file within the directory we just created. In our example, we assume that two minions exist with the hostname nginxwww1 and nginxwww2 whereas we will assign them both unique pillar files:

    - match: grain
    - nginxwww1
    - match: grain
    - nginxwww2

Next, we will continue with creating a pillar file for nginxwww1 whereas we will create a vhost listening on port 81 for the domain example.com, the document root being /var/www/example_com/ and the index files being index.shtml:

      listenPort: '81'
      serverName: 'example.com'
      documentRoot: '/var/www/example_com'
        - index.shtml

We will continue with creating a pillar file for nginxwww2 whereas we will create a vhost listening on port 82 for the domain example2.com, the document root being /var/www/example2_com/ and the index files being index.js and index.css:

      listenPort: '82'
      serverName: 'example2.com'
      documentRoot: '/var/www/example2_com'
        - index.js
        - index.css

Note: Pillar files are stored within /srv/pillar/


We can now complete our first-try with pillars by updating them on our minions:

salt '*' saltutil.refresh_pillar

Afterwards, we can run the SaltStack formula:

salt '*' state.sls nginx


Once the SaltStack formula has been run and completed without any errors, we should be able to see nginx listening on port 81 on nginxwww1 and on port 82 on nginxwww2 as confirmation.


This rather lightweight but already powerful SaltStack formula can be extended further to add support for HTTPS, possibly with an integration of Let’s Encrypt, support for CGI or PHP backends and everything you can manually do as well. This guide should have given you a basic idea of SaltStack formulas and pillars used for the deployment of configuration files. Happy automating!

Need help?

Do you need help setting up this on your own service?
Please contact us and we’ll provide you the best possible quote!