Run programs automatically at server startup (systemd and cron)

Published on Updated on 5 min read

How applications, game servers and scripts start by themselves after every reboot: with a systemd service unit as today's standard, or alternatively through a cron entry with @reboot.

Bringing every service back up by hand after each server reboot costs time and eventually goes wrong. Linux ships with its own mechanism for exactly that. In this guide we show you how to run your own applications, game servers, bots or scripts automatically at server startup.

We cover two approaches: a systemd service unit as the solution used today, and the older route through a cron entry with @reboot. Both work independently of the distribution, so on Debian, Ubuntu, AlmaLinux and Rocky Linux alike.

systemd or cron: which approach fits?

systemd is the standard for services on every current Linux distribution. A cron entry with @reboot does start your application as well, but it cannot do anything beyond that.

Featuresystemd unitcron with @reboot
Starts at bootyesyes
Restart after a crashyes, automaticallyno
Check the statusyes, via systemctlno
Log of the outputyes, in the journalonly if you redirect it yourself
Start order can be controlledyes, after the network for exampleonly roughly, via sleep

For anything that is meant to run permanently, the systemd unit is the better choice. The cron entry stays a quick stopgap for simple one-off commands.

Requirements

  • Root access to your VPS or root server over SSH.
  • A start script or program that already runs cleanly from the command line. Test that by hand first, before you automate it.
  • The absolute path to that script. Relative paths do not work reliably during system startup.

Creating a systemd service unit

Your own units live in /etc/systemd/system/ and end in .service. Create the file:

nano /etc/systemd/system/meinedienst.service

A simple skeleton that works right away looks like this:

[Unit]
Description=Mein eigener Dienst
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=meinbenutzer
WorkingDirectory=/opt/meinedienst
ExecStart=/bin/bash /opt/meinedienst/start.sh
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

What the individual lines mean

  • Description: The plain text name that systemctl status displays.
  • After and Wants: The service only starts once the network is available. That removes the need for the sleep trick you know from cron.
  • Type=simple: The program keeps running in the foreground. If your start script forks into the background by itself, you need Type=forking and a PIDFile entry instead.
  • User: The user the service runs as. Never let applications run as root without a reason.
  • WorkingDirectory: Replaces the cd from a start script.
  • Restart=on-failure: systemd restarts the service after a crash. With Restart=always it does so even when the program exits normally.
  • WantedBy=multi-user.target: Makes sure the service comes up with the regular system startup.

Enabling and testing the service

After every change to a unit file, systemd has to read it in again. Then you enable the service for system startup and start it right away:

systemctl daemon-reload
systemctl enable --now meinedienst.service

To see whether everything is running:

systemctl status meinedienst.service

The output of the application ends up in the journal. The following command lets you follow it live, which is the fastest way to track down a problem:

journalctl -u meinedienst.service -f

To stop it, restart it or disable it permanently:

systemctl stop meinedienst.service
systemctl restart meinedienst.service
systemctl disable meinedienst.service

Example: starting a TeamSpeak 3 server automatically

The start script shipped with TeamSpeak sends itself into the background and creates a PID file. That is why Type=forking is the correct setting here:

[Unit]
Description=TeamSpeak 3 Server
After=network-online.target
Wants=network-online.target

[Service]
Type=forking
User=teamspeak
WorkingDirectory=/home/teamspeak
ExecStart=/home/teamspeak/ts3server_startscript.sh start
ExecStop=/home/teamspeak/ts3server_startscript.sh stop
PIDFile=/home/teamspeak/ts3server.pid
Restart=on-failure
RestartSec=15

[Install]
WantedBy=multi-user.target

Adjust the user name and the directory to match your installation. What matters is that the user you specify really owns the directory.

Example: game server or bot via a start script

For Minecraft, ARK, Arma 3, LinuxGSM servers or a bot you wrote yourself, the simple variant is usually enough. The service runs in the foreground, systemd takes care of monitoring and restarts:

[Unit]
Description=Gameserver
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=gameserver
WorkingDirectory=/home/gameserver/server
ExecStart=/bin/bash /home/gameserver/server/start.sh
Restart=always
RestartSec=15

[Install]
WantedBy=multi-user.target

If several services start at the same time and slow each other down, spread the start out with different values for RestartSec, or extend After= with the name of the unit that has to run first.

Alternative: autostart through cron with @reboot

If you only want to run a single command at boot and do not need any monitoring, a cron entry is enough. First set the editor, then open the crontab:

export VISUAL=nano; crontab -e

Add a line there with @reboot:

@reboot sleep 60 && cd /<PATH-TO-SCRIPT>/ && bash <YOUR-SCRIPT>.sh

The @reboot makes sure the command is executed once at every system startup. The sleep 60 part waits 60 seconds, so that the network and the database are ready beforehand. The command then changes into the directory of your script and starts it.

An example for a voice server that is supposed to run under its own user:

@reboot sleep 45 && cd /home/<TEAMSPEAK-DIRECTORY>/ && sudo -u <TEAMSPEAK-USER> bash ts3server_startscript.sh start

If you add several lines, give each one a different sleep value (at least 45), so that not all services start at the same moment. The value is given in seconds.

Common mistakes

  • The service does not start although it works by hand: Usually an absolute path is missing. Inside a unit and in cron, the PATH environment variable is set very sparsely, so always write /bin/bash /voller/pfad/skript.sh.
  • "Unit not found" right after creating it: You forgot systemctl daemon-reload.
  • The service exits again immediately: The program forks into the background. Use Type=forking with a matching PIDFile, or start the program in foreground mode.
  • Permission errors at startup: The user given in User= is not allowed to access the directory. Check the owner with ls -la.
  • Nothing is running after the boot: The service was started but never enabled. systemctl enable is the step that registers it permanently.

And finally the best test of all: reboot the server once with reboot and then check with systemctl status whether all services are running as expected.

Frequently asked questions

Which is better: systemd or cron with @reboot?
For anything that has to run permanently, systemd is clearly ahead. It restarts the application after a crash, shows you the status and logs the output. A cron entry only runs the command once at boot.
Where do I put my own systemd unit?
Your own unit files belong in /etc/systemd/system/ and end in .service. After every change you have to run systemctl daemon-reload, otherwise systemd does not know the file exists.
My service runs by hand but does not start at boot. Why?
Usually an absolute path is missing, because the PATH environment variable is set very sparsely during system startup. The second most common reason: the service was only started, never enabled permanently with systemctl enable.
How do I see the output of my service?
systemd writes everything to the journal. With journalctl -u meinedienst.service -f you follow the output live, which is the fastest way to track down a problem.
Do I still need screen or tmux for a game server?
No. systemd keeps the process running itself, logs the output and restarts it automatically after a crash. For permanent operation alone, screen and tmux are therefore unnecessary.

Autostart systemd Crontab Linux Game Server TeamSpeak3 Server Boot