Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/wikioasis/salt/llms.txt

Use this file to discover all available pages before exploring further.

Salt’s pillar system is the recommended way to supply configuration values — including secrets — to state files without hard-coding them. Pillar data is stored as YAML in the pillar/ directory, served exclusively to the minion that matches the relevant top.sls target, and never written to disk on the minion itself. States read pillar values with the salt['pillar.get']() Jinja call, providing a safe default if the key is absent.

How pillar files are structured

Each service has its own subdirectory under pillar/. The init.sls inside that directory is the shared default file, applied to every minion that matches the service’s glob. Where a specific host needs different values — for example a larger InnoDB buffer pool for a production database — a per-host override file sits alongside init.sls and is assigned to that host individually in pillar/top.sls.
pillar/
├── mariadb/
│   ├── init.sls                   ← shared defaults for all db* hosts
│   ├── db-c1-us-east-021.sls      ← overrides for db-c1-us-east-021 only
│   ├── db-other-us-east-011.sls
│   └── db-pc-us-east-011.sls
├── redis/
│   ├── init.sls                   ← shared defaults for all redis* hosts
│   ├── redis-us-east-011.sls      ← overrides for redis-us-east-011 only
│   ├── redis-us-east-012.sls
│   └── redis-us-east-021.sls
└── metal/
    ├── init.sls                   ← shared defaults for all metal* hosts + VMs
    ├── metal-us-east-01.sls       ← overrides for metal-us-east-01 only
    └── metal-us-east-02.sls
When Salt compiles the pillar for a minion, all matching files are merged. Keys in per-host files take precedence over keys in init.sls.

Top-level pillar keys

timezone and apt

Defined in pillar/base/init.sls and applied to every minion. These two keys control the system timezone and the APT mirror used in /etc/apt/sources.list.
# pillar/base/init.sls
timezone: Etc/UTC

apt:
  mirror: deb.debian.org

haproxy

Applied to proxy* minions. Defines global settings, frontend bindings, backend pools, and per-route hostname matching. The routes list drives a Jinja template that generates HAProxy ACL rules; each entry maps a public hostname to a named backend.
# pillar/haproxy/init.sls (excerpt)
haproxy:
  global:
    maxconn: 4096
    log: /dev/log local0 info

  defaults:
    mode: http
    timeout_connect: 5s
    timeout_client: 50s
    timeout_server: 50s

  stats_socket: /run/haproxy/admin.sock

  routes:
    - hostname: icinga.wikioasis.org
      backend: icinga
      active: true
    - hostname: grafana.wikioasis.org
      backend: grafana
      active: true

  backends:
    mediawiki:
      balance: roundrobin
      options:
        - forwardfor
        - httpchk
      http_checks:
        - send meth GET uri /wiki/Main_Page ver HTTP/1.1 hdr Host wikioasis.org
        - expect str wikioasis
      servers:
        - name: mw-us-east-011
          host: mw-us-east-011.ovvin.wonet
          port: 80
          check: true
          weight: 1
          depooled: false
Set depooled: true on a server entry to remove it from the pool without deleting it from the config — useful during rolling deploys.

mariadb

Applied to db* minions. Shared defaults set conservative buffer sizes; per-host files override them for production workloads.
# pillar/mariadb/init.sls — shared defaults
mariadb:
  datadir: /var/lib/mysql
  bind_address: 0.0.0.0
  key_buffer_size: 128M
  max_allowed_packet: 1G
  thread_stack: 192K
  thread_cache_size: 8
  max_connections: 100
  table_cache: 64
  expire_logs_days: 10
  innodb:
    buffer_pool_size: 1G
    log_file_size: 256M
    flush_log_at_trx_commit: 1
    file_per_table: true
# pillar/mariadb/db-c1-us-east-021.sls — key differences from init.sls
mariadb:
  server_id: 1021
  max_connections: 1000
  innodb:
    buffer_pool_size: 20G

mediawiki

Applied to mw*, staging*, task*, and proxy* minions. Controls the deployment user, filesystem paths, the HAProxy socket used for canary draining, and the MediaWiki server list used by the deploy tooling.
# pillar/mediawiki/init.sls
mediawiki:
  deploy_user: mwdeploy
  staging_path: /srv/mediawiki-staging
  prod_path: /srv/mediawiki
  canary_vhost: test.wikioasis.org
  log_file: /var/log/mwdeploy.log
  haproxy_backend: mediawiki
  haproxy_socket: /run/haproxy/admin.sock
  backup_path: /srv/mediawiki-backup
  mw_servers:
    - task-us-east-011.ovvin.wonet
    - mw-us-east-011.ovvin.wonet
    - mw-us-east-012.ovvin.wonet
    - mw-us-east-021.ovvin.wonet
    - mw-us-east-022.ovvin.wonet
  proxy_servers:
    - proxy-us-east-011.ovvin.wonet
    - proxy-us-east-021.ovvin.wonet
  deploy_ssh_public_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBw+m6ZQT6Q7MPgfd5STamRLSUADflff/9uKVtbBZluM mwdeploy@staging-us-east-021"
  ssh_identity: /home/mwdeploy/.ssh/id_ed25519
  webhooks:
    discord: ""
    slack: ""
Webhook URLs for Discord and Slack deploy notifications are set here (or overridden in the private pillar).

monitoring

Applied to monitoring* minions. Configures Icinga 2 database names, the Grafana admin user, and Prometheus retention. Passwords are not stored here — they live in the private pillar.
# pillar/monitoring/init.sls
monitoring:
  icinga_api_user: root
  ido_db_name: icingadb
  ido_db_user: icingadb
  web_db_name: icingaweb
  director_db_name: icingaweb
  director_db_user: icingadb

  grafana:
    admin_user: admin

  prometheus:
    retention: 30d

nginx

Applied to mw*, staging*, and task* minions (the apps* role does not use the shared nginx pillar). Sets the document root, the Content Security Policy header (which covers all WikiOasis and SkyWiki domains), standard server blocks, and per-wiki custom domain mappings for ACME verification tokens.
# pillar/nginx/init.sls (excerpt)
nginx:
  doc_root: /srv/mediawiki

  csp_header: >-
    default-src 'self' https://*.betaoasis.xyz https://*.wikioasis.org;
    script-src 'self' blob: 'unsafe-inline' 'unsafe-eval' ...;
    ...

  server_blocks:
    - listen:
        - "80"
        - "[::]:80"
      server_name: ".wikioasis.org .skywiki.org .betaoasis.xyz"

  custom_domains:
    solarpunkwiki:
      server_name: 'www.solarpunk.wiki'
      listen: 80
      location: 'py_SqqfZnDI2q2LQkLUXETagCWz_XKLJfUavp8ncbmFlNaxrJ9RCTR1nt6bBLVdh'
      return: 'py_SqqfZnDI2q2LQkLUXETagCWz_XKLJfUavp8ncbmFlNaxrJ9RCTR1nt6bBLVdh.r54qAqCZSs4xyyeamMffaxyR1FWYVb5OvwUh8EcrhpI'
      database_name: 'solarpunkwiki'
Each custom_domains entry generates an nginx server block that handles the ACME challenge verification token and rewrites to the wiki’s canonical URL.

opensearch

Applied to opensearch* minions. Names the search cluster, sets the JVM heap size, and lists all nodes in the cluster for transport-layer discovery.
# pillar/opensearch/init.sls
opensearch:
  cluster_name: wikioasis-search
  heap_size: 3g
  http_port: 9200
  transport_port: 9300
  nodes:
    - name: opensearch-us-east-011
      host: opensearch-us-east-011.ovvin.wonet
    - name: opensearch-us-east-012
      host: opensearch-us-east-012.ovvin.wonet

php

Applied to mw*, staging*, task*, and apps* minions. Specifies the PHP version, the list of extensions to install, FPM pool tuning, and monitoring queue thresholds.
# pillar/php/init.sls
php:
  version: "8.4"
  extensions:
    - fpm
    - mysql
    - xml
    - mbstring
    - intl
    - curl
    - gd
    - zip
    - apcu
    - igbinary
    - redis
  extra_packages:
    - php-excimer
    - php-luasandbox
  fpm:
    pool: www
    listen: ""
    pm: dynamic
    pm_max_children: 10
    pm_start_servers: 6
    pm_min_spare_servers: 6
    pm_max_spare_servers: 8
    pm_max_requests: 500
    request_terminate_timeout: 60
  monitoring:
    queue_warn: 5
    queue_crit: 10

redis

Applied to redis* minions. Shared defaults use noeviction (suitable for sessions). Per-host files for the us-east-011 and us-east-012 nodes switch to allkeys-lru for use as an object cache — us-east-011 sets maxmemory to 12gb and us-east-012 sets it to 3gb.
# pillar/redis/init.sls — shared defaults
redis:
  bind: 0.0.0.0
  port: 6379
  timeout: 0
  tcp_keepalive: 300
  loglevel: notice
  logfile: ""
  databases: 16
  maxmemory: 0
  maxmemory_policy: noeviction
  protected_mode: "no"
  appendonly: "no"
  appendfsync: everysec
  save:
    - "900 1"
    - "300 10"
    - "60 10000"
# pillar/redis/redis-us-east-011.sls — larger object-cache node
redis:
  bind: 0.0.0.0
  maxmemory: 12gb
  maxmemory_policy: allkeys-lru
# pillar/redis/redis-us-east-012.sls — smaller object-cache node
redis:
  bind: 0.0.0.0
  maxmemory: 3gb
  maxmemory_policy: allkeys-lru

users and groups

Applied to all minions (via the '*' rule in pillar/top.sls). Defines the system users, their SSH public keys, UIDs/GIDs, and the sudo groups they belong to. User IDs start at 3000 to avoid conflicts with service accounts.
# pillar/users/init.sls (excerpt)
users:
  thomas:
    fullname: Thomas
    ssh-keys:
      - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBBENCQ1Vgjdl8ux9snbGF4s1SRbcU0EvaYlj7I51LWG zippybonzo@wikioasis.org
    uid: 3000
    gid: 3000

groups:
  ops:
    gid: 7000
    description: root, on all servers
    members: [thomas, unai]
    privileges: ['ALL = (ALL) NOPASSWD: ALL']
  mediawiki-admins:
    gid: 7001
    description: elevated permissions on webservers
    members: [tali64]
    privileges:
      - 'ALL = (www-data) NOPASSWD: ALL'
      - 'ALL = (www-data) NOPASSWD: /usr/local/bin/mwdeploy *'
      - 'ALL = (ALL) NOPASSWD: /usr/sbin/service nginx *'
      - 'ALL = (ALL) NOPASSWD: /usr/sbin/service php8.4-fpm *'
      - 'ALL = (ALL) NOPASSWD: /bin/journalctl *'
The users/servers/mediawiki.sls file adds a server_groups key that restricts which groups are provisioned on MediaWiki servers:
# pillar/users/servers/mediawiki.sls
server_groups:
  - ops
  - mediawiki-admins

metal (bare-metal / Proxmox)

Applied to metal* minions and all VMs (via the compound metal* or *-us-east-0[0-9][0-9]* rule). Provides the DNS/MAC address table for DHCP, the Proxmox bridge names, public IP addresses, per-hypervisor IPv6 prefixes, and IP forwarding rules.
# pillar/metal/init.sls (excerpt)
apt_bootstrap:
  http_cache: http://127.0.0.1:3129

metal_public_ips:
  - 40.160.53.92
  - 40.160.53.94

dns_hosts:
  mw-us-east-011.ovvin.wonet:
    ip: 10.0.1.60
    mac: bc:24:11:ac:18:e0

proxmox:
  public_bridge: "vmbr0"
  private_bridge: "vmbr-vrack"
  hosts:
    metal-us-east-01:
      ipv6_prefix: "2604:2dc0:100:295c"
      ipv6_gateway: "2604:2dc0:100:29ff:ff:ff:ff:ff"
The apt_bootstrap.http_cache value is an APT proxy address used only during initial VM provisioning, before Salt manages the host. The metal state removes this proxy configuration file once it takes control.

Pillar merging behaviour

Salt merges pillar data from all matching files using a shallow merge by default. For dictionary keys, the last file wins at the top level. Because per-host files are loaded after init.sls, their keys override the shared defaults:
Effective pillar for db-c1-us-east-021
= merge(mariadb/init.sls, mariadb/db-c1-us-east-021.sls)
The mariadb.innodb.buffer_pool_size from the per-host file (20G) replaces the default (1G) because both files define the mariadb top-level key and Salt merges dictionaries recursively when pillar_source_merging_strategy: recurse is set.

Build docs developers (and LLMs) love