Package hooks in Alpine Linux provide powerful automation capabilities, allowing you to execute custom scripts during package installation, upgrade, and removal processes. This comprehensive guide teaches you how to create, implement, and manage custom package hooks effectively.
🔍 Understanding Alpine Package Hooks
Package hooks are scripts that run automatically at specific points during package lifecycle events. They enable system administrators to automate configuration tasks, enforce policies, and integrate packages with existing infrastructure.
Hook Types and Triggers
- Pre-install hooks - Run before package installation 📥
- Post-install hooks - Run after package installation ✅
- Pre-upgrade hooks - Run before package upgrades ⬆️
- Post-upgrade hooks - Run after package upgrades 🔄
- Pre-remove hooks - Run before package removal ⚠️
- Post-remove hooks - Run after package removal 🗑️
📋 Hook System Architecture
Hook Directory Structure
# APK hook directories
/etc/apk/hooks/
├── pre-install.d/
├── post-install.d/
├── pre-upgrade.d/
├── post-upgrade.d/
├── pre-remove.d/
└── post-remove.d/
# Create hook directories if they don't exist
mkdir -p /etc/apk/hooks/{pre-install,post-install,pre-upgrade,post-upgrade,pre-remove,post-remove}.d
Hook Execution Environment
# Available environment variables in hooks
echo "Package: $APK_PACKAGE_NAME"
echo "Version: $APK_PACKAGE_VERSION"
echo "Action: $APK_ACTION"
echo "Root: $APK_ROOT"
echo "User: $APK_USER"
echo "Repository: $APK_REPOSITORY"
🛠️ Creating Basic Package Hooks
Simple Post-Install Hook
# Create basic post-install hook
cat > /etc/apk/hooks/post-install.d/01-welcome << 'EOF'
#!/bin/sh
# Welcome message for new package installations
if [ "$APK_ACTION" = "install" ]; then
echo "✅ Package $APK_PACKAGE_NAME ($APK_PACKAGE_VERSION) installed successfully!"
echo "📝 Installation completed at $(date)"
# Log installation
echo "$(date): Installed $APK_PACKAGE_NAME-$APK_PACKAGE_VERSION" >> /var/log/package-installs.log
fi
EOF
chmod +x /etc/apk/hooks/post-install.d/01-welcome
Service Management Hook
# Automatically manage services
cat > /etc/apk/hooks/post-install.d/10-service-manager << 'EOF'
#!/bin/sh
# Service management based on package names
case "$APK_PACKAGE_NAME" in
nginx)
echo "🔧 Configuring nginx service..."
rc-update add nginx default
rc-service nginx start
echo "✅ Nginx service enabled and started"
;;
docker)
echo "🐳 Configuring Docker service..."
rc-update add docker default
addgroup docker 2>/dev/null || true
echo "✅ Docker service configured"
;;
postgresql*)
echo "🐘 Configuring PostgreSQL..."
rc-update add postgresql default
su - postgres -c "initdb -D /var/lib/postgresql/data" 2>/dev/null || true
echo "✅ PostgreSQL configured"
;;
redis)
echo "🔴 Configuring Redis..."
rc-update add redis default
rc-service redis start
echo "✅ Redis service enabled and started"
;;
esac
EOF
chmod +x /etc/apk/hooks/post-install.d/10-service-manager
Configuration Backup Hook
# Backup configurations before upgrades
cat > /etc/apk/hooks/pre-upgrade.d/01-config-backup << 'EOF'
#!/bin/sh
# Configuration backup before upgrades
BACKUP_DIR="/var/backups/configs/$(date +%Y%m%d_%H%M%S)"
case "$APK_PACKAGE_NAME" in
nginx)
mkdir -p "$BACKUP_DIR/nginx"
cp -r /etc/nginx/* "$BACKUP_DIR/nginx/" 2>/dev/null || true
echo "📦 Nginx configuration backed up to $BACKUP_DIR/nginx"
;;
apache2)
mkdir -p "$BACKUP_DIR/apache2"
cp -r /etc/apache2/* "$BACKUP_DIR/apache2/" 2>/dev/null || true
echo "📦 Apache configuration backed up to $BACKUP_DIR/apache2"
;;
mysql*)
mkdir -p "$BACKUP_DIR/mysql"
cp -r /etc/mysql/* "$BACKUP_DIR/mysql/" 2>/dev/null || true
echo "📦 MySQL configuration backed up to $BACKUP_DIR/mysql"
;;
ssh*)
mkdir -p "$BACKUP_DIR/ssh"
cp -r /etc/ssh/* "$BACKUP_DIR/ssh/" 2>/dev/null || true
echo "📦 SSH configuration backed up to $BACKUP_DIR/ssh"
;;
esac
# Create backup index
echo "$APK_PACKAGE_NAME:$APK_PACKAGE_VERSION:$BACKUP_DIR:$(date)" >> /var/log/config-backups.log
EOF
chmod +x /etc/apk/hooks/pre-upgrade.d/01-config-backup
🔧 Advanced Hook Implementations
Security Hardening Hook
# Automatic security hardening
cat > /etc/apk/hooks/post-install.d/20-security-hardening << 'EOF'
#!/bin/sh
# Security hardening based on package type
case "$APK_PACKAGE_NAME" in
openssh*)
echo "🔒 Applying SSH security hardening..."
# Backup original config
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date +%Y%m%d)
# Apply hardening settings
sed -i 's/#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/#PermitEmptyPasswords.*/PermitEmptyPasswords no/' /etc/ssh/sshd_config
sed -i 's/#Protocol.*/Protocol 2/' /etc/ssh/sshd_config
# Restart SSH service
rc-service sshd restart
echo "✅ SSH security hardening applied"
;;
nginx)
echo "🔒 Applying Nginx security headers..."
# Create security configuration
cat > /etc/nginx/conf.d/security-headers.conf << 'NGINX_EOF'
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'" always;
# Hide server version
server_tokens off;
NGINX_EOF
echo "✅ Nginx security headers configured"
;;
apache2)
echo "🔒 Applying Apache security settings..."
# Create security module configuration
cat > /etc/apache2/conf.d/security.conf << 'APACHE_EOF'
# Security headers
Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set X-XSS-Protection "1; mode=block"
# Hide server information
ServerTokens Prod
ServerSignature Off
APACHE_EOF
# Enable security modules
a2enmod headers
echo "✅ Apache security settings applied"
;;
esac
EOF
chmod +x /etc/apk/hooks/post-install.d/20-security-hardening
Monitoring Integration Hook
# Integration with monitoring systems
cat > /etc/apk/hooks/post-install.d/30-monitoring-integration << 'EOF'
#!/bin/sh
# Monitoring system integration
MONITORING_ENABLED=${MONITORING_ENABLED:-"true"}
if [ "$MONITORING_ENABLED" = "true" ]; then
case "$APK_PACKAGE_NAME" in
nginx|apache2)
echo "📊 Setting up web server monitoring..."
# Create monitoring configuration for Prometheus
mkdir -p /etc/prometheus/exporters
cat > /etc/prometheus/exporters/${APK_PACKAGE_NAME}.yml << 'PROM_EOF'
scrape_configs:
- job_name: 'web-server'
static_configs:
- targets: ['localhost:80', 'localhost:443']
metrics_path: '/metrics'
scrape_interval: 30s
PROM_EOF
echo "✅ Monitoring configuration created"
;;
mysql*|postgresql*)
echo "📊 Setting up database monitoring..."
# Create database monitoring user
DB_MONITOR_PASSWORD=$(openssl rand -base64 32)
echo "DB_MONITOR_PASSWORD=$DB_MONITOR_PASSWORD" >> /etc/environment
echo "✅ Database monitoring prepared"
;;
redis)
echo "📊 Setting up Redis monitoring..."
# Enable Redis info endpoint
echo "# Monitoring enabled by package hook" >> /etc/redis/redis.conf
echo "# Use INFO command for metrics collection" >> /etc/redis/redis.conf
echo "✅ Redis monitoring configured"
;;
esac
# Send notification to monitoring system
if command -v curl >/dev/null 2>&1; then
curl -X POST "${MONITORING_WEBHOOK:-http://localhost:9093/api/v1/alerts}" \
-H "Content-Type: application/json" \
-d "{\"alerts\":[{\"labels\":{\"alertname\":\"PackageInstalled\",\"package\":\"$APK_PACKAGE_NAME\",\"version\":\"$APK_PACKAGE_VERSION\",\"hostname\":\"$(hostname)\"}}]}" \
>/dev/null 2>&1 || true
fi
fi
EOF
chmod +x /etc/apk/hooks/post-install.d/30-monitoring-integration
Cleanup and Maintenance Hook
# System cleanup after package removal
cat > /etc/apk/hooks/post-remove.d/01-cleanup << 'EOF'
#!/bin/sh
# Cleanup after package removal
case "$APK_PACKAGE_NAME" in
nginx)
echo "🧹 Cleaning up Nginx files..."
# Remove custom configurations
rm -f /etc/nginx/conf.d/custom-*.conf
# Clean log files (optional)
if [ "$CLEAN_LOGS" = "true" ]; then
rm -f /var/log/nginx/*.log*
fi
# Remove service from startup
rc-update del nginx default 2>/dev/null || true
echo "✅ Nginx cleanup completed"
;;
docker)
echo "🧹 Cleaning up Docker resources..."
# Stop all containers (if requested)
if [ "$DOCKER_CLEANUP_CONTAINERS" = "true" ]; then
docker stop $(docker ps -aq) 2>/dev/null || true
docker rm $(docker ps -aq) 2>/dev/null || true
fi
# Remove Docker group
delgroup docker 2>/dev/null || true
# Clean Docker data (if requested)
if [ "$DOCKER_CLEANUP_DATA" = "true" ]; then
rm -rf /var/lib/docker/*
fi
echo "✅ Docker cleanup completed"
;;
mysql*|mariadb*)
echo "🧹 Cleaning up database files..."
# Stop database service
rc-service mysql stop 2>/dev/null || true
rc-service mariadb stop 2>/dev/null || true
# Remove from startup
rc-update del mysql default 2>/dev/null || true
rc-update del mariadb default 2>/dev/null || true
# Backup and remove data (if requested)
if [ "$DB_CLEANUP_DATA" = "true" ]; then
mysqldump --all-databases > /var/backups/mysql-final-backup-$(date +%Y%m%d).sql 2>/dev/null || true
rm -rf /var/lib/mysql/*
fi
echo "✅ Database cleanup completed"
;;
esac
# Log removal
echo "$(date): Removed $APK_PACKAGE_NAME-$APK_PACKAGE_VERSION" >> /var/log/package-removals.log
EOF
chmod +x /etc/apk/hooks/post-remove.d/01-cleanup
📊 Hook Management and Configuration
Hook Configuration System
# Create hook configuration file
cat > /etc/apk/hook-config.conf << 'EOF'
# Package Hook Configuration
# Global settings
ENABLE_SECURITY_HARDENING=true
ENABLE_MONITORING_INTEGRATION=true
ENABLE_BACKUP_ON_UPGRADE=true
ENABLE_SERVICE_MANAGEMENT=true
# Cleanup settings
CLEAN_LOGS=false
DOCKER_CLEANUP_CONTAINERS=false
DOCKER_CLEANUP_DATA=false
DB_CLEANUP_DATA=false
# Monitoring settings
MONITORING_ENABLED=true
MONITORING_WEBHOOK=http://localhost:9093/api/v1/alerts
# Backup settings
BACKUP_RETENTION_DAYS=30
CONFIG_BACKUP_DIR=/var/backups/configs
# Notification settings
[email protected]
NOTIFICATION_SLACK_WEBHOOK=
EOF
# Load configuration in hooks
echo 'source /etc/apk/hook-config.conf 2>/dev/null || true' | \
tee -a /etc/apk/hooks/*/01-welcome > /dev/null
Hook Testing Framework
# Create hook testing utility
cat > /usr/local/bin/test-hooks << 'EOF'
#!/bin/sh
# Hook testing utility
PACKAGE_NAME="$1"
PACKAGE_VERSION="$2"
ACTION="$3"
if [ -z "$PACKAGE_NAME" ] || [ -z "$ACTION" ]; then
echo "Usage: $0 <package-name> <package-version> <action>"
echo "Actions: install, upgrade, remove"
exit 1
fi
# Set up test environment
export APK_PACKAGE_NAME="$PACKAGE_NAME"
export APK_PACKAGE_VERSION="$PACKAGE_VERSION"
export APK_ACTION="$ACTION"
export APK_ROOT="/"
export APK_USER="root"
echo "Testing hooks for package: $PACKAGE_NAME ($ACTION)"
echo "=============================================="
# Determine hook directory
case "$ACTION" in
install)
HOOK_DIRS="/etc/apk/hooks/pre-install.d /etc/apk/hooks/post-install.d"
;;
upgrade)
HOOK_DIRS="/etc/apk/hooks/pre-upgrade.d /etc/apk/hooks/post-upgrade.d"
;;
remove)
HOOK_DIRS="/etc/apk/hooks/pre-remove.d /etc/apk/hooks/post-remove.d"
;;
*)
echo "Invalid action: $ACTION"
exit 1
;;
esac
# Execute hooks in test mode
for hook_dir in $HOOK_DIRS; do
if [ -d "$hook_dir" ]; then
echo "Executing hooks in $hook_dir:"
for hook in "$hook_dir"/*; do
if [ -x "$hook" ]; then
echo " Running: $(basename "$hook")"
export APK_HOOK_TEST_MODE=true
"$hook"
echo " Exit code: $?"
fi
done
fi
done
echo "Hook testing completed"
EOF
chmod +x /usr/local/bin/test-hooks
# Test hooks
test-hooks nginx 1.24.0 install
test-hooks docker 24.0.5 upgrade
test-hooks mysql 8.0.34 remove
Hook Performance Monitoring
# Create hook performance monitor
cat > /etc/apk/hooks/post-install.d/00-performance-monitor << 'EOF'
#!/bin/sh
# Performance monitoring for hooks
HOOK_START_TIME=$(date +%s.%N)
HOOK_NAME=$(basename "$0")
# Function to log performance
log_performance() {
HOOK_END_TIME=$(date +%s.%N)
EXECUTION_TIME=$(echo "$HOOK_END_TIME - $HOOK_START_TIME" | bc -l)
echo "$(date): $APK_PACKAGE_NAME:$HOOK_NAME:${EXECUTION_TIME}s" >> /var/log/hook-performance.log
}
# Trap to ensure performance logging
trap log_performance EXIT
# Continue with normal hook execution
EOF
chmod +x /etc/apk/hooks/post-install.d/00-performance-monitor
# Copy to other hook directories
for dir in /etc/apk/hooks/{pre-install,pre-upgrade,post-upgrade,pre-remove,post-remove}.d; do
cp /etc/apk/hooks/post-install.d/00-performance-monitor "$dir/"
done
🔍 Hook Debugging and Troubleshooting
Debug Mode Hooks
# Create debug wrapper for hooks
cat > /usr/local/bin/debug-hook << 'EOF'
#!/bin/sh
# Hook debugging wrapper
HOOK_FILE="$1"
shift
echo "Debug: Executing hook $HOOK_FILE"
echo "Debug: Environment variables:"
env | grep APK_ | while read var; do
echo " $var"
done
echo "Debug: Arguments: $@"
echo "Debug: Working directory: $(pwd)"
echo "Debug: User: $(whoami)"
# Execute hook with debug output
if [ -x "$HOOK_FILE" ]; then
echo "Debug: Starting hook execution..."
bash -x "$HOOK_FILE" "$@"
EXIT_CODE=$?
echo "Debug: Hook execution completed with exit code: $EXIT_CODE"
return $EXIT_CODE
else
echo "Debug: Hook file not executable or not found"
return 1
fi
EOF
chmod +x /usr/local/bin/debug-hook
Hook Error Handling
# Enhanced error handling in hooks
cat > /etc/apk/hooks/post-install.d/00-error-handler << 'EOF'
#!/bin/sh
# Error handling wrapper for hooks
set -e # Exit on error
# Error reporting function
report_error() {
local error_msg="$1"
local hook_name="$(basename "$0")"
echo "❌ Error in hook $hook_name: $error_msg" >&2
echo "$(date): ERROR in $hook_name for $APK_PACKAGE_NAME: $error_msg" >> /var/log/hook-errors.log
# Send notification (if configured)
if [ -n "$NOTIFICATION_EMAIL" ]; then
echo "Hook error in $hook_name for package $APK_PACKAGE_NAME: $error_msg" | \
mail -s "Alpine Package Hook Error" "$NOTIFICATION_EMAIL" 2>/dev/null || true
fi
}
# Set up error trap
trap 'report_error "Unexpected error at line $LINENO"' ERR
# Validation functions
validate_package_name() {
if [ -z "$APK_PACKAGE_NAME" ]; then
report_error "APK_PACKAGE_NAME not set"
exit 1
fi
}
validate_action() {
case "$APK_ACTION" in
install|upgrade|remove) ;;
*) report_error "Unknown action: $APK_ACTION"; exit 1 ;;
esac
}
# Run validations
validate_package_name
validate_action
EOF
chmod +x /etc/apk/hooks/post-install.d/00-error-handler
🚀 Enterprise Hook Examples
Compliance and Auditing Hook
# Compliance and auditing automation
cat > /etc/apk/hooks/post-install.d/40-compliance << 'EOF'
#!/bin/sh
# Compliance and auditing hook
COMPLIANCE_LOG="/var/log/compliance-audit.log"
AUDIT_SERVER="${AUDIT_SERVER:-audit.company.com}"
# Log compliance event
log_compliance_event() {
local event_type="$1"
local details="$2"
timestamp=$(date -Iseconds)
hostname=$(hostname)
user=$(whoami)
# Create compliance record
compliance_record=$(cat << JSON
{
"timestamp": "$timestamp",
"hostname": "$hostname",
"user": "$user",
"event_type": "$event_type",
"package": "$APK_PACKAGE_NAME",
"version": "$APK_PACKAGE_VERSION",
"action": "$APK_ACTION",
"details": "$details"
}
JSON
)
# Log locally
echo "$compliance_record" >> "$COMPLIANCE_LOG"
# Send to audit server (if available)
if command -v curl >/dev/null 2>&1; then
curl -X POST "https://$AUDIT_SERVER/api/compliance" \
-H "Content-Type: application/json" \
-d "$compliance_record" \
>/dev/null 2>&1 || true
fi
}
# Check for security-sensitive packages
case "$APK_PACKAGE_NAME" in
openssh*|sudo|doas)
log_compliance_event "SECURITY_PACKAGE_INSTALL" "Critical security package installed"
;;
nginx|apache2|httpd*)
log_compliance_event "WEB_SERVER_INSTALL" "Web server package installed"
;;
mysql*|postgresql*|mariadb*)
log_compliance_event "DATABASE_INSTALL" "Database server package installed"
;;
esac
# Check for compliance violations
if [ "$APK_PACKAGE_NAME" = "telnet" ] || [ "$APK_PACKAGE_NAME" = "rsh" ]; then
log_compliance_event "COMPLIANCE_VIOLATION" "Insecure package installed: $APK_PACKAGE_NAME"
echo "⚠️ WARNING: Package $APK_PACKAGE_NAME violates security policy"
fi
EOF
chmod +x /etc/apk/hooks/post-install.d/40-compliance
Orchestration Integration Hook
# Container orchestration integration
cat > /etc/apk/hooks/post-install.d/50-orchestration << 'EOF'
#!/bin/sh
# Kubernetes/Docker integration hook
K8S_NAMESPACE="${K8S_NAMESPACE:-default}"
DOCKER_REGISTRY="${DOCKER_REGISTRY:-registry.company.com}"
# Update container images based on installed packages
case "$APK_PACKAGE_NAME" in
nginx)
if command -v kubectl >/dev/null 2>&1; then
echo "🚀 Updating Kubernetes nginx deployments..."
# Patch deployment with new image
kubectl patch deployment nginx-deployment \
-n "$K8S_NAMESPACE" \
-p '{"spec":{"template":{"metadata":{"annotations":{"restarted-at":"'$(date -Iseconds)'"}}}}}'
echo "✅ Kubernetes nginx deployment updated"
fi
;;
redis)
if command -v docker >/dev/null 2>&1; then
echo "🐳 Updating Docker Redis containers..."
# Update running Redis containers
docker ps --format "table {{.Names}}" | grep redis | while read container; do
docker restart "$container"
done
echo "✅ Docker Redis containers updated"
fi
;;
esac
# Send update notification to orchestration system
if [ -n "$ORCHESTRATION_WEBHOOK" ]; then
curl -X POST "$ORCHESTRATION_WEBHOOK" \
-H "Content-Type: application/json" \
-d "{\"event\":\"package_updated\",\"package\":\"$APK_PACKAGE_NAME\",\"version\":\"$APK_PACKAGE_VERSION\",\"node\":\"$(hostname)\"}" \
>/dev/null 2>&1 || true
fi
EOF
chmod +x /etc/apk/hooks/post-install.d/50-orchestration
🎯 Best Practices and Guidelines
Hook Development Standards
# Hook template with best practices
cat > /usr/local/share/apk-hook-template << 'EOF'
#!/bin/sh
# Hook Template - Follow these guidelines
# 1. Always start with shebang
# 2. Set error handling
set -e
# 3. Source configuration
source /etc/apk/hook-config.conf 2>/dev/null || true
# 4. Define functions first
cleanup() {
# Cleanup code here
return 0
}
# 5. Set up traps
trap cleanup EXIT
# 6. Validate environment
if [ -z "$APK_PACKAGE_NAME" ]; then
echo "Error: APK_PACKAGE_NAME not set" >&2
exit 1
fi
# 7. Main logic with case statements
case "$APK_PACKAGE_NAME" in
target-package)
echo "Processing $APK_PACKAGE_NAME..."
# Hook logic here
;;
*)
# Exit silently for non-target packages
exit 0
;;
esac
# 8. Always provide feedback
echo "✅ Hook completed successfully"
EOF
chmod +x /usr/local/share/apk-hook-template
Hook Security Considerations
- Validate all inputs 🔍
- Use absolute paths 📍
- Implement proper error handling ⚠️
- Log all actions 📝
- Test in isolated environments 🧪
- Follow principle of least privilege 🔒
🎉 Conclusion
Custom package hooks in Alpine Linux provide powerful automation capabilities for system administration and package management. By implementing well-designed hooks, you can ensure consistent system configuration, security compliance, and operational efficiency.
Key takeaways:
- Design hooks for specific package lifecycle events ⚙️
- Implement comprehensive error handling and logging 📊
- Follow security best practices and validation 🔐
- Test hooks thoroughly before deployment 🧪
- Document hook behavior and dependencies 📚
With custom package hooks, you can transform package management from a manual process into a fully automated, reliable system! 🚀