How to Run Bash Scripts at Startup

How to Run Bash Scripts at Startup

How to Run Bash Scripts at Startup

I still remember the first time I needed a script to run automatically every time a server rebooted — a small monitoring tool that had to start without anyone logging in manually. It took some trial and error to understand the right approach, because Linux actually offers several different ways to run scripts at startup, and picking the wrong one leads to scripts that silently fail or don’t run in the environment you expect.

This guide walks through every major method for running Bash scripts at startup, from the simplest desktop-friendly options to production-grade systemd services, along with the reasoning behind when to use each one.

Why Startup Scripts Matter

Startup scripts are essential for automating tasks that need to happen every time a machine boots: starting application servers, mounting network drives, setting up environment variables, launching monitoring agents, or running cleanup tasks. Getting this right means your systems recover automatically after a reboot instead of requiring manual intervention.

Method 1: Using systemd (The Modern Standard)

Most modern Linux distributions (Ubuntu 16.04+, CentOS 7+, Debian 8+) use systemd as their init system, and it’s by far the most robust and recommended way to run scripts at startup.

Here’s how to set it up. First, write your script and make it executable:

#!/bin/bash
echo "Starting my custom service..." >> /var/log/mystartup.log
/usr/local/bin/myapp

Save it as /usr/local/bin/mystartup.sh and make it executable:

chmod +x /usr/local/bin/mystartup.sh

Next, create a systemd service unit file at /etc/systemd/system/mystartup.service:

[Unit]
Description=My Custom Startup Script
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/mystartup.sh
Restart=on-failure
User=john

[Install]
WantedBy=multi-user.target

Let’s break down what each section does:

Now reload systemd’s configuration and enable your service:

sudo systemctl daemon-reload
sudo systemctl enable mystartup.service
sudo systemctl start mystartup.service

Check its status any time with:

systemctl status mystartup.service

Method 2: Using crontab with @reboot

If you don’t need the full power of systemd (no restart policies, no dependency management), cron’s @reboot directive is a lightweight alternative.

Open your crontab for editing:

crontab -e

Add a line like this:

@reboot /usr/local/bin/mystartup.sh >> /var/log/mystartup.log 2>&1

This tells cron to run the script exactly once, every time the system boots, and redirect both standard output and errors into a log file so you have a record of what happened. This method is quick, doesn’t require root (each user has their own crontab), and works well for simple personal automation.

Method 3: Using rc.local (Legacy Systems)

Older systems or minimal distributions sometimes still support /etc/rc.local, a script that runs at the end of the boot process.

#!/bin/bash
/usr/local/bin/mystartup.sh &
exit 0

Make sure the file is executable:

sudo chmod +x /etc/rc.local

Note that many modern distributions have deprecated rc.local in favor of systemd, so if it doesn’t exist on your system, you may need to enable it manually or fall back to one of the other methods.

Method 4: Desktop Autostart (.desktop files)

If you’re working on a Linux desktop environment (GNOME, KDE, XFCE) rather than a server, and you want a script to run when you log into your graphical session rather than at full system boot, autostart .desktop files are the right tool.

Create a file at ~/.config/autostart/myscript.desktop:

[Desktop Entry]
Type=Application
Exec=/usr/local/bin/mystartup.sh
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name=My Startup Script
Comment=Runs my custom script at login

This approach ties execution to a desktop login session rather than system boot, which is a meaningful difference — it’s ideal for user-specific tools like a clipboard manager or notification helper, but not appropriate for background services that should run regardless of whether anyone is logged in.

Method 5: Adding to Shell Profile Files

For lightweight tasks tied to opening a terminal session (not full boot), you can add commands directly to ~/.bashrc or ~/.bash_profile:

echo "Welcome back, $(whoami)! Today is $(date)."

This runs every time a new interactive Bash shell starts, which is useful for setting environment variables or printing reminders, but it is not a substitute for a proper startup service, since it only executes when a shell is actually opened.

How systemd, cron, and rc.local Compare

MethodRuns at bootSurvives crash (auto-restart)Runs without loginBest for
systemdYesYes (configurable)YesProduction services
cron @rebootYesNoYesSimple one-off tasks
rc.localYesNoYesLegacy systems
Desktop autostartNo (login only)NoNoDesktop apps
Shell profileNo (shell only)NoNoInteractive shell setup

Real-World Use Cases

1. Application servers. A Node.js, Python, or Java backend that needs to start automatically after every reboot, with automatic restart if it crashes — this is exactly what systemd’s Restart=on-failure is built for.

2. Network mounts. Scripts that mount NFS or SMB shares at boot, ensuring they’re available before dependent applications try to read from them (using After=network-online.target in your systemd unit).

3. IoT and embedded devices. Raspberry Pi projects often use @reboot cron jobs or systemd services to launch sensor-reading scripts automatically whenever the device powers on.

4. Monitoring agents. Lightweight health-check scripts that ping a service and log or alert on failures, running continuously from boot onward.

Best Practices

Security Considerations

Troubleshooting Common Issues

Script works manually but not at boot: This is almost always an environment issue — missing $PATH entries, unset environment variables, or the network not being available yet. Add After=network-online.target and Wants=network-online.target to your systemd unit if your script needs network access.

systemd service fails immediately: Check logs with:

journalctl -u mystartup.service -e

This shows the most recent log entries for that specific service, which usually reveals the exact error.

Cron @reboot job never runs: Confirm the cron daemon itself is enabled and running (systemctl status cron or crond depending on your distro), and check /var/log/syslog or /var/log/cron for related entries.

Common Mistakes to Avoid

FAQs

Q: What’s the best method for a production server? systemd, almost always. It gives you logging, restart policies, dependency ordering, and easy status checks.

Q: Can I run a script at both boot and login? Yes — combine a systemd service (for boot-time execution) with a .desktop autostart entry (for session-specific behavior) if you genuinely need both.

Q: Why does my script fail at boot but work when I run it manually? Almost always an environment difference — missing PATH entries, unavailable network, or a dependency (like a database) that hasn’t started yet.

Q: Is rc.local still supported? On many modern distributions it’s deprecated but can be re-enabled. It’s better to migrate to a systemd unit file for compatibility going forward.

Q: How do I stop a startup script from running automatically? For systemd: sudo systemctl disable mystartup.service. For cron: remove or comment out the @reboot line in crontab -e.

Summary

Running Bash scripts at startup is a foundational skill for anyone managing Linux systems, whether that’s a home server, a cloud VM, or a Raspberry Pi project. systemd is the modern, robust choice for anything resembling a real service, cron’s @reboot is great for quick one-off tasks, and desktop autostart files handle session-specific tools. Pick the method that matches how critical and long-running your task actually is, and always test your script’s behavior in the same environment it will actually run in.

References

Exit mobile version