Set up OpenSCAP security compliance scanning with automated systemd timers, generate HTML and XML audit reports, and configure SCAP security profiles for continuous compliance monitoring.
Prerequisites
- Root or sudo access
- Basic Linux command line knowledge
- Understanding of compliance frameworks
What this solves
OpenSCAP provides automated security compliance scanning against industry standards like CIS benchmarks, NIST 800-53, and PCI DSS. This tutorial shows you how to install OpenSCAP, configure security profiles, set up automated scanning with systemd timers, and generate detailed compliance reports in HTML and XML formats for audit trails.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest OpenSCAP tools and dependencies.
sudo apt update && sudo apt upgrade -y
Install OpenSCAP and dependencies
Install the core OpenSCAP scanner, utilities, and security content packages that contain the compliance profiles.
sudo apt install -y libopenscap8 openscap-utils scap-security-guide ssg-debderived ssg-base
Verify OpenSCAP installation
Check that OpenSCAP is installed correctly and view the available scanning capabilities.
oscap --version
oscap --help
Locate security content profiles
Find the installed SCAP security content that contains compliance profiles for different standards.
ls -la /usr/share/xml/scap/ssg/content/
oscap info /usr/share/xml/scap/ssg/content/ssg-ubuntu2004-ds.xml
List available compliance profiles
View all available security profiles to choose the appropriate compliance standard for your environment.
oscap info --profiles /usr/share/xml/scap/ssg/content/ssg-ubuntu2004-ds.xml
Create compliance scan directories
Set up directories to store scan results, reports, and configuration files with proper permissions.
sudo mkdir -p /var/lib/openscap/{reports,results,logs}
sudo mkdir -p /etc/openscap/profiles
sudo chmod 755 /var/lib/openscap
sudo chmod 755 /var/lib/openscap/{reports,results,logs}
Run initial compliance scan
Perform a test scan using the CIS benchmark profile to verify everything works correctly.
sudo oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_cis_level1_server \
--results /var/lib/openscap/results/initial-scan-results.xml \
--report /var/lib/openscap/reports/initial-scan-report.html \
/usr/share/xml/scap/ssg/content/ssg-ubuntu2004-ds.xml
Configure SCAP security profiles
Create custom profile configuration
Set up a configuration file to define which profiles to scan and customize scanning parameters.
# OpenSCAP Compliance Configuration
Profile selection and scanning parameters
Default profile for automated scanning
DEFAULT_PROFILE="xccdf_org.ssgproject.content_profile_cis_level1_server"
Content location
CONTENT_PATH="/usr/share/xml/scap/ssg/content/ssg-ubuntu2004-ds.xml"
Results and reports directories
RESULTS_DIR="/var/lib/openscap/results"
REPORTS_DIR="/var/lib/openscap/reports"
LOGS_DIR="/var/lib/openscap/logs"
Report formats to generate
GENERATE_HTML="true"
GENERATE_XML="true"
GENERATE_ARF="false"
Retention policy (days)
RETENTION_DAYS="30"
Email notifications
EMAIL_ALERTS="false"
EMAIL_ADDRESS="admin@example.com"
Create compliance scanning script
Build an automated script that reads the configuration and performs compliance scans with proper logging.
#!/bin/bash
OpenSCAP Compliance Scanner Script
Automated compliance scanning with reporting
set -euo pipefail
Source configuration
CONFIG_FILE="/etc/openscap/profiles/compliance-config.conf"
if [[ -f "$CONFIG_FILE" ]]; then
source "$CONFIG_FILE"
else
echo "Configuration file not found: $CONFIG_FILE"
exit 1
fi
Generate timestamp for unique filenames
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
HOSTNAME=$(hostname -s)
Define output files
RESULT_FILE="$RESULTS_DIR/compliance-results-$HOSTNAME-$TIMESTAMP.xml"
REPORT_FILE="$REPORTS_DIR/compliance-report-$HOSTNAME-$TIMESTAMP.html"
LOG_FILE="$LOGS_DIR/compliance-scan-$TIMESTAMP.log"
Logging function
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
log "Starting OpenSCAP compliance scan"
log "Profile: $DEFAULT_PROFILE"
log "Content: $CONTENT_PATH"
Check if content file exists
if [[ ! -f "$CONTENT_PATH" ]]; then
log "ERROR: Content file not found: $CONTENT_PATH"
exit 1
fi
Run the compliance scan
log "Executing compliance scan..."
if oscap xccdf eval \
--profile "$DEFAULT_PROFILE" \
--results "$RESULT_FILE" \
--report "$REPORT_FILE" \
"$CONTENT_PATH" >> "$LOG_FILE" 2>&1; then
SCAN_STATUS="SUCCESS"
else
SCAN_STATUS="COMPLETED_WITH_FINDINGS"
fi
log "Scan completed with status: $SCAN_STATUS"
log "Results saved to: $RESULT_FILE"
log "Report saved to: $REPORT_FILE"
Generate summary
if [[ -f "$RESULT_FILE" ]]; then
TOTAL_RULES=$(oscap xccdf generate report "$RESULT_FILE" | grep -o 'Rule.*:' | wc -l || echo "0")
log "Total rules evaluated: $TOTAL_RULES"
fi
Cleanup old files based on retention policy
find "$RESULTS_DIR" -name "*.xml" -mtime +"$RETENTION_DAYS" -delete 2>/dev/null || true
find "$REPORTS_DIR" -name "*.html" -mtime +"$RETENTION_DAYS" -delete 2>/dev/null || true
find "$LOGS_DIR" -name "*.log" -mtime +"$RETENTION_DAYS" -delete 2>/dev/null || true
log "Compliance scan completed successfully"
exit 0
Make the script executable
Set proper permissions on the scanning script to allow execution by root and the system.
sudo chmod 755 /usr/local/bin/openscap-compliance-scan.sh
sudo chown root:root /usr/local/bin/openscap-compliance-scan.sh
Update content path for distribution
Modify the configuration file to use the correct content path for your Linux distribution.
sudo sed -i 's|ssg-ubuntu2004-ds.xml|ssg-ubuntu2004-ds.xml|g' /etc/openscap/profiles/compliance-config.conf
Set up automated scanning with systemd timers
Create systemd service unit
Define a systemd service that runs the compliance scanning script with proper environment and security settings.
[Unit]
Description=OpenSCAP Compliance Scanner
After=network.target
Wants=network.target
[Service]
Type=oneshot
User=root
Group=root
ExecStart=/usr/local/bin/openscap-compliance-scan.sh
StandardOutput=journal
StandardError=journal
SyslogIdentifier=openscap-compliance
Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/var/lib/openscap
Resource limits
TimeoutSec=1800
MemoryMax=512M
[Install]
WantedBy=multi-user.target
Create systemd timer unit
Set up a timer to run compliance scans automatically on a regular schedule.
[Unit]
Description=Run OpenSCAP compliance scan
Requires=openscap-compliance.service
[Timer]
Run daily at 2 AM
OnCalendar=daily
Persistent=true
Add randomization to avoid system load spikes
RandomizedDelaySec=1800
Ensure timer doesn't accumulate if system was down
AccuracySec=1h
[Install]
WantedBy=timers.target
Enable and start the systemd timer
Activate the automated scanning timer and verify it's scheduled correctly.
sudo systemctl daemon-reload
sudo systemctl enable openscap-compliance.timer
sudo systemctl start openscap-compliance.timer
sudo systemctl status openscap-compliance.timer
Test the automated scan
Run the service manually to verify the automation works correctly before relying on the timer.
sudo systemctl start openscap-compliance.service
sudo systemctl status openscap-compliance.service
sudo journalctl -u openscap-compliance.service -n 20
Check timer schedule
Verify when the next automated scan is scheduled to run.
sudo systemctl list-timers openscap-compliance.timer
Generate HTML and XML compliance reports
Create report generation script
Build a script to generate comprehensive reports from existing scan results in multiple formats.
#!/bin/bash
OpenSCAP Report Generator
Generate reports from existing scan results
set -euo pipefail
Configuration
RESULTS_DIR="/var/lib/openscap/results"
REPORTS_DIR="/var/lib/openscap/reports"
LOGS_DIR="/var/lib/openscap/logs"
Check if results directory exists
if [[ ! -d "$RESULTS_DIR" ]]; then
echo "Results directory not found: $RESULTS_DIR"
exit 1
fi
Find the most recent result file
LATEST_RESULT=$(find "$RESULTS_DIR" -name "*.xml" -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-)
if [[ -z "$LATEST_RESULT" ]]; then
echo "No scan results found in $RESULTS_DIR"
exit 1
fi
echo "Processing results from: $LATEST_RESULT"
Generate timestamp for reports
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
HOSTNAME=$(hostname -s)
Generate HTML report
HTML_REPORT="$REPORTS_DIR/compliance-report-$HOSTNAME-$TIMESTAMP.html"
echo "Generating HTML report..."
oscap xccdf generate report "$LATEST_RESULT" > "$HTML_REPORT"
echo "HTML report saved: $HTML_REPORT"
Generate detailed XML report
XML_REPORT="$REPORTS_DIR/compliance-detailed-$HOSTNAME-$TIMESTAMP.xml"
echo "Generating detailed XML report..."
cp "$LATEST_RESULT" "$XML_REPORT"
echo "XML report saved: $XML_REPORT"
Generate summary statistics
SUMMARY_FILE="$REPORTS_DIR/compliance-summary-$HOSTNAME-$TIMESTAMP.txt"
echo "Generating compliance summary..."
{
echo "OpenSCAP Compliance Summary"
echo "Generated: $(date)"
echo "Hostname: $HOSTNAME"
echo "Source: $LATEST_RESULT"
echo ""
# Extract rule results
echo "Rule Results:"
oscap xccdf generate report "$LATEST_RESULT" | grep -E "(pass|fail|error|unknown|notapplicable|notchecked)" | \
sed 's/<[^>]*>//g' | sort | uniq -c | sort -rn || echo "Unable to extract rule statistics"
echo ""
echo "Report files generated:"
echo " HTML: $HTML_REPORT"
echo " XML: $XML_REPORT"
echo " Summary: $SUMMARY_FILE"
} > "$SUMMARY_FILE"
echo "Summary saved: $SUMMARY_FILE"
echo "Report generation completed successfully"
exit 0
Make report generator executable
Set appropriate permissions on the report generation script.
sudo chmod 755 /usr/local/bin/openscap-report-generator.sh
sudo chown root:root /usr/local/bin/openscap-report-generator.sh
Generate reports from existing scans
Run the report generator to create HTML and XML reports from your compliance scan results.
sudo /usr/local/bin/openscap-report-generator.sh
View generated reports
List the generated reports and check their contents to verify successful generation.
ls -la /var/lib/openscap/reports/
head -20 /var/lib/openscap/reports/compliance-summary-$(hostname -s)-*.txt
Set up web server for report viewing
Configure a simple web server to view HTML reports through a browser interface.
sudo apt install -y nginx
sudo systemctl enable --now nginx
Configure Nginx for compliance reports
Create a virtual host to serve compliance reports securely with basic authentication.
server {
listen 80;
server_name compliance.example.com;
# Redirect to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name compliance.example.com;
# SSL configuration (replace with your certificates)
ssl_certificate /etc/ssl/certs/compliance.crt;
ssl_certificate_key /etc/ssl/private/compliance.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
# Document root for compliance reports
root /var/lib/openscap/reports;
index index.html;
# Basic authentication
auth_basic "Compliance Reports Access";
auth_basic_user_file /etc/nginx/.htpasswd-compliance;
# Security headers
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
# Serve HTML reports
location ~* \.html$ {
try_files $uri =404;
expires 1h;
}
# Deny access to XML files and logs
location ~* \.(xml|log)$ {
deny all;
return 404;
}
# Logging
access_log /var/log/nginx/compliance-reports.access.log;
error_log /var/log/nginx/compliance-reports.error.log;
}
Verify your setup
Check that all components are working correctly and compliance scanning is automated.
# Check OpenSCAP installation
oscap --version
Verify systemd timer is active
sudo systemctl status openscap-compliance.timer
sudo systemctl list-timers openscap-compliance.timer
Check recent scan results
ls -la /var/lib/openscap/results/
ls -la /var/lib/openscap/reports/
View compliance service logs
sudo journalctl -u openscap-compliance.service -n 20
Test manual scan execution
sudo /usr/local/bin/openscap-compliance-scan.sh
Verify report generation
sudo /usr/local/bin/openscap-report-generator.sh
Check disk space usage
du -sh /var/lib/openscap/
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Scanner fails with "content not found" | Incorrect path to SCAP content files | Check /usr/share/xml/scap/ssg/content/ and update config file paths |
| Permission denied writing reports | Incorrect directory permissions | sudo chmod 755 /var/lib/openscap/{reports,results,logs} |
| Systemd timer not running | Timer unit not enabled | sudo systemctl enable --now openscap-compliance.timer |
| HTML reports show formatting errors | Malformed XML results file | Re-run scan with --oval-results flag and check content file integrity |
| Scan takes too long and times out | Resource constraints or large profile | Increase TimeoutSec in service unit and add memory limits |
| Old reports not being cleaned up | Retention policy not working | Check script has write access to directories and RETENTION_DAYS setting |
Next steps
- Configure centralized cron management with Ansible automation and systemd timers to manage compliance scanning across multiple servers
- Configure auditd with Elasticsearch and Kibana for compliance reporting to centralize audit logs with compliance scan results
- Configure OpenSCAP automated remediation and system hardening to automatically fix compliance violations
- Integrate OpenSCAP with Ansible for fleet-wide compliance management
- Set up centralized OpenSCAP reporting with Grafana dashboards
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# OpenSCAP Automated Compliance Scanner Setup Script
# Production-ready installation with cross-distro support
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m'
# Global variables
PROFILE_NAME=""
SCAN_INTERVAL="daily"
# Logging function
log() {
echo -e "${GREEN}[INFO]${NC} $1"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
# Usage message
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -p PROFILE Compliance profile (cis, pci-dss, nist) [default: cis]"
echo " -i INTERVAL Scan interval (daily, weekly) [default: daily]"
echo " -h Show this help message"
exit 1
}
# Cleanup function
cleanup() {
if [[ $? -ne 0 ]]; then
error "Installation failed. Cleaning up..."
systemctl stop openscap-scanner.timer 2>/dev/null || true
systemctl disable openscap-scanner.timer 2>/dev/null || true
rm -f /etc/systemd/system/openscap-scanner.{service,timer}
rm -rf /etc/openscap /var/lib/openscap
fi
}
trap cleanup ERR
# Parse command line arguments
while getopts "p:i:h" opt; do
case $opt in
p) PROFILE_NAME="$OPTARG" ;;
i) SCAN_INTERVAL="$OPTARG" ;;
h) usage ;;
*) usage ;;
esac
done
# Set default profile
[[ -z "$PROFILE_NAME" ]] && PROFILE_NAME="cis"
# Validate interval
if [[ "$SCAN_INTERVAL" != "daily" && "$SCAN_INTERVAL" != "weekly" ]]; then
error "Invalid interval. Use 'daily' or 'weekly'"
exit 1
fi
# Check prerequisites
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root"
exit 1
fi
# Detect distribution
if [[ ! -f /etc/os-release ]]; then
error "/etc/os-release not found. Cannot detect distribution"
exit 1
fi
source /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
SCAP_PACKAGES="libopenscap8 openscap-utils scap-security-guide ssg-debderived ssg-base"
CONTENT_FILE="ssg-ubuntu2004-ds.xml"
if [[ "$ID" == "debian" ]]; then
CONTENT_FILE="ssg-debian10-ds.xml"
fi
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
SCAP_PACKAGES="openscap openscap-utils scap-security-guide"
CONTENT_FILE="ssg-almalinux9-ds.xml"
if [[ "$ID" == "centos" ]]; then
CONTENT_FILE="ssg-centos8-ds.xml"
elif [[ "$ID" == "rhel" ]]; then
CONTENT_FILE="ssg-rhel9-ds.xml"
fi
;;
fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
SCAP_PACKAGES="openscap openscap-utils scap-security-guide"
CONTENT_FILE="ssg-fedora-ds.xml"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
SCAP_PACKAGES="openscap openscap-utils scap-security-guide"
CONTENT_FILE="ssg-amzn2-ds.xml"
;;
*)
error "Unsupported distribution: $ID"
exit 1
;;
esac
# Map profile names to XCCDF identifiers
case "$PROFILE_NAME" in
cis)
if [[ "$ID" =~ ^(ubuntu|debian)$ ]]; then
XCCDF_PROFILE="xccdf_org.ssgproject.content_profile_cis_level1_server"
else
XCCDF_PROFILE="xccdf_org.ssgproject.content_profile_cis"
fi
;;
pci-dss)
XCCDF_PROFILE="xccdf_org.ssgproject.content_profile_pci-dss"
;;
nist)
XCCDF_PROFILE="xccdf_org.ssgproject.content_profile_moderate"
;;
*)
error "Unsupported profile: $PROFILE_NAME"
exit 1
;;
esac
log "[1/10] Starting OpenSCAP compliance scanner installation..."
log "[2/10] Updating system packages..."
eval $PKG_UPDATE
log "[3/10] Installing OpenSCAP packages..."
eval $PKG_INSTALL $SCAP_PACKAGES
log "[4/10] Verifying OpenSCAP installation..."
if ! command -v oscap &> /dev/null; then
error "OpenSCAP installation failed"
exit 1
fi
OSCAP_VERSION=$(oscap --version | head -n1)
log "OpenSCAP installed: $OSCAP_VERSION"
log "[5/10] Creating compliance directories..."
mkdir -p /var/lib/openscap/{reports,results,logs}
mkdir -p /etc/openscap/profiles
chmod 755 /var/lib/openscap
chmod 755 /var/lib/openscap/{reports,results,logs}
chmod 755 /etc/openscap
chmod 755 /etc/openscap/profiles
log "[6/10] Locating security content..."
CONTENT_PATH="/usr/share/xml/scap/ssg/content/$CONTENT_FILE"
# Fallback content detection
if [[ ! -f "$CONTENT_PATH" ]]; then
AVAILABLE_CONTENT=$(find /usr/share/xml/scap/ssg/content/ -name "ssg-*.xml" | head -n1)
if [[ -n "$AVAILABLE_CONTENT" ]]; then
CONTENT_PATH="$AVAILABLE_CONTENT"
warn "Using fallback content: $CONTENT_PATH"
else
error "No SCAP security content found"
exit 1
fi
fi
log "[7/10] Creating configuration file..."
cat > /etc/openscap/scanner.conf << EOF
# OpenSCAP Compliance Scanner Configuration
PROFILE="$XCCDF_PROFILE"
CONTENT_PATH="$CONTENT_PATH"
RESULTS_DIR="/var/lib/openscap/results"
REPORTS_DIR="/var/lib/openscap/reports"
LOGS_DIR="/var/lib/openscap/logs"
RETENTION_DAYS="30"
EOF
chmod 644 /etc/openscap/scanner.conf
log "[8/10] Creating compliance scanner script..."
cat > /usr/local/bin/openscap-scanner << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
# Load configuration
source /etc/openscap/scanner.conf
# Generate timestamp
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
RESULT_FILE="$RESULTS_DIR/scan-$TIMESTAMP.xml"
REPORT_FILE="$REPORTS_DIR/scan-$TIMESTAMP.html"
LOG_FILE="$LOGS_DIR/scan-$TIMESTAMP.log"
# Perform compliance scan
{
echo "Starting OpenSCAP compliance scan at $(date)"
oscap xccdf eval \
--profile "$PROFILE" \
--results "$RESULT_FILE" \
--report "$REPORT_FILE" \
"$CONTENT_PATH" 2>&1
echo "Compliance scan completed at $(date)"
} | tee "$LOG_FILE"
# Clean up old files
find "$RESULTS_DIR" -name "*.xml" -mtime +$RETENTION_DAYS -delete 2>/dev/null || true
find "$REPORTS_DIR" -name "*.html" -mtime +$RETENTION_DAYS -delete 2>/dev/null || true
find "$LOGS_DIR" -name "*.log" -mtime +$RETENTION_DAYS -delete 2>/dev/null || true
echo "Scan results: $RESULT_FILE"
echo "HTML report: $REPORT_FILE"
EOF
chmod 755 /usr/local/bin/openscap-scanner
log "[9/10] Setting up systemd service and timer..."
cat > /etc/systemd/system/openscap-scanner.service << EOF
[Unit]
Description=OpenSCAP Compliance Scanner
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/openscap-scanner
User=root
StandardOutput=journal
StandardError=journal
EOF
# Set timer interval
if [[ "$SCAN_INTERVAL" == "daily" ]]; then
TIMER_SPEC="OnCalendar=daily"
else
TIMER_SPEC="OnCalendar=weekly"
fi
cat > /etc/systemd/system/openscap-scanner.timer << EOF
[Unit]
Description=Run OpenSCAP compliance scan $SCAN_INTERVAL
Requires=openscap-scanner.service
[Timer]
$TIMER_SPEC
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl daemon-reload
systemctl enable openscap-scanner.timer
systemctl start openscap-scanner.timer
log "[10/10] Running initial compliance scan..."
/usr/local/bin/openscap-scanner
log "Verifying installation..."
if systemctl is-active --quiet openscap-scanner.timer; then
log "✓ OpenSCAP scanner timer is active"
else
error "✗ OpenSCAP scanner timer is not active"
exit 1
fi
if [[ -d "/var/lib/openscap/reports" ]] && [[ $(ls -1 /var/lib/openscap/reports/*.html 2>/dev/null | wc -l) -gt 0 ]]; then
LATEST_REPORT=$(ls -1t /var/lib/openscap/reports/*.html | head -n1)
log "✓ Initial scan completed successfully"
log "✓ Latest report: $LATEST_REPORT"
else
error "✗ Initial scan failed or no reports generated"
exit 1
fi
log ""
log "OpenSCAP compliance scanner installation completed successfully!"
log ""
log "Configuration:"
log " Profile: $PROFILE_NAME ($XCCDF_PROFILE)"
log " Content: $CONTENT_PATH"
log " Scan interval: $SCAN_INTERVAL"
log ""
log "Management commands:"
log " Check timer status: systemctl status openscap-scanner.timer"
log " Run manual scan: /usr/local/bin/openscap-scanner"
log " View reports: ls -la /var/lib/openscap/reports/"
log " Check logs: journalctl -u openscap-scanner.service"
Review the script before running. Execute with: bash install.sh