Skip to content

docs(blog): rootless design and PUID/PGID rationale#3105

Open
fallenbagel wants to merge 2 commits into
developfrom
docs-blogpost-about-rootless-image
Open

docs(blog): rootless design and PUID/PGID rationale#3105
fallenbagel wants to merge 2 commits into
developfrom
docs-blogpost-about-rootless-image

Conversation

@fallenbagel

@fallenbagel fallenbagel commented Jun 2, 2026

Copy link
Copy Markdown
Member

Description

Adds a blog post explaining why Seerr runs rootless and does not support PUID/PGID environment variables, covering the security rationale behind the decision and the correct chown approach for setting up host directory permissions.

How Has This Been Tested?

(This is a blog post).

Screenshots / Logs (if applicable)

image

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
    • Added a guide explaining Seerr’s rootless container security model and why PUID/PGID environment variables aren’t supported.
    • Describes the non-root runtime and stricter dependency handling, plus host-side steps to set mounted data ownership to UID/GID 1000.
    • Includes a platform-specific note for Unraid and reaffirms the project’s current security posture.

@fallenbagel fallenbagel requested a review from Copilot June 2, 2026 20:21
@fallenbagel fallenbagel requested a review from a team as a code owner June 2, 2026 20:21
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new blog post documenting why Seerr avoids PUID/PGID (requires starting the container as root to run chown), describes Seerr’s rootless shipping (runs as the node user), and instructs users to pre-own bind-mounted data directories on the host with UID/GID 1000.

Changes

Seerr Rootless Security Blog Post

Layer / File(s) Summary
Rootless container security explanation
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md
Blog post front-matter and content explaining that PUID/PGID relies on running the container as root to chown at startup (undermining security), describing Seerr's shipped rootless approach using the official Node.js node user and pnpm constraints, instructing host-side ownership of mounted data directories to UID/GID 1000 with a chown -R 1000:1000 ... example, including an Unraid note and concluding position statement.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 In rootless fields I nibble notes tonight,
No startup chown — we keep permissions right.
Mounts owned by one-zero-zero-zero, set with care,
Host hands tidy files so Seerr can fare.
A quiet hop, secure and light, I share.

🚥 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 summarizes the main change: a new blog post explaining why Seerr runs rootless and does not support PUID/PGID environment variables.
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.


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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new Docusaurus blog post documenting Seerr’s rootless-by-default container design, explaining why PUID/PGID env-based user switching is not supported, and guiding users toward the correct host-side chown workflow.

Changes:

  • Introduces a new blog article detailing the security rationale for avoiding root entrypoints and PUID/PGID.
  • Documents the recommended host bind-mount permissions setup (chown to UID/GID 1000).
  • Links to upstream references (Docker, OWASP, Node.js Docker image docs) and related Seerr docs (Unraid).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md Outdated
@fallenbagel fallenbagel force-pushed the docs-blogpost-about-rootless-image branch from 864d30e to ca5d0d3 Compare June 2, 2026 20:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md (1)

6-6: ⚡ Quick win

Consider using a commit hash or tag for the image URL.

The image URL references refs/heads/develop, which points to the latest commit on the develop branch. This means the image could change unexpectedly with future commits, or break if the branch is renamed or deleted.

📎 Suggested fix: pin to a specific commit or release tag
-image: https://raw.githubusercontent.com/seerr-team/seerr/refs/heads/develop/gen-docs/static/img/logo_full.svg
+image: https://raw.githubusercontent.com/seerr-team/seerr/<commit-hash-or-tag>/gen-docs/static/img/logo_full.svg
🤖 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 `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md` at line 6, The image URL
currently uses the mutable path "refs/heads/develop" (the line with image:
https://raw.githubusercontent.com/seerr-team/seerr/refs/heads/develop/gen-docs/static/img/logo_full.svg),
which can change or break; update that URL to pin to an immutable identifier by
replacing "refs/heads/develop" with a specific commit SHA or a release tag
(e.g., the commit hash or a vX.Y.Z tag) so the image is stable, and verify the
updated URL serves correctly in the blog post (adjust other references to
logo_full.svg if necessary).
🤖 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 `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md`:
- Line 53: Replace the broken relative link
"./getting-started/third-parties/unraid" in the blog content with an absolute
site path (e.g. "/getting-started/third-parties/unraid") so the link resolves
correctly from /blog/[slug]/ pages; locate the string
"./getting-started/third-parties/unraid" in the blog post and update it to the
absolute path.
- Line 38: Update the sentence about pnpm to tighten security claims: state that
pnpm's content-addressable store, hard links and non-hoisted/symlinked
node_modules layout (mentioning hoist=false/semi-strict hoisting) reduce
phantom-dependency risks, and separately attribute mitigation of
dependency-confusion attacks to correct registry scoping (e.g.,
.npmrc/private-registry scoping) plus hardened install controls
(lockfile/integrity checks, lifecycle-script controls), rather than implying the
CAS/hard-links alone prevent dependency confusion.

---

Nitpick comments:
In `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md`:
- Line 6: The image URL currently uses the mutable path "refs/heads/develop"
(the line with image:
https://raw.githubusercontent.com/seerr-team/seerr/refs/heads/develop/gen-docs/static/img/logo_full.svg),
which can change or break; update that URL to pin to an immutable identifier by
replacing "refs/heads/develop" with a specific commit SHA or a release tag
(e.g., the commit hash or a vX.Y.Z tag) so the image is stable, and verify the
updated URL serves correctly in the blog post (adjust other references to
logo_full.svg if necessary).
🪄 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: a5effe10-83ff-4b8d-88ee-c2f5544abffc

📥 Commits

Reviewing files that changed from the base of the PR and between 759e359 and 864d30e.

📒 Files selected for processing (1)
  • gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md

Comment thread gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md Outdated
Comment thread gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md (1)

38-38: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Tighten pnpm security claims: separate phantom dependencies from dependency confusion mitigation.

As noted in the previous review, the claim about dependency confusion needs refinement. While pnpm's content-addressable store and non-hoisted structure do reduce phantom dependencies, dependency confusion attacks are primarily mitigated through registry scoping (.npmrc configuration for private registries) and install-time controls (lockfile integrity checks, lifecycle script restrictions), not through pnpm's internal architecture alone.

Consider rewording to: "Unlike npm, pnpm uses a content-addressable store with hard links and does not hoist packages into a flat node_modules structure, preventing phantom dependencies. Combined with proper registry scoping and strict install controls, this approach strengthens defense against supply chain attacks."

🤖 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 `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md` at line 38, Update the
paragraph that begins "We also use pnpm as our package manager..." to separate
claims about phantom dependencies and dependency confusion: keep the explanation
that pnpm's content-addressable store, hard links, and non-hoisted node_modules
prevent phantom dependencies, but then add that dependency confusion is
primarily mitigated by registry scoping and install-time controls (e.g., .npmrc
private registries, lockfile integrity, lifecycle script restrictions); replace
the existing sentence with the suggested rewording "Unlike npm, pnpm uses a
content-addressable store with hard links and does not hoist packages into a
flat node_modules structure, preventing phantom dependencies. Combined with
proper registry scoping and strict install controls, this approach strengthens
defense against supply chain attacks."
🧹 Nitpick comments (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md (1)

10-10: 💤 Low value

Consider rephrasing for clarity.

The sentence "why chown is not the workaround it might seem like at first glance. It is actually the correct approach" creates unnecessary uncertainty by framing it as "not a workaround" before clarifying it's correct. Consider direct phrasing like: "This post explains the reasoning behind that decision and why using chown on the host is the correct approach."

🤖 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 `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md` at line 10, The sentence
currently phrased as "why chown is not the workaround it might seem like at
first glance. It is actually the correct approach." should be rewritten to a
direct, clear statement; replace that fragment in the paragraph that begins "A
common question we get..." with a concise alternative such as "This post
explains the reasoning behind that decision and why using chown on the host is
the correct approach." Update the string in the blog text so the paragraph reads
smoothly and removes the contradictory "not a workaround" phrasing.
🤖 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.

Duplicate comments:
In `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md`:
- Line 38: Update the paragraph that begins "We also use pnpm as our package
manager..." to separate claims about phantom dependencies and dependency
confusion: keep the explanation that pnpm's content-addressable store, hard
links, and non-hoisted node_modules prevent phantom dependencies, but then add
that dependency confusion is primarily mitigated by registry scoping and
install-time controls (e.g., .npmrc private registries, lockfile integrity,
lifecycle script restrictions); replace the existing sentence with the suggested
rewording "Unlike npm, pnpm uses a content-addressable store with hard links and
does not hoist packages into a flat node_modules structure, preventing phantom
dependencies. Combined with proper registry scoping and strict install controls,
this approach strengthens defense against supply chain attacks."

---

Nitpick comments:
In `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md`:
- Line 10: The sentence currently phrased as "why chown is not the workaround it
might seem like at first glance. It is actually the correct approach." should be
rewritten to a direct, clear statement; replace that fragment in the paragraph
that begins "A common question we get..." with a concise alternative such as
"This post explains the reasoning behind that decision and why using chown on
the host is the correct approach." Update the string in the blog text so the
paragraph reads smoothly and removes the contradictory "not a workaround"
phrasing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7ac23f92-25cf-4e41-903c-947c2d9b1cdc

📥 Commits

Reviewing files that changed from the base of the PR and between 864d30e and ca5d0d3.

📒 Files selected for processing (1)
  • gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md

@fallenbagel fallenbagel force-pushed the docs-blogpost-about-rootless-image branch from ca5d0d3 to d35f102 Compare June 2, 2026 20:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md (1)

38-38: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Tighten the pnpm claim to avoid overstatement of default behavior.

The sentence still reads as absolute (“non-hoisted … prevents phantom dependencies”). pnpm’s defaults are nuanced (semi-strict/hoisting behavior), so this should be phrased as risk reduction under strict config, and dependency-confusion mitigation should be attributed primarily to registry scoping plus install-policy controls.

Proposed wording update
-We also use [pnpm](https://pnpm.io) as our package manager, which takes a stricter and more secure approach to dependency management than npm. Unlike npm, pnpm uses a content-addressable store with hard links and a non-hoisted, symlinked `node_modules` layout that prevents phantom dependencies (packages silently relying on undeclared transitive dependencies). pnpm also ships with hardened install defaults, including integrity verification and lifecycle script controls, that reduce the supply-chain attack surface.
+We also use [pnpm](https://pnpm.io) as our package manager, which takes a stricter approach to dependency management than npm. Its content-addressable store and symlinked `node_modules` model can reduce accidental reliance on undeclared transitive dependencies (especially with strict hoisting settings). Separately, dependency-confusion risk is primarily mitigated by correct private-registry scoping and hardened install controls (lockfiles, integrity checks, and lifecycle-script policies).
What are pnpm's current default hoisting semantics (including "semi-strict" behavior), and which controls are documented for dependency-confusion mitigation (registry scoping, lockfiles, integrity checks, lifecycle script policies)?
🤖 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 `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md` at line 38, The pnpm
description overstates defaults; revise the sentence that begins "Unlike npm,
pnpm uses a content-addressable store..." to soften absolutes: note pnpm uses a
content-addressable store and a strict/non-hoisted-by-default layout with
"semi-strict" hoisting semantics rather than claiming it outright prevents
phantom dependencies, and state it can reduce dependency-supply risks when
configured correctly (e.g., strict install policies). Also attribute
dependency-confusion mitigation to registry scoping, lockfiles, integrity
verification, and lifecycle script controls (rather than implying npm-style
issues are fully prevented by pnpm alone).
🤖 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.

Duplicate comments:
In `@gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md`:
- Line 38: The pnpm description overstates defaults; revise the sentence that
begins "Unlike npm, pnpm uses a content-addressable store..." to soften
absolutes: note pnpm uses a content-addressable store and a
strict/non-hoisted-by-default layout with "semi-strict" hoisting semantics
rather than claiming it outright prevents phantom dependencies, and state it can
reduce dependency-supply risks when configured correctly (e.g., strict install
policies). Also attribute dependency-confusion mitigation to registry scoping,
lockfiles, integrity verification, and lifecycle script controls (rather than
implying npm-style issues are fully prevented by pnpm alone).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1f461edc-d395-4e39-aaf0-dbc115f876ea

📥 Commits

Reviewing files that changed from the base of the PR and between ca5d0d3 and d35f102.

📒 Files selected for processing (1)
  • gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md

@fallenbagel fallenbagel force-pushed the docs-blogpost-about-rootless-image branch from d35f102 to 5e86513 Compare June 2, 2026 20:48
@fallenbagel fallenbagel changed the title fix(blog): rootless design and PUID/PGID rationale docs(blog): rootless design and PUID/PGID rationale Jun 2, 2026
@fallenbagel fallenbagel force-pushed the docs-blogpost-about-rootless-image branch 4 times, most recently from 5668438 to 9dcfc97 Compare June 2, 2026 21:57
@fallenbagel fallenbagel force-pushed the docs-blogpost-about-rootless-image branch from 9dcfc97 to 79bd30c Compare June 2, 2026 21:59
Comment thread gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md Outdated
Comment thread gen-docs/blog/2026-06-03-why-seerr-runs-rootless.md
@M0NsTeRRR

Copy link
Copy Markdown
Member

Maybe add the blog link into https://docs.seerr.dev/getting-started/docker/ something like "PUID/PGUID is not supported if you want to find out why check our blog blabla"

For additional hardening, you can mount the container filesystem as [read-only](https://docs.docker.com/reference/compose-file/services/#read_only) and grant write access only to your data directory. Since all runtime writes go through `CONFIG_DIRECTORY`, nothing outside that volume needs to be writable.
:::

If you need the PUID/PGID pattern, third-party images that implement it already exist. But it is not something we will maintain here, because it would mean knowingly reintroducing a security regression we deliberately moved away from.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It might also be worth while to note that "adding PGID/GUID+root, as an option, besides running as a limited user, while possible, also would require significant additional testing and maintenance requirements to an unreasonable degree"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

To be honest, not really. We could use s6-overlay, which is what everyone uses when they support PUID/PGID, like LinuxServer.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

While s6-overlay, in theory, would support offering the two options, it is flaky at best.
Even through s6-overlay supporting both requires the same maintenance and testing burden as doing so with out it.

(I know, having worked with about a hundred s6-overlay based containers in Helm-Charts, its extremely unreliable weither the "offer both options" features work)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@fallenbagel it might be worth mentioning that then?

@fallenbagel fallenbagel force-pushed the docs-blogpost-about-rootless-image branch from 0834c2c to 7850bbc Compare June 10, 2026 21:56
@seerr-automation-bot seerr-automation-bot added this to the v3.4.0 milestone Jun 10, 2026
@fallenbagel

Copy link
Copy Markdown
Member Author

Maybe add the blog link into https://docs.seerr.dev/getting-started/docker/ something like "PUID/PGUID is not supported if you want to find out why check our blog blabla"

Follow up pr once this is merged

@fallenbagel fallenbagel enabled auto-merge (squash) June 10, 2026 23:27
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.

6 participants