> ## Documentation Index
> Fetch the complete documentation index at: https://help.freakhosting.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Create a systemd Service File on Linux

> Create a systemd service file in /etc/systemd/system/myapp.service with ExecStart, User and Restart, then run daemon-reload and systemctl enable --now myapp.

To create a systemd service, save a unit file as `/etc/systemd/system/myapp.service` with a `[Unit]`, `[Service]` (including `ExecStart=` and `User=`) and `[Install]` section, then run `sudo systemctl daemon-reload` and `sudo systemctl enable --now myapp`. systemd then starts your program at boot, restarts it if it crashes (with `Restart=on-failure`) and collects its output in `journalctl -u myapp`.

| Difficulty | Time | Works on | Needs |
| - | - | - | - |
| Intermediate | 15 minutes | Ubuntu 22.04 / 24.04, Debian 12 / 13, AlmaLinux / Rocky 9 / 10 and other systemd distributions | sudo or root access |

## Before you start

* [Connect with SSH](https://help.freakhosting.com/portals/other/how-to-connect-to-a-linux-server-with-ssh.md) as a [sudo user](https://help.freakhosting.com/portals/other/how-to-create-a-sudo-user-on-linux.md). Root can leave out `sudo`.
* Your program must run in the **foreground**: started from a terminal, it keeps running until you press `Ctrl+C`. Test it by hand first.
* Know the full path of the program, for example `/usr/bin/node` (find it with `command -v node`) or `/opt/myapp/run.sh`.

## How to create a systemd service

**1. Create a user for the app (recommended)**

Running as its own user limits the damage if the app is compromised.

```bash theme={null}
sudo useradd -r -m -d /opt/myapp -s /usr/sbin/nologin myapp
```

Put your app in `/opt/myapp` and make sure `myapp` owns it: `sudo chown -R myapp:myapp /opt/myapp`.

**2. Write the unit file**

```bash theme={null}
sudo nano /etc/systemd/system/myapp.service
```

Paste this example and change the paths:

```ini theme={null}
[Unit]
Description=My example app
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/run.sh
Restart=on-failure
RestartSec=5
Environment=APP_ENV=production

[Install]
WantedBy=multi-user.target
```

Save with `Ctrl+O`, `Enter`, and exit with `Ctrl+X`.

**3. Check the file for mistakes**

```bash theme={null}
sudo systemd-analyze verify /etc/systemd/system/myapp.service
```

No output means systemd found no problems. A typo such as `Restart=sometimes` gives a line like `Failed to parse service restart specifier, ignoring: sometimes`.

**4. Load, start and enable it**

```bash theme={null}
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
```

## What each line means

| Setting | Meaning |
| - | - |
| `Description=` | Name shown in `systemctl status` |
| `After=` / `Wants=network-online.target` | Start after the network is up |
| `Type=simple` | The program in `ExecStart` is the service and stays in the foreground (the default when `ExecStart` is set) |
| `User=` / `Group=` | Run as this user instead of root |
| `WorkingDirectory=` | Folder the program starts in |
| `ExecStart=` | The command. Use an absolute path for programs outside `/usr/bin` and `/usr/local/bin` |
| `Restart=on-failure` | Restart when it exits with an error or crashes. Default is `no`. `always` restarts even after a clean exit |
| `RestartSec=5` | Wait 5 seconds before restarting (default 100 ms) |
| `Environment=` | Sets an environment variable. Use `EnvironmentFile=/opt/myapp/.env` for many variables or secrets |
| `WantedBy=multi-user.target` | Start it during normal boot when the service is enabled |

### Other service types

| `Type=` | Use it when |
| - | - |
| `simple` / `exec` | The program stays in the foreground (most apps) |
| `forking` | An old-style daemon that puts itself in the background; add `PIDFile=` |
| `oneshot` | A script that runs once and exits; add `RemainAfterExit=yes` if it should count as "active" afterwards |
| `notify` | The program tells systemd when it is ready (supported by some apps) |

## Example: a Node.js or Python app

```ini theme={null}
[Service]
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/node /opt/myapp/server.js
# Python virtual environment instead:
# ExecStart=/opt/myapp/venv/bin/python /opt/myapp/app.py
Restart=on-failure
EnvironmentFile=/opt/myapp/.env
```

`EnvironmentFile` takes `KEY=value` lines. Protect it with `sudo chmod 600 /opt/myapp/.env`. For Node.js apps you can also use PM2; see [Node.js with PM2](https://help.freakhosting.com/portals/other/how-to-install-nodejs-and-run-apps-with-pm2.md).

## How to check it worked

```bash theme={null}
systemctl status myapp
```

```text theme={null}
● myapp.service - My example app
     Loaded: loaded (/etc/systemd/system/myapp.service; enabled; preset: enabled)
     Active: active (running) since Wed 2026-11-04 10:20:11 UTC; 3s ago
```

Follow its output live:

```bash theme={null}
sudo journalctl -u myapp -f
```

To test automatic restarts, find the main PID in the status output and kill it with `sudo kill <PID>`. After `RestartSec` seconds, `systemctl status` shows a new PID.

## How to change or remove the service

* **Change it:** edit the file, then `sudo systemctl daemon-reload` and `sudo systemctl restart myapp`.
* **Override a package's service** (for example nginx) instead of editing its file: `sudo systemctl edit nginx`. Your settings go in a drop-in file that package updates don't overwrite.
* **Remove it:**
  ```bash theme={null}
  sudo systemctl disable --now myapp
  sudo rm /etc/systemd/system/myapp.service
  sudo systemctl daemon-reload
  ```

## Frequently asked questions

### Why does my service show "status=203/EXEC"?

systemd couldn't run `ExecStart`: the path is wrong, the file isn't executable (`chmod +x`), or a script lacks a first line such as `#!/bin/bash`.

### Why does my service start and then stop straight away?

The program goes into the background or exits. Use the app's foreground option, or use `Type=forking` for a classic daemon. Check `journalctl -u myapp` for errors.

### Can I run a service as my own user without sudo?

Yes. Put the file in `~/.config/systemd/user/` and use `systemctl --user`. To keep it running after you log out, run `sudo loginctl enable-linger alex`.

### Should I use a systemd timer instead of cron?

Either works. Timers log to the journal and can catch up missed runs with `Persistent=true`; cron is quicker to set up. See [schedule tasks with cron](https://help.freakhosting.com/portals/other/how-to-schedule-tasks-with-cron.md).

## Related guides

> [card] [VPS and dedicated server guides](https://help.freakhosting.com/portals/other/vps-and-dedicated-server-guides.md)
>
> Every server guide in one place.

> [card] [Manage services with systemctl](https://help.freakhosting.com/portals/other/how-to-manage-services-with-systemctl.md)
>
> Start, stop and enable services.

> [card] [Read logs with journalctl](https://help.freakhosting.com/portals/other/how-to-read-logs-with-journalctl.md)
>
> See your service's output.

> [card] [Deploy a Python app with Gunicorn](https://help.freakhosting.com/portals/other/how-to-deploy-a-python-app-with-gunicorn.md)
>
> A complete systemd example.

> [card] [Environment variables](https://help.freakhosting.com/portals/other/how-to-use-environment-variables-and-bashrc.md)
>
> Pass settings to your app.

***

> [!NOTE]
>
> **Checked against the official [systemd.service](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html) and [systemd.unit](https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html) manuals** on 4 November 2026; the unit file was validated with `systemd-analyze verify` (systemd 255) on Ubuntu 24.04 LTS. Starting the service was not tested because our test container doesn't run systemd as its init system. Commands can differ on other distributions or releases.

> [!NOTE]
>
> ### Need Extra Help?
>
> If you encounter any issues, our support team is ready to assist:
>
> * **Live Chat:** Quick assistance via our website.
> * **Support Ticket:** [Open a Ticket](https://freakhosting.com/clientarea/submitticket.php)
> * **Discord:** [Join our Community](https://discord.gg/freakhosting)
> * **Email:** [support@freakhosting.com](mailto:support@freakhosting.com)

> [!TIP]
>
> ### Save on Your Hosting
>
> Ready to upgrade your hosting? Use code **KB20** at checkout for **20% off** your first order!

***

**Last Updated:** November 2026


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.