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.