Skip to content

Commit ddfb478

Browse files
committed
feat: update systemd guide with Copyparty example and enhance instructions for user services
1 parent 74bc574 commit ddfb478

1 file changed

Lines changed: 71 additions & 23 deletions

File tree

src/posts/systemd.md

Lines changed: 71 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ You've learned how to write Bash scripts and run Python code. But running a scri
1111

1212
To run something automatically when your Deck boots, we don't put it in a Startup folder like Windows. Instead, we use Linux's master service manager: **systemd**.
1313

14+
> [!NOTE]
15+
> If you installed a tool through Home Manager or Linuxbrew, prefer their built-in service workflows first. Those approaches are more reproducible and easier to maintain. This chapter covers the manual `systemd` route for one-off scripts that are *not* managed by those tools.
16+
1417
## What is systemd?
1518

1619
`systemd` is the central nervous system of SteamOS (and almost all modern Linux systems). It controls what starts up, what shuts down, and what runs in the background.
@@ -22,47 +25,65 @@ When you install an app that runs in the background (like *EmuDeck's* background
2225

2326
## Creating Your First Service
2427

25-
Let's imagine you wrote a Python script called `my-cool-script.py` and saved it in your `Documents` folder. You want it to run quietly in the background as soon as you turn on your Deck.
28+
Let's use a real example: running **Copyparty** as a personal file server in the background, so your Deck is always ready to receive or share files on your local network.
29+
30+
If Copyparty came from Home Manager or Linuxbrew, configure the service there instead of creating a manual unit. The manual unit below is for the unmanaged case where you installed it yourself and want a straightforward autostart.
2631

2732
> [!WARNING]
2833
> You should never run custom scripts as the `root` user unless absolutely necessary. We will use `systemctl --user`, which safely limits your background script to only control things *your* user profile can touch.
2934
30-
### 1. Make the Service File
35+
### 1. Create the Service File
3136

3237
`systemd` looks for your custom background services in a specific hidden folder:
33-
`/home/deck/.config/systemd/user/`
38+
`~/.config/systemd/user/`
3439

35-
Open Konsole and create your new service file, which must end in `.service`.
40+
Create it now:
3641
```bash
37-
nano ~/.config/systemd/user/my-cool-script.service
42+
mkdir -p ~/.config/systemd/user
43+
nano ~/.config/systemd/user/copyparty.service
3844
```
3945

40-
### 2. Write the Instructions
46+
### 2. Write the Unit File
47+
48+
Because Copyparty is a Python package, we can use `uvx` — which you already have from the Python chapter — to run it directly without a separate install step. This keeps the unit file short and means `systemd` doesn't need to know anything about Python paths or virtual environments.
4149

42-
Every service file needs three basic sections: `[Unit]`, `[Service]`, and `[Install]`.
50+
Paste this into nano:
4351

44-
Copy this template into your file:
4552
```ini
4653
[Unit]
47-
Description=My Cool Background Service
48-
After=network.target
54+
Description=Copyparty File Server
55+
After=network-online.target
4956

5057
[Service]
51-
ExecStart=/usr/bin/python3 /home/deck/Documents/my-cool-script.py
58+
WorkingDirectory=/home/deck/Sync
59+
ExecStart=/home/deck/.local/bin/uvx copyparty
5260
Restart=always
5361
RestartSec=10
5462

5563
[Install]
5664
WantedBy=default.target
5765
```
5866

59-
**Let's break this down:**
60-
- `After=network.target` means the script will wait until your Deck connects to Wi-Fi before it runs.
61-
- `ExecStart` is the exact command you would normally type in the terminal. **Important:** You must use full paths in `systemd` files (e.g., `/usr/bin/python3` instead of just `python3`).
62-
- `Restart=always` tells the system: "If this script crashes, wait 10 seconds and start it again automatically."
63-
- `WantedBy=default.target` makes sure it actually starts when you log in.
67+
> [!NOTE]
68+
> If you installed Copyparty through Nix instead of `uvx`, swap the `ExecStart` line for:
69+
> ```
70+
> ExecStart=/nix/var/nix/profiles/default/bin/nix run nixpkgs#copyparty
71+
> ```
72+
> The [upstream unit file](https://raw.githubusercontent.com/9001/copyparty/refs/heads/hovudstraum/contrib/systemd/copyparty.service) is available as a reference, but it targets a system-wide install and needs significant adaptation for a user service — the version above is all you need.
73+
74+
**What these lines mean:**
75+
- `After=network-online.target` — wait for the network to be ready before starting. For a user service, the system will already have brought the network up by the time this runs, but the `After=` line adds an explicit ordering guarantee.
76+
- `WorkingDirectory` — Copyparty serves the current working directory by default, so setting this to your `Sync` folder is all you need. No volume flags required.
77+
- `ExecStart` — `uvx` fetches and runs Copyparty from PyPI in an isolated environment. The web UI is available at `http://<your-deck-ip>:3923` from any device on your network.
78+
- `Restart=always` — if Copyparty crashes, wait 10 seconds and restart it automatically.
79+
- `WantedBy=default.target` — the correct target for user services (not the system-wide `multi-user.target`).
80+
81+
Press `Ctrl+O` then `Enter` to save, then `Ctrl+X` to exit.
6482
65-
Press `Ctrl+O` then `Enter` to save, and `Ctrl+X` to exit out of `nano`.
83+
Then tell systemd about the new file:
84+
```bash
85+
systemctl --user daemon-reload
86+
```
6687
6788
## How to Control Your Service
6889

@@ -72,27 +93,54 @@ Because we put our service in the `user/` folder, we must add the `--user` flag
7293

7394
### Start the script right now:
7495
```bash
75-
systemctl --user start my-cool-script.service
96+
systemctl --user start copyparty.service
7697
```
7798

7899
### Enable it to start automatically on every boot:
79100
```bash
80-
systemctl --user enable my-cool-script.service
101+
systemctl --user enable copyparty.service
81102
```
82103

83104
### Stop the script:
84105
```bash
85-
systemctl --user stop my-cool-script.service
106+
systemctl --user stop copyparty.service
86107
```
87108

88109
### Check if it's running (The ultimate troubleshooting tool):
89110
```bash
90-
systemctl --user status my-cool-script.service
111+
systemctl --user status copyparty.service
112+
```
113+
The `status` command shows whether Copyparty is running and prints the last few lines of its output. If your file server is not reachable, this is the very first command you should run.
114+
115+
### See the full log output:
116+
```bash
117+
journalctl --user -u copyparty.service
91118
```
92-
The `status` command will even print out the last few lines of `print()` statements or errors your script spit out. If your background app isn't working, this is the very first command you should run!
119+
This streams the complete journal for Copyparty. When it starts successfully, you should see a QR code and URL appear in the logs. If it fails, the error message here will be your best clue to what went wrong.
120+
121+
> [!TIP]
122+
> Add `-f` to follow the log live: `journalctl --user -u copyparty.service -f`. Press `Ctrl+C` to stop following.
123+
124+
## Surviving Game Mode: Enable Lingering
125+
126+
There's one gotcha you should know about. By default, Linux only runs your `--user` services while you have an active login session (like Desktop Mode). When you switch back to Game Mode, the system may consider your desktop session "closed" and quietly kill all your background scripts.
127+
128+
The fix is a one-time command called `loginctl enable-linger`:
129+
130+
```bash
131+
loginctl enable-linger deck
132+
```
133+
134+
This tells `systemd`: "Keep this user's services running even when they don't have a desktop session open." After running this once, your services will stay alive in the background whether you're in Desktop Mode, Game Mode, or even if you never open the desktop at all.
135+
136+
> [!TIP]
137+
> You only need to run `loginctl enable-linger` once — it's permanent. You can verify it's active with `loginctl show-user deck | grep Linger`, which should print `Linger=yes`. Run `loginctl disable-linger deck` to revert if you change your mind.
138+
139+
> [!CAUTION]
140+
> Background services consume CPU and battery even while you're gaming. If you notice shorter battery life, a runaway service may be the culprit — check with `systemctl --user status copyparty.service`. Also keep in mind that when your Deck goes to **sleep**, all services are suspended until it wakes back up. If your service needs to do work on a strict schedule, those intervals will slip during sleep.
93141
94142
## The Power of Auto-Start
95143

96-
You just leveled up. Turning scripts into resilient, auto-starting `systemd` services is a core Linux skill. This ensures that your customizations survive reboots, seamlessly blending into the console-like experience of Game Mode.
144+
You just leveled up. Turning scripts into resilient, auto-starting `systemd` services is a core Linux skill for unmanaged, one-off scripts. With lingering enabled, your customizations survive reboots *and* mode switches, seamlessly running in the background whether you're gaming or tinkering.
97145

98146
{% next_chapter %}

0 commit comments

Comments
 (0)