This guide provides a complete Ansible playbook to install Scrutiny using the official Docker image with proper configuration for SMART drive monitoring, alerts, and web interface.
Current Scrutiny version: 0.7.0 (Docker image)
Create a file named scrutiny.yml:
---
- name: Install and Configure Scrutiny
hosts: scrutiny
become: true
vars:
scrutiny_version: "latest"
scrutiny_port: 8080
scrutiny_data_dir: "/opt/scrutiny/data"
scrutiny_config_dir: "/opt/scrutiny/config"
scrutiny_smartctl_path: "/usr/sbin/smartctl"
tasks:
- name: Install smartmontools (Debian/Ubuntu)
apt:
name: smartmontools
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Install smartmontools (RHEL/CentOS)
yum:
name: smartmontools
state: present
when: ansible_os_family == "RedHat"
- name: Create Scrutiny directories
file:
path: "{{ item }}"
state: directory
owner: root
group: root
mode: '0755'
loop:
- "{{ scrutiny_data_dir }}"
- "{{ scrutiny_config_dir }}"
- name: Create Scrutiny configuration
copy:
dest: "{{ scrutiny_config_dir }}/scrutiny.yaml"
owner: root
group: root
mode: '0644'
content: |
# Scrutiny Configuration
# Web interface settings
web:
listen:
port: {{ scrutiny_port }}
host: 0.0.0.0
database:
location: /opt/scrutiny/data/scrutiny.db
# Email notifications (optional)
# notification:
# email:
# enabled: true
# smtp:
# host: smtp.example.com
# port: 587
# username: scrutiny@example.com
# password: smtp_password
# from: scrutiny@example.com
# to:
# - admin@example.com
# Collector settings
collector:
smartctl:
path: {{ scrutiny_smartctl_path }}
# Scan interval (in hours)
scan_interval: 24
# Devices to monitor (leave empty for auto-detect)
# devices:
# - /dev/sda
# - /dev/sdb
# - /dev/nvme0n1
- name: Create Docker Compose file
copy:
dest: "{{ scrutiny_data_dir }}/docker-compose.yml"
owner: root
group: root
mode: '0644'
content: |
version: '3.8'
services:
scrutiny:
image: ghcr.io/analogj/scrutiny:{{ scrutiny_version }}
container_name: scrutiny
restart: unless-stopped
ports:
- "{{ scrutiny_port }}:8080"
volumes:
- {{ scrutiny_data_dir }}:/opt/scrutiny/data
- {{ scrutiny_config_dir }}:/opt/scrutiny/config
- /run/udev:/run/udev:ro
cap_add:
- SYS_RAWIO
- SYS_ADMIN
devices:
- /dev/sda
- /dev/sdb
environment:
- COLLECTOR_ENABLED=true
group_add:
- disk
privileged: true
- name: Start Scrutiny container
community.docker.docker_compose:
project_src: "{{ scrutiny_data_dir }}"
state: present
build: false
pull: true
- name: Wait for Scrutiny to start
wait_for:
port: "{{ scrutiny_port }}"
delay: 5
timeout: 120
- name: Configure firewall (UFW)
ufw:
rule: allow
port: "{{ scrutiny_port }}"
proto: tcp
comment: "Scrutiny web interface"
when: ansible_os_family == "Debian"
failed_when: false
- name: Configure firewall (firewalld)
firewalld:
port: "{{ scrutiny_port }}/tcp"
permanent: true
immediate: true
state: enabled
when: ansible_os_family == "RedHat"
failed_when: false
- name: Verify Scrutiny is running
uri:
url: "http://localhost:{{ scrutiny_port }}/api/health"
method: GET
status_code: 200
register: health_check
retries: 3
delay: 5
until: health_check.status == 200
- name: Display Scrutiny status
debug:
msg: |
Scrutiny {{ scrutiny_version }} installed successfully!
Web Interface: http://{{ ansible_default_ipv4.address | default(ansible_host) }}:{{ scrutiny_port }}
Data directory: {{ scrutiny_data_dir }}
Config directory: {{ scrutiny_config_dir }}
---
scrutiny:
hosts:
scrutiny-server:
ansible_host: 192.168.1.113
ansible_user: ansible
ansible_become: true
# Test connectivity
ansible all -i inventory.yml -m ping
# Run the Scrutiny playbook
ansible-playbook -i inventory.yml scrutiny.yml
# Check container status
ssh scrutiny-server "docker ps | grep scrutiny"
# View container logs
ssh scrutiny-server "docker logs scrutiny"
# Test web interface
curl http://scrutiny-server:8080/api/health
# Access web UI
# http://scrutiny-server:8080
- name: Run initial Scrutiny scan
hosts: scrutiny
become: true
vars:
scrutiny_data_dir: "/opt/scrutiny/data"
tasks:
- name: Run initial data collection
community.docker.docker_container_exec:
container: scrutiny
command: /opt/scrutiny/scrutiny-collector
register: scan_result
- name: Display scan result
debug:
var: scan_result.stdout
- name: Configure Scrutiny email notifications
hosts: scrutiny
become: true
vars:
scrutiny_config_dir: "/opt/scrutiny/config"
smtp_host: "smtp.example.com"
smtp_port: 587
smtp_user: "scrutiny@example.com"
smtp_password: "smtp_password"
alert_email: "admin@example.com"
tasks:
- name: Update Scrutiny configuration for email
copy:
dest: "{{ scrutiny_config_dir }}/scrutiny.yaml"
owner: root
group: root
mode: '0644'
content: |
# Scrutiny Configuration
web:
listen:
port: 8080
host: 0.0.0.0
database:
location: /opt/scrutiny/data/scrutiny.db
notification:
email:
enabled: true
smtp:
host: {{ smtp_host }}
port: {{ smtp_port }}
username: {{ smtp_user }}
password: {{ smtp_password }}
from: {{ smtp_user }}
to:
- {{ alert_email }}
collector:
smartctl:
path: /usr/sbin/smartctl
scan_interval: 24
- name: Restart Scrutiny container
community.docker.docker_compose:
project_src: "{{ scrutiny_data_dir }}"
state: present
restarted: true
- name: Configure Scrutiny webhook notifications
hosts: scrutiny
become: true
vars:
scrutiny_config_dir: "/opt/scrutiny/config"
webhook_url: "https://hooks.slack.com/services/XXX/YYY/ZZZ"
tasks:
- name: Update Scrutiny configuration for webhooks
copy:
dest: "{{ scrutiny_config_dir }}/scrutiny.yaml"
owner: root
group: root
mode: '0644'
content: |
web:
listen:
port: 8080
host: 0.0.0.0
database:
location: /opt/scrutiny/data/scrutiny.db
notification:
webhook:
enabled: true
url: {{ webhook_url }}
collector:
smartctl:
path: /usr/sbin/smartctl
scan_interval: 24
- name: Restart Scrutiny
community.docker.docker_compose:
project_src: "{{ scrutiny_data_dir }}"
state: present
restarted: true
- name: Configure specific drives for Scrutiny
hosts: scrutiny
become: true
vars:
scrutiny_config_dir: "/opt/scrutiny/config"
drives_to_monitor:
- /dev/sda
- /dev/sdb
- /dev/nvme0n1
tasks:
- name: Update Scrutiny configuration with specific drives
copy:
dest: "{{ scrutiny_config_dir }}/scrutiny.yaml"
owner: root
group: root
mode: '0644'
content: |
web:
listen:
port: 8080
host: 0.0.0.0
database:
location: /opt/scrutiny/data/scrutiny.db
collector:
smartctl:
path: /usr/sbin/smartctl
scan_interval: 24
devices:
{% for drive in drives_to_monitor %}
- {{ drive }}
{% endfor %}
- name: Update Docker Compose with device mappings
template:
src: templates/docker-compose-devices.yml.j2
dest: "{{ scrutiny_data_dir }}/docker-compose.yml"
owner: root
group: root
mode: '0644'
- name: Restart Scrutiny
community.docker.docker_compose:
project_src: "{{ scrutiny_data_dir }}"
state: present
restarted: true
- name: Backup Scrutiny data
hosts: scrutiny
become: true
vars:
scrutiny_data_dir: "/opt/scrutiny/data"
scrutiny_config_dir: "/opt/scrutiny/config"
backup_dir: "/backup/scrutiny"
tasks:
- name: Create backup directory
file:
path: "{{ backup_dir }}"
state: directory
mode: '0755'
- name: Backup SQLite database
copy:
src: "{{ scrutiny_data_dir }}/scrutiny.db"
dest: "{{ backup_dir }}/scrutiny-db-{{ ansible_date_time.date }}.db"
remote_src: true
- name: Backup configuration
archive:
path: "{{ scrutiny_config_dir }}"
dest: "{{ backup_dir }}/config-backup-{{ ansible_date_time.date }}.tar.gz"
- name: Clean up old backups (keep 7 days)
find:
paths: "{{ backup_dir }}"
patterns: "*.db,*.tar.gz"
age: 7d
register: old_backups
- name: Remove old backups
file:
path: "{{ item.path }}"
state: absent
loop: "{{ old_backups.files }}"
# Check container logs
docker logs scrutiny
# Check container status
docker ps -a | grep scrutiny
# Check device permissions
ls -la /dev/sd*
# Run manual scan
docker exec scrutiny /opt/scrutiny/scrutiny-collector
# Check smartctl access
docker exec scrutiny smartctl --scan
# Verify device mappings in docker-compose.yml
cat /opt/scrutiny/data/docker-compose.yml
# Add user to disk group
sudo usermod -aG disk $USER
# Check device permissions
ls -la /dev/sd*
# Restart container with privileged mode
docker-compose -f /opt/scrutiny/data/docker-compose.yml up -d
# Check database file
ls -la /opt/scrutiny/data/scrutiny.db
# Backup and recreate
docker-compose down
mv /opt/scrutiny/data/scrutiny.db /opt/scrutiny/data/scrutiny.db.bak
docker-compose up -d
Beyond this playbook, we offer:
Contact our automation team: office@linux-server-admin.com