Skip to content

chore: Create seerr.service - hardened template systemd unit file#3029

Open
keraldi wants to merge 3 commits into
seerr-team:developfrom
keraldi:develop
Open

chore: Create seerr.service - hardened template systemd unit file#3029
keraldi wants to merge 3 commits into
seerr-team:developfrom
keraldi:develop

Conversation

@keraldi
Copy link
Copy Markdown

@keraldi keraldi commented May 14, 2026

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:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • Documentation
    • Updated Unix (Linux/macOS) installation guide with a hardened systemd service sample included in the project root.
    • Clarified that the service expects a dedicated seerr user owning the application directory and config.
    • Added security hardening details: namespace isolation, syscall filtering, reduced privileges, and protected filesystem access.

Review Change Stack

keraldi added 2 commits May 14, 2026 17:28
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
@keraldi keraldi requested a review from a team as a code owner May 14, 2026 15:36
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 124e7adf-bb73-4aab-9fd7-6a09921e0866

📥 Commits

Reviewing files that changed from the base of the PR and between e9d4c42 and e38f409.

📒 Files selected for processing (1)
  • docs/getting-started/buildfromsource.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/getting-started/buildfromsource.mdx

📝 Walkthrough

Walkthrough

Adds a hardened seerr.service systemd unit and updates build-from-source docs to reference the bundled sample; the unit includes environment loading, Node.js execution, dedicated seerr user, restart policy, and extensive sandboxing directives.

Changes

Systemd Hardened Deployment

Layer / File(s) Summary
Seerr systemd service definition
seerr.service
New systemd unit with [Unit], [Service], and [Install] sections. Loads /etc/seerr/seerr.conf, runs Node.js app from /opt/seerr as user seerr, restarts on failure, and applies comprehensive hardening: NoNewPrivileges, namespace/device isolation, ProtectSystem=strict, restricted address families and syscall filtering, tightened filesystem and permission settings.
Installation documentation with hardening guidance
docs/getting-started/buildfromsource.mdx
Unix installation instructions updated to point to the hardened seerr.service sample bundled in the project root. The example [Service] block is replaced/extended with security hardening directives and a note that the unit expects a dedicated seerr user owning the app directory and config file.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A config snug in systemd's nest,
With sandboxes trimmed and privileges less,
The docs show the sample to deploy and test,
A tiny user runs the rest,
Securely springing code to rest.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: creating a hardened systemd unit file for Seerr, which matches the primary additions (seerr.service file and documentation updates).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Missing prerequisite steps: create the seerr user and set directory ownership.

The hardened unit specifies User=seerr (line 85) and uses ReadWritePaths=/opt/seerr /etc/seerr (line 106), but the documented installation flow never:

  1. Creates the seerr system user/group — systemctl start seerr will fail with Failed to determine user credentials: No such process / unknown user.
  2. Creates /etc/seerr/ directory before writing seerr.conf at line 53.
  3. Re-owns /opt/seerr and /etc/seerr to seerr:seerr after sudo mkdir (step 1 at line 25 creates /opt/seerr as root-owned). With ProtectSystem=strict and the service running as seerr, 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 value

Hardening 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_UNIXAF_NETLINK is correctly retained because libuv/getifaddrs(3) and some name-resolution paths need it on Linux.
  • SystemCallFilter=@system-service mincore followed by SystemCallFilter=~@privileged is fine; @system-service already excludes @privileged, so the second line is mostly defense-in-depth — leaving as-is is reasonable.
  • ProtectHome=read-only could be yes (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 value

Remove /etc/seerr from ReadWritePaths.

EnvironmentFile=/etc/seerr/seerr.conf is parsed by systemd before the sandbox is applied, so the service process does not need write access to it. Seerr writes all state to CONFIG_DIRECTORY (which defaults to /opt/seerr/config or is explicitly set as an environment variable), never to /etc/seerr. Tightening this to ReadWritePaths=/opt/seerr improves 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

📥 Commits

Reviewing files that changed from the base of the PR and between 92c486d and e9d4c42.

📒 Files selected for processing (2)
  • docs/getting-started/buildfromsource.mdx
  • seerr.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:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

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.

@keraldi
Copy link
Copy Markdown
Author

keraldi commented May 14, 2026

Before:
grafik

After:
grafik

@keraldi keraldi changed the title Create seerr.service - template systemd unit file chore Create seerr.service - template systemd unit file May 14, 2026
@keraldi keraldi changed the title chore Create seerr.service - template systemd unit file chore: Create seerr.service - template systemd unit file May 14, 2026
@keraldi keraldi changed the title chore: Create seerr.service - template systemd unit file chore: Create seerr.service - hardened template systemd unit file May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant