SaltStack Tutorial: Learn Configuration Management from Scratch (2026)
When I needed to run a command on a thousand servers simultaneously, SSH loops took forever. SaltStack changed that with its fast, scalable publish-subscribe architecture using ZeroMQ for communication.
By the end of this tutorial, you will understand how to manage nodes at scale with remote execution, write idempotent state files, use Grains and Pillar, and build event-driven automation.
Salt Architecture: Master, Minions, and Syndic
Salt follows a master-minion architecture with ZeroMQ pub/sub. The master daemon listens for connections. Minions connect and authenticate with cryptographic keys. For large deployments, Syndic creates a hierarchy. The salt-key command manages key acceptance.
salt-key -L
salt-key -A
salt '*' test.ping
salt '*' cmd.run 'uptime'
Remote Execution with Salt Modules
Salt ships with hundreds of execution modules. Targeting can be by glob, regex, list, Grains, Compound, or Nodegroup. I use the pkg module for packages, service for daemon control, cp for files. The --batch-size flag controls parallel execution rate.
salt '*' pkg.install nginx
salt '*' service.status nginx
salt -G 'os_family:Debian' pkg.upgrade
salt --batch-size 10% 'web-*' service.restart apache2
Salt State Files: Infrastructure as Code
Salt State files define the desired state declaratively. States use modules: pkg.installed, service.running, file.managed. The top.sls file maps minions to states. State requisites control ordering. States are idempotent and report changes clearly.
# /srv/salt/top.sls
base:
'web-*':
- nginx
'db-*':
- postgres
Grains and Pillar: Data Separation
Grains are static system info — OS, CPU, memory. Custom grains can be defined. Pillar is a secure data store for minion-specific configuration. I use Pillar for secrets and environment-specific config. Ext-pillar pulls data from external sources like Vault.
grains.get roles
salt 'web-01' grains.item roles os_family
# /srv/pillar/top.sls
base:
'web-*':
- web.settings
Jinja Templates and Complex States
Salt integrates Jinja2 templating in state files and Pillar. Templates enable dynamic configuration based on Grains and Pillar. The map.jinja pattern loads OS-specific package names. The orchestrate runner coordinates state application across multiple minions.
{% from 'nginx/map.jinja' import nginx with context %}
server {
listen {{ nginx.port }};
proxy_pass http://{{ salt['pillar.get']('upstream') }};
}
Event System, Reactor, and Beacons
Salt's event bus carries every significant occurrence. The Reactor listens for events and triggers actions. Beacons monitor system events on minions — file changes, process starts — and fire events to the master for real-time response.
reactor:
- 'salt/minion/*/start':
- /srv/reactor/startup.sls
beacons:
inotify:
- files:
/etc/nginx/nginx.conf:
mask:
- modify
Frequently Asked Questions
What is the difference between SaltStack and Ansible?
Salt uses a persistent agent connecting to a master and is faster at scale. Ansible is agentless with SSH push. Salt has more complex architecture but better scalability.
Does SaltStack require a master?
Salt can run in masterless mode with salt-call --local. This is useful for golden image building and air-gapped environments.
How do I secure Salt communication?
Salt encrypts all communication with AES. Firewall rules should restrict ports 4505 and 4506 to known minions only.
How does Salt handle high availability?
Multi-master setup with shared filesystems. Minions list multiple masters for failover. Salt Syndic creates a hierarchy for geographic distribution.
Originally published on Ayodhyyya. Last updated June 1, 2026.