chore: Create seerr.service - hardened template systemd unit file#3029
chore: Create seerr.service - hardened template systemd unit file#3029keraldi wants to merge 3 commits into
Conversation
Add template systemd unit file to register seerr as systemd service. Includes (some) security hardening as well but can probably be extended. Tested to be working with 'compile from source' and pgsql backend
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds a hardened ChangesSystemd Hardened Deployment
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/getting-started/buildfromsource.mdx (1)
49-86:⚠️ Potential issue | 🟠 Major | ⚡ Quick winMissing prerequisite steps: create the
seerruser and set directory ownership.The hardened unit specifies
User=seerr(line 85) and usesReadWritePaths=/opt/seerr /etc/seerr(line 106), but the documented installation flow never:
- Creates the
seerrsystem user/group —systemctl start seerrwill fail withFailed to determine user credentials: No such process/ unknown user.- Creates
/etc/seerr/directory before writingseerr.confat line 53.- Re-owns
/opt/seerrand/etc/seerrtoseerr:seerraftersudo mkdir(step 1 at line 25 creates/opt/seerras root-owned). WithProtectSystem=strictand the service running asseerr, the app will be unable to write its config/cache under/opt/seerr.Without these steps users following the doc literally will hit an immediate startup failure.
📝 Proposed insertion before the `seerr.conf` step (around line 52)
To run seerr as a systemd service: -1. create the environment file at `/etc/seerr/seerr.conf`: +1. Create the dedicated system user and group that the service will run as: +```bash +sudo useradd --system --no-create-home --shell /usr/sbin/nologin seerr +``` + +2. Set ownership of the working directory so the service user can read/write it: +```bash +sudo chown -R seerr:seerr /opt/seerr +``` + +3. Create the environment file at `/etc/seerr/seerr.conf` (readable only by `seerr`, since it may contain secrets): +```bash +sudo mkdir -p /etc/seerr +sudo touch /etc/seerr/seerr.conf +sudo chown root:seerr /etc/seerr/seerr.conf +sudo chmod 640 /etc/seerr/seerr.conf +``` +Then populate it with: ```bash ## Seerr's default port is 5055, if you want to use both, change this.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/getting-started/buildfromsource.mdx` around lines 49 - 86, The docs miss steps to create the seerr system user and set directory ownership required by the hardened systemd unit (User=seerr, ReadWritePaths=/opt/seerr /etc/seerr) so service startup will fail; update the installation instructions before the seerr.conf creation to: create a system user/group "seerr" (system, no-login), ensure /opt/seerr exists and is chown -R seerr:seerr, create /etc/seerr with proper permissions and ownership (so seerr.conf can be created/edited and is readable by the seerr user), and then proceed to populate /etc/seerr/seerr.conf; reference the unit fields User=seerr and ReadWritePaths when adding these steps so readers understand why the user/ownership changes are necessary.
🧹 Nitpick comments (2)
seerr.service (2)
16-44: 💤 Low valueHardening block is well-chosen overall.
The directive set is internally consistent (capability drop + no-new-privs + namespace/proc isolation + strict FS + syscall allowlist with privileged denylist). A couple of small notes worth thinking about, but not blockers:
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX—AF_NETLINKis correctly retained because libuv/getifaddrs(3)and some name-resolution paths need it on Linux.SystemCallFilter=@system-service mincorefollowed bySystemCallFilter=~@privilegedis fine;@system-servicealready excludes@privileged, so the second line is mostly defense-in-depth — leaving as-is is reasonable.ProtectHome=read-onlycould beyes(no access) since the service has no business reading user homes, but read-only is a safe choice.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@seerr.service` around lines 16 - 44, Review the hardening directives and, if Seerr truly does not need to access user home directories, change ProtectHome=read-only to ProtectHome=yes in the unit file (leave RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX and the SystemCallFilter lines as-is since AF_NETLINK is required for getifaddrs/libuv and `@system-service/`@privileged filtering is intentional); ensure no code paths in the service (startup, config read, or runtime) require reading from /home before making this change.
34-34: 💤 Low valueRemove
/etc/seerrfromReadWritePaths.
EnvironmentFile=/etc/seerr/seerr.confis parsed by systemd before the sandbox is applied, so the service process does not need write access to it. Seerr writes all state toCONFIG_DIRECTORY(which defaults to/opt/seerr/configor is explicitly set as an environment variable), never to/etc/seerr. Tightening this toReadWritePaths=/opt/seerrimproves the security boundary.♻️ Proposed tightening
-ReadWritePaths=/opt/seerr /etc/seerr +ReadWritePaths=/opt/seerr🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@seerr.service` at line 34, Remove the unnecessary write permission by editing the unit's ReadWritePaths setting: change the ReadWritePaths entry so it only includes /opt/seerr (remove /etc/seerr). Update the unit file line that defines ReadWritePaths to reference only /opt/seerr (the identifier to edit is ReadWritePaths) and reload/restart the systemd unit after the change so the tightened sandbox takes effect.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/getting-started/buildfromsource.mdx`:
- Line 71: The docs line suggesting "sudo systemctl edit seerr" is incorrect
because it only creates drop-in overrides; update the sentence mentioning
seerr.service to either remove the "systemctl edit" option or replace it with
"sudo systemctl edit --force --full seerr" and/or recommend copying the shipped
sample unit (e.g., "sudo cp /opt/seerr/seerr.service
/etc/systemd/system/seerr.service" followed by "sudo systemctl daemon-reload");
ensure the text references the sample seerr.service in the repo and presents the
copy-or-manual-create alternatives clearly.
---
Outside diff comments:
In `@docs/getting-started/buildfromsource.mdx`:
- Around line 49-86: The docs miss steps to create the seerr system user and set
directory ownership required by the hardened systemd unit (User=seerr,
ReadWritePaths=/opt/seerr /etc/seerr) so service startup will fail; update the
installation instructions before the seerr.conf creation to: create a system
user/group "seerr" (system, no-login), ensure /opt/seerr exists and is chown -R
seerr:seerr, create /etc/seerr with proper permissions and ownership (so
seerr.conf can be created/edited and is readable by the seerr user), and then
proceed to populate /etc/seerr/seerr.conf; reference the unit fields User=seerr
and ReadWritePaths when adding these steps so readers understand why the
user/ownership changes are necessary.
---
Nitpick comments:
In `@seerr.service`:
- Around line 16-44: Review the hardening directives and, if Seerr truly does
not need to access user home directories, change ProtectHome=read-only to
ProtectHome=yes in the unit file (leave RestrictAddressFamilies=AF_INET AF_INET6
AF_NETLINK AF_UNIX and the SystemCallFilter lines as-is since AF_NETLINK is
required for getifaddrs/libuv and `@system-service/`@privileged filtering is
intentional); ensure no code paths in the service (startup, config read, or
runtime) require reading from /home before making this change.
- Line 34: Remove the unnecessary write permission by editing the unit's
ReadWritePaths setting: change the ReadWritePaths entry so it only includes
/opt/seerr (remove /etc/seerr). Update the unit file line that defines
ReadWritePaths to reference only /opt/seerr (the identifier to edit is
ReadWritePaths) and reload/restart the systemd unit after the change so the
tightened sandbox takes effect.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 24db4e89-0f9a-491d-81c9-2455dc225ccc
📒 Files selected for processing (2)
docs/getting-started/buildfromsource.mdxseerr.service
| Copy the path to node, it should be something like `/usr/bin/node`. | ||
|
|
||
| 3. Create the systemd service file at `/etc/systemd/system/seerr.service`, using either `sudo systemctl edit seerr` or `sudo nano /etc/systemd/system/seerr.service`: | ||
| 3. Create the systemd service file at `/etc/systemd/system/seerr.service`, using either `sudo systemctl edit seerr` or `sudo nano /etc/systemd/system/seerr.service`. A hardened sample `seerr.service` file is located in the project root: |
There was a problem hiding this comment.
sudo systemctl edit seerr won't create the unit from scratch.
Without --force --full, systemctl edit <unit> requires the unit to already exist and only creates a drop-in override (under /etc/systemd/system/seerr.service.d/override.conf) — not the main unit. As written, the "either ... or ..." choice will lead users who pick the first option to a confusing failure.
Either drop the systemctl edit mention, replace it with sudo systemctl edit --force --full seerr, or — given the sample file shipped in the repo — recommend copying it directly.
📝 Suggested rewording
-3. Create the systemd service file at `/etc/systemd/system/seerr.service`, using either `sudo systemctl edit seerr` or `sudo nano /etc/systemd/system/seerr.service`. A hardened sample `seerr.service` file is located in the project root:
+3. Install the systemd unit at `/etc/systemd/system/seerr.service`. The repository ships a hardened sample `seerr.service` in the project root that you can copy directly:
+```bash
+sudo cp /opt/seerr/seerr.service /etc/systemd/system/seerr.service
+sudo systemctl daemon-reload
+```
+Or create it manually with the following contents:🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/getting-started/buildfromsource.mdx` at line 71, The docs line
suggesting "sudo systemctl edit seerr" is incorrect because it only creates
drop-in overrides; update the sentence mentioning seerr.service to either remove
the "systemctl edit" option or replace it with "sudo systemctl edit --force
--full seerr" and/or recommend copying the shipped sample unit (e.g., "sudo cp
/opt/seerr/seerr.service /etc/systemd/system/seerr.service" followed by "sudo
systemctl daemon-reload"); ensure the text references the sample seerr.service
in the repo and presents the copy-or-manual-create alternatives clearly.


Description
Add template systemd unit file to register seerr as systemd service. Includes (some) security hardening as well but can probably be extended.
How Has This Been Tested?
Tested to be working with 'compile from source' and pgsql backend. Spun up a seerr instance with latest build from 2026-05-14 using postgresql backend. Changed settings, requested 2 movies and restarted the service to check persistency. No errors in log.
Screenshots / Logs (if applicable)
Checklist:
pnpm buildpnpm i18n:extractSummary by CodeRabbit