How to run a script at startup in Linux
How to Run a Script at Startup in Linux
Running scripts automatically at system startup is a fundamental requirement for Linux system administrators, developers, and power users. Whether you need to start services, mount drives, initialize applications, or perform maintenance tasks, Linux provides several robust methods to execute scripts during the boot process. This comprehensive guide explores multiple approaches to autostart scripts in Linux, from traditional methods to modern systemd implementations.
Table of Contents
- [Prerequisites and Requirements](#prerequisites-and-requirements)
- [Method 1: Using systemd (Recommended)](#method-1-using-systemd-recommended)
- [Method 2: Using Cron Jobs](#method-2-using-cron-jobs)
- [Method 3: Using init.d Scripts](#method-3-using-initd-scripts)
- [Method 4: Desktop Environment Autostart](#method-4-desktop-environment-autostart)
- [Method 5: Using rc.local](#method-5-using-rclocal)
- [Method 6: Profile and Bashrc Files](#method-6-profile-and-bashrc-files)
- [Practical Examples and Use Cases](#practical-examples-and-use-cases)
- [Troubleshooting Common Issues](#troubleshooting-common-issues)
- [Best Practices and Security Considerations](#best-practices-and-security-considerations)
- [Performance Optimization Tips](#performance-optimization-tips)
- [Conclusion](#conclusion)
Prerequisites and Requirements
Before implementing startup scripts in Linux, ensure you have the following prerequisites:
System Requirements
- Linux distribution with appropriate init system (systemd, SysV, or Upstart)
- Root or sudo privileges for system-wide scripts
- Basic understanding of shell scripting
- Text editor (nano, vim, or gedit)
Essential Knowledge
- Command line navigation and file permissions
- Understanding of Linux boot process
- Basic shell scripting concepts
- System service management fundamentals
Preparation Steps
1. Identify your init system: Most modern distributions use systemd, but older systems may use SysV init or Upstart.
```bash
# Check if systemd is running
ps --no-headers -o comm 1
# Alternative method
systemctl --version
```
2. Create a test script: Before implementing complex automation, create a simple test script to verify functionality.
```bash
#!/bin/bash
echo "Startup script executed at $(date)" >> /var/log/startup-test.log
```
3. Set proper permissions: Ensure your script has execute permissions.
```bash
chmod +x /path/to/your/script.sh
```
Method 1: Using systemd (Recommended)
Systemd is the modern init system used by most contemporary Linux distributions including Ubuntu 16.04+, CentOS 7+, Debian 8+, and Fedora. It provides robust service management with dependency handling, logging, and restart capabilities.
Creating a systemd Service
Step 1: Create the Service File
Create a service unit file in the `/etc/systemd/system/` directory:
```bash
sudo nano /etc/systemd/system/my-startup-script.service
```
Step 2: Define the Service Configuration
```ini
[Unit]
Description=My Custom Startup Script
After=network.target
Wants=network.target
[Service]
Type=oneshot
ExecStart=/path/to/your/script.sh
RemainAfterExit=yes
StandardOutput=journal
StandardError=journal
User=root
Group=root
[Install]
WantedBy=multi-user.target
```
Step 3: Service Configuration Explanation
[Unit] Section:
- `Description`: Human-readable description of the service
- `After`: Specifies dependencies - service starts after network is available
- `Wants`: Soft dependency - service wants network but won't fail without it
[Service] Section:
- `Type=oneshot`: Service runs once and exits
- `ExecStart`: Path to the script or command to execute
- `RemainAfterExit=yes`: Service remains active after script completion
- `StandardOutput/StandardError`: Redirect output to systemd journal
- `User/Group`: Specify the user context for script execution
[Install] Section:
- `WantedBy`: Defines the target that should include this service
Step 4: Enable and Start the Service
```bash
Reload systemd daemon to recognize new service
sudo systemctl daemon-reload
Enable service to start at boot
sudo systemctl enable my-startup-script.service
Start service immediately (optional)
sudo systemctl start my-startup-script.service
Check service status
sudo systemctl status my-startup-script.service
```
Advanced systemd Configuration
Environment Variables
```ini
[Service]
Type=oneshot
ExecStart=/path/to/your/script.sh
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
Environment="CUSTOM_VAR=value"
EnvironmentFile=/etc/environment
```
Restart Policies
```ini
[Service]
Type=simple
ExecStart=/path/to/your/script.sh
Restart=always
RestartSec=10
StartLimitInterval=60
StartLimitBurst=3
```
Dependencies and Ordering
```ini
[Unit]
Description=Database Backup Script
After=mysql.service postgresql.service
Requires=mysql.service
Conflicts=shutdown.target
```
Method 2: Using Cron Jobs
Cron provides time-based job scheduling, including the ability to run scripts at system startup using the `@reboot` directive.
System-wide Cron Jobs
Step 1: Edit System Crontab
```bash
sudo crontab -e
```
Step 2: Add Reboot Entry
```bash
@reboot /path/to/your/script.sh
```
Step 3: Advanced Cron Scheduling
```bash
Run script at reboot with logging
@reboot /path/to/your/script.sh >> /var/log/startup-script.log 2>&1
Run script at reboot with delay
@reboot sleep 60 && /path/to/your/script.sh
Run multiple commands
@reboot /bin/bash -c 'cd /opt/myapp && ./startup.sh'
```
User-specific Cron Jobs
For user-specific startup tasks:
```bash
Edit user crontab
crontab -e
Add reboot entry for user context
@reboot /home/username/scripts/user-startup.sh
```
Cron Environment Considerations
Cron runs with a minimal environment. Specify full paths and set environment variables:
```bash
#!/bin/bash
Set PATH explicitly
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
Set other required environment variables
export HOME=/root
export USER=root
Your script logic here
/usr/local/bin/my-application --start
```
Method 3: Using init.d Scripts
The init.d method is traditional but still widely supported, especially useful for creating services that need start/stop/restart functionality.
Creating an init.d Script
Step 1: Create the Script
```bash
sudo nano /etc/init.d/my-service
```
Step 2: Script Template
```bash
#!/bin/bash
my-service My Custom Service
chkconfig: 35 99 99
description: Custom service description
. /etc/rc.d/init.d/functions
USER="root"
DAEMON="my-application"
ROOT_DIR="/opt/myapp"
SERVER="$ROOT_DIR/$DAEMON"
LOCK_FILE="/var/lock/subsys/my-service"
start() {
if [ -f $LOCK_FILE ]; then
echo "Service is already running"
return 1
fi
echo -n "Starting $DAEMON: "
runuser -l "$USER" -c "$SERVER" && echo_success || echo_failure
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch $LOCK_FILE
return $RETVAL
}
stop() {
if [ ! -f "$LOCK_FILE" ]; then
echo "Service is not running"
return 1
fi
echo -n "Shutting down $DAEMON: "
pid=$(ps -aefw | grep "$DAEMON" | grep -v " grep " | awk '{print $2}')
kill -9 $pid > /dev/null 2>&1
[ $? -eq 0 ] && echo_success || echo_failure
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f $LOCK_FILE
return $RETVAL
}
restart() {
stop
start
}
status() {
if [ -f $LOCK_FILE ]; then
echo "$DAEMON is running."
else
echo "$DAEMON is stopped."
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
restart
;;
*)
echo "Usage: {start|stop|status|restart}"
exit 1
;;
esac
exit $?
```
Step 3: Enable the Service
```bash
Make script executable
sudo chmod +x /etc/init.d/my-service
Add to startup (Debian/Ubuntu)
sudo update-rc.d my-service defaults
Add to startup (RedHat/CentOS)
sudo chkconfig my-service on
Start the service
sudo service my-service start
```
Method 4: Desktop Environment Autostart
For GUI applications and user-specific scripts that should run when a user logs into their desktop environment.
XDG Autostart Method
Step 1: Create Desktop Entry
```bash
nano ~/.config/autostart/my-script.desktop
```
Step 2: Desktop Entry Configuration
```ini
[Desktop Entry]
Type=Application
Name=My Startup Script
Comment=Runs my custom startup script
Exec=/home/username/scripts/startup.sh
Icon=application-x-executable
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
StartupNotify=false
Terminal=false
```
Step 3: System-wide Autostart
For all users:
```bash
sudo nano /etc/xdg/autostart/my-script.desktop
```
Desktop Environment Specific Methods
GNOME
```bash
Using GNOME Tweaks
gnome-tweaks
Or using gsettings
gsettings set org.gnome.desktop.application-folders folder-children "['my-scripts']"
```
KDE
```bash
Copy script to autostart directory
cp /path/to/script.sh ~/.config/autostart-scripts/
chmod +x ~/.config/autostart-scripts/script.sh
```
Method 5: Using rc.local
The rc.local method is simple but deprecated in many modern distributions. It's still available for backward compatibility.
Implementing rc.local
Step 1: Check if rc.local Exists
```bash
ls -la /etc/rc.local
```
Step 2: Create or Edit rc.local
```bash
sudo nano /etc/rc.local
```
Step 3: Add Your Script
```bash
#!/bin/bash
rc.local
This script is executed at the end of each multiuser runlevel.
Make sure that the script will "exit 0" on success or any other
value on error.
Add your script here
/path/to/your/script.sh &
Always exit with 0
exit 0
```
Step 4: Make Executable and Enable
```bash
sudo chmod +x /etc/rc.local
For systemd systems, enable rc.local service
sudo systemctl enable rc-local.service
```
Method 6: Profile and Bashrc Files
For user-specific environment setup and lightweight scripts that should run when users log in.
System-wide Profile Scripts
/etc/profile
```bash
sudo nano /etc/profile
```
Add at the end:
```bash
Custom startup script
if [ -x /opt/scripts/system-startup.sh ]; then
/opt/scripts/system-startup.sh
fi
```
/etc/bash.bashrc
```bash
sudo nano /etc/bash.bashrc
```
User-specific Profile Scripts
~/.bashrc
```bash
nano ~/.bashrc
```
Add:
```bash
Custom user startup script
if [ -f ~/scripts/user-startup.sh ]; then
source ~/scripts/user-startup.sh
fi
```
~/.profile
```bash
nano ~/.profile
```
Practical Examples and Use Cases
Example 1: Database Backup Service
Create an automated database backup service using systemd:
```bash
/opt/scripts/db-backup.sh
#!/bin/bash
BACKUP_DIR="/backups/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/db-backup.log"
mkdir -p $BACKUP_DIR
echo "$(date): Starting database backup" >> $LOG_FILE
mysqldump -u backup_user -p'password' --all-databases > $BACKUP_DIR/backup_$DATE.sql
if [ $? -eq 0 ]; then
echo "$(date): Backup completed successfully" >> $LOG_FILE
# Keep only last 7 days of backups
find $BACKUP_DIR -name "backup_*.sql" -mtime +7 -delete
else
echo "$(date): Backup failed" >> $LOG_FILE
fi
```
Systemd service file:
```ini
[Unit]
Description=Database Backup Service
After=mysql.service
Requires=mysql.service
[Service]
Type=oneshot
ExecStart=/opt/scripts/db-backup.sh
User=backup
Group=backup
[Install]
WantedBy=multi-user.target
```
Example 2: Network Drive Mounting
Automatically mount network drives at startup:
```bash
#!/bin/bash
/opt/scripts/mount-drives.sh
MOUNT_POINT="/mnt/network-storage"
NFS_SERVER="192.168.1.100:/exports/data"
LOG_FILE="/var/log/mount-drives.log"
Wait for network to be ready
sleep 30
echo "$(date): Attempting to mount network drive" >> $LOG_FILE
Create mount point if it doesn't exist
mkdir -p $MOUNT_POINT
Mount the drive
mount -t nfs $NFS_SERVER $MOUNT_POINT
if [ $? -eq 0 ]; then
echo "$(date): Network drive mounted successfully" >> $LOG_FILE
else
echo "$(date): Failed to mount network drive" >> $LOG_FILE
fi
```
Example 3: Application Server Startup
Start a custom application server with proper error handling:
```bash
#!/bin/bash
/opt/myapp/startup.sh
APP_DIR="/opt/myapp"
APP_USER="appuser"
PID_FILE="/var/run/myapp.pid"
LOG_FILE="/var/log/myapp/startup.log"
cd $APP_DIR
Check if already running
if [ -f $PID_FILE ] && kill -0 $(cat $PID_FILE) 2>/dev/null; then
echo "$(date): Application is already running" >> $LOG_FILE
exit 1
fi
Start the application
echo "$(date): Starting application server" >> $LOG_FILE
sudo -u $APP_USER ./myapp --daemon --pid-file=$PID_FILE
Verify startup
sleep 5
if [ -f $PID_FILE ] && kill -0 $(cat $PID_FILE) 2>/dev/null; then
echo "$(date): Application started successfully" >> $LOG_FILE
else
echo "$(date): Application failed to start" >> $LOG_FILE
exit 1
fi
```
Troubleshooting Common Issues
Issue 1: Script Not Executing
Symptoms: Script doesn't run at startup, no error messages.
Solutions:
1. Check permissions:
```bash
ls -la /path/to/script.sh
chmod +x /path/to/script.sh
```
2. Verify shebang line:
```bash
head -1 /path/to/script.sh
# Should show: #!/bin/bash
```
3. Test script manually:
```bash
/path/to/script.sh
```
4. Check service status (systemd):
```bash
systemctl status my-service.service
journalctl -u my-service.service
```
Issue 2: Environment Variables Missing
Symptoms: Script fails due to missing environment variables or PATH issues.
Solutions:
1. Set environment explicitly in script:
```bash
#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
export HOME=/root
```
2. Use absolute paths:
```bash
/usr/bin/python3 /opt/scripts/myscript.py
```
3. Source environment files:
```bash
source /etc/environment
source ~/.bashrc
```
Issue 3: Timing and Dependencies
Symptoms: Script fails because required services aren't ready.
Solutions:
1. Add delays:
```bash
sleep 30 # Wait 30 seconds
```
2. Check service availability:
```bash
while ! systemctl is-active --quiet mysql; do
sleep 5
done
```
3. Use proper systemd dependencies:
```ini
[Unit]
After=network-online.target
Wants=network-online.target
```
Issue 4: Permission Denied Errors
Symptoms: Script fails with permission denied errors.
Solutions:
1. Check file ownership:
```bash
chown root:root /path/to/script.sh
```
2. Verify directory permissions:
```bash
chmod 755 /path/to/script/directory
```
3. Use appropriate user context:
```ini
[Service]
User=appropriate-user
Group=appropriate-group
```
Issue 5: Logging and Debugging
Enable comprehensive logging:
```bash
#!/bin/bash
Enable debugging
set -x
Redirect all output to log file
exec > /var/log/startup-script.log 2>&1
echo "Script started at $(date)"
echo "Running as user: $(whoami)"
echo "Current directory: $(pwd)"
echo "Environment variables:"
env
Your script logic here
```
Best Practices and Security Considerations
Security Best Practices
1. Use Least Privilege Principle:
```bash
# Run services as dedicated users, not root
useradd -r -s /bin/false myservice
```
2. Secure File Permissions:
```bash
chmod 750 /path/to/script.sh
chown root:root /path/to/script.sh
```
3. Input Validation:
```bash
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "Error: Configuration file not found"
exit 1
fi
```
4. Avoid Hardcoded Credentials:
```bash
# Use configuration files or environment variables
source /etc/myapp/config
DB_PASSWORD=$(cat /etc/myapp/db_password)
```
Performance Optimization
1. Parallel Execution:
```bash
# Run independent tasks in parallel
task1.sh &
task2.sh &
wait # Wait for all background jobs
```
2. Resource Management:
```ini
[Service]
MemoryLimit=512M
CPUQuota=50%
IOSchedulingClass=2
IOSchedulingPriority=4
```
3. Conditional Execution:
```bash
# Only run if necessary
if [ ! -f /var/lib/myapp/initialized ]; then
initialize_application
touch /var/lib/myapp/initialized
fi
```
Monitoring and Maintenance
1. Health Checks:
```bash
# Add health check to your script
check_service_health() {
if ! curl -f http://localhost:8080/health; then
echo "Service health check failed"
return 1
fi
}
```
2. Log Rotation:
```bash
# /etc/logrotate.d/my-startup-script
/var/log/startup-script.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
}
```
3. Monitoring Integration:
```bash
# Send notifications on failure
if ! /path/to/critical-script.sh; then
echo "Critical script failed" | mail -s "Startup Failure" admin@company.com
fi
```
Performance Optimization Tips
Startup Time Optimization
1. Minimize Boot Dependencies:
- Only include necessary dependencies in systemd units
- Use `Wants` instead of `Requires` when possible
- Implement proper ordering with `After` and `Before`
2. Asynchronous Operations:
```bash
# Run time-consuming tasks in background
long_running_task &
TASK_PID=$!
# Continue with other tasks
quick_task
# Wait for background task if needed
wait $TASK_PID
```
3. Resource Preallocation:
```bash
# Pre-create directories and files
mkdir -p /var/log/myapp /var/lib/myapp /var/run/myapp
touch /var/log/myapp/application.log
```
System Resource Management
1. Memory Usage:
```ini
[Service]
MemoryAccounting=true
MemoryLimit=256M
MemoryHigh=200M
```
2. CPU Scheduling:
```ini
[Service]
CPUAccounting=true
CPUQuota=25%
Nice=10
```
3. I/O Priority:
```ini
[Service]
IOSchedulingClass=2
IOSchedulingPriority=4
```
Conclusion
Running scripts at startup in Linux offers multiple approaches, each with distinct advantages and use cases. Systemd represents the modern standard with robust features including dependency management, logging, and restart policies, making it the recommended choice for most scenarios. Traditional methods like init.d scripts and cron jobs remain valuable for specific requirements and legacy system compatibility.
When implementing startup scripts, prioritize security by following the principle of least privilege, use proper error handling and logging, and implement appropriate monitoring. Consider the boot sequence timing and dependencies to ensure reliable execution. Regular testing and maintenance of startup scripts ensures system stability and performance.
The choice of method depends on your specific requirements: use systemd for robust service management, cron for simple time-based execution, desktop autostart for GUI applications, and profile scripts for user environment setup. Regardless of the chosen method, comprehensive testing, proper documentation, and regular maintenance are essential for reliable automated startup processes.
By following the practices and examples outlined in this guide, you can implement reliable, secure, and efficient startup automation that enhances your Linux system's functionality and reduces manual intervention requirements.